코딩테스트준비

2022 카카오 테크 인턴십 - 프로그래머스

haeullee 2023. 8. 29. 19:40

https://school.programmers.co.kr/learn/challenges?order=recent&partIds=31236 

 

코딩테스트 연습 | 프로그래머스 스쿨

개발자 취업의 필수 관문 코딩테스트를 철저하게 연습하고 대비할 수 있는 문제를 총망라! 프로그래머스에서 선발한 문제로 유형을 파악하고 실력을 업그레이드해 보세요!

school.programmers.co.kr

1. 성격 유형 검사하기

  • 특징: map
  • 구현방법: map을 이용하여, 점수 부여
  • 코드
#include <string>
#include <vector>
#include <unordered_map>
using namespace std;

unordered_map<char, int> _map;
string solution(vector<string> survey, vector<int> choices) 
{
    string answer = "";
    int n = survey.size();
    int score[7] = {3, 2, 1, 0, 1, 2, 3};
    _map['R'] = 0; _map['T'] = 0; _map['C'] = 0; _map['F'] = 0;
    _map['J'] = 0; _map['M'] = 0; _map['A'] = 0; _map['N'] = 0;
    for(int i = 0; i < n; i++)
    {
        char first = survey[i][0];
        char second = survey[i][1];
        int curv = choices[i];
        if(curv >= 5) 
        {
            _map[second] += score[curv-1];
        }
        if(curv <= 3)
        {
            _map[first] += score[curv-1];
        } 
    }
    
    if(_map['R'] >= _map['T']) answer.push_back('R');
    else answer.push_back('T');
    if(_map['C'] >= _map['F']) answer.push_back('C');
    else answer.push_back('F');
    if(_map['J'] >= _map['M']) answer.push_back('J');
    else answer.push_back('M');
    if(_map['A'] >= _map['N']) answer.push_back('A');
    else answer.push_back('N');
    
    
    return answer;
}


2. 두 큐 합 같게 만들기

  • 특징: queue, 그리디
  • 구현방법: 
    • 입력으로 들어온 queue1, queue2 벡터값을 _queue1, _queue2(queue<int> 형)에 넣고, 각각의 합을 구해서 q1(long long형), q2(long long형)에 저장함
    • while(true)
      • q1 > q2 이면, q1의 맨 앞의 값을 빼서 q2에 넣고, answer(몇번 이 연산을 했는지 저장)을 1증가시킴 (반대의 경우에도)
      • q1 == q2이면, break
      • **_queue1, _queue2가 empty이거나, p1 + p2값이 홀수이거나, answer이 600000보다 커지면 종료
  • 어려웠던 부분
    • 마지막 종료 조건을 못찾아서 시간 초과가 발생했다..... queue1 = queue2 <= 300,000이므로 600000연산을 수행하면, 이미 탐색했던 구간으로 돌아온다...프로그래머스에서 제공하는 테스트케이스로 시간초과가 난건데,,, 시험때 이부분까지 생각해서 종료 조건을 넣을 수 있을지,,,, 모르겠다. 
  • 코드
#include <bits/stdc++.h>

using namespace std;

int solution(vector<int> queue1, vector<int> queue2) {
    int answer = 0;
    long long q1 = 0; long long q2 = 0;
    queue<int> _queue1;  queue<int> _queue2; 
    for(int i = 0; i < queue1.size(); i++)
    {
        q1 += queue1[i];
        _queue1.push(queue1[i]);
    }
    for(int i = 0; i < queue2.size(); i++)
    {
        q2 += queue2[i];
        _queue2.push(queue2[i]);

    }
    long long avg = (q1 + q2) % 2;
    long long avg1 = (q1 + q2) / 2;
    
    
    while(true)
    {
        if(_queue1.empty() || _queue2.empty() || avg == 1 || answer > 600000)
        {
            answer = -1;
            break;
        }

        if(q1 > q2)
        {
            int q1front = _queue1.front();
            _queue1.pop();
            _queue2.push(q1front);
            q1 -= q1front;
            q2 += q1front;
            answer++;
        }   
        else if(q1 < q2)
        {
            int q2front = _queue2.front();
            _queue2.pop();
            _queue1.push(q2front);
            q2 -= q2front;
            q1 += q2front;
            answer++;
        }
        else
        {
            break;
        }
    }
    
    return answer;
}

