프로그래머스 42588 - 탑

문제 링크

생각과 접근

  • 문제의 분야는 스택/큐에 있었지만, 굳이 사용하지 않고 for문 두 개를 쓰면 간단히 풀 수 있는 문제였습니다.
  • 신호는 오른쪽에서 왼쪽으로 흐르니 heights를 탐색할 때 거꾸로 탐색합니다. (i-for문)
  • 두 번째 j-for문에서 i보다 제일 가깝고 heights[i]보다 큰 값을 찾습니다.
    • 큰 값이 있다면, 그 타워의 인덱스를 push_back
    • 큰 값이 없다면, 0을 push_back
  • 탐색은 거꾸로 하여 값 또한 거꾸로 push_back되어 있으므로, vector answer에 다시 거꾸로 넣어줍니다.

코드

#include <bits/stdc++.h>
using namespace std;

vector<int> solution(vector<int> heights) {
    vector<int> answer;
    vector<int> temp;

    for(int i = heights.size() - 1; i >= 0; i--) {
        for(int j = i - 1; j >= 0; j--) {
            if(heights[j] > heights[i]){
                temp.push_back(j + 1);
                break;
            }
            if(j == 0) temp.push_back(0);
        }
        if(i == 0) temp.push_back(0);
    }

    for(int i = temp.size() - 1; i >= 0; i--){
        answer.push_back(temp[i]);
    }
    return answer;
}

채점 결과

프로그래머스 42579 - 베스트앨범

문제 링크

생각 및 접근

  • 시간이 꽤 걸린 문제였고, 새롭게 알게 된 C++ 지식들이 많았다.
  • 선언한 자료 구조
    • 음악 장르 별로 음악 재생 수의 합을 구해서 내림차순으로 정리하기 위한 map<string, int> sumGenre; vector<pair<string, int>> v;
    • 음악 장르 별로 음악을 저장하고, 음악의 index 번호와 재생 수를 저장하는 map<string, vector<Music>> groupByGenre;
    • 음악의 index 번호와 재생 수를 한꺼번에 저장하고, operator 함수를 선언하기 위해 선언한 객체 struct Music{};



새로 배운 내용은 볼드 처리 하였습니다.

    • struct Music
        struct Music{
            int index;
            int play;
            Music(int b, int c){
                index = b;
                play = c;
            }
            bool operator < (const Music & b) const {
                if(play == b.play){
                    return index < b.index;
                }
                return play > b.play;
            }
        };
    • sumGenre와 groupByGenre에 값을 채워넣는다.
        for(int i = 0; i < numMusic; i++){
            sumGenre[genres[i]] += plays[i];
            groupByGenre[genres[i]].push_back(Music(i, plays[i]));
        }
    • map을 vector로 변환하기
      • vector로 변환하고, sum이 큰 순서대로 sort한다.
        bool cmp(pair<string, int> a, pair<string , int> b){
          return a.second > b.second;
        }
        vector<pair<string, int>> v;
        for(auto & k : sumGenre){
          v.push_back(make_pair(k.first, k.second));
        }
        sort(v.begin(), v.end(), cmp);
  • 전, 결

    • vector v를 순회하면서, groupByGenre의 value인 vector를 sort한다.

        for(int i = 0; i < v.size(); i++){
            string target = v[i].first;
            sort(groupByGenre[target].begin(), groupByGenre[target].end());
      • sort의 방식은 play 오름차순, play 수가 같다면 index 내림차순으로 정렬한다.
    • 정렬 이후, 장르의 음악 수에 따라서 2개를 넣을 지, 1개를 넣을 지 판단한다.

            for(int i = 0; i < min(2, (int) groupByGenre[target].size()); i++){
                answer.push_back(groupByGenre[target][i].index);
            }
        }
      
        return answer;
      

코드

#include <bits/stdc++.h>
using namespace std;

struct Music{
    int index;
    int play;
    Music(int b, int c){
        index = b;
        play = c;
    }
    bool operator < (const Music & b) const {
        if(play == b.play){
            return index < b.index;
        }
        return play > b.play;
    }
};

bool cmp(pair<string, int> a, pair<string , int> b){
    return a.second > b.second;
}

