일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 엘리스 AI 트랙 5기
- 자바스크립트 날씨 웹 만들기
- 코딩부트캠프
- 자바스크립트 sort()
- [파이썬 실습] 심화 문제
- 개발일기
- 프로그래머스
- 프론트개발공부
- 부트캠프
- 프론트개발
- leetcode
- 자바스크립트 날씨
- 삼항연산자
- 엘리스
- 리트코드
- HTML
- RN 프로젝트
- 자바스크립트
- JavaScript
- 날씨 웹 만들기
- [파이썬 실습] 중급 문제
- [AI 5기] 연습 문제집
- 간단한 날씨 웹 만들기
- [파이썬 실습] 기초 문제
- 코드스테이츠
- 자바스크립트 reduce()
- 엘리스 ai 트랙
- 개발공부
- 자바스크립트 split()
- reactnativecli
- Today
- Total
개발조각
[프로그래머스] 행렬의 곱셈 본문
행렬의 곱셈이라... 행렬이 제가 고등학교 올라갔을 때 사라져서 배운 기억이 없어요.😅
그래서 검색해서 행렬의 곱셈이 뭔지 공부하고 풀었습니다.
행렬의 곱셈이 뭔지 아시면 쉽게 풀었을 것 같아요.
행렬의 곱셈이란
위키백과에 나와있는 행렬의 곱셈이란
행렬 곱셈(matrix multiplication)은 두 개의 행렬에서 한 개의 행렬을 만들어내는 이항 연산이다.
이때 첫째 행렬의 열 개수와 둘째 행렬의 행 개수가 동일해야 한다.
곱셈의 결과 새롭게 만들어진 행렬은 행렬곱(matrix product)라 하며, 첫째 행렬의 행 개수와 둘째 행렬의 열 개수를 가진다.
행렬 A와 B의 곱은 간단히 AB로 나타낸다.
이렇게 씌여져 있긴 한데 저는 이걸 봐서는 행렬 곱셈이 뭔지 이해가 안 돼서 다른 자료를 찾아보았습니다.🙂
저는 행렬의 곱셈이 뭔지 아래 링크로 알게 되었습니다.👇
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=junhyuk7272&logNo=50128686426
(2013수정)2강 행렬의 곱셈
1. 행렬의 곱셈 행렬의 곱셈은 계산 방법이 매우 독특하므로 여러번 반복해서 잘 익혀두어야 한다. 그 과정...
blog.naver.com
행렬의 곱셈은 이게 전부입니다.
이걸로 봐서 이해가 안 되시는 분들을 위해
제가 행렬의 곱셉 문제에 나와 있는 테스트로 손으로 써가면서 행렬의 곱셈을 해보았습니다.
(악필 주의)
테스트 1
arr1 = [[1, 4], [3, 2], [4, 1]]
arr2 = [[3, 3], [3, 3]]
return = [[15, 15], [15, 15], [15, 15]]
테스트 2
arr1 = [[2, 3, 2], [4, 2, 4], [3, 1, 4]]
arr2 = [[5, 4, 3], [2, 4, 1], [3, 1, 1]]
return = [[22, 22, 11], [36, 28, 18], [29, 20, 14]]
위의 이미지를 보시면 행렬의 곱셈은 규칙성이 있습니다.
이 규칙성을 토대로 코드를 짜면 됩니다.
해결방안
function solution(arr1, arr2) {
// 버전 1
var answer = [];
for(let i=0; i<arr1.length; i++){
let matrixArr =[]
let matrixSum = 0;
for(let j=0; j<arr2[0].length; j++){
matrixSum = arr1[i].reduce((acc, cur, idx)=> acc+ cur*arr2[idx][j], 0);
matrixArr.push(matrixSum);
}
answer.push(matrixArr);
}
return answer;
// 버전 2
return arr1.map((row) => arr2[0].map((a,i) => row.reduce((acc,cur,idx) => acc + cur * arr2[idx][i], 0)))
}
이번 해결방안도 두 가지 버전으로 들고 왔습니다.
버전 1은 for문과 reduce를 사용해서 행렬의 곱셈을 answer배열에 담아주는 방법이고
버전 2는 map()과 reduce를 사용해서 arr1를 행렬의 곱셈의 값으로 바꾸어주는 방법입니다.
버전 1, 버전 2 둘 다 결국은 위에 있는 이미지를 토대로 코드를 짜줍겁니다.
단지 방식만 다를 뿐이고요.
버전 1
// 버전 1
var answer = [];
for(let i=0; i<arr1.length; i++){
let matrixArr =[]
let matrixSum = 0;
for(let j=0; j<arr2[0].length; j++){
matrixSum = arr1[i].reduce((acc, cur, idx)=> acc+ cur*arr2[idx][j], 0);
matrixArr.push(matrixSum);
}
answer.push(matrixArr);
}
return answer;
첫 번째 for문은 arr1[여기][]를 나타냅니다.
그래서 첫 번째 for문은 arr1.length만큼 반복문으로 돌려주었습니다.
두 번째 for문은 arr2[][여기]를 나타냅니다.
그래서 두 번째 for문은 arr2[0].length만큼 반복문으로 돌려주었습니다.
여기서 arr2.length만 쓰거나 arr2[i].length로 쓰면 "제출 후 채점하기"에서 전부 다~ 틀립니다.
이유는 두 번째 for문에서는 2차원 배열의 원소의 길이만큼 반복해야 되기 때문입니다.
(즉, [[5, 4, 3], [2, 4, 1], [3, 1, 1]]에서 [5, 4, 3]-> 3번 [2, 4, 1] -> 3번 [3, 1, 1] -> 3번 3번씩만 반복해야 됨)
여기서 arr2[i]를 쓰면 안 되는 이유는
arr1의 배열 길이가 arr[?]의 배열 길이 같지 않을 수도 있기 때문이기도 하고
arr2[0].length, arr2[1].length, arr2[2].length은 다 같기 때문에 [0]이라고 써주어야 됩니다.
(그래서 제가 이거 때문에 삽질했습니다.😔)
세 번째는 반복문에서는 arr1[][여기], arr2[여기][]
여기서는 for문으로 적을 수 있지만 reduce로 적었습니다.
reuduce는 배열의 누적된 값을 구할 때 사용하기 편한 것 같아요.
reuduce 에는 누산기 (acc), 현재 값 (cur), 현재 인덱스 (idx)를 인자로 사용할 수 있어서 좋은 것 같아요.
이렇게 3개 다 쓸 경우에는 초기값 필수입니다.
reduce안에 acc+ cur*arr2[idx][j] 쓴 이유는 아래 이미지를 보시면 아실 것 같습니다.
테스트 2에서 i=0, j=0일 경우에만 테스트해보자면
테스트 2
arr1 = [[2, 3, 2], [4, 2, 4], [3, 1, 4]]
arr2 = [[5, 4, 3], [2, 4, 1], [3, 1, 1]]
return = [[22, 22, 11], [36, 28, 18], [29, 20, 14]]
i = 0; j=0;
arr1[i].reduce((acc, cur, idx)=> acc+ cur*arr2[idx][j], 0);
arr1[0].reduce((acc, cur, idx)=> acc+ cur*arr2[idx][0], 0);
arr1[0][0], idx=0
acc = 0
cur = arr1[0][0] -> 2
arr2[idx][0] -> arr2[0][0] -> 5
=> 0+ 2*5 = 10
arr1[0][1], idx=1
acc = 10
cur = arr1[0][1] -> 3
arr2[idx][0] -> arr2[1][0] -> 2
=> 10+ 3*2 = 10+6 = 16
arr1[0][2], idx=2
acc = 16
cur = arr1[0][2] -> 2
arr2[idx][0] -> arr2[2][0] -> 3
=> 16+ 2*3 = 16+6 = 22
reduce에서 나온 22라는 값은 return[0][0]값과 같습니다.
이런 식으로 반복하게 됩니다.
버전 2
// 버전 2
return arr1.map((row) => arr2[0].map((a,i) => row.reduce((acc,cur,idx) => acc + cur * arr2[idx][i], 0)))
버전 2는 arr1를 return으로 바꾸어 주는 코드입니다.
map()은 배열은 새로운 배열을 반환할 때 사용하는 메서드인데요.
map() 메서드를 중복으로 쓰면 1차원 배열에서 2차원 배열로 만들 수 있습니다.
첫 번째 map
row는 버전 1로 비유하면 arr[i]와 같습니다.
두 번째 map
i는 버전 1에서 j와 같습니다.
두 번째 map에서 arr2[0].map()이라 쓴 이유는 버전 1에서 j<arr2[0].length;랑 쓴 이유랑 같다고 생각하시면 됩니다.
여기서는 index값이 필요한데 이 값을 map메서드에서 두 번째로 들어가서 a, i로 넣어주었습니다.
reduce
버전 1에서는 arr1[i].reduce((acc, cur, idx)=> acc+ cur*arr2[idx][j], 0); 이렇게 써주었습니다.
버전 2에는 row.reduce((acc,cur,idx) => acc + cur * arr2[idx][i], 0) 이렇게 써주었습니다.
위에서 row는 arr[i]와 같다고 했고, i는 j와 같다고 했습니다.
사실상 버전 1 축약 버전이 버전 2라고 생각하시면 됩니다.
여기까지 프로그래머스 행렬의 곱셈 해결방안에 대해 설명해보았습니다.
'알고리즘🅰 > 프로그래머스' 카테고리의 다른 글
[프로그래머스] 주차 요금 계산 (0) | 2022.04.22 |
---|---|
[프로그래머스] 이진 변환 반복하기 (0) | 2022.04.21 |
[프로그래머스] 모음 사전 (0) | 2022.04.20 |
[프로그래머스] 짝지어 제거하기 (0) | 2022.04.18 |
[프로그래머스] [3차] n진수 게임 (0) | 2022.04.17 |