문제 링크
문제 해설
사용 알고리즘 : 이진탐색
문제 자체는 단순히 배열을 정렬한 후 M번에 걸쳐서 해당 요소의 첫 위치를 찾아내면 되는 문제이다. N과 M이 작다면 그냥 \(O(N\times M)\)인 indexOf()
로 해결할 수 있지만 N과 M이 각각 최대 20만이기 때문에 이 방법은 시간초과가 발생한다.
코틀린에서는 이진탐색을 수행하는 binarySearch()
메소드가 존재하지만 이 메소드는 찾고자 하는 값을 발견하면 가장 첫 위치가 아니라 이진 탐색중에 발견한 위치를 바로 반환하기 때문에 사용할 수 없다.
때문에 직접 이진탐색을 위한 메소드를 구현해야 하는데 이는 어렵지 않다. 기본으로 구현되어 있는 binarySearch()
메소드에서 값을 찾았을 때 바로 위치를 반환하지 않고 계속 이진탐색을 수행하도록 하면 된다.
마지막에 반환할 때 발견한 위치의 요소가 찾고자 하는 값과 같다면 발견한 위치를 반환하면 된다.(이 때, ArrayIndexOutOfBoundsException을 방지하기 위한 예외 처리를 해줘야 한다.) 그렇지 않은 경우에는 -1을 반환한다.
속도는 느리지만 Map을 사용하는 방법도 있다. 배열을 정렬한 후 배열을 순회하면서 Map에 요소를 key로, 위치를 value로 저장하면 된다. 이 때, 해당 key가 Map에 존재하지 않는 경우에만(= 해당 key의 value가 null
일 때만) value를 설정해주면 된다. 이후 Map에서 값을 꺼내면서 값이 없는 경우에는 -1을 출력하면 된다.
Code
이진 탐색
fun main() = with(System.`in`.bufferedReader()) {
val bw = System.out.bufferedWriter()
val (n, m) = readLine().split(' ').map { it.toInt() }
val arr = IntArray(n) { readLine().toInt() }.sortedArray()
repeat(m) { bw.write("${arr.binarySearch(readLine().toInt())}\n") }
bw.close()
}
private fun IntArray.binarySearch(target: Int): Int {
var start = 0
var end = size
while (start < end) {
val mid = (start + end) / 2
if (this[mid] >= target) end = mid
else start = mid + 1
}
return if (start < size && this[start] == target) start else -1
}
Map
fun main() = with(System.`in`.bufferedReader()) {
val bw = System.out.bufferedWriter()
val (n, m) = readLine().split(' ').map { it.toInt() }
val map = IntArray(n) { readLine().toInt() }.sortedArray().run { HashMap<Int, Int>().apply { forEachIndexed { i, v -> get(v) ?: put(v, i) } } }
repeat(m) { bw.write("${map[readLine().toInt()] ?: -1}\n") }
bw.close()
}
두 방법의 속도 차이
아래가 이진 탐색을 사용한 코드, 위가 Map을 사용한 코드이다. 확실히 이진탐색이 더 빠른 것을 볼 수 있다.
'Algorithm > BOJ' 카테고리의 다른 글
[Kotlin] 백준 27162 : Yacht Dice (0) | 2023.09.05 |
---|---|
[Kotlin] 백준 6568 : 귀도 반 로썸은 크리스마스날 심심하다고 파이썬을 만들었다 (0) | 2023.08.31 |
[Kotlin] 백준 1644 : 소수의 연속합 (0) | 2023.08.11 |
[Kotlin] 백준 12789 : 도키도키 간식드리미 (0) | 2023.08.09 |
[Kotlin] 백준 13305 : 주유소 (0) | 2023.07.27 |
댓글