프로그래머스 level 2 탐욕법(Greedy) 문제를 설명한다. 코딩테스트 연습은 매번 python3를 기준으로 작성한다.
[ 문제 설명 ]
어떤 숫자에서 k개의 수를 제거했을 때 얻을 수 있는 가장 큰 숫자를 구하려 합니다.
예를 들어, 숫자 1924에서 수 두 개를 제거하면 [19, 12, 14, 92, 94, 24] 를 만들 수 있습니다. 이 중 가장 큰 숫자는 94 입니다.
문자열 형식으로 숫자 number와 제거할 수의 개수 k가 solution 함수의 매개변수로 주어집니다. number에서 k 개의 수를 제거했을 때 만들 수 있는 수 중 가장 큰 숫자를 문자열 형태로 return 하도록 solution 함수를 완성하세요.
제한 조건
- number는 1자리 이상, 1,000,000자리 이하인 숫자입니다.
- k는 1 이상 number의 자릿수 미만인 자연수입니다.
입출력 예
1924 | 2 | 94 |
1231234 | 3 | 3234 |
4177252841 | 4 | 775841 |
문제를 이해하기는 어렵지 않다. k개 만큼의 숫자를 빼서 가장 큰 수를 만들면 되는 문제이다.
이 문제를 풀기 위해서 다양한 방법을 시도해보았는데..
다 런타임 에러가 났다...
이거 짜는 것만으로도 머리를 엄청 썼는데ㅠㅠㅠ
우선 이 문제를 풀기 위한 알고리즘을 설명한다.
[ 알고리즘 설명 ]
'1924' 에서 '94'를 만드는 방법은
10의 자리에 들어갈 수 있는 수 중 가장 큰 수를 찾고 일의 자리에 들어가는 수 중 가장 큰 수를 찾는 방법이다.
[ 1 9 2 ] 중에서 가장 큰 수 인 9를 찾고 그 이후 수 인 [ 2 4 ] 에서 가장 큰 수를 찾는다.
이 방법을 이용할 경우 가장 큰 수 조합을 찾을 수 있고, 이 알고리즘 또한 탐욕법이라고 할 수 있다.
나는 이 방법을 무식하게 이용하여 max함수를 이용하여 무식하게 문제를 풀었는데
max로 찾기보다는 반복문을 돌려가며 번째에 맞게 찾는 것이 훨씬 빠르게 문제를 풀 수 있다.
(max로 찾았다 효율성 다 실패하였다. )
내가 짠 코드는 아니지만 참고하기 좋은 방법의 코드로 설명해본다.
내가 짠 코드가 아니므로 전체를 가지고 올 수 는 없었으니
내가 놓친 중요한 부분만 설명한다.
[ 이 풀이는 알고리즘이 다르다.] (비슷한 자리수를 기반으로 계산하고 있기는 하다.)
for num in number[1:]:
while len(stack) > 0 and stack[-1] < num and k > 0:
k -= 1
stack.pop()
stack.append(num)
stack에는 먼저 제일 앞자리 수가 들어가 있다. num에는 이후 값들이 차례대로 들어오게 된다.
예시 문제에 있는 "1231234"를 예로 들어 문제를 푼다.
먼저 stack에는 [1]이 들어있다. 여기에서 num은 첫번째 for문을 돌면서 2가들어오는데,
[num = 2, stack = 1, k = 3]
2가 1보다 큼으로 1을 뺴고 2를 넣는다.
여기에서 중요하게 작용하는 것이 k인데, k는 뺄 수 있는 수의 개수가 된다.
1보다 2가 크게 되므로 1 하나를 뺀다.
[num = 3, stack = [2], k =2 ]
그럼 stack은 [2]이고 다시 반복문을 돈다. 2와 3을 비교 해서 또 한번 3이 2보다 크므로, stack은 3이 된다.
똑같이 stack을 뺴고 k를 뺀다.
[ num = 1, stack = [3] k = 1]
이제 num으로 더 작은 값이 들어오므로 while 조건에 맞지 않아 다음으로 넘어간다.
[num = 2, stack = [ 3 1 ], k = 1 ]
다시 stack의 마지막 값보다 큰 값이 들어왔으므로, 앞의 과정을 반복한다.
[num = 3 , stack = [ 3 2 ] , k = 0 ]
이제 k는 0이 되었다. k가 0이므로 앞의 while조건문에 부합하지 않고.
[num = 3, stack = [ 3 2 3 ], k = 0 ]
[ num = 4, stack = [ 3 2 3 4 ], k = 0 ]
이 된다. 최종 stack에 담긴 값이 3234로 가장 큰 수를 만들게 된다.
그리고 이후
if k != 0 :
stack = stakc[:-k]
가 추가로 들어가야 하는데 이 경우는 다 돌았지만 크기순으로 배열되어 있어, k개를 빼지 못한 경우를 의미한다.
이럴 경우 순차적으로 k개를 뺴고 입력하면 된다.
이렇게 쉽고 효율적으로 푸는 방법은 써 봤고 , 앞의 알고리즘을 이용하여 어렵게 푼 나의 풀이를 설명한다.
자릿수를 이용하여 비교를 한다는 생각에서 착안하였다.
앞의 코드가 훨씬 간단하고 이해하기 좋으니 그 코드를 이용하도록 하자...
여기에서 num = [ int(i) for i in number] 가 지워진 이유는 이 과정에서 너무 많은 수가 들어온 경우
런타임 오류가 생긴다. 이를 위해 maxstr로 숫자만 비교하는 코드를 따로 적용하였다.
그 코드는 간단하고 귀찮으니 따로 첨부하지 않는다. 그냥 숫자로 된 문자 가장 큰 수 반환해주는 함수이다.
그렇게 문자만 비교해주도록 함수를 수정하니 모두 통과가 되었다.!
하지만 앞으로는 앞서 말한 알고리즘을 쓰도록 하자.. 훨씬 깔끔하므로...
'코딩테스트 연습 > 프로그래머스' 카테고리의 다른 글
[ Programmers ] level 2 - 타겟 넘버 ( python ) (0) | 2020.01.09 |
---|---|
[ 프로그래머스 ] level 2 카펫 - 파이썬 (0) | 2019.12.16 |
[ 프로그래머스 ] 구명 보트 - level 2 ( 파이썬 ) (0) | 2019.12.13 |
[프로그래머스] 숫자 야구 -파이썬 (0) | 2019.12.12 |
[프로그래머스/코딩테스트 연습] 완전탐색 소수 찾기 (0) | 2019.12.10 |