https://programmers.co.kr/learn/courses/30/lessons/60059

 

코딩테스트 연습 - 자물쇠와 열쇠 | 프로그래머스

[[0, 0, 0], [1, 0, 0], [0, 1, 1]] [[1, 1, 1], [1, 1, 0], [1, 0, 1]] true

programmers.co.kr

lock의 크기와 key의 크기가 최대 20이므로 완전 탐색으로 해결할 수 있다.

(key를 90도씩 회전시키는 네 가지 경우) X (자물쇠에 열쇠를 맞춰보는 모든 경우)를 구해주면 된다.

 

주의할 점은 예제에는 똑같이 나와있지만 lock의 크기와 key의 크기는 다를 수 있다.

또, 열쇠를 회전시킬 때 회전시키는 함수에서 실제 key 벡터를 회전시켜야 하므로 &로 받아야 한다.

 

 

문제 조건에 따라서 열쇠는 자물쇠 밖으로 나가도 되므로

열쇠를 자물쇠 홈에 맞춰보는 모든 경우를 위해서 아래 그림과 같이 새로운 2차원 vector를 만들어줬다.

 

열쇠의 가장 오른쪽 아랫부분과 자물쇠의 가장 위쪽 부분을 맞추는 경우부터

열쇠의 가장 왼쪽 윗부분과 자물쇠의 가장 오른쪽 아래 부분을 맞추는 경우까지를 모두 해주면 되기 때문에

lock의 크기 + (key의 크기 -1)*2 크기의 벡터를 만들어주면 된다.

 

 

 

그러면 매 회전 때마다 key의 시작 부분이

(0,0)에서 시작하는 경우부터 lock의 가장 마지막 부분(boardsize-keysize)에서부터 시작하는 경우까지 해보면서

key를 board에 더해 lock부분이 모두 1인지(홈이 모두 채워졌는지)를 확인하면 된다

한 곳이라도 0이거나(비어있는 홈) 2(돌기 두 개가 만남) 이면 안되므로 바로 false를 리턴한다.

 

 

 

**기존 상태에서 먼저 열쇠를 맞춰보면 회전은 3번만 하면 된다고 생각해서

반복문을 3번만 실행하도록 했어서 한참 헤맸다;;

맞춰보는 경우는 어쨌든 4번 해야 하므로 반복문을 4번 실행해주어야 한다...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <string>
#include <vector>
using namespace std;
 
int keysize, locksize, boardsize;
 
