codingtest

행렬과 연산

2025-11-01
2분 분량
JAVA프로그래머스

문제 링크

문제 풀이 시간 : 1시간

문제 요약

  • 주어진 행렬 rc에 대해 두 가지 연산을 수행해야 한다.
  • 여러 번의 연산을 순서대로 수행한 후의 행렬을 반환해야 한다.
  • 시간 효율을 고려해야 함 — 단순 배열 기반으로 회전시키면 시간초과 발생

문제 풀이

이 문제는 처음보자마자 배열로 행렬을 만들어서 하면 절대 안될거라고 생각했다.

그래서 생각한게 Deque를 사용해서 계산하면 앞뒤로 넣고, 뺄 수 있으니 더 빠르게 계산이 가능할 것이라고 생각했다.

그래서 처음에는 단순하게 ArrayList<ArrayDeque> 를 이용해 각 행을 deque로 저장하고, Rotate 연산 시 두 번의 for문으로 직접 앞뒤 원소를 하나씩 밀고 당기는 방식을 사용했다.

java
for(int j=0;j<r;j++){
    if(j!=0)
        a.get(j).removeFirst();
    if(j==r-1)
        break;
    a.get(j).addFirst(a.get(j+1).getFirst());
}
for(int j=r-1;j>=0;j--){
    if(j!=r-1)
        a.get(j).removeLast();
    if(j==0)
        break;
    a.get(j).addLast(a.get(j-1).getLast());
}

하지만 이렇게 하면 각 회전마다 O(r)O(r)의 시간이 들고,

연산 수가 많을 때 시간초과가 발생한다.

실패 코드


핵심 아이디어

이 문제는 “행렬의 전체를 움직이지 않고, 경계선만 빠르게 회전시킬 수 있느냐”가 포인트다.

그래서 행렬을 세 부분으로 분리했다.

plain text
[왼쪽 열]   [가운데 중간 행들]   [오른쪽 열]

이렇게 세 부분을 각각 Deque으로 관리하면 다음과 같은 장점이 생긴다.

  • ShiftRow → 세 deque 각각을 맨 앞/뒤에서 한 칸씩 옮기면 끝 (O(1)O(1))
  • Rotate → 경계 네 구역만 한 칸씩 옮기면 끝 (O(1)O(1))

즉, 한 번의 연산을 상수 시간에 처리할 수 있다.


세부 구현

  1. 분리
  2. ShiftRow 연산
  3. Rotate 연산
  4. 결과 조립

최종 코드

java
import java.util.*;

class Solution {
    public int[][] solution(int[][] rc, String[] operations) {
        int r = rc.length;
        int c = rc[0].length;
        int[][] answer = new int[r][c];
        
        ArrayDeque<Integer> left = new ArrayDeque<>();
        ArrayDeque<Integer> right = new ArrayDeque<>();
        ArrayDeque<ArrayDeque<Integer>> middle = new ArrayDeque<>();
        
        for(int i=0;i<r;i++){
            left.add(rc[i][0]);
            right.add(rc[i][c-1]);
            
            ArrayDeque<Integer> mid = new ArrayDeque<>();
            for(int j=1;j<c-1;j++){
                mid.add(rc[i][j]);
            }
            middle.add(mid);
        }
        
        for(int i=0;i<operations.length;i++){
            String op = operations[i];
            
            if(op.equals("Rotate")){
                middle.getFirst().addFirst(left.removeFirst());
                
                right.addFirst(middle.getFirst().removeLast());
                
                middle.getLast().addLast(right.removeLast());
                
                left.addLast(middle.getLast().removeFirst());
            }
            else{
                left.addFirst(left.removeLast());
                middle.addFirst(middle.removeLast());
                right.addFirst(right.removeLast());
            }
        }
        
        for(int i=0;i<r;i++){
            answer[i][0] = left.removeFirst();
            int idx = 1;
            for(int val : middle.removeFirst()){
                answer[i][idx++] = val;
            }
            answer[i][c-1] = right.removeFirst();
        }
        return answer;
    }
}

함께 읽으면 좋은 글

코딩 테스트2026-08-23

택배상자

order 배열은 택배 기사님이 원하는 상자 적재 순서다 기존 컨테이너 벨트는 1번부터 순서대로만 꺼낼 수 있다 보조 벨트는 스택처럼 마지막에 넣은 것부터 꺼낼 수 있다 원하는 순서대로 최대한 실을 수 있는 상자 개수를 구하는 문제다 처음에는 기존 벨트를 실제 리스트로 만들어…

코딩 테스트2026-08-23

롤케이크 자르기

topping 배열은 롤케이크에 일렬로 올라간 토핑 번호다 한 지점을 잘라 두 조각으로 나눴을 때, 양쪽 토핑 종류 수가 같아야 공평하게 나눈 것이다 공평하게 자를 수 있는 방법의 수를 구하는 문제다 처음에는 자르는 위치마다 왼쪽과 오른쪽 배열을 나눠서 각각 서로 다른 토핑…

코딩 테스트2026-08-23

할인 행사

want, number 배열로 정현이가 원하는 제품과 수량을 표현한다 discount 배열은 XYZ 마트가 매일 할인하는 제품 목록이다 연속된 10일 동안 할인 제품 종류와 수량이 want, number와 정확히 일치해야 회원가입할 수 있다 그런 시작일이 총 몇 번 있는지…

코딩 테스트2026-08-23

숫자 변환하기

자연수 x를 y로 바꾸는 데 x+n, x2, x3 세 가지 연산을 쓸 수 있다 x를 y로 바꾸는 최소 연산 횟수를 구하는 문제다 만들 수 없으면 -1을 반환한다 처음에는 x에서 시작해서 세 가지 연산을 재귀적으로 다 시도해보고 y에 도달하는 경로 중 가장 짧은 걸 고르면…