2차원 행렬 arr1과 arr2를 입력받아, arr1에 arr2를 곱한 결과를 반환하는 함수, solution을 완성해주세요.
arr1 | arr2 | return |
---|---|---|
[[1, 4], [3, 2], [4, 1]] | [[3, 3], [3, 3]] | [[15, 15], [15, 15], [15, 15]] |
[[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]] |
arr1과 arr2를 이용하여 행렬 곱셈을 수행한다.
행렬의 곱셈은 아래와 같이 2X3, 3X2 배열이 예시로 있을 경우
2X3 | [0] | [1] | [2] |
---|---|---|---|
[0] | a | b | c |
[1] | d | e | f |
3X2 | [0] | [1] |
---|---|---|
[0] | A | D |
[1] | B | E |
[2] | C | F |
다음과 같이 계산한다.
2X2 | [0] | [1] |
---|---|---|
[0] | aA + bB + cC | aD + aE + aF |
[1] | dA + eB + fC | dD + eE + fF |
결과로 나오는 행렬은 (배열1의 세로(행) 길이 X 배열2의 가로(열) 길이) 크기로 생성된다.
answer
)을 초기화 해준다.let answer = new Array(arr1.length);
for(let i = 0; i < answer.length; i++) {
answer[i] = new Array(arr2[0].length).fill(0);
}
반복되어야 하는 순서가 중요하다.
우선 반복되어야 하는 것은 다음과 같다.
첫 번째 반복문(i
)은 arr1의 세로 인덱스를 제어할 수 있고
두 번째 반복문(j
)은 arr2의 가로 인덱스를 제어할 수 있다.
그렇다면 마지막으로 arr1의 가로 인덱스와 arr2의 세로 인덱스를 제어해 줄 반복문(k
)을 하나 더 추가한다.
arr1 가로 길이와 arr2 세로 길이가 같아야 식이 성립할 수 있는데, 제한 조건으로 항상 계산할 수 있는 식이 오기 때문에 따로 처리할 필요는 없다.
for(let i = 0; i < arr1.length; i++) { // arr1의 세로만큼 반복 : answer의 세로, arr1의 세로 인덱스 제어
for(let j = 0; j < arr2[0].length; j++) { // arr2의 가로만큼 반복 : answer의 가로, arr2의 가로 인덱스 제어
for(let k = 0; k < arr1[0].length; k++) { // arr1의 가로만큼 반복 : arr1의 가로, arr2의 세로 인덱스 제어
answer[i][j] = "계산한 값";
}
}
}
arr1의 가로와 arr2의 세로를 제어하기 위해서 k를 이용한다.
앞서 말했듯이, 각각이 제어할 수 있는 인덱스가 정해져 있다.
i
: arr1의 세로 인덱스j
: arr2의 가로 인덱스k
: arr1의 가로, arr2의 세로 인덱스그대로 식에 넣기만 하면 된다.
answer[i][j]
에 계속 더해주는 이유는 아래 예시에서 알 수 있다.
answer[0][0]
에 저장되는 값은 arr1[0][0] * arr2[0][0]
, arr1[0][1] * arr2[1][0]
, arr1[0][2] * arr2[2][0]
이 세 가지 값을 더한 값이기 때문이다.
answer[i][j] += arr1[i][k] * arr2[k][j];
// 계산 예시
// answer[0][0] =
// 1: (arr1[0][0] * arr2[0][0]) +
// 2: (arr1[0][1] * arr2[1][0]) +
// 3: (arr1[0][2] * arr2[2][0]);
// answer[0][1] =
// (arr1[0][0] * arr2[0][1]) +
// (arr1[0][1] * arr2[1][1]) +
// (arr1[0][2] * arr2[2][1]);
// answer[1][0] =
// (arr1[1][0] * arr2[0][0]) +
// (arr1[1][1] * arr2[1][0]) +
// (arr1[1][2] * arr2[2][0]);
// answer[1][1] =
// (arr1[1][0] * arr2[0][1]) +
// (arr1[1][1] * arr2[1][1]) +
// (arr1[1][2] * arr2[2][1]);
function solution(arr1, arr2) {
let row1 = arr1.length;
let col1 = arr1[0].length;
let col2 = arr2[0].length;
let answer = new Array(arr1.length);
for(let i = 0; i < answer.length; i++) {
answer[i] = new Array(arr2[0].length).fill(0);
}
// let count = 0;
for(let i = 0; i < row1; i++) { // arr1의 세로만큼 반복 : answer의 세로, arr1의 세로 인덱스 제어
for(let j = 0; j < col2; j++) { // arr2의 가로만큼 반복 : answer의 가로, arr2의 가로 인덱스 제어
for(let k = 0; k < col1; k++) { // arr1의 가로만큼 반복 : arr1의 가로, arr2의 세로 인덱스 제어
answer[i][j] += arr1[i][k] * arr2[k][j];
// console.log(`arr1[${i}][${k}] : ${arr1[i][k]}`);
// console.log(`arr2[${k}][${j}] : ${arr2[k][j]}`);
// console.log(`answer[${i}][${j}] : ${answer[i][j]}`);
// count += 1;
}
// console.log();
}
// console.log();
}
// console.log("전체 계산 횟수", count);
return answer;
}
function solution(arr1, arr2) {
return arr1.map((row) => // arr1의 세로 반복
arr2[0].map((x, y) => // arr2의 가로 반복
// reduce(콜백 함수, 초기값)
row.reduce(
(a, b, c) => {
return a + b * arr2[c][y];
}, 0)
// 콜백으로 arr1의 가로 요소 반복
// a : 누적 값
// b : arr1의 가로 요소
// c : arr2 세로 인덱스 제어
// => b * arr2[c][y] : 계산한 값
)
);
}
테스트 1 〉 통과 (3.37ms, 33.3MB)
테스트 2 〉 통과 (6.23ms, 34.4MB)
테스트 3 〉 통과 (7.45ms, 34.8MB)
테스트 4 〉 통과 (3.30ms, 33.1MB)
테스트 5 〉 통과 (6.61ms, 34.6MB)
테스트 6 〉 통과 (7.50ms, 34.3MB)
테스트 7 〉 통과 (1.67ms, 30.5MB)
테스트 8 〉 통과 (0.44ms, 30.7MB)
테스트 9 〉 통과 (0.37ms, 30.6MB)
테스트 10 〉 통과 (5.81ms, 34.1MB)
테스트 11 〉 통과 (3.44ms, 33.1MB)
테스트 12 〉 통과 (0.47ms, 30.6MB)
테스트 13 〉 통과 (7.29ms, 34.2MB)
테스트 14 〉 통과 (7.61ms, 34.5MB)
테스트 15 〉 통과 (4.39ms, 32.9MB)
테스트 16 〉 통과 (5.48ms, 33.6MB)
- 정확성 : 100.0
- 합계 : 100.0 / 100.0