[24.06.11] TIL - 008

0. 오늘은 무엇을 했는가

오늘은 알람이 제대로 울려서 늦지 않았습니다.

먼저 코드 카타를 풀고, 오늘 하루 계획을 세웠습니다.

그리고 오늘부터 Kotlin 심화 강의를 시작하는 날이기에,

이와 관련된 발제를 들었습니다.

그리고, 심화 강의를 듣기 전 컬렉션에 대해 조금 공부했습니다.

점심을 먹고 난 뒤에 4강을 들었고, 이후 코드 카타 21~30번까지 풀어봤습니다.

1. 코드 카타

[ 09:00 ~ 10:00 ]

오늘의 코드 카타 주제는 카펫이었습니다.

엥? 카펫? 이건 어떤 알고리즘이지? 하고 들어갔습니다.

아... 진짜 그 카펫이었습니다.

코드 카타 링크

Leo는 집으로 돌아와서 아까 본 카펫의 노란색과 갈색으로 색칠된 격자의 개수는 기억했지만, 전체 카펫의 크기는 기억하지 못했습니다.
Leo가 본 카펫에서 갈색 격자의 수 brown, 노란색 격자의 수 yellow가 매개변수로 주어질 때 카펫의 가로, 세로 크기를 순서대로 배열에 담아 return 하도록 solution 함수를 작성해주세요.

어떤 사람이 이 타일의 개수까지 외우는 건지 의문이 들었지만, 문제이기 때문에 풀어보기 위해 접근 방법을 생각해봤습니다.

일단 카펫의 패턴의 경우의 수에 대해 생각했습니다.

노란색이 3개일 때까지는 그대로 3개를 가로로 나열하면 되지만, 4개는 경우의 수가 2개가 생깁니다.

갈갈갈갈갈갈 갈갈갈갈
갈노노노노갈 갈노노갈
갈갈갈갈갈갈 갈노노갈
ㅁㅁㅁㅁㅁㅁ 갈갈갈갈

이런 식으로 2가지로 나뉩니다.

그래서 저는 이 카펫을 분석했습니다. 먼저, 테두리의 모서리는 총 4개 고정이고,
모서리를 제외한 테두리는 노란색의 가로, 세로와 같은 길이를 갖고 있습니다.

즉, 갈색의 개수는 (노란색 가로 길이 + 노란색 세로 길이) x 2 + 4 개입니다.

그래서 저는 갈색의 개수를 구하기 위해 노란색 가로, 세로에 해당할 수 있는 값을 찾기 위해

노란색의 개수에 대한 약수들을 구하고, 해당 값들이 갈색 개수식에 들어갔을 때 입력된 갈색 개수와 같다면,
그 값이 정답이다! 라는 코드를 적었습니다.

class Solution {
   fun solution(brown: Int, yellow: Int): IntArray {
       var answer = intArrayOf(0, 0)
       if(yellow == 1) answer = intArrayOf(3, 3)
       for(i in 1..(yellow / 2) ) {
           if(yellow % i == 0) {
               val hor = yellow / i
               val guess = (i + hor) * 2 + 4
               if(guess == brown) {
                   answer = intArrayOf(hor + 2, i + 2)
                   break
               }
           }
       }
       return answer
   }
}

오늘 코드 카타는 이전 문제들과 다르게 어느 정도 수학적인 풀이가 있어서 재밌었던 것 같습니다.

2. Kotlin 컬렉션 - 1

[ 11:00 ~ 12:00 ]

오늘은 컬렉션에 대해서 개인적으로 공부했습니다.

컬렉션은 종류도 워낙 다양하고, 확장 함수, 프로퍼티도 많기 때문에 천천히 진행하려고 합니다.

그래서 오늘은 List, Set, Map에 대해서 먼저 공부했습니다.

먼저 List는 순서가 있는 요소들을 모아둔 컬렉션입니다. 중복 값이 있어도 됩니다.

val list:List<타입> = listOf(값)

기본적으로 컬렉션들은 Mutable이 붙으면 가변으로 변합니다.

우선 불변 상태인 List의 확장 함수부터 알아보겠습니다.

// 인덱스에 해당하는 값
list.get(인덱스) 또는 list[인덱스]

// 값이 있는 위치 찾기
list.indexOf(값)

// 끝에서부터 찾기
list.lastIndexOf(값)

먼저 간단하게 값을 반환하는 함수들입니다. 이 내용은 기존에도 알고 있었으니 빠르게 넘어가겠습니다.

val mutableList: MutableList<타입> = mutableListOf(값)

위와 같이 mutable만 붙여주면 만들 수 있습니다.

다음은 확장 함수입니다.

// 값 추가
mutableList.add(값)

// 특정 위치의 값 설정
mutableList.set(인덱스, 값)

// 특정 위치 요소 삭제
mutableList.removeAt(인덱스)

