코딩테스트

프로그래머스 - 행렬의 곱셈 (레벨2, swift)

momo_9 2020. 7. 10. 08:29

문제출처

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

 

문제설명

2차원 행렬 arr1과 arr2를 입력받아, arr1에 arr2를 곱한 결과를 반환하는 함수, solution을 완성해주세요.

 

제한 조건

    -  행렬 arr1, arr2의 행과 열의 길이는 2 이상 100 이하입니다.

    -  행렬 arr1, arr2의 원소는 -10 이상 20 이하인 자연수입니다.

    -  곱할 수 있는 배열만 주어집니다.

 

입출력 예

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]]

 

 문제풀이

ㅋㅋㅋ 드디어 for문 3개를 중첩해보는 경험을 했다!

for문 3개를 중첩해본 적이 없어서 코드를 짤때는 죄짓는(??) 기분이 들었으나

다 풀고 다른 사람풀이를 보니 많이들 이렇게 한 것 같아 안심했다ㅋㅋ...

 

먼저 행렬의 곱셈 계산식부터 알아야 한다. 이것을 모르면 이 문제는 절대 풀 수 없다.

첫번째 입출력 예를 가지고 간단하게 살펴보도록 하자.

 

행렬의 곱셈은 좌측 행렬의 행과 우측 행렬의 열을 곱해주면 된다.

먼저 arr1의 첫번째 행과 arr2의 첫번째 열을 곱해주면 된다.

arr1의 첫번째 행 arr2의 두번째 열
[1, 4] [3]
[3]

 

arr1          arr2  return
[1, 4]       [3, 3]
[3, 2]       [3, 3]
[4, 1]                
[15, 15]
[15, 15]
[15, 15]

-> 1 * 4 + 3 * 3 = 15  

 

arr1          arr2  return
[1, 4]       [3, 3]
[3, 2]       [3, 3]
[4, 1]
[15, 15]
[15, 15]
[15, 15]

-> 1 * 4 + 3 * 3 = 15

 

arr1          arr2  return
[1, 4]       [3, 3]
[3, 2]      [3, 3]
[4, 1]
[15, 15]
[15, 15]
[15, 15]

-> 3 * 3 + 2 * 3 = 15

 

이런식으로 행렬을 행과 열끼리 곱하게 하는 것이 행렬의 곱셈이다.

 

이제 이것을 코드로 구현해야 하는데 처음엔 어떻게 해야할 지 아무런 생각이 떠오르지 않아 막막했다.

그래서 계산에 사용되는 배열 index를 일일이 써보고 숫자들이 어떻게 변화하는지 살펴보았다.

 

arr1[0][0] * arr2[0][0] + arr1[0][1] * arr2[1][0]

arr1[0][0] * arr2[0][1] + arr1[0][1] * arr2[1][1]

---------------------------------------------

arr1[1][0] * arr2[0][0] + arr1[1][1] * arr2[1][0]

arr1[1][0] * arr2[0][1] + arr1[1][1] * arr2[1][1]

---------------------------------------------

arr1[2][0] * arr2[0][0] + arr1[2][1] * arr2[1][0]

arr1[2][0] * arr2[0][1] + arr1[2][1] * arr2[1][1]

 

수고스럽긴 하지만 이렇게 써놓고 보니 반복되는 부분과 변화하는 부분이 한눈에 보인다.

arr1은 각 행의 0번 인덱스와 1번 인덱스가 번갈아 가며 나타난다.

그리고 그와 함께 arr2는 [00] [10] [01] [11] 순서로 index가 반복된다.

 

반복문을 통해 위의 인덱스에 해당하는 숫자들을 표현할 수만 있다면 이 문제는 끝이다!

 

0과 1의 인덱스가 반복되도록 하는 것은 단순하게 for문을 사용하면 되니 따로 설명하지 않겠다.

[00] [10] [01] [11]는 이중 for문을 사용하고 출력 순서를 바꾸면 된다.

아래 코드를 참고하자

 

j와 i의 순서를 바꾸면 원하는 순서대로 숫자를 출력할 수 있다.

 

따라서 이 문제는 arr1을 한 행씩 출력하게 하는 반복문 안에 위의 2중 for문을 넣어서 arr2의 index를 출력하게 하면 된다.

 

1) var result: [[Int]] = [] 

  -> 결과값을 저장할 이중배열을 변수로 생성한다.

 

2) var temp = 0

  -> 반복문을 통해 계산되는 값을 임시로 저장해줄 변수를 생성한다.

 

3) for index in 0..<arr1.count {

  -> arr1의 각 행이 순차적으로 반복되도록 반복문을 만들어준다.

 

4) result.append([])

  -> 각 행이 시작될 때 result에 빈 배열을 초기화 해준다.

 

5) for i in 0..<arr2[0].count {

      for j in 0..<arr2.count {

  -> 이중 for문을 만들어 준다. i는 arr2의 열, j는 arr2의 행을 의미한다는 것을 잊지 말아야 한다.

      따라서, i는 arr2의 각 행이 가진 값의 개수(arr2[0].count) 만큼 반복되도록 해주고, j는 행의 개수(arr2.count)만큼 반복되도록 해주어야 한다. i와 j를 뒤집어 사용하기 때문에 이 부분이 헷갈릴 수 있는데 이 부분을 정확하게 적어주지 않으면 채점 결과 0점이 나오게 된다...(ㅠㅠ)

 

6) temp += arr1[index][j] * arr2[j][i]

 -> 행렬 곱셈식을 적어준다. 가장 안쪽에 있는 반복문이 전부 돌아야 하나의 식이 완성되므로 temp에 계속 +해주며 계산을 해주면 된다. 이 반복문이 한 바퀴 돌아 식이 완성되면 해당 값을 result에 append해주고 temp는 0으로 초기화 해준다.