3. 코딩테스트 공부

  • 특징: dp
  • 어려웠던 부분
    • 문제 읽고 포기했다. 해답을 보니 역시나 dp였다... dp인거 알고 풀어보려했는데,,, 못풀었다. 
  • 참고 블로그: https://taehoung0102.tistory.com/211
  • 구현 방법
    • 목표 알고력과 목표 코딩력을 구함
    • alp가 목표 알고력보다 클 경우, alp = 목표 알고력/ cop가 목표 코딩력 클 경우, cop= 목표 알고력 (dp 배열의 인덱스가 초과하는 경우를 막기 위해)
    • dp[i][j] 정의 (알고력이 i이고, 코딩력이 j일 때, 최단시간)
    • alp부터 목표 알고력, cop부터 목표 코딩력을 순회하면서
      • dp[i+1][j] = min(dp[i+1][j], dp[i][j] + 1);
      • dp[i][j+1] = min(dp[i][j+1], dp[i][j] + 1);
      • 문제 순회하면서 문제 풀수 있는 경우
        • dp[i+p[2]][j+p[3]] = min(dp[i+p[2]][j+p[3]] , dp[i][j] + p[4]);
        • i+p[2]와 j+p[3]가 각각 ga, gc보다 클경우는 따로 처리 -> 목표보다 값이 클경우도 목표값으로 설정해둬야 anwer을 dp[목표알고력][목표코딩력]으로 구할 수 있다.
  • 코드
#include <bits/stdc++.h>

using namespace std;

int dp[155][155];
int solution(int alp, int cop, vector<vector<int>> problems) {
    int answer = 0;
    
    int ga = 0; int gc = 0;
    //목표값 구하기
    for(int i = 0; i< problems.size(); i++)
    {
        ga = max(ga, problems[i][0]);
        gc = max(gc, problems[i][1]);
    }
    
    if(alp >= ga && cop >= gc)
    {
        return answer;
    }
    
    if(alp >= ga) alp = ga;
    if(cop >= gc) cop = gc;
    
    for(int i = 0; i < 155; i++)
    {
        fill(dp[i], dp[i]+154, INT_MAX);
    }
    dp[alp][cop] = 0;
    for(int i = alp; i <= ga; i++)
    {
        for(int j = cop; j <= gc; j++)
        {
            dp[i+1][j] = min(dp[i+1][j], dp[i][j] + 1);
            dp[i][j+1] = min(dp[i][j+1], dp[i][j] + 1);
            
            for(auto p: problems)
            {
                if(i >= p[0] && j >= p[1]) //문제 풀 수 있으면
                {
                    if(i+p[2] >= ga && j+p[3] >= gc)
                    {
                        dp[ga][gc] = min(dp[ga][gc], dp[i][j] + p[4]);
                    }
                    else if(i+p[2] >= ga && j+p[3] < gc)
                    {
                        dp[ga][j+p[3]] = min(dp[ga][j+p[3]], dp[i][j] + p[4]);
                    }
                    else if(i+p[2] < ga && j+p[3] >= gc)
                    {
                        dp[i+p[2]][gc] = min(dp[i+p[2]][gc], dp[i][j] + p[4]);
                    }
                    else
                    {
                        dp[i+p[2]][j+p[3]] = min(dp[i+p[2]][j+p[3]] , dp[i][j] + p[4]);
                    }
                }
            }
        }
    }
    
    answer = dp[ga][gc];
    return answer;
}

4. 등산코스 정하기

  • 특징: 다익스트라
  • 어려웠던 부분
    • 이 문제를 dfs로 풀었다,,, 그러면 시간초과가 난다. 
      • 뭔가 아이디어가 떠오르면 바로 구현하는 데, 시간 복잡도랑 예외 상황을 충분히 생각하는 습관을 들여야 될거같다.
    • 답지를 찾아보니 다익스트라로 푸는 문제였다. 
      • 다익스트라는 한 노드에서 모든 노드로의 최단거리를 구하는 알고리즘으로, 시간복잡도는 O(E logV) 이다. 이문제에서 출입구별로 다익스트라 알고리즘을 돌리게되면, V * O(E logV) 가되어 대략 10^10이된다. 
      • 이 문제에서는 출입구가 어디인지는 상관이 없다. 따라서 모든 출입구에서 동시에 출발하여 다익스트라 알고리즘을 한번만 돌리는 방식으로 문제를 풀 수 있다. 
      • 한가지 주의할 점은 , paths를 순회하면서, adj 그래프를 받을 때, 노드를 나타내는 u나 v가 출입구 혹은 산봉우리라면 따로 처리를 해주어야 한다는 것이다.
        • 산봉우리 노드에서는 다른 노드로 갈 수 없고, 출입구 노드에서는 다른 노드로부터 들어올 수 없다. 따라서 단방향 그래프로 받아줘야한다. 
        • 산봉우리나 출입구가 아닌 노드는 양방향 그래프로 받아준다. 
//dfs 코드로 시간초과가 난다
#include <bits/stdc++.h>

using namespace std;

