Problem Solving/PROGRAMMERS

[프로그래머스] 42883_큰 수 만들기(c++)

dia_0108 2019. 11. 12. 20:40

 

 

문제 설명

 

어떤 숫자에서 k개의 수를 제거했을 때 얻을 수 있는 가장 큰 숫자를 구하려 합니다.

예를 들어, 숫자 1924에서 수 두 개를 제거하면 [19, 12, 14, 92, 94, 24] 를 만들 수 있습니다. 이 중 가장 큰 숫자는 94 입니다.

 

문자열 형식으로 숫자 number와 제거할 수의 개수 k가 solution 함수의 매개변수로 주어집니다. number에서 k 개의 수를 제거했을 때 만들 수 있는 수 중 가장 큰 숫자를 문자열 형태로 return 하도록 solution 함수를 완성하세요.

 

제한 조건

  • number는 1자리 이상, 1,000,000자리 이하인 숫자입니다.
  • k는 1 이상 number의 자릿수 미만인 자연수입니다.

 

입출력 예

numberkreturn

1924 2 94
1231234 3 3234
4177252841 4 775841

 


 

#C++ 첫 접근

 

- 처음 접근은 들어온 수를 오름차순으로 정렬하고 k개의 개수만큼 삭제하면 된다고 생각함.

- 그래서 sv(sorted vector)를 선언하고 sort()를 실행함. 원소들이 오름차순으로 정렬됨.

- sv와 nv를 비교하여 일치하는 곳의 숫자를 지우는 방식으로 구현함.

 

 


#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <cstdlib>

using namespace std;

string solution(string number, int k) {
    string answer = "";
    vector<char> nv, sv;
    
    for(int i = 0; i < number.length(); i++) {
        nv.push_back(number.at(i));
        sv.push_back(number.at(i));
    }
    
    sort(sv.begin(), sv.end());
    
    for(int i = 0; i < k; i++){
        char dNum = sv[i];
        for(int j = 0; j < nv.size(); j++){
            if(dNum == nv[j]) {
                nv.erase(nv.begin() + j);
                break;
            }
        }
    }
    
    for(int i = 0; i < nv.size(); i++) answer += nv[i];
            
    return answer;
}

 

 실행 결과

 

테스트 케이스가 일부만 통과됨. 예제를 다시 살펴보고 기존에 들어온 수의 순서가 바뀌면 안된다는 것을 알게 됨.

 

 

#C++ 두 번째 접근

 

- number로 넘어온 데이터를 한자리(한개)씩 처리하기로 결정함.

- 그래서 현재 처리할 데이터와 기존 데이터를 비교하여 삽입, 삭제를 수행하기 위해 스택 자료구조를 사용함.

- 기존에 삽입된 원소보다 처리할 원소가 크다면 기존 원소를 삭제하고 현재 데이터를 삽입함.

- 숫자의 맨 앞자리의 숫자가 크면 클 수록 좋기 때문임. 

- 이때 주의할 점은 삭제 가능한 크기를 담은 k 이상으로 삭제 연산이 일어나면 안되기 때문에 조건으로 걸어줘야 함.

- 또한, 처리할 데이터가 스택의 top에 있는 원소보다 큰 경우에 삭제를 수행하는데 반복적으로 top의 원소와 대소 비교 연산을 해야함. 

- 입출력 예제 3 (4177252841) 을 보자. 처음에 스택에는 4가 삽입되고 그 뒤로 1이 push됨. 그리고 7이 들어올 때 1과 비교해서 7이 더 크기 때문에 pop이 수행됨. 데이터 하나 당 loop를 한번만 실행한다면 아래와 같은 순서로 stack 연산이 일어남.

- 이렇게 될 경우 가장 맨 앞자리의 수가 7이 아닌 4가 되기 때문에 가장 큰 수를 만든다고 할 수 없음.

 

                2 push 2 pop 8 push
          2 push 2 pop 5 push 5  5 5
        7 push 7 7 7 7 7 7
  1 push 1 pop 7 push 7 7 7 7 7 7 7
4 push 4 4 4 4 4 4 4 4 4

  [stack 상황]

 

 

- 따라서, 비교를 수행했을 때 스택에 있는 원소를 삭제하고 계속 top에 있는 원소와 비교하여 삭제를 처리해주어야 함. 그래서 whlie문을 통해 삭제 후에도 top의 원소를 반복적으로 비교할 수 있도록 구현함.

 

                     
                   2 push 2 pop
            2 push 2 pop 5 push 5 5
  1 push 1 pop     7 push 7 7 7 7 7
4 push 4 4 pop 7 push 7 7 7 7 7 7

  [stack 상황]

 

- 그리고 k개만큼 삭제를 못한 경우도 있기 때문에 k개와 같아지도록 pop 연산을 수행함.

- 이것이 가능한 이유는 스택에 들어간 원소는 이전 원소보다 작거나 같다는 의미이기 때문임. 

 

 


#include <string>
#include <vector>
#include <stack>
#include <algorithm>

using namespace std;

string solution(string number, int k) { //큰 수 만들기 - success
    string answer = "";
    int size = number.length() - k;
    stack<char> st;
    
    for(int i = 0; i < number.length(); i++){
        char cur = number.at(i); //처리할 숫자
        while(!st.empty() && k > 0){ //
            char top = st.top(); //스택의 가장 맨 위의 값
            if(top < cur){ //값 비교
                st.pop(); //처리할 값이 더 크기 때문에 pop 수행
                k--; //제거 횟수 감소
            }
            else break; //비교할 때 값이 같거나 스택에 있는 값이 더 큰 경우
        } 
        st.push(cur); //처리하는 값이 큰 경우를 제외하고 모든 경우 스택에 삽입
    }
    
    //처리하고 남은 스택의 사이즈와 제거하고 남아야하는 수가 같아야함.
    //아닌 경우 같아질 때까지 제거(스택에 남아있다는 것은 제거할 원소보다 이전 원소가 작거나 같다는 의미이므로)
    while(st.size() != size) st.pop(); 

    
    while(!st.empty()){ //결과값 생성
        answer += st.top();
        st.pop();
    }
    
    //위에서 거꾸로 값이 이어졌기 때문에 reverse 수행
    reverse(answer.begin(), answer.end()); 
    
    return answer;
}

 

 

실행 결과