문제 설명
어떤 숫자에서 k
개의 수를 제거하였을 때 얻을 수 있는 가장 큰 수를 구하려고 합니다.
예를들어, 숫자 1924
에서 수 두 개를 제거하면 [19, 12, 14, 92, 94, 24]를 만들 수 있습니다.
이 중 가장 큰 숫자는 94
입니다.
문자열 형식으로 숫자 number
와 제거할 수의 개수 k
가 solution 함수의 매개변수로 주어집니다. number
에서 k
개의 수를 제거했을 때 만들 수 있는 수 중 가장 큰 숫자를 문자열 형태로 return 하도록 solution 함수를 작성해주세요.
제한사항
-
number
는 1자리 이상, 1,000,000자리 이하인 숫자입니다. -
k
는 1 이상number의 자릿수
미만의 숫자입니다.
입출력 예
number | k | return |
---|---|---|
“1924” | 2 | “94” |
“1231234” | 3 | “3234” |
“4177252841” | 4 | “775841” |
Solution
일전에 풀었던 문제를 복기할 겸 다시 풀었다.
문제 해결을 위해 주의해야 할 점이 두 가지 있다.
첫 째는 1,000,000
자리의 문자열 형태
가 주어지기 때문에 문자열 자체를 자르는 등의 코드는 시간 초과
를 일으키기 쉽다.
두번째는 문자열 제거
문제라고 했지만 사실 문자열 선택
문제로 접근하는 것이 훨씬 더 쉽고 깔끔한 코드를 구현할 수 있다.
선택
으로 문제를 해결할 경우 큰 수
를 선택해야 하는 명확한 기준이 생기기 때문이다.
즉, k
개의 수를 제거
하는게 아니라 number.length() - k
개의 수를 선택
하는 방향으로 진행한다.
단, 선택 시 고려해야 할 부분이 있다. 바로 선택 범위 조정이다. 우리가 만들어야 하는 수는 특정 길이
를 만족해야 한다. 다시말해 number.length() - k
라는 길이를 만족해야 한다.
만일 선택 범위를 제한하지 않는다면 첫 번째 선택한 수가 문자열의 마지막 인덱스가 되어버릴 수 있다.
이를테면 12341299
중 3
개를 선택해야 할 때 처음 선택한 수가 1231299
라면 다음 2개의 수를 선택할 수가 없어진다.
즉, 12312
99 사이로 범위를 좁혀야 그 다음 두번의 선택을 할 수 있게된다.
이 범위 제한은 toSearch
라는 변수로 표현할 수 있는데, 구하는 수식은 int toSearch = 문자열 전체 길이 - 남은 선택 개수
로 구할 수 있겠다.
코드를 살펴보자.
Code
복기 문제(문자열 선택 변수에 관심)
기존에 풀었던 문제(문자열 삭제 변수에 관심)
두 코드를 비교해보면 우선 toSearch
의 범위가 서로 다르다. 삭제할 변수의 남은 수
에 관심을 갖는 두 번째 코드의 경우 cutoff + 1
개 만큼 탐색을 하여 그 중 가장 큰 값(max) 아래의 문자열은 제거 한다. cutoff + 1
개만큼의 탐색을 하는 이유는 cutoff
개 만큼의 문자열을 앞에서 삭제 할 수 있어야 하기 때문이다.
그리고 첫 번째 코드의 toSearch
는 선택할 문자의 남은 수
를 고려한다. number.length - toGetSize
범위를 탐색하는 이유는 toGetSize
개 만큼의 문자열을 뒤에서 선택할 수 있어야 하기 때문이다.
몇줄 평
기존에 풀었던 문제
를 다시 파악하느라 고생했다. 왜 저렇게 로직을 짰을까? 아마 제대로 파악하고 짰다기 보단 흐름대로 흘러가다 보니 저렇게 구현한 것 같다. 이번 기회에 복기 문제와 기존 문제를 좀 더 심층적으로 분석하는 시간을 가졌다.
문자열 선택 변수에 관심을 둔 "복기 문제"
와 문자열 삭제 변수에 관심을 둔 "기존에 풀었던 문제"
를 보면 알겠지만 문자열 삭제 변수에 관심을 둔 로직
의 경우 다시 봐도 내가 무슨 생각으로 저런 로직을 짯는지 한번에 파악이 잘 안된다. 다시말하면 문자열 선택 변수에 관심
을 둔 로직이 보다 직관적
이다.
왜 문자열 선택을 위한 범위가 i <= curIdx + cutOff
인가 생각해보면 삭제해야할 문자열 개수(cutOff) + 1
개만큼의 범위에서 가장 큰 수를 선택한다. 그리고 선택한 수와 curIdx
사이에 어떤 문자가 존재한다면 그 수는 자동적으로 삭제
됨을 의미하므로 cutOff = toSearch - maxIdx
를 취해준다. 이로써 삭제해야할 문자열의 개수가 갱신된다.
반면 toGetSize
변수에 관심을 둔 복기 문제는 좀 더 깔끔하게 처리가 가능하다.
사실 처음 복기 문제를 풀었을때는 while
이 아닌 Recursion
으로 구현했었다.
하지만 계속해서 9, 10번에서 실패
를 해서 반례를 계속 찾아보려고 노력했지만 결국 찾지 못했다.
거의 2시간 가까이 삽질한 끝에 Recursion
이 문제라는 점을 깨달았다. (처음 문제 해결시 재귀로 해결했다)
즉, call stack
이 터져버리는 현상이 발생한 것이다.
재귀를 loop로 수정하니 정상 제출이 되었다.
참고 및 출처
- 프로그래머스