IT Study/백준 알고리즘
[백준 알고리즘/Kotlin] 4673번 셀프 넘버 (feat. Array의 fill과 초기화 람다 차이)
three kim
2023. 12. 25. 17:02
728x90
다른 돌파구가 있을까 생각했지만, 이 문제는 브루트포스.
완전 탐색으로 접근합니다.
1. 최종 코드
// 완전 탐색
// (1) 1 ~ 9999, 모든 수 d(n) 계산
// (2) isSelfNumber, d(n)인 수는 false 표기
fun main() {
var isSelfNumber = BooleanArray(10000) { true }
for (i in 1 until 10000) {
var num = i
var sum = i
while (num > 0) {
sum += num % 10
num /= 10
}
if (sum < 10000) {
isSelfNumber[sum] = false
}
}
for (i in 1 until 10000) {
if (isSelfNumber[i] == true) {
println(i)
}
}
}
1부터 9999 (10000보다 작은) 사이의 수에서 문제에 주어진 조건을 만족하지 않는 셀프넘버가 아닌 수를 찾
isSelfNumber를 false로 만들었습니다.
2. 최적화된 코드
코드를 더 최적화하기 위해 다른 분들의 코드를 살펴보면 중, StringBuilder()를 사용하여 결과를 모은 다음
한 번에 출력하는 방식을 많이 사용하는 듯 보였습니다.
이를 통해 출력에 소요되는 시간을 최적화하는 듯 보였는데요. 저의 코드에도 적용시켜 봤습니다.
fun main() {
val isSelfNumber = BooleanArray(10000) { true }
val result = StringBuilder()
for (i in 1 until 10000) {
var num = i
var sum = i
while (num > 0) {
sum += num % 10
num /= 10
}
if (sum < 10000) {
isSelfNumber[sum] = false
}
}
for (i in 1 until 10000) {
if (isSelfNumber[i]) {
result.append("$i\n")
}
}
print(result)
}
메모리도, 시간도 꽤 많이 줄여진 듯 보입니다.
3. Array의 fill(e), { e } 차이
3-1. fill 메서드 사용
val array = BooleanArray(5).fill(true)
여기서 fill(true)는 해당 배열을 true 값으로 채우고, 이 메서드는 Unit을 반환합니다.
따라서 위 코드에서 array는 BooleanArray가 아니라 Unit 타입이 됩니다.
3-2. 초기화 람다 { } 사용
val array = BooleanArray(5) { true }
여기서는 배열을 생성할 때 초기화 람다를 사용하여 각 요소를 초기화합니다.
이때 람다는 배열의 각 인덱스에 대해 호출되며, 반환 값이 해당 인덱스의 초기값이 됩니다.
위 코드에서는 모든 값이 true로 초기화됩니다.
4. isSelfNumber와 result는 가변 상태인데 왜 val을 사용할까?
val 키워드는 변수에 할당된 값이 변경될 수 없음을 나타냅니다.
그러나 val로 선언된 변수가 참조하는 객체의 내부 상태는 변경될 수 있습니다.
예를 들어, val로 선언된 리스트에 원소를 추가하거나 제거하는 것은 가능합니다.
isSelfNumber 배열은 한 번 생성되면 그 크기와 내용이 변경되지 않습니다. 따라서 val로 선언하는 것이 적절합니다.
하지만 result는 중간에 문자열이 계속해서 추가되므로 내용이 변경됩니다.
이 경우 val로 선언했더라도 참조 자체가 변경되지 않기 때문에 val로 선언해도 무방합니다.