✔Algorithm/programmers/정렬/level2/가장 큰 수 (with python)

yellow·2021년 6월 8일
0

알고리즘 문제

목록 보기
26/58

📖문제

❌ 시행 착오

문제에서 numbers의 원소가 1000 이하라고 했으니, 최대 3자리 수라는 걸 알 수 있다. 그래서 numbers에 있는 원소들을 모두 3자리로 만들어놓고 비교하도록 했다.

풀이 과정

  1. 주어진 리스트의 모든 요소를 문자열로 변환
  2. 비교를 위한 리스트를 생성. 이 리스트에는 [비교 숫자(3자리), 원래 숫자]가 담긴다.
  3. 비교 숫자를 만들어서 2.에서 만든 리스트에 담아주기

3자리로 만드는 과정

  • 주어진 숫자가 한 자리 수일 때
    -> 해당 숫자로 남은 자리수를 채운다.(원래 숫자가 3일 때, 비교 숫자는 333)
  • 주어진 숫자가 두 자리 수일 때
    -> 해당 숫자의 첫 숫자로 남은 자리수를 채운다.
    (원래 숫자가 12일 때, 비교 숫자는 121)
  • 주어진 숫자가 세 자리 수 이상일 때
    -> 원래 숫자와 비교 숫자는 같다.
  1. 비교 숫자를 기준으로 2.리스트를 내림차순으로 정렬한다. 그런데 비교하는 두 개의 숫자가 같을 경우에는 원래 숫자의 길이가 짧은 것이 먼저 오도록 순서를 정한다.
  2. 2.리스트에 있는 원래 숫자들을 순서대로 answer에 담는다.
# 잘못된 코드입니다~!
def solution(numbers):

    # 1. 주어진 리스트의 모든 요소를 문자열로 변환
    numbers = list(map(str, numbers))
    # 2. 비교를 위한 리스트 생성 [비교 숫자, 원래 숫자]
    cmp_list = list()
    
    # 3. 비교 숫자를 만들어서 cmp_list에 추가해주기
    for num in numbers:
        if len(num) == 1: # 한 자리 수일 때
            cmp_list.append([num * 3, num])
        elif len(num) == 2: # 두 자리 수일 때
            cmp_list.append([num + num[0], num])
        else: # 세 자리 수 이상일 때
            cmp_list.append([num, num])
            
    # 4. 비교숫자 기준으로 cmp_list 내림차순 정렬하기
    cmp_list = sorted(cmp_list, key=lambda x : (x[0], -len(x[1])), reverse = True)
    
    # 5. cmp_list에 있는 원래 숫자들을 순서대로 answer에 담기
    answer = []
    for i in cmp_list:
        answer.append(i[1])
    
    return str(int(''.join(answer)))

문제점

풀이과정 4번에서 cmp_list를 정렬할 때, 정렬의 두번째 조건인 "원래 숫자의 길이가 짧은 것이 앞에 오도록 한다"가 잘못된 생각이었다.
이 조건을 생각하게 된 이유는
예를들어 numbers = [121, 121]인 경우를 생각해보자. 위의 풀이과정 3번까지 수행하면 cmp_list = [["121", "121"], ["121", "12"]]이 된다. 이때 비교 숫자는 "121"로 같기 때문에 추가적인 조건이 없으면 "12112"를 답으로 내어 틀리게 되기 때문이었다. 따라서 정답 "12121"을 내기 위해서 길이조건을 넣어주었다.
하지만 numbers = [10,101]인 경우를 생각해보면 길이가 짧은 "10"보다 "101"이 먼저 나와야 정답이므로 내 풀이과정은 틀렸다.
결론적으로 문자열을 어떻게 조합하는 게 숫자가 더 큰지 비교하는 과정이 있어야 하는데, 그러면 굳이 주어진 리스트의 모든 원소를 3자리수로 만들어줄 필요가 없어진다.


이번 문제는 모두 다른 사람들의 코드를 참고하여 작성하였다😢 분발해야지

📝 풀이과정1과 ⌨코드1

문자열을 어떻게 조합하는 것이 숫자가 더 큰지 비교하는 방법!

import functools

# 숫자 문자열 2개가 주어졌을 때 어느 조합이 더 큰지 알아내서 큰 수가 뒤에 오도록 만드는 비교 함수 
def cmp(x, y):
    t1 = x + y
    t2 = y + x
    # 리턴값이 음수이면 t1이 앞에, 리턴값이 양수이면 t2가 앞에 온다.
    return int(t1) - int(t2)

def solution(numbers):
    # 1. 주어진 리스트의 모든 요소를 문자열로 변환
    numbers = list(map(str, numbers))
    # 2. functools.cmp_to_key에 내가 만든 비교함수를 넣어서 정렬
    answer = sorted(numbers, key=functools.cmp_to_key(cmp), reverse = True)
    
    return str(int(''.join(answer)))

📝 풀이과정2와 ⌨코드2

모든 수를 3자리 이상으로 만들어서 문자열 비교를 통한 방법!

def solution(numbers):
    # 1. 주어진 리스트의 모든 요소를 문자열로 변환
    numbers = list(map(str, numbers))
    # 2. 모든 수를 3자리 이상으로 만들어서 key값으로 사용하여 정렬
    order = sorted(numbers, key=lambda x: x * 3, reverse=True)
    answer = str(int(''.join(order)))

    return answer

☺ 느낀점

내 풀이가 풀이과정1과 풀이과정2의 중간점 정도에 있는 것 같다는 느낌이 많이 들었다. 내 풀이에서 좀만 더 생각했으면 모든 테스트케이스를 통과할 수 있었을 텐데...좀 아쉬웠다 흑흑
솔직히 풀이과정2를 처음 봤을 때는 '내 풀이와 뭐가 다른 거지?'라는 생각을 했다. 왜냐하면 최대 숫자가 1000인데, 네자리수는 1000뿐이고 만약 1000이 배열에 담아서 들어온다고 해도 1000은 항상 맨 끝에 와야 가장 큰 수를 만들 수 있기 때문에, 숫자들을 비교할 때 세 자리 수까지만 비교해도 된다고 생각했기 때문이다.
하지만 [10, 101]과 같이 세자리를 다 채웠을 때 같은 값을 가지게 되는 경우에 어떻게 처리할 건지 생각해내는 게 이 문제에서 가장 중요한 포인트였던 것 같다.

profile
할 수 있어! :)

0개의 댓글