코딩연습

(javascript) 행렬과 연산

Realuda72 2025. 8. 7. 02:21

https://school.programmers.co.kr/learn/courses/30/lessons/118670

 

프로그래머스

SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

은근히 어려운 문제였다.

핵심 아이디어를 떠올리지 못하면 효율성 테스트를 통과하지 못할 것 같다.

 

 정확도 테스트만 있었다면 단순하게 모든 원소를 일일이 이동하도록 구현해도 통과할 수 있었을 것이다.

 그러나 효율성 테스트를 통과하려면 그래서는 안된다.

 

 핵심 아이디어는 회전 명령을 수행하기 위해 행렬의 테두리만을 따로 관리하는 것이다.

 

 행렬의 제일 왼쪽 열, 제일 오른쪽 열, 제일 윗 행, 제일 아랫 행을 각각 큐로 관리하면 회전 연산을 O(1)만에 처리할 수 있다는 아이디어다.

 나는 아무리해도 효율성 테스트를 통과할만한 아이디어가 떠오르지 않아서 인터넷에 검색해봤다.

 

 자바스크립트에서는 배열에 직접 push, pop, shift, unshift 연산을 수행할 수 있지만, 내부적으로는 모든 원소의 위치를 하나씩 밀고 당기기 때문에 O(n)의 시간복잡도를 가진다. 따라서 이 문제에서 사용하기 위한 커스텀 큐를 구현해야했다.

 직접 구현한 큐는 내부에 배열을 가지고, 큐의 시작 인덱스, 끝 인덱스를 따로 가리키는 방법으로 구현했다. 배열의 원소 전체를 옮기기 보다 가리키는 위치만 옮기는 방법으로 O(1)만에 모든 연산을 처리할 수 있다.

 

 마지막으로 한가지 함정같은 케이스가 있었는데, 행렬의 열의 갯수가 2개인 경우이다.

 내가 구현한 방법으로는 열이 2개인 경우, 즉 body가 없는 경우 예외 처리를 해주어야 했다. 이 부분을 놓쳐서 효율성 테스트 하나를 실패했다.

 

코드

function solution(rc, operations) {
    const col = rc.length;
    const row = rc[0].length;
    var answer = Array.from({ length: col }, () => new Array(row));

    var head = new Queue(col);
    var tail = new Queue(col);
    var body = new Array(col);
    for (var i = 0; i < col; i++) {
        head.push(rc[i][0]);
        tail.push(rc[i][row - 1]);
    }
    for (var i = 0; i < col; i++) {
        var q = new Queue(row - 2);
        for (var j = 1; j < row - 1; j++) {
            q.push(rc[i][j]);
        }
        body[i] = q;
    }

    let top = 0;
    let bot = col - 1;
    for (var i = 0; i < operations.length; i++) {
        if (operations[i] === 'ShiftRow') {
            // 평행이동
            head.translate();
            tail.translate();
            top--;
            bot--;
            if (top < 0) top += col;
            if (bot < 0) bot += col;
        } else if (operations[i] === 'Rotate') {
            // 회전
            if (row == 2) {
                var temp = head.unshift();
                head.push(tail.pop());
                tail.shift(temp);
            } else {
                var temp = head.unshift();
                head.push(body[bot].unshift());
                body[bot].push(tail.pop());
                tail.shift(body[top].pop());
                body[top].shift(temp);
            }
        }
    }

    for (var i = 0; i < col; i++) {
        answer[i][0] = head.unshift();
        answer[i][row - 1] = tail.unshift();
        for (var j = 1; j < row - 1; j++) {
            var t = i + top;
            if (t >= col) t -= col;
            answer[i][j] = body[t].unshift();
        }
    }
    return answer;
}

class Queue {
    constructor(size) {
        this.size = size;
        this.array = new Array(size);
        this.head = 0;
        this.tail = -1;
    }

    // 앞에서 추가
    shift(value) {
        this.head--;
        if (this.head < 0)
            this.head += this.size;
        this.array[this.head] = value;
    }

    // 앞에서 제거
    unshift() {
        let result = this.array[this.head];
        this.head++;
        if (this.head >= this.size)
            this.head -= this.size;
        return result;
    }

    // 뒤에 추가
    push(value) {
        this.tail++;
        if (this.tail >= this.size)
            this.tail -= this.size;
        this.array[this.tail] = value;
    }

    // 뒤에서 제거
    pop() {
        let result = this.array[this.tail];
        this.tail--;
        if (this.tail < 0) this.tail += this.size;
        return result;
    }

    translate() {
        this.head--;
        this.tail--;
        if (this.head < 0) this.head += this.size;
        if (this.tail < 0) this.tail += this.size;
    }

    toArray() {
        let result = new Array(this.size);
        for (var i = 0; i < this.size; i++) {
            result[i] = this.array[this.head];
            this.head++;
            if (this.head >= this.size) this.head -= this.size;
        }
        return result;
    }
}

'코딩연습' 카테고리의 다른 글

(javascript) 경주로 건설  (0) 2025.09.12
(javascript) 외벽 점검  (0) 2025.09.11
(javascript) 자물쇠와 열쇠  (2) 2025.08.05
(C#) 110 옮기기  (1) 2025.08.04
(C#) 방의 개수  (3) 2025.08.01