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 | return |
---|---|
[6, 10, 2] | "6210" |
[3, 30, 34, 5, 9] | "9534330" |
def solution(numbers):
if not any(numbers):
return "0"
numbers = [str(num) for num in numbers]
# numbers = list(map(str, numbers))
# functional programming 방식이지만 comprehension 방식 보다 소요시간이 길다.
numbers.sort(key = lambda x : x * 3, reverse = True)
return "".join(numbers)
첫 번째 풀이 방법은 수학적 해결 방안이다. list의 숫자 비교 시 자리수를 통합하기 위해 3을 곱해 sorting한다.
any
any
는 iterable한 객체 요소에 하나라도 Trusy한 값이 있다면 True(boolean 값)를 반환해 주는 함수이다. 이 문제에서는 numbers
의 요소로 모두 0이 들어올 경우 함수 return 값으로 0을 주기 위해 사용되었다.if not any(numbers):
# same w/
def any(iterable_obj) -> bool:
for element in iterable_obj:
if element:
return True
return False
x * 3
의 이유x * 3
수학적 풀이법인 이유이자 핵심이다. 굳이 3인 이유는 1000이하의 수라는 제한 사항이 있기 때문이다.x * 3
을 하여 자릿수를 늘린 수를 비교해보면 555 vs 545454가 된다. 이 두 숫자는 str형태로 비교되어 아스키코드의 크기에 따라 555가 앞으로 오게 된다.key = lambda x : x * 3
from functools import cmp_to_key
def compare_nums(num1: str, num2: str) -> int:
compare1 = (num2 + num1) > (num1 + num2)
compare2 = (num2 + num1) < (num1 + num2)
return compare1 - compare2
def solution(numbers: list) -> str:
if not any(numbers):
return "0"
numbers = [str(num) for num in numbers]
numbers.sort(key = cmp_to_key(compare_nums))
return "".join(numbers)
const solution = function(numbers) {
let str_numbers = numbers.map((num) => num.toString())
let sorted_numbers = str_numbers.sort((n1, n2) => (n2 + n1) - (n1 + n2))
let answer = sorted_numbers.join("")
return answer[0] === "0" ? "0" : answer
}
많은 사람들이 사용한 방법을 내 스타일로 다시 풀어보았다. 개인적으로는 이 방법이 1번 풀이보다 출제된 의도에 더 부합한 해결방법인 것 같다. 또한 제한 사항과 상관없이 주어진 문제를 해결할 수 있는 코드이기도 하고, 내장 모듈인 functools와 customize된 비교 함수를 작성 해 인접한 두 수의 합을 비교해 소팅하는 형식으로 이루어져 있다.
numbers
의 모든 요소가 0일 때 리턴 값이 0이어야 하기 때문에 예외 처리 코드를 넣어놓았다. python의 경우에는 any
함수를 사용해 미리 처리될 수 있게 하였고 javascript에서는 삼항연산자를 이용해 처리했다.
boolean
값인 True
와 False
끼리 연산이 된다는 사실을 처음 알 수 있었다. compare1 - compare2
은 결국 True - False
, False - True
또는 False - False
인데 세 경우 각각 1, -1, 0으로 반환된다. 이건 나중에도 요긴하게 쓸 수 있을 것 같다.
print(True - False) # 1
print(False - True) # -1
print(True - True) # 0
print(False - False) # 0
print(True + True) # 2
print(False + False) # 0
방법 1 | 방법 2 |
---|---|
![]() | ![]() |
두 방법의 소요시간은 확연한 차이가 난다. 내장 모듈을 활용하여 계산한 결과가 더 오래걸리는 것을 확인할 수 있었다.
1줄 코딩 해결 방법
def solution(numbers):
return str(int("".join(sorted([str(num) for num in numbers], key = lambda x : x * 3, reverse = True))))
const solution = function(numbers) {
return numbers.map((num) => num.toString()).sort((a, b) => (b + a) - (a + b)).join("")[0] === "0" ? "0" : numbers.map((num) => num.toString()).sort((a, b) => (b + a) - (a + b)).join("")
}
물론 좋은 해결방법은 아니다. ^모^