void rotateKey(vector<vector<int>> &key) {
        
    vector<vector<int>> tmp(keysize, vector<int>(keysize));
 
    for (int j = keysize - 1; j >= 0; j--) {
        for (int i = 0; i < keysize; i++) {
            tmp[i][j] = key[keysize - j - 1][i];
        }
    }
 
    key = tmp;
}
 
 
bool putKey(int x, int y, vector<vector<int>> key, vector<vector<int>> board) {
     //(x, y)를 시작점으로 열쇠를 자물쇠에 맞춰본다.
 
    //key를 더한다
    for (int i = x; i < x + keysize; i++) {
        for (int j = y; j < y + keysize; j++) {
            board[i][j] += key[i - x][j - y];
        }
    }
 
 
    //좌물쇠 부분 확인
    for (int i = keysize - 1; i <= boardsize - keysize; i++) {
        for (int j = keysize - 1; j <= boardsize - keysize; j++) {
            if (board[i][j] == 1continue;
 
            //1이 아니라면 바로 false를 리턴
            return false;
        }
    }
 
 
    return true;
}
 
bool solution(vector<vector<int>> key, vector<vector<int>> lock) {
    bool answer = false;
 
    keysize = key.size();
    locksize = lock.size();
 
 
    boardsize = locksize + (keysize - 1* 2;
    vector<vector<int>> board(boardsize, vector<int>(boardsize, 0));
 
 
    //board에 lock을 미리 더해놓는다. (lock은 고정되어 있고 key를 움직일 것 이므로)
    for (int i = keysize - 1; i <= boardsize - keysize; i++) {
        for (int j = keysize - 1; j <= boardsize - keysize; j++) {
            board[i][j] = lock[i - keysize + 1][j - keysize + 1];
        }
    }
 
    //회전 방향 네번
    for (int r = 0; r < 4; r++) {
        
        for (int i = 0; i <= boardsize - keysize; i++) {
            for (int j = 0; j <= boardsize - keysize; j++) {
 
                //i,j 를 key의 시작칸으로 자물쇠 홈에 맞춰본다.
                if (putKey(i, j, key, board)) {
                    answer = true;
                    return answer;
                }
 
            }
        }
 
 
        //key 시계방향으로 90도 회전
        rotateKey(key);
 
    }
 
 
    return answer;
}
Colored by Color Scripter
 

https://programmers.co.kr/learn/courses/30/lessons/60063

 

코딩테스트 연습 - 블록 이동하기 | 프로그래머스

[[0, 0, 0, 1, 1],[0, 0, 0, 1, 0],[0, 1, 0, 1, 1],[1, 1, 0, 0, 1],[0, 0, 0, 0, 0]] 7

programmers.co.kr

 

백준의 1938번 통나무 옮기기(문제 링크)와 비슷한 느낌의 BFS 문제다.

(통나무 옮기기 풀이 링크)

 

이게 조금 더 어려운 것 같기는 하다...

좌표를 어떻게 저장할까 하다가 아래 카카오 기술 블로그에 있는 해설에서 아이디어를 얻어서 풀었다.

 

https://tech.kakao.com/2019/10/02/kakao-blind-recruitment-2020-round1/

 

2020 신입 개발자 블라인드 채용 1차 코딩 테스트 문제 해설

올해에도 2020이라는 멋진 숫자와 함께, 카카오의 신입 개발자 채용을 시작했습니다! 그 여정 중 첫 단계로 1차 코딩 테스트가 지난 9월 7일 토요일 오후 2시부터 오후 7시까지 5시간 동안 진행됐는데요. 저희 준비위원들도 설렘과 긴장 속에 원활한 진행을 위해 노력했고, 무사히 1차 테스트를 마칠 수 있었습니다. 테스트에는 총 7문제가 출제됐고, 응시자는 5시간 이내에 순서와 상관없이 문제를 해결해야 […]

tech.kakao.com

 

위의 해설에

(r, c, d) : (r, c) 위치에서 d 방향에 있는 칸을 한 칸 더 차지하고 있음이라고 나와있어서

로봇의 x, y좌표, 방향, 시간을 구조체로 저장해 큐에 넣어서 BFS를 진행하였다.

로봇의 나머지 한 칸은 방향 정보를 이용하여 구한다.

 

 

매번 상, 하, 좌, 우로 이동하는 경우와

로봇의 두 칸 중 한 칸에서 시계방향으로 90도 회전하는 경우 / 반시계 방향으로 90도 회전하는 경우

나머지 한 칸에서 시계방향으로 90도 회전하는 경우 /반시계 방향으로 90도 회전하는 경우

이동 가능한 위치(벽이 아니고 범위를 벗어나지 않는 곳)를 계속 큐에 넣어주면서 진행하면 된다.

 

 

 

로봇을 이동시킬 때, 두 칸 중 한 칸만의 좌표를 기준으로 이동시키므로

로봇의 한 칸을 (x, y)라고 하고 다른 한칸을 (xx, yy)라고 했을 때, visit 배열을 (x, y)를 기준으로 방문을 확인하고 큐에도 (x, y)좌표와 (x, y) 기준의 방향이 들어간다.


따라서 (x, y)축을 기준으로 회전할때는 (x, y)의 좌표는 변화가 없고 방향만 변화하므로 새로 큐에 넣을 때도 (x, y) 좌표 그대로와 회전된 새 방향을 넣어준다.

반대로, (xx, yy)를 축으로 (x, y)를 회전한 경우에는 (x, y)를 이동시킨 위치인 (nx, ny)를 기준으로 만들어주기 위해서 방향을 반대로 바꿔주고 큐에 넣어줄 때에도 (xx, yy)가 아닌 (nx, ny) 좌표와 (nx, ny) 기준의 방향을 넣어준다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include <vector>
#include <queue>
using namespace std;
 
int n;
bool visit[100][100][4];
 
int dx[] = { 010-1 };
int dy[] = { 10-10 };
 
//회전할 때 지나칠 곳
int ndx[] = { -1,1,1,-1 };
int ndy[] = { 1,1,-1,-1 };
 
struct Robot {
    int x;
    int y;
    int dir;
    int time;
    Robot(int a, int b, int d, int t) {
        x = a;
        y = b;
        dir = d;
        time = t;
    }
};
 
bool rangeCheck(int x, int y, int xx, int yy) {
    if (x < 0 || x >= n || y < 0 || y >= n) return false;
    if (xx < 0 || xx >= n || yy < 0 || yy >= n) return false;
 
    return true;
}
 
 
int solution(vector<vector<int>> board) {
 
    queue<Robot> q;
    q.push(Robot(0000));
    visit[0][0][0= true;
 
    n = board.size();
    int destX = n - 1;
    int destY = n - 1;
 
    int cnt = 0;
    while (!q.empty()) {
        int x = q.front().x;
        int y = q.front().y;
        int dir = q.front().dir;
        int time = q.front().time;
        q.pop();
 
        //로봇의 나머지 한칸
        int xx = x + dx[dir];
        int yy = y + dy[dir];
 
 
        //로봇의 한칸이라도 도착하면 종료
        if (x == destX && y == destY) return time;
        if (xx == destX && yy == destY) return time;
 
 
        int nx, ny, nxx, nyy;
 
        //우, 하, 좌, 상 이동
        for (int k = 0; k < 4; k++) {
            nx = x + dx[k];
            ny = y + dy[k];
            nxx = xx + dx[k];
            nyy = yy + dy[k];
            
            //이동할 곳의 범위 체크
            if (!rangeCheck(nx, ny, nxx, nyy)) continue;
            //이동할 곳의 방문 체크
            if (visit[nx][ny][dir]) continue;
            //이동할 수 있는지 체크
            if (board[nx][ny] == 1 || board[nxx][nyy] == 1continue;
 
            visit[nx][ny][dir] = true;
            q.push(Robot(nx, ny, dir, time + 1));
 
        }
 
 
        //x,y 를 축으로 90도 회전
        for (int i = 1; i < 4; i += 2) {
            int ndir = (dir + i) % 4;
            nxx = x + dx[ndir];
            nyy = y + dy[ndir];
 
            int rx, ry; //회전하면서 지나갈 곳의 좌표
            if (i == 1) {
                //시계방향 회전인 경우
                rx = x + ndx[ndir];
                ry = y + ndy[ndir];
            }
            else {
                //반시계방향 회전인 경우
                rx = x + ndx[dir];
                ry = y + ndy[dir];
            }
            
            if (!rangeCheck(rx, ry, nxx, nyy)) continue;
            if (visit[x][y][ndir]) continue;
            if (board[nxx][nyy] == 1continue;
            if (board[rx][ry]) continue;
 
            visit[x][y][ndir] = true;
            q.push(Robot(x, y, ndir, time + 1));
        }
        
 
        //xx, yy 를 축으로 90도 회전
        dir = (dir + 2) % 4//xx, yy가 기준이므로 방향이 반대로 바뀐다.
        for (int i = 1; i < 4; i += 2) {
            int ndir = (dir + i) % 4;
            nx = xx + dx[ndir];
            ny = yy + dy[ndir];
 
            int rx, ry; //회전하면서 지나갈 곳의 좌표
            if (i == 1) {
                //시계방향 회전인 경우
                rx = xx + ndx[ndir];
                ry = yy + ndy[ndir];
            }
            else {
                //반시계방향 회전인 경우
                rx = xx + ndx[dir];
                ry = yy + ndy[dir];
            }
 
            if (!rangeCheck(nx, ny, rx, ry)) continue;
            if (board[nx][ny] == 1continue;
            if (board[rx][ry] == 1continue;
 
            ndir = (ndir + 2) % 4;
            if (visit[nx][ny][ndir]) continue;
            visit[nx][ny][ndir] = true;
            q.push(Robot(nx, ny, ndir, time + 1));
        }
        
 
 
    }
 
}
Colored by Color Scripter
 

 

https://programmers.co.kr/learn/courses/30/lessons/60058

 

코딩테스트 연습 - 괄호 변환 | 프로그래머스

카카오에 신입 개발자로 입사한 콘은 선배 개발자로부터 개발역량 강화를 위해 다른 개발자가 작성한 소스 코드를 분석하여 문제점을 발견하고 수정하라는 업무 과제를 받았습니다. 소스를 컴파일하여 로그를 보니 대부분 소스 코드 내 작성된 괄호가 개수는 맞지만 짝이 맞지 않은 형태로 작성되어 오류가 나는 것을 알게 되었습니다. 수정해야 할 소스 파일이 너무 많아서 고민하던 콘은 소스 코드에 작성된 모든 괄호를 뽑아서 올바른 순서대로 배치된 괄호 문자열을 알려주는

programmers.co.kr

문제가 복잡해 보이지만 정말 시키는 대로만 재귀로 잘 구현하면 된다. 재귀로 구현해야하는 부분도 문제에 잘 나와있다.

 

올바른 괄호 문자열인지 검사하는 부분만 스택을 이용해서 따로 구현했다.

문자열의 모든 문자들에 대해서 여는 괄호면 스택에 넣어주고 닫는 괄호면 스택에서 빼준다. 이때, 스택이 비어있다면 올바른 괄호 문자열이 아니므로 false를 바로 리턴한다.

 

문자열 검사가 끝났는데 스택에 아직 괄호가 남아있다면 그것도 올바른 괄호 문자열이 아니므로 false를 리턴한다.

위에서 false를 리턴하지 않았다면 올바른 괄호 문자열이므로 true를 리턴한다.

 

 

각 조건을 구현한 부분에 주석을 달아놨다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <string>
#include <vector>
#include <stack>
using namespace std;
 
//올바른 괄호 문자열인지 검사
bool isok(string s) {
    stack<char> st;
 
    for (char c : s) {
        if (c == '(') {
            st.push(c);
        }
        else if (c == ')') {
            if (st.empty()) {
                return false;
            }
            else {
                st.pop();
            }
        }
    }
 
    if (st.empty()) return true;
    else return false;
 
}
 
 
string seperate(string p) {
    if (p == ""return "";
 
    string u = "";
    string v = "";
    string result = "";
 
    int cnt1 = 0;
    int cnt2 = 0;
    int index = 0;
 
    //2번 조건
    for (char c : p) {
        if (c == '(') {
            cnt1++;
        }
        else {
            cnt2++;
        }
        index++;
 
        //균형잡힌 상태가 되면 바로 break(더 분리할 수 없도록);
        if (cnt1 == cnt2) break;
    }
 
    //u와 v로 나누다. 
    u += p.substr(0, index);
    v += p.substr(index);
 
 
    //3번 조건
    if (isok(u)) {
        result += u;
        result += seperate(v);
    }
    else {
        //4번 조건
 
        //4-1
        result = "(";
        //4-2
        result += seperate(v);
        //4-3
        result += ")";
 
        //4-4
        u = u.substr(1, u.size() - 2);
        int len = u.size();
        for (int i = 0; i<len; i++) {
            if (u[i] == '(') {
                result += ")";
            }
            else {
                result += "(";
            }
        }
    }
 
 
    //4-5
    return result;
 
}
 
 
string solution(string p) {
    string answer = "";
    
    //1번 조건
    if (isok(p)) return p;
 
 
    answer = seperate(p);
 
 
    return answer;
}
Colored by Color Scripter
 

https://programmers.co.kr/learn/courses/30/lessons/60057

 

코딩테스트 연습 - 문자열 압축 | 프로그래머스

데이터 처리 전문가가 되고 싶은 어피치는 문자열을 압축하는 방법에 대해 공부를 하고 있습니다. 최근에 대량의 데이터 처리를 위한 간단한 비손실 압축 방법에 대해 공부를 하고 있는데, 문자열에서 같은 값이 연속해서 나타나는 것을 그 문자의 개수와 반복되는 값으로 표현하여 더 짧은 문자열로 줄여서 표현하는 알고리즘을 공부하고 있습니다. 간단한 예로 aabbaccc의 경우 2a2ba3c(문자가 반복되지 않아 한번만 나타난 경우 1은 생략함)와 같이 표현할 수

programmers.co.kr

문자열을 자르는 단위를 1부터 시작해서 모두 해보면 된다.

단위가 문자열의 길이의 반보다 커지면 절대 더 압축되지 않으므로 1부터 문자열의 길이/2 까지만 해보면 된다.

 

 

i개로 자른다고 했을 때, 문자열의 처음부터 i개만큼씩을 문자열 끝까지 계속 검사해주면 된다.

(i개로 나누어 떨어지지 않고 남은 부분은 마지막에 추가적으로 붙여준다.)

 

 

i개로 자른 문자열이 바로 이어서 나타난다면 cnt값을 증가시킨다.

그렇지 않다면, 압축된 결과를 저장할 문자열(result)에 문자열 단위를 붙여주고 문자열 단위를 새로 j번부터 i개로 업데이트한다. 이때, 문제 조건에 따라서 이 문자열 단위가 여러 개였다면(cnt가 1 이상이라면) cnt를 문자열 앞에 붙여서 result에 추가하고 cnt는 1로 다시 초기화한다.

 

 

i개로 잘라서 압축한 경우의 문자열을 모두 완성했다면 그때의 길이를 최솟값과 비교한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <string>
#include <vector>
using namespace std;
 
int solution(string s) {
    int len = s.size();
    int answer = len;
 
    int n = len / 2;
 
 
    //i개 단위로 잘라서 압축
    for (int i = 1; i <= n; i++) {
 
        //i개 단위로 잘라서 압축한뒤 만들어지는 문자열
        string result = "";
 
        //자를 문자열 단위
        string ss = s.substr(0, i);
 
        int cnt = 1;
 
        //앞에서 자른 문자열 단위를 제외한 뒷부분(j번 문자부터) 문자열을 검사한다.
        for (int j = i; j <= len; j += i) {
            //j번 부터 i개 만큼이 문자열 단위와 똑같은 경우 cnt 증가
            if (ss == s.substr(j, i)) {
                cnt += 1;
            }
            else {
                //다른 경우 중 cnt가 1이면 result에 그대로 ss를 붙인다.
                if (cnt == 1) {
                    result += ss;
                }
                else {
                    //cnt가 1보다 크다면 cnt를 문자열 단위 앞에 붙여서 result에 이어준다.
                    result += (to_string(cnt) + ss);
                }
 
                //문자열 단위를 j번부터 i개로 변경 
                ss = s.substr(j, i);
                //cnt값 다시 1로 초기화
                cnt = 1;
            }
 
        }
 
        //문자열이 i로 나누어 떨어지지 않는다면 result에 나머지 부분을 붙여줘야한다.
        if ((len%i) != 0) {
            result += s.substr((len / i)*i);
        }
 
        //최솟값을 answer에 저장
        if (answer > result.size()) answer = result.size();
    }
 
 
    return answer;
}
Colored by Color Scripter
 

+ Recent posts