행렬의 곱셈

신연우·2021년 2월 16일
0

알고리즘

목록 보기
38/58
post-thumbnail

프로그래머스 - 행렬의 곱셈

문제 설명

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

제한 조건

  • 행렬 arr1, arr2의 행과 열의 길이는 2 이상 100 이하입니다.
  • 행렬 arr1, arr2의 원소는 -10 이상 20 이하인 자연수입니다.
  • 곱할 수 있는 배열만 주어집니다.

입출력 예

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

풀이

def solution(arr1, arr2):
    answer = [[] for _ in range(len(arr1))]

    for i in range(len(arr1)):
        for j in range(len(arr2[0])):
            total = 0

            for row_num, col in zip(arr1[i], arr2):
                total += (row_num * col[j])

            answer[i].append(total)

    return answer

해결 과정

(고등학교 교육 과정이 개편되면서 행렬을 안 배워서 행렬을 배우고, 그 방식을 구현하느로 꽤나 애를 잡았다.)

행렬의 곱셈 방식이 꽤나 특이하다고 할 수 있다(사실 이거 이해하는데만 꽤나 오랜 시간이 필요했다).


사진 출처 : 행렬의 곱셈 - 수학방

이렇다 보니 arr1에서 행을 가져오고, arr2에서는 열을 가져와 그 둘끼리 곱한 값을 더해야 한다는 건데, 생각이 턱하고 막혔었다.

그 방법을 고민하다 생각난 접근법이 다음과 같다.

  1. arr1에서 행의 인덱스를 가져온다.
  2. arr2에서 열의 인덱스를 가져온다.
  3. arr1의 한 행의 각 숫자들을 arr2의 한 행끼리 연결시킨다.
  4. 2번에서 가져온 열의 인덱스에 해당하는 수와 행의 숫자들을 곱한다.
  5. 그 값을 더해 최종적으로 나온 값을 answer의 (1번에서 가져온 값)행에 새로 push한다.

예시를 든 설명

입출력 예의 2번을 예시로 설명하면......

  • 1번 과정에 의해 현재 arr[i][2, 3, 2]이다.
  • 이를 zip 내장 함수를 통해 arr2와 엮는다.
    • row_num이 2일 때, col[5, 4, 3]이 된다.
    • row_num이 3일 때, col[2, 4, 1]이 된다.
    • row_num이 2일 때, col[3, 1, 1]이 된다.
  • 2번 과정에 의해 현재 j는 0이다.
    • row_num이 2일 때, row_num * col[j]는 10이다.
    • row_num이 3일 때, row_num * col[j]는 6이다.
    • row_num이 2일 때, row_num * col[j]는 6이다.
    • 고로, 이 경우 total은 22이다.
  • 이는 return 행렬에서 첫 번째 행의 첫 번째 열의 값을 구한 것이다.
    • answer[i]는 현재 첫 번째 행을 가리키므로, 이 값을 push하면 된다.

이 과정을 풀이에 맞게 반복하면 전체적인 행렬의 곱셈을 구할 수가 있다.

다른 사람의 풀이

def solution(A, B):
    return [[sum(a*b for a, b in zip(A_row,B_col)) for B_col in zip(*B)] for A_row in A]

(역시 파이썬... 최적의 코드는 언제나 한 줄인 것인가?)

*B가 나에게는 어색한 문법이다. 실제로 *[[5, 4, 3], [2, 4, 1], [3, 1, 1]] 값을 찍어보니 다음과 같이 출력된다.

[5, 4, 3] [2, 4, 1] [3, 1, 1]

기본적으로 printsep가 공백 문자인 것을 감안하면 세 개의 배열이 출력되었다는 것이다.

그렇다면, 이걸 zip으로 묶으면 같은 열에 위치한 값들끼리 묶을 수 있다.

고로, 행렬을 조금 더 쉽게 구할 수 있게 된다는 것을 의미한다.

profile
남들과 함께하기 위해서는 혼자 나아갈 수 있는 힘이 있어야 한다.

0개의 댓글