특이한 내용은 없는 것 같습니다.

Set은 순서가 없고 중복이 되지 않는 집합 객체입니다.

val set: Set<타입> = setOf(값)

Set은 값을 찾기보다도 값이 있는지를 찾습니다.

// 값 포함 여부 확인
set.contains(값)

// 컬렉션과 비교해서 값 포함 여부 확인
set.containsAll(컬렉션)

// Set이 비어있는지 확인
set.isEmpty()

mutableSet은 다음과 같습니다.

val mutableSet: MutableSet<타입> = mutableSetOf(값)

// 값 추가
mutableSet.add(값)
mutableSet.addAll(컬렉션)

// 값 삭제
mutableSet.remove(값)
mutableSet.removeAll(컬렉션)

Set의 가장 큰 특징은 실제 집합처럼 합집합, 교집합, 차집합을 지원한다는 것입니다.

// 합집합
val unionSet = set1.union(set2)

// 교집합
val intersectSet = set1.intersect(set2)

// 차집합
val subtractSet = set1.subtract(set2)

Map의 경우는 다른 컬렉션과 느낌이 조금 다릅니다.

val map:Map<키타입, 값타입> = mapOf(키 to 값)

먼저 키와 값을 갖고, 키를 통해 값을 찾는 게 목적입니다.

mapOf에도 키 to 값으로 값을 넣어줍니다.

// 맵에 키가 포함돼 있는지 확인
map.containsKey(키)

// 맵에 값이 포함돼 있는지 확인
map.containsValue(값)

// 지정된 키와 연결된 값을 반환
map.get(키)

// 맵의 모든 키-값 쌍을 포함하는 Set 반환
map.entries

// 맵의 모든 키를 포함하는 Set 반환
map.keys

// 맵의 모든 값을 포함하는 Collection 반환
map.values

위처럼 키를 통해 값이 있는지 확인하고, 값을 반환합니다.

그리고 모든 키나 값만 가진 집합이나 컬렉션을 반환하기도 합니다.

MutableMap도 존재합니다.

// 키-값 쌍 추가
mutableMap.put(키, 값)

// 키에 해당하는 키-값 쌍 제거
mutableMap.remove(키)

// 맵을 통째로 넣음
mutableMap.putAll(맵)

// 요소 전부 삭제
mutableMap.clear()

확실히 컬렉션을 공부하다보니까 조금씩 헷갈리는 부분이 생기는 것 같습니다.

StringBuilder의 함수를 List에서 쓴다던지... List의 함수를 Array에서 쓴다던지 하는 식으로요.

문제는 아직 다루지 않은 컬렉션이 한두 개가 아니라는 것...

열심히 공부해야겠습니다.

3. Kotlin 문법 종합반 4주차

[ 13:00 ~ 15:00 ]

심화 주차의 시작인 만큼 4주차 강의를 들었습니다.

강의의 전체적인 주제를 말해보자면, 안정성과 관련된 내용이었습니다.

물론, 배열과 컬렉션에 대한 내용도 다루기는 했습니다만, 이 부분은 가볍게 다루겠습니다.

먼저 접근 제한자에 대해 배웠습니다.

이전에 아토믹 코틀린에서는 internal에 대해 알려주지 않아서 궁금했었는데, 진실이 드러났습니다.

public은 모든 곳에서 쓸 수 있고, private는 해당 클래스에서만 쓸 수 있습니다.

protected는 상속 관계에서 쓸 수 있었고... internal은? 바로 모듈 내에서만 쓸 수 있었습니다.

아무래도 이 부분은 후에 쓸 일이 있을지 한번 판단해봐야 할 것 같습니다.

그리고, 예외 처리에 관해 들었습니다.

try {
// 예외가 될 만한 내용
} catch (예외 내용) {
// 예외 발생 시 처리할 방법
} finally {
// 무조건 쓰는 코드
}

throw 예외 

try-catch는 다른 언어에서도 자주 쓰이는 내용이니, 가볍게 다루겠습니다.

근데 try-catch에 대해 찾아보니까 이것도 식이라고 하네요...

다음은 지연 초기화입니다.

지연 초기화와 늦은 초기화에 대해 배웠습니다. 해당 부분에서 위임이 살짝 나오긴 했는데, 이 부분도 저는 헷갈려서 이후 공부할 생각입니다.

// 지연 초기화
lateinit var A : String

A = "0"

// 늦은 초기화
val B : String by lazy {
// 추가하고 싶은 내용들
// 맨 마지막 줄엔 초기화할 값
}

지연 초기화의 경우는 var를 사용합니다. 그래서 그냥 나중에 초기화한다는 느낌이 강하다면,

늦은 초기화는 val를 사용하고, by lazy { } 로 결국엔 그 자리에서 초기화하긴 합니다.

