문제 : Programmers-행렬과 연산
문제 출처: 프로그래머스 코딩 테스트 연습, https://programmers.co.kr/learn/challenges
필요 알고리즘 개념
- Linked List, Deque
- 이 문제에서는 양방향에서의 삽입, 값 획득이 O(1)로 이루어질 수 있는 자료구조를 사용해야 한다. 따라서 Linked List 혹은 Deque에 대한 개념을 알고 있어야 풀 수 있다. 내 코드에서는 둘 다 사용하지만, 둘 중 하나로만 진행해도 동일한 결과를 얻을 수 있다.
rc가 r*c 크기의 배열이라고 할 경우, 이 문제의 경우 그냥 배열 자체만 보고 진행을 하게 되면 shiftRow는 배열의 모든 원소를 건드려야 하므로 O(r*c)가 필요하고, rotate는 맨 위와 맨 아래 행, 그리고 좌우의 열을 건드려야 하므로 O(r+c)가 필요하다. 하지만 당연히 이렇게 짜면 효율성 테스트를 통과할 수 없다.
내가 프로그래머스를 잘 안하는 이유가 이것때문인데, 정확성 테스트는 10초라고 해두고 효율성 테스트는 대충 '언어별로 작성된 정답 코드의 실행 시간의 적정 배수'라고 해놨다. 저거 10초의 배수도 아니다 ㅋㅋㅋ 대충 한 0.1~0.2초 걸어둔 것 같다. 대강이라도 어느정도 시간을 요구하는질 알아야지 사람들이 연습하면서 자신의 풀이의 시간복잡도 따져보고 이건 되겠다, 이건 안되겠으니 난 더 지식을 알아야 한다 판단할 수 있다고 본다. 코테에서야 '니가 생각하는 최선으로 함 짜봐'라는 식으로 생각할 수 있으니 변별력일 수 있지만, 코딩테스트 '연습'인데 연습할 수 있게 그래도 어느정도 시간 기준은 달아놔줘야 한다고 본다. 적어도 leetcode처럼 시간 복잡도로라도 달아놔줘야 연습하는 사람들이 연습을 할 수 있다고 본다. 뭐 사람마다 생각이 다를 수 있지만, 개인적으로는 로직을 전체적으로 구성하고 시간복잡도, 메모리복잡도 따져보는 설계과정이 끝난 후 코드를 짜는게 연습이지, 뭐 통과될 때 까지 왜 효율성 테스트를 통과할 수 없는지는 모르겠지만 대충 계속 바꿔보면서 넣어보는 과정은 짜증만 날 뿐이지 연습이 될거라고 보진 않는다.
아무튼 그럼 어떻게 효율성을 통과할 수 있을지 생각해보자. 대충 자기가 생각하는 최선의 방법을 쓰면 되는데, 내가 생각하는 최선의 방법은 아래처럼 나눠서 생각하는 것이다. 좌, 우의 세로방향은 LinkedList 혹은 Deque로 처리하고, 중간부분은 LinkedList<Deque>라던지, Linked<LinkedList> 라던지, Deque<Deque> 라던지.. 마음에 드는걸로 고르면 된다.
ShiftRow
좌우의 세로부분을 col1, col2라 하고, 중간에 있는 가로부분들을 row, row들을 다시 묶어둔걸 rows라고 하겠다. 코드로 나타내면 Deque col1, Deque col2, List<Deque> rows 와 같은 형태이고, rows 내의 Deque 각각이 row이다. ShiftRow 명령의 경우엔 그럼 다음과 같은 로직으로 변경된다.
1. col1에서 마지막껄 빼내서 맨 앞에 넣는다. -> O(1)
2. rows에서 마지막 row를 빼서 rows의 맨 앞에 넣는다. -> O(1)
3. col2에서 마지막껄 맨 앞에 넣는다. -> O(1)
과정을 그려보면 다음과 같다.
Rotate
Rotate도 마찬가지로 다음과 같이 변경된다.
1. col1의 맨 앞껄 빼서 rows 첫 번째 row의 맨 앞에 넣는다. -> O(1)
2. rows의 첫 번째 row의 마지막껄 빼서 col2의 맨 앞에 넣는다. -> O(1)
3. col2의 마지막껄 빼서 rows 마지막 row의 마지막에 넣는다. -> O(1)
4. rows의 마지막 row의 맨 앞껄 빼서 col1의 마지막에 넣는다. -> O(1)
이번에도 과정으로 그려보면 다음과 같다.
따라서 각 operations마다 각 O(1)로 처리가 가능하고, 이렇게 되면 실제로 0.1초가 안걸려서 효율성 테스트를 통과할 수 있다. 주의점은 c가 2인 경우엔 중간부분이 없으므로 그 부분은 생각하면서 짜야 한다.
코드 : github
import java.util.ArrayDeque;
import java.util.LinkedList;
/**
* 문제 출처: 프로그래머스 코딩 테스트 연습, https://programmers.co.kr/learn/challenges
*/
class Solution {
int r, c;
ArrayDeque<Integer> col1, col2;
LinkedList<ArrayDeque<Integer>> rows;
private void init(int[][] rc) {
r = rc.length;
c = rc[0].length;
col1 = new ArrayDeque<>();
col2 = new ArrayDeque<>();
for (int i = 0; i < r; i++) {
col1.add(rc[i][0]);
col2.add(rc[i][c-1]);
}
rows = new LinkedList<>();
for (int i = 0; i < r; i++) {
ArrayDeque<Integer> tmp = new ArrayDeque<>();
for (int j = 1; j < c-1; j++) {
tmp.add(rc[i][j]);
}
rows.add(tmp);
}
}
private int[][] getAnswer() {
int[][] ans = new int[r][c];
for (int i = 0; i < r; i++) {
ans[i][0] = col1.pollFirst();
ans[i][c-1] = col2.pollFirst();
}
int i = 0;
for (ArrayDeque<Integer> row : rows) {
for (int j = 1; j < c-1; j++) {
ans[i][j] = row.pollFirst();
}
i++;
}
return ans;
}
private void rotate() {
if (c == 2) {
col2.addFirst(col1.pollFirst());
col1.addLast(col2.pollLast());
return;
}
rows.peekFirst().addFirst(col1.pollFirst());
col2.addFirst(rows.peekFirst().pollLast());
rows.peekLast().addLast(col2.pollLast());
col1.addLast(rows.peekLast().pollFirst());
}
private void shiftRow() {
rows.addFirst(rows.pollLast());
col1.addFirst(col1.pollLast());
col2.addFirst(col2.pollLast());
}
public int[][] solution(int[][] rc, String[] operations) {
init(rc);
for (String op : operations) {
switch (op.charAt(0)) {
case 'R' : rotate(); break;
case 'S' : shiftRow(); break;
}
}
return getAnswer();
}
}
'PS > Programmers' 카테고리의 다른 글
[자바] 프로그래머스 - 두 큐 합 같게 만들기 (Lv2, Java) (0) | 2022.08.28 |
---|---|
[자바] 프로그래머스 - 성격 유형 검사하기 (Lv1, Java) (2) | 2022.08.20 |
[자바] 프로그래머스 - 프린터 (programmers java) (0) | 2022.05.04 |
[자바] 프로그래머스 - 신고 결과 받기 (programmers java) (0) | 2022.05.01 |
[자바] 프로그래머스 - 도둑질 (코딩테스트 연습 Lv4) (0) | 2022.04.21 |
댓글