vector<int> solution(vector<string> genres, vector<int> plays) {
    vector<int> answer;

    int numMusic = genres.size();

    map<string, int> sumGenre;
    map<string, vector<Music>> groupByGenre;

    for(int i = 0; i < numMusic; i++){
        sumGenre[genres[i]] += plays[i];
        groupByGenre[genres[i]].push_back(Music(i, plays[i]));
    }

    vector<pair<string, int>> v;
    for(auto & k : sumGenre){
        v.push_back(make_pair(k.first, k.second));
    }
    sort(v.begin(), v.end(), cmp);

    for(int i = 0; i < v.size(); i++){
        string target = v[i].first;
        sort(groupByGenre[target].begin(), groupByGenre[target].end());

        for(int i = 0; i < min(2, (int) groupByGenre[target].size()); i++){
            answer.push_back(groupByGenre[target][i].index);
        }
    }

    return answer;
}

채점 결과

프로그래머스 42578 - 위장 (c++)

문제 링크

접근 및 생각

  • 의상의 종류가 있기 때문에, 단순 vector로 다루기엔 어려워서 map이라는 자료구조를 활용했습니다.
    • C++ STL map에 대한 정보
    • 문제에서 활용된 map의 pair는 <string, int>로 하여, string에는 옷의 종류 이름이, int에는 옷의 종류에 해당하는 옷의 가짓수를 저장하였습니다.
  • 전부 다 벗은 경우를 제외해야 하고, 최소한 하나의 옷을 입어야 합니다. 옷의 종류가 아래와 같다면,
      a : 3, b : 2, c : 1, d : 7
    (3 + 1) * (2 + 1) * (1 + 1) * (7 + 1) - 1이 문제의 답이 됩니다.
    괄호 안의 + 1 은 그 옷의 종류를 입지 않은 경우를 넣은 것이고, 괄호 밖의 - 1 은 전부 다 벗은 경우를 제외한 것입니다.

코드

#include <bits/stdc++.h>
using namespace std;

int solution(vector<vector<string>> clothes) {
    int answer = 1;
    map<string, int> m;

    // 옷의 종류에 해당하는 map value를 하나씩 늘려줍니다.
    for(int i = 0; i < clothes.size(); i++){
        m[clothes[i][1]]++;
    }

    // map을 순회하면서 (k.second + 1)를 곱해줍니다.
    for(auto & k : m){
        answer *= (k.second + 1);
    }

    // 전부 다 벗은 경우를 빼주고 반환해줍니다.
    return answer - 1;
}

채점 결과

프로그래머스 42577 - 전화번호 목록

문제 링크

접근 및 생각

  • 우선, vector string을 sort했을 때 어떤 식으로 나열되는지 알아야 문제를 쉽게 풀 수 있었습니다. phone_book의 vector type이 int인 경우와 vector type이 string인 경우의 sort 결과가 다릅니다.

  • 입출력 예제에서 준 vector string sort의 결과는 아래와 같습니다.

  • string은 int와 달리 문자로 취급되므로 사전순으로 나열 됩니다. 사전을 펼쳐서 다음에 가나 가 나오듯이, phone_book을 sort하면 119 다음엔 1195524421 이 나옵니다. sort한 vector를 앞 원소와 바로 뒤 원소를 비교하여 접두어가 있는지 없는지를 판단하면 되겠습니다.

  • 접두어가 있는지 어떻게 판단하느냐. 저는 string의 substr() 함수를 사용했습니다. substr()은 문자열의 일부분을 문자열로 반환하는 함수로, 파라미터를 1개, 2개를 넣을 수 있습니다.

    • 1개일 경우 : ( 시작위치 ) : 시작위치부터 끝까지의 문자들을 문자열로 반환합니다.

    • 2개일 경우 : ( 시작위치, 개수 ) : 시작위치부터 개수만큼의 문자를 문자열로 반환합니다.

      string s = "ABCDEF";
      string s2 = s.substr(4);      // s2 = "EF"    ( index 4부터 끝까지의 문자열을 반환한다. )
      string s3 = s.substr(1,3);    // s3 = "BCD"   ( index 1부터 3까지의 문자열을 반환한다. )
    • 출처 C++ 라이브러리 - String 클래스 함수 정리|작성자 김랜턴

  • 이 점을 활용해서 앞의 원소의 string length만큼 뒤의 원소를 substr한 값을 앞의 원소와 비교합니다. 같다면 return false, 다르다면 다음 원소를 비교합니다. phone_book을 모두 비교해도 return false되지 않았다면, 접두어가 없는 phone_book이므로 return true해주시면 되겠습니다.