그래서 뭔가 부랴부랴 일을 끝내고 마무리로 초기화하는 느낌이 강합니다.

다음은 널 세이프티입니다. Null은 어느 코드에서나 말썽입니다. 그래서 Kotlin은 이에 대해 대비하려 했습니다.

val a: String?

위처럼 써져 있는 경우는 null이 될 수도 있는 값입니다. 일반적인 경우는 null을 허락하지 않지만, 위는 null을 허락합니다.

위험하긴 하지만, 만약 null인지 알고 싶다면, 사용할 수 있습니다.

val a: String = b!!

위는 b가 null이 아니라는 걸 자신있게 프로그래머가 주장하는 것입니다.

만약 null이면 예외가 나오겠죠? 그러니까 정말 자신있는 게 아니라면 사용하지 않는 게 좋습니다.

a?.toChar()

위는 안전 호출 연산자(?.)입니다. null이 아니라면 그대로 가고, null 이라면 뒤에 있는 내용을 호출하지 않습니다.

 a ?: "NULL값임!"

위는 엘비스 연산자(?:)입니다. 값이 null 이라면 뒤에 있는 값을 대신 반환합니다.

마지막으로, single-expression function입니다.

검색해보니까 단일 표현식 함수라고 합니다. 이전에 공부했을 때 슬쩍 지나갔던

fun print() = println("String!?")

이렇게 바로 =을 써서 해결하는 방식을 뜻합니다.

또한, 람다식을 써서

{ 매개변수 : 타입, ... -> 코드 }

처럼 간결하게 작성할 수도 있습니다.

람다식같은 경우는 조금 더 공부해봐야 할 것 같습니다.

4. 알고리즘 기억 노트(21~30번)

오늘도 남는 시간동안 알고리즘을 해결했습니다.

백문이 불여일견! 역시 직접 해봐야 좋은 것 같습니다.

약 200개 정도의 알고리즘이 있는 것 같은데, 200개를 전부 풀고 나면,

백준의 골드~플래티넘 단계 또는 프로그래머스의 3~4레벨에 도전해볼 생각입니다.

이전에 하루 걸려서 플래티넘 1문제 풀어본 기억이 있었지만, 그때는 지금보다 문법을 모를 때였고,

C언어로 그냥 막 풀었었습니다. 지금 도전하면, 그래도 조금은 나아지지 않았을까 생각합니다.

어쨌든 오늘 알고리즘 기억 노트를 시작하겠습니다.

23. 콜라츠 추측

콜라츠 추측은 주어진 수가 1이 될 때까지 짝수는 2로 나누고, 홀수는 3을 곱한 뒤 1을 더하는 작업을
반복해서 1을 만드는 것입니다.

이 알고리즘을 짤 때, 몇몇 경우가 실패했습니다. 이유는 너무 컸기 때문입니다.

그래서 Int 대신 Long으로 바꿔서 해결했습니다.

25. 나누어 떨어지는 숫자 배열

이 문제는 array 요소들 중 divisor라는 Int로 나뉘는 값들만 모아 오름차순으로 정렬한 배열을 리턴하는 것이었습니다.

이때, sorted를 써줬는데, array에는 sort만 되더라고요... 하나 알아갑니다.

27. 전화번호가 문자열로 주어졌을 때 전화번호 뒷 4자리 제외 전부 *로 바꾸는 문제

문제명이 기억 안 나서 내용 그대로 쓰겠습니다. 여기에는 String의 replace를 써봤는데,

String의 replace는 값을 다른 값으로 바꾸는 거고,

StringBuilder의 replace가 범위에 해당하는 값을 다른 값으로 바꾸는 것이었습니다.

심지어 그 다른 값이 한 글자면 범위가 1000000000이어도 한 글자로 변경됩니다.

이 두 replace를 헷갈리지 말고 잘 써야겠습니다.

29. 제일 작은 수 제거하기

저는 당연히 max(), min() 함수가 있을 거라 생각했지만...

오류가 나왔습니다. 해당 함수가 없다면서요.

물론, 직접 최대, 최소를 구해도 되지만, 이왕 kotlin 쓰는 거 함수를 쓰고 싶었습니다.

그래서 다른 함수를 찾았습니다.

Array.minOf { it }
Array.maxOf { it }

안 되면 이걸로 해야 할 것 같습니다. 또, filter도 써봤습니다.

.filter { 조건 }

filter라는 이름에 걸맞게 조건에 해당하는 값들만 모아 List로 만들어줍니다.

오늘 많이 배워갑니다.

5. 끝

오늘은 조금 한가하지만, 공부한 내용들이 적지는 않은 날이었습니다.

내일은 심화 강의를 끝내고, 코드 카타를 푼 뒤, 과제에 들어갈 생각입니다.

아마 조금 바쁠 것 같네요...

끝.

profile
여기는 공부 기록용 블로그

0개의 댓글