[Programmers] 큰 수 만들기

Updated:

문제링크

문제 해설

주어진 string 형태의 숫자에서 k개의 수를 제거했을 때 얻을 수 있는 가장 큰 숫자를 구하는 문제이다. 단 숫자의 순서는 바뀌어서는 안된다.

가장 쉽게 접근할 수 있는 방법으로는 입력 숫자의 길이가 l일 때 (l-k) 길이의 모든 숫자 조합을 구하여 이들 중 max값을 찾으면 된다. 하지만 입력 숫자의 길이가 길어질수록 조합을 구하는데 많은 연산이 필요하기 때문에 이 방법으로 문제를 해결하게 되면 정답이 될 수는 있으나 효율성에서 통과하기 어렵다.

따라서 나는 다음과 같은 방법으로 조금 더 효율적인 알고리즘을 구상하였다.

주어진 number의 앞 숫자부터 차례대로 answer에 이어 붙인다.

이 때 붙이려는 수를 $C$, 제거 횟수를 $K$, 그리고 제거 후 길이를 $L = len(number) - K$ 로 정의하자.

만약 $C$가 마지막 수보다 작은 경우, 현재 answer의 길이가 $L$보다 작다면 answer에 $C$를 이어붙인다. 현재 answer의 길이가 이미 $L$이 되었다면 더이상 수를 이어붙일 수 없으므로 $C$를 버린다 (이 때 $C$라는 수를 제거했기 때문에 $K$가 차감된다).

$C$가 answer의 마지막 수보다 큰 경우에는 answer의 뒤에서부터 $C$보다 큰 수가 나올 때 까지 차례대로 숫자를 제거한다 (마찬가지로 answer의 숫자를 제거할 때마다 $K$를 1씩 감소시킨다).

위 알고리즘을 코드로 구현한 것이 아래와 두 풀이이다.

python 코드

# Solution 1
def solution(number, k):
    answer = ""
    for c in number:
        if not answer or answer[-1] >= c:
            if len(answer) < len(number)-k:
                answer += c
        else:
            while answer and k > 0 and answer[-1] < c:
                answer = answer[:-1]
                k -= 1
            answer += c

    return answer
    
# Solution 2
def solution(number, k):
    answer, number = pop(number)
    while k > 0 and number:
        n, number = pop(number)
        if answer[-1] < n:
            while answer and n > answer[-1]:
                answer = answer[:-1]
                k -= 1
                if k == 0:
                    break
            answer += n
        else:
            answer += n
    if len(number) > 0:
        answer += number
    elif k != 0:
        answer = answer[:-k]
    return answer

def pop(n_list):
    return n_list[0], n_list[1:]

아래는 삽질 열심히 한 흔적들이다..

# 시간 초과 using combination

채점 결과
정확성: 33.3
합계: 33.3 / 100.0

from itertools import combinations
def solution(number, k):
    tmp = [x for x in number]
    comb_list = sorted([int(''.join(x)) for x in list(combinations(tmp, len(tmp)-k))])
    return str(comb_list[-1])

=====================================================================

# 시간 초과 using recursive function 

채점 결과
정확성: 58.3
합계: 58.3 / 100.0

def func(sliced, l):
    if l == 1:
        return max(sliced)
    len_sliced = len(sliced)
    tmp_sliced = sorted(list(enumerate(sliced)), key=lambda x: x[1], reverse=True)

    for pair in tmp_sliced:
        if len_sliced - pair[0] >= l:
            return str(pair[1]) + str(func(sliced[pair[0]+1:], l-1))
    return []


def solution(number, k):
    tmp = [int(x) for x in number]
    if len(number)-1 == k:
        return str(max(tmp))
    answer = func(tmp, len(number) - k)
    return answer

=====================================================================

# 시간 초과....

채점 결과
정확성: 75.0
합계: 75.0 / 100.0

def solution(number, k):
    def find_max(tup):
        max_tup = tup[0]
        for t in tup:
            if t[0] > max_tup[0]:
                max_tup = t
        return max_tup

    tmp = [int(x) for x in number]
    l = len(number)
    if l-1 == k:
        return str(max(tmp))
    length = l-k
    tmp_list = list(enumerate(tmp))
    tmp_list = [(v, i) for (i, v) in tmp_list]
    org_list = [i for i in tmp_list]
    answer = ''
    while True:
        if length == 1:
            answer += str(max(tmp_list)[0])
            break
        max_val = find_max(tmp_list[:-length+1])
        answer += str(max_val[0])
        tmp_list = org_list[max_val[1]+1:]
        length -= 1
    return answer

=====================================================================

# 또 시간 초과...

채점 결과
정확성: 91.7
합계: 91.7 / 100.0

def solution(number, k):
    def find_max(start, end):
        max_tup = tmp_list[start]
        for i in range(start, end + 1):
            if tmp_list[i][0] > max_tup[0]:
                max_tup = tmp_list[i]
        return max_tup
    l = len(number)
    if l-1 == k:
        return max(number)
    num_to_pick = l-k
    tmp_list = [(int(v), i) for (i, v) in enumerate(number)]
    answer = ''
    start_ind = 0
    while True:
        if num_to_pick == 1:
            answer += str(find_max(start_ind, l-1)[0])
            break
        max_val = find_max(start_ind, l - num_to_pick)
        answer += str(max_val[0])
        start_ind = max_val[1]+1
        num_to_pick -= 1
    return answer


=====================================================================

# 찐막 가즈아~

채점 결과
정확성: 100.0
합계: 100.0 / 100.0

def solution(number, k):
    answer = ""
    for c in number:
        if not answer or answer[-1] >= c:
            if len(answer) < len(number)-k:
                answer += c
        else:
            while answer and k > 0 and answer[-1] < c:
                answer = answer[:-1]
                k -= 1
            answer += c
    return answer

Leave a comment