코딩테스트 공부

[프로그래머스] 행렬의 곱셈 - 자바스크립트

codevil 2022. 4. 25. 00:06

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

 

코딩테스트 연습 - 행렬의 곱셈

[[2, 3, 2], [4, 2, 4], [3, 1, 4]] [[5, 4, 3], [2, 4, 1], [3, 1, 1]] [[22, 22, 11], [36, 28, 18], [29, 20, 14]]

programmers.co.kr

문제의 난이도가 어렵진 않다. 단지, 행렬의 계산이 어떻게 되는지를 머리로 잘그리고, 반복문에 수행되는 i, j, k 를 지정하는게 상당히 불편하다. 

1. 사람마다 array를 만들면서, 문제를 푸는경우, 혹은 나처럼, 먼저 0을 넣어서 행렬의 모양을 만드는 풀이 두가지로 처음 풀이가 갈릴꺼 같다. (맨처음 for문을 사용한이유에 대한설명)

    let num = arr1.length;
    let num2 = arr2[0].length;
    let list = [];
    for (let i = 0 ; i<num;i++){
        let l = []
        for(let j=0; j<num2;j++){
            l.push(0);
        }
        list.push(l)
    }

2. 반복문이 3개 필요한 이유는 다음과 같다 행렬에는 2 * 3 행렬이 있으면 2 * 3의 행렬과 곱해야하는 행렬은 3 * x가 되야한다 그렇기에, x * y와 y * z 와 같이 이어주는 문자가 하나 필요하다.여기서는 y (행렬을 풀기 위한 선행지식)

3. 행렬을 곱은, 1 * 2 행렬과 2 *1의 행렬을 간단하게 곱해보면, list[0][0] = arr1[0][0] * arr2[0][0] + arr1[0][1] * arr2[1][0] 과 같다, 즉 list[i][j] = arr1[i][k]*arr2[k][j] + arr1[i][k]*arr2[k][j] 과 같은 모양이 나온다. 사실 i j 의 위치가 중요한게 아니라, 0 0 고정되있는 두개의 값과, 움지기는 유동의 값이 i j 사이에 들어가야 한다는 것을 인지하는게 중요하다.

    for(let i=0;i<num;i++){
        for(let j=0;j<arr2[0].length;j++){
            for(let k =0; k<arr1[0].length;k++){
                list[i][j] = arr1[i][k]*arr2[k][j]+list[i][j];
            }
        }
    }

그리고 다음과 같이 만들면 (사실, 위으 풀이처럼 +를 누적해서 하지않고, k에대한 값을 sum으로 받아서 풀이하는 방법도 있다.

 

모든 풀이를 붙이면 다음과 같다.

function solution(arr1, arr2) {

    let num = arr1.length;
    let num2 = arr2[0].length;
    let list = [];
    for (let i = 0 ; i<num;i++){
        let l = []
        for(let j=0; j<num2;j++){
            l.push(0);
        }
        list.push(l)
    }

    for(let i=0;i<num;i++){
        for(let j=0;j<arr2[0].length;j++){
            for(let k =0; k<arr1[0].length;k++){
                list[i][j] = arr1[i][k]*arr2[k][j]+list[i][j];
            }
        }
    }
    return list;
}

문제를 풀때 하나씩 플로우 차트를 못하던 시절에는 상당히 귀찮았었...던 문제다 (지금 다시푸니까 그래도 쉽게 풀리는거지 이전엔 반복문을 어떻게 잡을지 못했었다). 플로우 차트를 작성하는 연습을 조금씩 늘리다보면 점점 좋아질꺼같다