본문 바로가기

[TIL][내일배움캠프]

[내일배움캠프][TIL] 23.12.15 (금) - 행렬의 곱셈, Android 앱개발 입문 실습과제 : 자기소개 앱 Lv. 2, Lv. 3

1. 코드카타

 

오늘 푼 알고리즘 문제는 '행렬의 곱셈' 이다.

 

 행렬의 곱셈
2차원 행렬 arr1과 arr2를 입력받아, arr1에 arr2를 곱한 결과를 반환하는 함수, solution을 완성하기

 

이 문제를 풀기 전에, 행렬의 곱셈은 어떻게 하는지부터 알아야 한다.

 

행렬의 곱셈

저렇게만 보면 뭘 어떻게 해야하는지 헷갈릴 수도 있는데 간단하게 설명하자면 다음과 같다.

 

첫번째 행렬에서 같은 행에 있는 수와 두번째 행렬에서 같은 열에 있는 수끼리 곱한다. 즉.

 

이런 식으로 계산하면 된다.

이를 arr과 answer 배열 식으로 나타내면 다음과 같다.

 

answer[0][0] = arr1[0][0] * arr2[0][0] + arr1[0][1] * arr2[1][0] + 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 행렬의 행은 arr1의 행의 개수와 일치하고, 열은 arr2의 열의 개수와 일치한다.

 

그리고 이 곱셈에는 조건이 하나가 있는데 바로 arr1의 열의 개수와 arr2의 행의 개수가 일치해야 하는 것.

만약 arr1의 열과 arr2의 행의 개수가 일치하지 않으면 곱셈 자체가 성립할 수 없다.

 

여기까지가 수학적으로 풀어본 행렬의 곱셈이다.

 

 

문제는 이걸 컴퓨터 언어로 어떻게 적절히 표현하느냐인데.

왜 이걸 고민하느냐면 하다보니 꽤나 여러 오류와 맞닥뜨렸기 때문이다.

 

식만 보면 분명 for문으로 하는 게 맞는데 막상 이걸 for문으로 옮겨적으면 오류가 생기게 된다.

 

예를 들면.

 

for (i in 0 until arr1.size) {
    for (j in 0 until arr2.size) {
       for (k in 0 until arr2[j].size) {
           answer[i][k] += arr1[i][j] * arr2[j][k]
     	 }
     }
}

 

이런 식으로 반복문을 적으면 k가 바로 1씩 올라가기 때문에 더해지지 않고 그대로 넘어간다. 당연히 잘못된 식.

하지만, 그렇다고 arr2.size와 arr2[j].size의 자리를 바꾸자니 애초에 식이 성립이 되지 않는다. (j가 정의가 되어야 하는데 저걸 먼저 적으면 정의가 안 되어 있는데 어떻게 써먹을 수 있나)

 

그래서 이거는 다음과 같이 표현해서 해결하였다.

 

for (i in 0 until arr1.size) {
    for (j in 0 until arr2[0].size) {
        for (k in 0 until arr2.size) {
            answer[i][j] += arr1[i][k] * arr2[k][j]
         }
    }
}

 

어차피 arr의 행마다 존재하는 열의 개수는 동일하기 때문에 arr2[0]을 적든 arr2[1]을 적든 똑같은 크기인 것이다.

 

이렇게 하면 우리가 원하는 행렬의 곱셈 식을 구할 수 있게 된다.

 

 

그런데 이렇게 적어도 'index 0 out of bounds for length 0'라는 오류가 뜬다.

이게 무슨 오륜가 싶어서 검색해보니 배열이나 리스트가 비어있는데 접근하려고 할 때 뜨는 오류란다.

 

음…. 뭐가 문제지?

혹시나 뭔가를 빠뜨린 게 아닐까?

 

예를 들면 answer의 크기 설정을 안 했다던가.

 

그래서 ChatGPT에게 2차원 행렬을 만드는 방법을 물어봤더니 이런 대답을 하더라.

 

Array(arr1.size){IntArray(arr2[0].size)}

 

() 안에 있는 글자는 Array의 길이를 말하는 거고, {} 안에 있는 글자는 Array의 인덱스를 말하는 건데 그 안에는 또 IntArray를 집어 넣어서 결국 [[1, 2], [3, 4]]와 같은 배열을 만들 수 있게 된다 한다.

 

그래서 answer를 저렇게 설정해두고 다시 돌려보니 이럴수가. 완벽하게 통과.

 

