지난포스트 (deprecated)/Algorithm & Data Structure (deprecated)

[정렬] 가장큰수 with JS - Lv2

.log('FE') 2018. 12. 19. 12:11
728x90
반응형

* 프로그래머스 > 코딩테스트연습 > 정렬 > 가장 큰 수

 

 

문제설명

 

0 또는 양의 정수가 주어졌을 때, 정수를 이어 붙여 만들 수 있는 가장 큰 수를 알아내 주세요.

 

예를 들어, 주어진 정수가 [6, 10, 2]라면 [6102, 6210, 1062, 1026, 2610, 2106]를 만들 수 있고, 이중 가장 큰 수는 6210입니다.

 

0 또는 양의 정수가 담긴 배열 numbers가 매개변수로 주어질 때, 순서를 재배치하여 만들 수 있는 가장 큰 수를 문자열로 바꾸어 return 하도록 solution 함수를 작성해주세요.

 

 

제한사항

 

- numbers의 길이는 1 이상 100,000 이하입니다.
- numbers의 원소는 0 이상 1,000 이하입니다.
- 정답이 너무 클 수 있으니 문자열로 바꾸어 return 합니다.

 

 

입출력 예

 

numbers = [6, 10, 2]

return = "6210"

 

numbers = [3, 30, 34, 5, 9]

return "9534330"

 

 

Step 1. 생각해보기

 

어떻게하면 쉽게 풀수 있을까 어떤 규칙이 있을까 등을 한번 생각해봤는데

제일 왼쪽에 있는 앞에있는 자릿수에 따라 숫자가 나오는것같습니다.

 

첫번째 [6, 10, 2]

 

비교를위해 한자리 숫자에만 뒤에 0을 붙여서 만들어보면

 

[60, 10, 20]

 

정렬하면

 

[60, 20, 10]

 

붙였던 0을 빼면

 

[6, 2, 10]

 

이걸 하나로 합치면

 

"6210"

 

 

 

설명은 생략하고 두번째 예제도 한번 해봅니다.

 

두번째 [3, 30, 34, 5, 9]

 

[30, 30, 34, 50, 90]

 

[90, 50, 34, 30, 30]

 

[9, 5, 34, 3, 30]

 

"9534330"

 

 

Step 2. 코드로 짜기

 

function solution(numbers) {
var a = numbers.sort(function(i, j){
return (
String(j).length < 2 ? j + '0' : j
) - (
String(i).length < 2 ? i + '0' : i
);
})
return a.map(convert => String(convert))
.reduce((k, z) => k + z);


}

 

- sort() 함수로 정렬을 할건데 어떻게 할건지 내부에 함수로 정의합니다.

- 자릿수가 1자리인것만 0을 붙여서 비교를 하기위해 3항연산자를 만들고

- 2자릿수 이하면 0을붙이고 아니면 그냥 출력한 후에

- 큰수부터 정렬하기위해 j - i 를 해줍니다.

- 마지막으로 정렬된 배열을 문자형으로 바꾸고 reduce 로 문자화된 배열을 하나의 값으로 합쳐줍니다.

 

 

Step 3. 테스트

 

 

 

실행 테스트는 통과하였습니다.

 

 

 

정확성 테스트....심각하네요 겨우 3개 통과했습니다.

 

 

 

Step 4. Why?

 

1. 2자릿수비교만 생각함

제한사항중에 numbers 의 원소는 0~1,000 까지 라고 되어있습니다.

즉 두자릿수 이상의 숫자도 얼마든지 들어올 수 있고 그 부분의 테스트가 실패했을거라 생각합니다.

 

2. 예외

만약 주어진 numbers 가 [0, 0, 0, 0] 이라면? 그냥 0이 나오면 됩니다.

그러나 숫자로 바꿔주었기 때문에 0000 이 나와버립니다. 이 부분도 문제가 될 수 있다고 하네요

 

3. 특이한 경우?