코드

#include <bits/stdc++.h>
using namespace std;

bool solution(vector<string> phone_book) {
    sort(phone_book.begin(), phone_book.end());

    // 출력을 위한 코드
    // for(auto k : phone_book){
    //     cout << k << endl;
    // }

    for(int i = 1; i < phone_book.size(); i++){
        string temp = phone_book[i].substr(0, phone_book[i - 1].length());
        if(temp == phone_book[i - 1])
            return false;
    }
    return true;
}

채점 결과

프로그래머스 42576 - 완주하지 못한 선수

문제 사이트

접근 및 생각

  • 문제의 조건 중 "단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다."와 "마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때"를 보고, participant와 completion을 sort하여 앞에서부터 비교해나가야겠다 는 생각을 했습니다.

코드

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

using namespace std;

string solution(vector<string> participant, vector<string> completion) {
    string answer = "";

    // participant와 completion을 sort
    sort(participant.begin(), participant.end());
    sort(completion.begin(), completion.end());

    // 앞에서부터 비교
    for(int i = 0; i < completion.size(); i++){

        // 비교해서 같으면 무시
        if(participant[i] == completion[i]) continue;

        // 비교해서 다르면, participant[i]는 완주하지 못한 선수
        else{
            answer = participant[i];
            break;
        }

    }

    // answer에 무언가가 지정되어 있지 않다면, participant의 맨 마지막 선수가 완주하지 못한 선수
    if(answer == ""){
        answer = *(participant.end() - 1);
    }

    return answer;
}

채점 결과

컴파일러 업그레이드 (in dev-cpp)

  • 도구 - 컴파일러 설정 - 컴파일러 - 컴파일러 추가 명령에 아래 문구를 추가

    -std=c++14
    
  • 컴파일러 업그레이드 시 예약어 auto 사용 가능

    for(auto x : a) cout << x << endl;
    

입출력 속도 향상

  • main 함수 시작할 때 다음과 같은 문구 삽입

    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    
    • ios_base

      • 표준 스트림 클래스의 타입과 무관한 멤버들을 포함하고 있는 기초 클래스
        그림1
      • 더 자세한 정보
    • sync_with_stdio(true)

      • cin과 cout 등의 C++ 표준 스트림 버퍼와 printf와 scanf 등의 C 표준 버퍼를 병행 및 동기화해서 사용하게 됨
    • sync_with_stdio(false)

      • cin과 cout 등의 C++ 표준 스트림 버퍼만 사용하겠다. -> 속도 C 표준 버퍼보다 빨라지게 됨.
    • cin.tie(NULL);

      • cin을 cout으로부터 untie한다. stream을 tie하면 다른 stream에서 입출력 요청이 오기 전에 stream을 flush한다.

        cout << "Enter name:";
        cin >> name;
        
      • 위의 예시에서 cin과 cout이 tie된 상태라면, 프로그램이 user에게 입력을 요구하기 전에 output이 flush된다.
        stream을 untie하면 output이 flush되지 않은 채로 user에게 입력을 요구하게 되고, 따라서 "Enter name" 메시지는 출력되지 않을 것이다. 그러므로 untie가 되어있다면 cin으로 입력을 받기 전에 수동적으로 cout을 flush 시켜주어야 한다.

    • 실제 입력 속도 비교 결과

    • 실제 출력 속도 비교 결과

모든 라이브러리를 대체하는 라이브러리

  • 모든 표준 라이브러리 헤더들을 모두 한 번에 컴파일될 수 있도록 함.

  • 보통 알고리즘 대회에서는 컴파일 시간을 고려하지 않으므로, 사용해도 무관함.

    #include <bits/stdc++.h>
    

+ Recent posts