와…. 이걸 설정하는 것도 정말 중요하구나.

 

그리하여 최종 완성된 코드는 다음과 같다.

class Solution {
    fun solution(arr1: Array<IntArray>, arr2: Array<IntArray>): Array<IntArray> {
        var answer = Array(arr1.size){IntArray(arr2[0].size)}
        
        for (i in 0 until arr1.size) {
            for (j in 0 until arr2[0].size) {
                for (k in 0 until arr2.size) {
                    answer[i][j] += arr1[i][k] * arr2[k][j]
                }
               }
        }
        
        return answer
    }
}

 

 

 

2. Android 앱개발 입문 실습과제 : 자기소개 앱 Lv. 2, Lv. 3

 

지난 시간에 이어서 개인 과제인 자기소개 앱을 완성해보도록 하겠다.

 

우선, 지난 시간에는 SignUpActivity의 UI까지 구현하는 데에는 성공했지만, 코딩은 아직 구현하지 않았는데 오늘 완성하였다.

 

// 이름, 아이디, 비밀번호 셋 중 하나라도 비어있으면 “입력되지 않은 정보가 있습니다.” 라는 토스트 메세지 출력
// 회원가입 버튼을 누르면 SignInActivity로 이동

btnSignUp.setOnClickListener{
	if (nameEditText.text.isEmpty() || idEditText.text.isEmpty() || passwordEditText.text.isEmpty()) {
		Toast.makeText(this, "입력되지 않은 정보가 있습니다.", Toast.LENGTH_SHORT).show()
		return@setOnClickListener
	}

	finish()
}

 

회원가입 버튼을 눌렀을 때, 이름, 아이디, 비밀번호 셋 중 하나라도 비어 있으면 "입력되지 않은 정보가 있습니다."를 출력한 뒤 아무것도 일어나지 않게 하고, 만약 셋 다 입력했으면 finish를 통해서 SignUpActivity를 빠져나온다.

 

 

그리고 대망의 Lv. 3.

더보기

Lv3. 자기소개 페이지 만들기 (HomeActivity)

  • HomeActivity를 생성해 주세요.
  • SignInActivity에서 받은 extra data(아이디)를 화면에 표시해주세요.
  • ImageView, TextView 외에 각종 Widget을 활용해 자유롭게 화면을 디자인 해주세요.
  • 이름, 나이, MBTI 등 자기소개등이 들어가는 위젯을 자유롭게 디자인해주세요.
  • 종료 버튼이 눌리면 SignInActivity로 이동합니다. (finish 활용)

 

우선은 내가 구현한 자기소개 페이지(HomeActivity) UI이다.

자기소개 앱 자기소개 화면

 

역시나 이번에도 우리를 반기는 곽철이.

그리고 신상은 밝힐 수 없으니 MBTI만 빼고 익명처리 해놨다.

 

여기서 아이디 칸만 공란인데 이건 당연히 로그인 화면에서 적은 아이디 정보를 그대로 받아와야 하기 때문에 내가 임의로 적을 수가 없다.

 

이제 코딩을 통해 그 아이디를 출력하는 걸 구현시키면 된다.

겸사겸사 종료 버튼을 눌러서 종료시키는 것까지.

// SignInActivity에서 입력한 아이디 Extras를 받아서 아이디에 출력
// 종료 버튼을 누르면 SignInActivity 화면으로 이동

val idData = intent.getStringExtra("id")
val seeIdData = findViewById<TextView>(R.id.txt_id_confirm)
val btnFinish = findViewById<Button>(R.id.btn_finish)

seeIdData.setText(idData)
btnFinish.setOnClickListener {
	finish()
    }

 

사실 이전에도 val 선언은 했는데 딱히 중요한 정보는 없어서 생략했다.

그 말인즉슨, 이번에는 중요한 정보가 있으니 이렇게 오픈한 것이다.

  • val idData = intent.getStringExtra("id") : Extras에 저장된 값을 불러와서 저장
  • val seeIdData = findViewById<TextView>(R.id.txt_id_confirm) : 위에 있는 UI 화면에서 아이디 옆에 있는 공란 지정
  • seeIdData.setText(idData) : 그 공란에 Extras에 저장된 아이디 채우기

그리고 밑에 종료 버튼을 누르면 끝내는 것까지 완료.

 

 

남는 시간에는 뭔가 밋밋할 수 있는 배경을 한번 꾸며보는 것도 나쁘지 않을 것 같다.