- 큰 수 만들기
어떤 숫자에서 k개의 수를 제거했을 때 얻을 수 있는 가장 큰 숫자를 구하려 합니다.
예를 들어, 숫자 1924에서 수 두 개를 제거하면 [19, 12, 14, 92, 94, 24] 를 만들 수 있습니다. 이 중 가장 큰 숫자는 94 입니다.
문자열 형식으로 숫자 number와 제거할 수의 개수 k가 solution 함수의 매개변수로 주어집니다. number에서 k 개의 수를 제거했을 때 만들 수 있는 수 중 가장 큰 숫자를 문자열 형태로 return 하도록 solution 함수를 완성하세요.
제한 조건- number는 2자리 이상, 1,000,000자리 이하인 숫자입니다.
- k는 1 이상 number의 자릿수 미만인 자연수입니다.
number | k | return |
"1924" | 2 | "94" |
"1231234" | 3 | "3234" |
"4177252841" | 4 | "775841" |
💡 그리디 (Greedy)
그리디는 현재 상황에서 지금 당장 좋은 것만 고르는 방법을 말한다.
매 순간 가장 좋아보이는 것을 선택하고, 현재의 선택이 나중에 미칠 영향은 고려하지 않는다.
그리디는 단순 암기가 아닌 창의력을 요구하는 문제 유형이 많기 때문에 문제를 풀기 위한 최소한의 아이디어를 떠올릴 수 있는 능력이 필요하다.
대체로 정렬 알고리즘과 짝을 이뤄 출제되고, 문제에서 "가장 큰 순서대로" 혹은 "가장 작은 순서대로"와 같은 기준을 알게 모르게 제시한다.
어떤 코딩 테스트 문제를 만났을 때, 바로 문제 유형을 파악하기 어렵다면 그리디 알고리즘 의심하고, 문제를 해결할 수 있는 탐욕적인 해결법이 존재하는지 고민
⇒ 찾을 수 없다면, 다이나믹 프로그래밍이나 그래프 알고리즘 등으로 고민
나는 이 문제를 처음 풀 때 문자열을 내림차순으로 정렬한 뒤, 왼쪽에서 오른쪽으로 진행하며 오른쪽 수가 더 큰 경우 왼쪽 수를 지우기만 하면 되는 줄 알았다...!
최종적인 풀이는 아래와 같다.
#include <string>
#include <vector>
#include <algorithm>
#include <stack>
using namespace std;
string solution(string number, int k) {
stack<char> st;
string str = "";
bool isPoped = false;
st.push(number[0]);
for(int i = 1; i < number.size(); i++)
{
if(st.top() < number[i])
{
while (!st.empty() && st.top() < number[i] && k > 0)
{
st.pop();
isPoped = true;
k--;
}
}
st.push(number[i]);
if (k <= 0)
{
if (i == number.size() - 1) break;
for (int j = i+1; j < number.size(); j++)
st.push(number[j]);
break;
}
}
if (!isPoped)
return number.substr(0, number.size() - k);
while(!st.empty())
{
str += st.top();
st.pop();
}
reverse(begin(str), end(str));
return str;
}
스택을 이용하여 문제를 풀이하였다.
숫자의 순서대로 스택에 넣으면서, 스택의 Top과 현재 인덱스의 char를 비교하며 Top보다 더 큰 수가 나왔을 때, 스택의 Top이 더 작아질때까지 스택의 요소를 Pop으로 삭제한다.
Pop으로 스택 요소를 삭제할때마다 k-- 를 진행하여 삭제할 수 있는 개수 k를 지켜야한다.
string = "9437227", k = 4 를 예시로 들어보면
* stack = [9], char = "437227" 를 두고 비교했을 때 stack의 Top인 9가 char의 4보다 더 크기때문에 그냥 넘어가고 4를 다음 stack에 삽입한다.
* stack = [9, 4], char = "37227" 를 두고 비교했을때도 4 < 3 = false이므로 넘어가고 3을 넣는다.
* stack = [9, 4, 3], char = "7227" 를 비교하면 3 < 7 = true 이므로 3을 삭제한다. 이후 k-- 이므로 k = 4->3
* stack = [9, 4], char = "7227" 를 또 비교하면 4 < 7 = true 이므로 4를 삭제한다. 이후 k-- 이므로 k = 2
* stack = [9], char = "7227" 를 비교했을땐 9 < 7 = false이므로 넘어가고 7을 넣는다.
* stack = [9, 7], char = "227" 를 비교했을 때 7 < 2 = false이므로 넘어가고 2를 넣는다.
* stack = [9, 7, 2], char = "27" 를 비교했을 때 2 < 2 = false 이므로 넘어가고 2를 넣는다.
* stack = [9, 7, 2, 2], char = "7" 를 비교했을 때 2 < 7 = true 이므로 2를 삭제한다. 이후 k-- 이므로 k = 1
* stack = [9, 7, 2], char = "7" 를 비교했을 때 2 < 7 = true 이므로 2를 삭제한다. 이후 k-- 이므로 k = 0
* stack = [9, 7], char = "7"를 비교했을 때 7 < 7 = false 이므로 넘어가고 7을 넣는다.
* stack = [9, 7, 7]
이후, stack 에 있는 char 들을 string 변수에 += top() 으로 저장한 뒤, 스택의 특성상 문자열이 뒤집어져 출력되므로 reverse 함수로 뒤집어준다.
참조
1-1. Greedy 개념 & 실전 문제
'현재 상황에서 지금 당장 좋은 것만 고르는 방법'매 순간 가장 좋아보이는 것을 선택 ⇒ 현재의 선택이 나중에 미칠 영향은 고려 안함 '사전에 외우고 있지 않아도 풀 수 있을 가능성이 높은 문
velog.io
'💻코딩테스트 > 프로그래머스' 카테고리의 다른 글
[프로그래머스/C++] 입국심사 - 이분탐색 (0) | 2023.05.10 |
---|---|
[프로그래머스/C++] 소수 찾기 - 완전탐색 (순열) (0) | 2023.05.02 |
[프로그래머스/C++] 디스크 컨트롤러 - 힙(Heap), SJF (0) | 2023.04.17 |
[프로그래머스/C++] 게임 맵 최단거리 - BFS (너비우선탐색) (0) | 2023.04.02 |
[프로그래머스/C++] 타켓넘버 - DFS (깊이우선탐색) (0) | 2023.04.02 |