programmers 경주로 건설 : programmers.co.kr/learn/courses/30/lessons/67259

 

코딩테스트 연습 - 경주로 건설

[[0,0,0,0,0,0,0,1],[0,0,0,0,0,0,0,0],[0,0,0,0,0,1,0,0],[0,0,0,0,1,0,0,0],[0,0,0,1,0,0,0,1],[0,0,1,0,0,0,1,0],[0,1,0,0,0,1,0,0],[1,0,0,0,0,0,0,0]] 3800 [[0,0,1,0],[0,0,0,0],[0,1,0,1],[1,0,0,0]] 2100 [[0,0,0,0,0,0],[0,1,1,1,1,0],[0,0,1,0,0,0],[1,0,0,1,0,1],[

programmers.co.kr

2020 카카오 인턴십에서 출제된 경주로 건설입니다.

Level 3에 해당하며, 기법으로는 다익스트라 알고리즘에 살짝(?)의 방향까지 생각해주셔야 합니다.

방향을 일방적으로 고려하시면 틀립니다!

 

이 문제에서 다익스트라를 구현할 실력이 되신다면 대부분 테스트케이스 14번?이 틀리게 될 것입니다.

14번 테스트케이스를 대략적으로 만들어보면 아래와 같습니다.

 

{0, 0, 0, 0, 0}

{0, 1, 1, 1, 0}

{0, 0, 1, 0, 0}

{1, 0, 0, 0, 1}

{0, 1, 1, 0, 0}

 

0,0을 기점으로 오른쪽으로 출발했을 때는 board[3][3]에서 2300을,

0,0을 기점으로 아래쪽으로 출발했을 때는 board[3][3]에서 2100을 갖게 될 것입니다.

 

당장 [3][3]에서 출발했을 때 2300을 기준으로 [4][4]에 도달하면 3000이 되고

2100을 기준으로 도달하면 3300이 됩니다.

'코너'가 한번 더 발생하기 때문입니다.

 

만약 방향을 일방적으로 고려한 다익스트라를 구현한다면,

[3][3]에서 2300을 꺼냈을 떄

다익스트라로 갱신한 최솟값 배열을 min_dist라고 한다면

이미 min_dist[3][3] 은 2100이기 때문에 continue되면서 탐색하지 않게 되겠죠,,

 

이정도 설명이면 충분히 이해하셨을 거라 생각합니다.

즉, 다익스트라를 통해 '그 지점의 방향'에 대한 최솟값을 가지고 계셔야 합니다.

min_dist[y][x][방향] 이렇게 3차원배열로 해결가능합니다.

 

#include <string>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
struct pii {
    int dist, y, x, way;
};
struct piicmp {
    bool operator()(pii& A, pii& B) {
        return A.dist > B.dist;
    }
};

int my[4] = { -1,0,1,0 };
int mx[4] = { 0,1,0,-1 };
int arr[26][26][4];

int solution(vector<vector<int>> board) {
    int answer = 987654321;
    int bs = board.size();
    for (int i = 0; i < bs; i++) {
        for (int j = 0; j < bs; j++) {
            for(int k = 0; k<4; k++){
                arr[i][j][k] = 987654321;                
            }
        }
    }

    priority_queue<pii, vector<pii>, piicmp> pq;
    if (!board[0][1]) pq.push({ 0,0,0,1 });
    if (!board[1][0]) pq.push({ 0,0,0,2 });
    while (!pq.empty()) {
        int y = pq.top().y;
        int x = pq.top().x;
        int dist = pq.top().dist;
        int way = pq.top().way;
        pq.pop();

        if (arr[y][x][way] < dist) continue;
        if (y == bs - 1 && x == bs - 1) {
            answer = min(answer, dist);
        }

        for (int i = 0; i < 4; i++) {
            int yy = y + my[i];
            int xx = x + mx[i];
            if (yy >= 0 && yy < bs && xx >= 0 && xx < bs && board[yy][xx] != 1) {
                if (i == way) {
                    int distance = dist + 100;
                    if (distance < arr[yy][xx][i]) {
                        arr[yy][xx][i] = distance;
                        pq.push({ distance, yy, xx, way });
                    }
                }
                else if (i == (way + 1)%4 || i == (4 + way - 1)%4) {
                    int distance = dist + 600;
                    if (distance < arr[yy][xx][i]) {
                        arr[yy][xx][i] = distance;
                        pq.push({ distance, yy, xx, i });
                    }
                }
            }
        }
    }


    return answer;
}

'algorithm > programmers' 카테고리의 다른 글

programmers [1차] 뉴스 클러스터링 c++  (0) 2020.12.21
programmers 무지의 먹방 라이브  (0) 2020.12.20
programmers 보석 쇼핑  (0) 2020.12.16
programmers 키패드 누르기  (0) 2020.12.14
programmers 수식 최대화  (0) 2020.12.14

programmers 보석 쇼핑 : programmers.co.kr/learn/courses/30/lessons/67258#

 

코딩테스트 연습 - 보석 쇼핑

["DIA", "RUBY", "RUBY", "DIA", "DIA", "EMERALD", "SAPPHIRE", "DIA"] [3, 7]

programmers.co.kr

 

2020 카카오 인턴십에 나온 보석 쇼핑 문제입니다.

 

처음에는 아무생각없이 이분탐색으로 체킹할 범위를 주고 범위를 줄여나가는 식으로 코딩하였는데,

생각해보니 이 '범위'를 파악하는게 결국 순차탐색이여서 O(N^2)가 된다는걸 보고 방법을 바꿨습니다.

 

풀이과정

1. set 을 이용해서 보석의 종류를 파악합니다.

2. 2개의 인덱스변수(lp, rp)를 가지고 map을 사용해서 1번만 순차탐색을 합니다.

3. lp, rp를 통해서 *현재 범위의 보석 종류를 파악할 수 있습니다.

아래 코드에 보시면 gemCnt라는 변수가 있는데, 이게 lp~rp 사이의 보석의 종류입니다.

map[gems[index]] 가 만약 0이라면, gems[index]를 map에 넣어줄 때 gemCnt의 값을 증가시킵니다.

0이 아니라면, 이미 있는 보석이니 그냥 ++를 통하여 현재 범위내의 gems[index]보석의 '갯수'만 증가시킵니다.

4. 이 gemCnt의 값이 1번에서 파악한 보석의 종류와 같다면,

  4.1 lp, rp의 범위를 통하여 최솟값을 파악하고, 정답을 갱신합니다.

  4.2 lp인덱스의 보석을 map에서 제거합니다.

     map[gems[lp]]-- 를 했을 때 0이 된다면 보석의 종류인 gemCnt가 1 감소됩니다.

  4.3 lp는 +1 하여 값을 증가시켜 범위를 갱신합니다.

5. gemCnt의 값이 보석의 종류보다 작다면

  5.1 rp를 증가시킵니다.

  5.2 rp의 범위가 보석갯수를 넘어가면 더 파악할 수 없기 때문에 break 됩니다.

  5.3 rp 보석을 map에 추가시킬 때 gemCnt도 4번과 마찬가지로 계산해줍니다.

6. 반복합니다.

 

설명을 적고보니 '투포인터' 문제인 것 같습니다.

투포인터 문제는 풀어본 경험이 별로없어서 이 문제를 기점으로 필요성을 느낀 것 같습니다.

조만간 '투포인터'에 대한 문제를 백준을 통해서 풀어봐야할 것 같습니다.

#include <string>
#include <vector>
#include <set>
#include <map>
using namespace std;

set<string> gem;
map<string,int> getgem;

vector<int> solution(vector<string> gems) {
    vector<int> answer;
    for(auto i : gems) gem.insert(i);
    
    int gs = gem.size();
    
    int ans_lp, ans_rp, ans_min=987654321;
    int lp = 0, rp = 0;
    int gemCnt = 1;
    getgem[gems[0]]++;
    while(1){
        if(gemCnt == gs){
            if(rp-lp<ans_min){
                ans_min = rp-lp;
                ans_lp = lp;
                ans_rp = rp;
            }
            string lp_str = gems[lp];
            getgem[lp_str]--;
            if(getgem[lp_str] == 0) gemCnt--;
            lp++;
        }
        else{
            rp++;
            if(rp>=gems.size()) break;
            
            string rp_str = gems[rp];
            if(getgem[rp_str] == 0) gemCnt++;
            getgem[rp_str]++;
        }
    }
    
    answer.push_back(ans_lp+1);
    answer.push_back(ans_rp+1);
    
    return answer;
}

 

'algorithm > programmers' 카테고리의 다른 글

programmers 무지의 먹방 라이브  (0) 2020.12.20
Programmers 경주로 건설  (0) 2020.12.20
programmers 키패드 누르기  (0) 2020.12.14
programmers 수식 최대화  (0) 2020.12.14
programmers 호텔 방 배정  (0) 2020.12.13

programmers 키패드 누르기 : programmers.co.kr/learn/courses/30/lessons/67256

 

코딩테스트 연습 - 키패드 누르기

[1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5] "right" "LRLLLRLLRRL" [7, 0, 8, 2, 8, 3, 1, 5, 7, 6, 2] "left" "LRLLRRLLLRR" [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] "right" "LLRLLRLLRL"

programmers.co.kr

2020 카카오 인턴십에서 출제된 키패드 누르기 입니다.

문제에서 요구하는 대로 구현할 수 있는지 묻는 문제이며,

노가다해도되지만 귀찮아서 bfs로 탐색하였습니다.

 

설명할 부분이 따로 없다고 생각되어서 간단히 코드만 첨부하겠습니다..

길긴하지만 간단하기 때문에 코드 읽어보시면 충분히 이해하실거라 생각합니다. 

 

#include <string>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;

struct point{
  int y, x, cnt;  
};
int arr[4][3] = {{10,2,10},{10,5,10},{10,8,10},{10,0,10}};
int my[4] = {-1,1,0,0};
int mx[4] = {0,0,1,-1};
bool visit[4][3];

// 2,5,8,0 부분에 대한 bfs
int findMinKey(int y, int x, int key){
    queue<point> q;
    memset(visit, false, sizeof(visit));
    q.push({y,x,0});
    while(!q.empty()){
        int y = q.front().y;
        int x = q.front().x;
        int cnt = q.front().cnt;
        q.pop();
        
        if(arr[y][x] == key) return cnt;
        if(visit[y][x]) continue;
        visit[y][x] = true;
        for(int i = 0; i<4; i++){
            int yy = y+my[i];
            int xx = x+mx[i];
            if(yy>=0&&yy<4&&xx>=0&&xx<3&&!visit[yy][xx]) q.push({yy,xx,cnt+1});
        }
    }
}

string solution(vector<int> numbers, string hand) {
    string answer = "";
    
    pair<int,int> left = {3,0};
    pair<int,int> right = {3,2};
    for(auto key : numbers){
        if(key == 1 || key == 4 || key == 7){
            answer += 'L';
            if(key == 1) left = {0,0};
            if(key == 4) left = {1,0};
            if(key == 7) left = {2,0};
        }
        else if(key == 3 || key == 6 || key == 9){
            answer += 'R';
            if(key == 3) right = {0,2};
            if(key == 6) right = {1,2};
            if(key == 9) right = {2,2};
        }
        else{
            int moveCntL = findMinKey(left.first, left.second, key);
            int moveCntR = findMinKey(right.first, right.second, key);
            if(moveCntL == moveCntR){
                if(hand.compare("left") == 0){
                    answer += 'L';
                    if(key == 2) left = {0,1};
                    if(key == 5) left = {1,1};
                    if(key == 8) left = {2,1};
                    if(key == 0) left = {3,1};
                }
                else{
                    answer += 'R';
                    if(key == 2) right = {0,1};
                    if(key == 5) right = {1,1};
                    if(key == 8) right = {2,1};
                    if(key == 0) right = {3,1};
                }
            }
            else if(moveCntL < moveCntR){
                answer += 'L';
                if(key == 2) left = {0,1};
                if(key == 5) left = {1,1};
                if(key == 8) left = {2,1};
                if(key == 0) left = {3,1};
            }
            else{
                answer += 'R';
                if(key == 2) right = {0,1};
                if(key == 5) right = {1,1};
                if(key == 8) right = {2,1};
                if(key == 0) right = {3,1};
            }
        }
    }
    
    return answer;
}

'algorithm > programmers' 카테고리의 다른 글

Programmers 경주로 건설  (0) 2020.12.20
programmers 보석 쇼핑  (0) 2020.12.16
programmers 수식 최대화  (0) 2020.12.14
programmers 호텔 방 배정  (0) 2020.12.13
programmers 징검다리 건너기  (0) 2020.12.13

programmers 수식 최대화 : programmers.co.kr/learn/courses/30/lessons/67257

 

코딩테스트 연습 - 수식 최대화

IT 벤처 회사를 운영하고 있는 라이언은 매년 사내 해커톤 대회를 개최하여 우승자에게 상금을 지급하고 있습니다. 이번 대회에서는 우승자에게 지급되는 상금을 이전 대회와는 다르게 다음과

programmers.co.kr

 

2020 카카오 인턴십 문제에서 출제된 수식 최대화 입니다.

연산자의 우선순위를 강제하여 해결해야 하는데,

문자열을 다뤄야하며 이 문제에서는 범위가 커질수록 링크드리스트를 사용하는 것이

효율면에서는 좋을 것 같습니다.

 

저는 범위가 작아서 평소에 편하게 사용하는 배열만으로 문제를 해결하였습니다.

처음에 주어진 문자열을 숫자와 연산자로 구분지어준 후에

강제한 연산자 순서대로 계산해주시면 됩니다.

 

문자열에 나온 연산자가 무엇이 있는지 알 수 없기 때문에

무엇이 나왔는지 구분해주고 순서를 줘야된다고 생각할 수도 있는데,

아래 코드 중 calcluate 함수에서 처음에 for문을 0-2까지 3번 반복합니다.

3번 반복하면서 + - * 에 대한 문자열을 강제로 확인하기 때문에

solution 내부에 *-+ *+- .. 의 6가지 경우의 수를 사용한 것 처럼 해주셔도 문제를 해결하는데 문제없습니다.

 

단, 계산이 끝났으면 숫자를 담고있는 배열은 반드시 길이가 1이 되어야 계산이 완벽하게 된 것입니다.

또한 절대값 계산해주시는 것도 잊으시면 안됩니다.

코드에 주석으로 설명을 첨부하였으니 읽어보시면 될 것 같습니다.

 

#include <string>
#include <vector>
using ll = long long;
using namespace std;

ll answer = 0;

void calculate(vector<ll> number, vector<char> exp, string str){
    // 연산자 3개를 찾습니다. (i in 0~2)
    for(int i = 0; i<3; i++){
        for(int k = 0; k<exp.size(); k++){
            char ch = exp[k];
            if(ch == str[str.size()-1]){
                // erase 때문에 링크드리스트를 사용하시는 것이 효율면에서는 좋습니다.
                if(ch == '*'){
                    ll cal = number[k]*number[k+1];
                    number.erase(number.begin()+k+1);
                    number[k] = cal;
                    exp.erase(exp.begin()+k);
                }
                else if(ch == '+'){
                    ll cal = number[k]+number[k+1];
                    number.erase(number.begin()+k+1);
                    number[k] = cal;
                    exp.erase(exp.begin()+k);
                }
                else if(ch == '-'){
                    ll cal = number[k]-number[k+1];
                    number.erase(number.begin()+k+1);
                    number[k] = cal;
                    exp.erase(exp.begin()+k);
                }
                k--;
            }
        }
        //탐색한 연산자는 삭제해줍니다.
        str.pop_back();
    }
    
    // 계산이 끝났을 때 길이가 1이여야 완벽히 계산된 것입니다.
    if(number.size() == 1){
        answer = max(answer, abs(number[0]));
    }
    
}

long long solution(string expression) {
    
    vector<ll> number;
    vector<char> exp;
    int num = 0;
    // 숫자와 연산자를 구분해줍니다.
    for(int i = 0; i<expression.size(); i++){
        char ch = expression[i];
        if(ch >= '0' && ch <= '9') num = num*10 + (ch-'0');
        else{
            number.push_back(num);
            num = 0;
            exp.push_back(ch);
        }
    }
    // 마지막 숫자를 추가시켜줍니다.
    number.push_back(num);
    
    // 강제로 우선순위를 지정해줍니다.
    // 총 6가지의 경우의 수가 필요합니다.
    string chstring;
    chstring = "-+*";
    calculate(number, exp, chstring);
    chstring = "+-*";
    calculate(number, exp, chstring);
    chstring = "-*+";
    calculate(number, exp, chstring);
    chstring = "*-+";
    calculate(number, exp, chstring);
    chstring = "*+-";
    calculate(number, exp, chstring);
    chstring = "+*-";
    calculate(number, exp, chstring);
        
    return answer;
}

'algorithm > programmers' 카테고리의 다른 글

programmers 보석 쇼핑  (0) 2020.12.16
programmers 키패드 누르기  (0) 2020.12.14
programmers 호텔 방 배정  (0) 2020.12.13
programmers 징검다리 건너기  (0) 2020.12.13
Programmers 불량 사용자  (0) 2020.12.12

+ Recent posts