
리트코드 994 Rotting Oranges - Kotlin 타입에 따른 시간 단축 팁
DoDoBest
·2024. 11. 28. 08:06
https://leetcode.com/problems/rotting-oranges/description/
문제 풀이
이 문제는 matrix 탐색을 구현하는 간단한 문제입니다.

위 생각에 따라 작성한 답안은 다음과 같습니다.

class Solution { private val diff = listOf(0 to 1, 1 to 0, 0 to -1, -1 to 0) fun orangesRotting(grid: Array<IntArray>): Int { val m = grid.size val n = grid.first().size var rotCount = 0 val fresh = ArrayDeque<Pair<Int, Int>>() for ((y, row) in grid.withIndex()) { for ((x, org) in row.withIndex()) { if (org == 1) { fresh.add(y to x) } else if (org == 2) { rotCount++ } } } if (fresh.isNotEmpty() && rotCount == 0) { return -1 } var time = 0 while (fresh.isNotEmpty()) { var freshCount = fresh.size for (i in 0 until freshCount) { val (y, x) = fresh.removeFirst() // 네 방향 탐색 var isRotted = false for ((dy, dx) in diff) { val ny = y + dy val nx = x + dx if (ny in 0 until m && nx in 0 until n && grid[ny][nx] in 2..(time + 2)) {1 // 이번에 썩은 오렌지가 인접한 신선한 오렌지에 영향을 주지 않도록 2 + 썩은 시간으로 표시 grid[y][x] = time + 3 isRotted = true break } } if (!isRotted) { fresh.add(y to x) } } if (fresh.size == freshCount) { return -1 } time++ } return time } }
저는 신선한 오렌지의 인근에 썩은 오렌지가 있는 것을 확인했는데, 썩은 오렌지 인근에 신선한 오렌지가 있는 것을 확인하는 것이 더 효율적입니다. 신선한 오렌지는 썩을 때까지 queue에 존재하여 불필요한 탐색을 반복하지만, 썩은 오렌지는 더 이상 영향을 줄 수 없는 경우 queue에서 삭제되기 때문입니다.

class Solution { private val diff = listOf(0 to 1, 1 to 0, 0 to -1, -1 to 0) fun orangesRotting(grid: Array<IntArray>): Int { val m = grid.size val n = grid.first().size var freshCount = 0 val rotted = ArrayDeque<Pair<Int, Int>>() for ((y, row) in grid.withIndex()) { for ((x, org) in row.withIndex()) { if (org == 1) { freshCount++ } else if (org == 2) { rotted.add(y to x) } } } if (freshCount == 0) { return 0 } else if (rotted.isEmpty()) { return -1 } var time = -1 // 더 이상 썩을 오렌지가 없더라도 한 번 더 순회하므로 0 대신 -1 while (rotted.isNotEmpty()) { var rottedCount = rotted.size for (i in 0 until rottedCount) { val (y, x) = rotted.removeFirst() // 네 방향 탐색 for ((dy, dx) in diff) { val ny = y + dy val nx = x + dx if (ny in 0 until m && nx in 0 until n && grid[ny][nx] == 1) { grid[ny][nx] = 2 freshCount-- rotted.add(ny to nx) } } } time++ } return if (freshCount == 0) { time } else { -1 } } }
시간 단축 팁
4ms에 풀리는 코드를 보고, 제 코드와 어떤 차이가 있는지 분석해봤습니다.
import java.util.* class Solution2 { fun orangesRotting(grid: Array<IntArray>): Int { return bfs(grid) } fun bfs(grid: Array<IntArray>): Int { val rows = grid.size val cols = grid[0].size val directions = arrayOf( intArrayOf(1, 0), // jos intArrayOf(-1, 0), // sus intArrayOf(0, 1), // dreapta intArrayOf(0, -1) // stânga ) val queue: Queue<Pair<Int, Int>> = LinkedList() var freshOranges = 0 for (i in 0 until rows) { for (j in 0 until cols) { when (grid[i][j]) { 2 -> queue.add(Pair(i, j)) 1 -> ++freshOranges } } } if (freshOranges == 0) return 0 var minutes = 0 while (queue.isNotEmpty()) { val size = queue.size var infected = false for (i in 0 until size) { val (row, col) = queue.poll() for (dir in directions) { val newRow = row + dir[0] val newCol = col + dir[1] if (newRow in 0 until rows && newCol in 0 until cols && grid[newRow][newCol] == 1) { grid[newRow][newCol] = 2 queue.add(Pair(newRow, newCol)) --freshOranges infected = true } } } if (infected) ++minutes } return if (freshOranges == 0) minutes else -1 } }
1. listOf 대신 arrayOf 사용하기
네 방향의 움직임을 저장한 diff 변수를 listOf 대신 arrayOf로 변경해 시간을 절반 단축시킬 수 있었습니다.
private val diff = arrayOf(0 to 1, 1 to 0, 0 to -1, -1 to 0)
2. ArrayDeque 지양하기
썩은 오렌지를 저장하는 rotted의 타입을 ArrayDeque 대신 Queue 타입의 LinkedList로 변경해 시간을 절반 단축시킬 수 있었습니다. 자바 타입이기 때문에 java.util import가 필요합니다.
Stack과 Queue를 동시에 사용할 수 있는 ArrayDeque를 즐겨 사용했는데, 타입에 따라 구분해서 사용해야 함을 배웠습니다.
import java.util.* val rotted: Queue<Pair<Int, Int>> = LinkedList()
마무리 & 변경된 코드
알고리즘이 아닌 타입에 따른 시간 차이로 코테에서 떨어지면 억울할 것입니다. 특히 프로그래머스는 타입에 따른 시간차이가 더 심한데, 아래 블로그 글을 확인해주세요.
https://dodobest.tistory.com/96
프로그래머스 시간 측정 오류와 H-Index 문제
프로그래머스 Kotlin 시간 측정 오류 https://dodobest.tistory.com/86 Kotlin Boxing Type 쓰지 마세요 체질이라는게바뀝니다 프로그래머스 문자열 내림차순으로 배치하기 문제를 풀어보며, String을 다룰 때 어
dodobest.tistory.com

import java.util.* class Solution { private val diff = arrayOf(0 to 1, 1 to 0, 0 to -1, -1 to 0) fun orangesRotting(grid: Array<IntArray>): Int { val m = grid.size val n = grid[0].size var freshCount = 0 val rotted: Queue<Pair<Int, Int>> = LinkedList() for (y in 0 until m) { for (x in 0 until n) { when (grid[y][x]) { 2 -> rotted.add(y to x) 1 -> freshCount++ } } } if (freshCount == 0) { return 0 } else if (rotted.isEmpty()) { return -1 } var time = -1 // 더 이상 썩을 오렌지가 없더라도 한 번 더 순회하므로 0 대신 -1 while (rotted.isNotEmpty()) { val rottedCount = rotted.size for (i in 0 until rottedCount) { val (y, x) = rotted.poll() // 네 방향 탐색 for ((dy, dx) in diff) { val ny = y + dy val nx = x + dx if (ny in 0 until m && nx in 0 until n && grid[ny][nx] == 1) { grid[ny][nx] = 2 freshCount-- rotted.add(ny to nx) } } } time++ } return if (freshCount == 0) { time } else { -1 } } }
'코딩테스트' 카테고리의 다른 글
Kotlin 카카오 주차 요금 계산 - ConcurrentModificationException, HashMap, hashing (3) | 2024.09.04 |
---|---|
프로그래머스 모음사전 Kotlin (0) | 2024.04.25 |
프로그래머스 2개 이하로 다른 비트 Kotlin (0) | 2024.04.25 |
Leetcode 42. Trapping Rain Water (0) | 2024.04.12 |
프로그래머스 시간 측정 오류와 H-Index 문제 (0) | 2024.04.09 |