vector<pair<int, int>> adj[50004];  // 거리, 이어진지점
int pri[50004]; // 지점 속성(0: 쉼터, 1: 출입구, 2: 산봉우리) *1부터 시작
int ans[50004]; //테스트용
int dist[50004]; 
map<int, int> m; //산봉우리, 최솟값
int firstgate;
int mx;
int tn; int gsize; int ssize;
void dfs(int cur, int curn)
{
    if(cur == tn-gsize-ssize+1) return;

    for(auto nxt: adj[curn])
    {
        int nxtw = nxt.first;
        int nxtp = nxt.second;

        if(dist[nxtp] != -1) continue;
        if(pri[nxtp] == 1) continue; 
     
        int prevmx = mx;
        dist[nxtp] = 1;
        mx = max(mx, nxtw);
        if(pri[nxtp] == 2) 
        {
            if(m.find(nxtp) != m.end() && m[nxtp] > mx)
            {
                m[nxtp] = mx;
            }
            if(m.find(nxtp) == m.end() ) 
            {
                m[nxtp] = mx;
            }
            dist[nxtp] = -1;
            mx = prevmx;
            continue;
        } 

        dfs(cur+1, nxtp);
        dist[nxtp] = -1;
        mx = prevmx;
    }
}

bool cmp(const pair<int,int>& a, const pair<int,int>& b) {
	if (a.second == b.second) return a.first < b.first;
	return a.second < b.second;
}

vector<int> solution(int n, vector<vector<int>> paths, vector<int> gates, vector<int> summits) {
    vector<int> answer;
    tn = n;
    gsize = gates.size();
    ssize = summits.size();
    for(int i = 0; i < paths.size(); i++) //지점 1부터 시작
    {
        int st = paths[i][0];
        int en = paths[i][1];
        int w = paths[i][2];
        adj[st].push_back(make_pair(w, en));
        adj[en].push_back(make_pair(w, st));
    }

    for(int i = 0; i < gates.size(); i++)
    {
        pri[gates[i]] = 1;
    }
    
    for(int i = 0; i < summits.size(); i++)
    {
        pri[summits[i]] = 2;
    }
    
    //게이트 기준으로 dfs
    for(int i = 0; i < gates.size(); i++)
    {
        fill(dist, dist+50003, -1);
        mx = 0;
        firstgate = gates[i];
        dist[firstgate] = 1;
        dfs(0, firstgate); //cur, 시작점
    }

    vector<pair<int,int>> vec( m.begin(), m.end() );
    sort(vec.begin(), vec.end(), cmp);
    answer.push_back(vec[0].first); answer.push_back(vec[0].second);
    
    return answer;
}

 

  • 코드
#include <bits/stdc++.h>

using namespace std;

int u, v, w;
vector<pair<int, int>> adj[50002];
int d[50002];
int mn;
int answer_summits;
unordered_set<int> s;
unordered_set<int> g;
vector<int> solution(int n, vector<vector<int>> paths, vector<int> gates, vector<int> summits) {
    vector<int> answer;
    
    for(int i = 0; i < summits.size(); i++)
    {
        s.insert(summits[i]);
    }
    for(int i = 0; i < gates.size(); i++)
    {
        g.insert(gates[i]);
    }
    
    for(int i = 0; i < paths.size(); i++)
    {
        u = paths[i][0]; v = paths[i][1]; w= paths[i][2];
        if(s.find(u) != s.end()) // u가 산봉우리이면 나가는 간선 없음
        {
            adj[v].push_back(make_pair(w, u));
        } 
        else if(s.find(u) != g.end()) // u가 입구이면 들어오는 간선 없음
        {
            adj[u].push_back(make_pair(w, v));
        } 
        else if(s.find(v) != s.end()) // v가 산봉우리이면
        {
            adj[u].push_back(make_pair(w, v));
        } 
        else if(s.find(v) != s.end()) // v가 입구이면
        {
            adj[v].push_back(make_pair(w, u));
        } 
        else
        {
            adj[u].push_back(make_pair(w, v));
            adj[v].push_back(make_pair(w, u));
        }
        
    }
    
    fill(d, d+n+1, INT_MAX); 
    mn = INT_MAX;
    priority_queue<pair<int ,int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
    
    for(int i = 0; i < gates.size(); i++)
    {
        d[gates[i]] = 0;
        pq.push(make_pair(d[gates[i]], gates[i])); // 비용, 노드
    }
    
    while(!pq.empty())
    {
        auto cur = pq.top(); pq.pop();
        if(d[cur.second] != cur.first) continue;
        
        for(auto nxt: adj[cur.second])
        {
            if(d[nxt.second] <= max(d[cur.second], nxt.first)) continue;
            d[nxt.second] = max(d[cur.second], nxt.first);
            pq.push(make_pair(d[nxt.second], nxt.second));
        } 
        
    }
    
    for(int i = 0; i < summits.size(); i++)
    {

        mn = min(mn, d[summits[i]]);
    }
    
    sort(summits.begin(), summits.end());
    for(int i = 0; i < summits.size(); i++)
    {

        if(d[summits[i]] == mn) 
        {
            answer_summits = summits[i]; 
            break;
        }
        
    }
    
    answer.push_back(answer_summits); answer.push_back(mn);
    return answer;
}