그럼 그냥 가장 많은 자릿수를 가진 숫자만큼 다른숫자들을 0을 붙여서 비교해서 출력하면 되지않을까 싶었는데 [12, 121] 같은경우 "12121" 이 가장 큰수 입니다. 하지만 제가 하는 방식대로 진행해버리면

 

[120, 121] => [121, 120] => [121, 12] => "12112"

 

가 나와버린다는거죠

 

자릿수 숫자만 맞춰서 비교해주면 될거라 생각했는데 생각해야 할 부분이 많습니다.

 

 

Step 5. 그렇다면 어떻게?

 

다른분의 예시로 힌트를 좀 받았는데

 

해당숫자를 반복하는데 4자릿수에서 딱 자르고 비교를하고 [0, 0, 0, 0] 이렇게 0만 나오는 경우는 예외처리로 넘겨주면 될것같습니다.

 

그렇게하면 위의 [12,121] 도 다른 값들도 적용이 가능합니다.

 

[12, 121] => [1212, 1211(21)] => [12, 121] => "12121"

* (잘린숫자)

 

나머지도 한번 해보겠습니다.

 

[6, 10, 2] => [6666, 1010, 2222] => [6666, 2222, 1010] => [6, 2, 10] => "6210"

 

[3, 30, 34, 5, 9] => [3333, 3030, 3434, 5555, 9999] =>

                                                  [9999, 5555, 3434, 3333, 3030] => [9, 5, 34, 3, 30] => "9534330"

 

 

일단 가능한것같습니다. 혹시 또 다른 상황이 예외에 대해 제시할 부분이 있다면 댓글로 달아주시면 감사하겠습니다.

 

 

Step 6. 리팩토링

 

function solution(numbers) {
if(numbers.reduce((a, b) => a + b) === 0 ) {
return "0";
} else {
var x = numbers.sort(function(i, j) {
return (String(j).repeat(4).slice(0, 4)) - (String(i).repeat(4).slice(0, 4))
})
var result = x.map(answer => String(answer)).reduce((a, b) => a + b);
return result;
}
}

 

 

- if 문으로 배열을 돌면서 만약 모두 값이 0이라면 "0" 을 리턴합니다.

- 변수 x 에는 j - i 의 역순의 배열을 넣을겁니다.

- repeat() 메소드는 문자만 가능합니다. 따라서 sting 으로 변경된 숫자를 4번 반복합니다.

- 자릿수가 1의자릿수도 있기때문에 4번 반복 후 slice(0, 4) 로 왼쪽부터 4자릿수로 끊어줍니다.

- x 에는 내부에 정의한 함수대로 정렬된 배열이 들어가고

- result 에는 그 배열을 문자로 치환하고 모든 문자의 합을 더하는 함수를 작성합니다.

 

 

프로그래머스 실행테스트 및 정확성테스트 모두 통과하였습니다.

질문하기에 다른 분들이 남겨준 예외상황이나 특수한 상황에 대한 힌트가 있었어서 풀 수 있었습니다.

 

세상엔 참 똑똑한 사람들이 많습니다. 힌트 감사합니다.

 

 

Step 7. 다른사람의 풀이

 

function solution(numbers) {
var answer = numbers.map(v => v + '')
.sort((a, b) => (b + a) * 1 - (a + b) * 1)
.join('');


return answer[0]==='0'?'0':answer;
}

 

정말 심플합니다.

 

저와 다른점은 String 을 이용한 문자열 변환이 아닌 map() 메소드로 해결해 버렸네요

sort() 메소드 또한 저와는 다른 방식의 풀이 입니다.

그리고 전 reduce() 메서드를 이용했는데 join() 으로도 간단하게 합쳐버릴수가 있네요

 

마지막으로 삼항연산자를 사용하여 0의 예외처리와 답변 부분까지 깔끔하게 처리되었네요

 

 

 

code-reading 블로그에 방문해 주셔서 환영합니다.
댓글은 모두 환영하니 많이 달아주세요.

 

 

728x90
반응형