Skip to content

Commit

Permalink
Decode Ways
Browse files Browse the repository at this point in the history
  • Loading branch information
JisooPyo committed Dec 15, 2024
1 parent 582101e commit 8e221d8
Showing 1 changed file with 111 additions and 0 deletions.
111 changes: 111 additions & 0 deletions decode-ways/JisooPyo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package leetcode_study

import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test

/**
* Leetcode
* 91. Decode Ways
* Medium
*
* idea:
* Dynamic Programming
* μˆ«μžλŠ” μ΅œμ†Œ ν•œ μžλ¦¬μ—μ„œ μ΅œλŒ€ λ‘μžλ¦¬κΉŒμ§€ 해석될 수 μžˆλŠ” 여지가 μžˆλ‹€.
* λ”°λΌμ„œ "1111"μ΄λΌλŠ” λ¬Έμžμ—΄μ΄ κ°€μ§ˆ 수 μžˆλŠ” Decoding 경우의 μˆ˜λŠ” λ‹€μŒ 두 가지가 될 수 μžˆλ‹€.
* - "111"이 κ°€μ§€λŠ” Decoding 경우의수 + "1"
* - "11"이 κ°€μ§€λŠ” Decoding 경우의 수 + "11"
* Note.
* "0"이 κ°€μ§€λŠ” Decoding 경우의 μˆ˜λŠ” μ—†λ‹€λŠ” 것.
* "1"λΆ€ν„° "26"κΉŒμ§€λ§Œ λ””μ½”λ”© κ°€λŠ₯ν•œ 것.
*/
class DecodeWays {
/**
* Runtime: 17 ms(Beats: 11.98 %)
* Time Complexity: O(n)
*
* Memory: 38.81 MB(Beats: 6.08 %)
* Space Complexity: O(n)
* - s의 길이만큼의 DP λ°°μ—΄(dp) ν•„μš”
*/
fun numDecodings(s: String): Int {
val dp = IntArray(s.length)

// μ΄ˆκΈ°ν•­: dp[0]
dp[0] = if (s[0] == '0') 0 else 1
if (s.length == 1) return dp[0]

// μ΄ˆκΈ°ν•­: dp[1]
val oneDigit = dp[0] * (if (s[1] == '0') 0 else 1)
val twoDigitNumber = (s[0] - '0') * 10 + (s[1] - '0')
val twoDigit = if (twoDigitNumber < 10 || 26 < twoDigitNumber) 0 else 1
dp[1] = oneDigit + twoDigit

if (s.length == 2) return dp[1]

// λ‚˜λ¨Έμ§€ ν•­ 계산
for (i in 2 until s.length) {
// ν•œ 자리 숫자둜 ν•΄μ„ν•˜λŠ” 경우
val oneDigit = dp[i - 1] * (if (s[i] == '0') 0 else 1)

// 두 자리 숫자둜 ν•΄μ„ν•˜λŠ” 경우
val twoDigitNumber = (s[i - 1] - '0') * 10 + (s[i] - '0')
val twoDigit = dp[i - 2] * (if (twoDigitNumber < 10 || 26 < twoDigitNumber) 0 else 1)

dp[i] = oneDigit + twoDigit
}

return dp[dp.lastIndex]
}

/**
* early return, λ²”μœ„ μ—°μ‚°μž, λ©”μ„œλ“œλ₯Ό ν™œμš©ν•˜μ—¬ 가독성 κ°œμ„ ν•˜κΈ°
*/
fun numDecodings2(s: String): Int {
if (s[0] == '0') return 0
if (s.length == 1) return 1

val dp = IntArray(s.length)
// μ΄ˆκΈ°ν•­: dp[0]
dp[0] = 1

// μ΄ˆκΈ°ν•­: dp[1]
val oneDigit = dp[0] * (if (s[1] == '0') 0 else 1)
val twoDigitNumber = (s[0] - '0') * 10 + (s[1] - '0')
val twoDigit = if (twoDigitNumber in 10..26) 1 else 0
dp[1] = oneDigit + twoDigit

if (s.length == 2) return dp[1]

// λ‚˜λ¨Έμ§€ ν•­ 계산
for (i in 2 until s.length) {
// ν•œ 자리 숫자둜 ν•΄μ„ν•˜λŠ” 경우
if (s[i] != '0') {
dp[i] += dp[i - 1]
}

// 두 자리 숫자둜 ν•΄μ„ν•˜λŠ” 경우
val twoDigitNumber = (s[i - 1] - '0') * 10 + (s[i] - '0')
if (twoDigitNumber in 10..26) {
dp[i] += dp[i - 2]
}
}

return dp.last()
}

@Test
fun test() {
numDecodings("12") shouldBe 2
numDecodings("226") shouldBe 3
numDecodings("06") shouldBe 0
numDecodings("2101") shouldBe 1
}
}
/**
* κ°œμ„ ν•  점:
* 1) κ³΅κ°„λ³΅μž‘λ„ O(1)둜 κ°œμ„ 
* 배열을 λ§Œλ“€μ§€ μ•Šκ³  "μ „μ˜ 경우의 수"와 "μ „μ „μ˜ 경우의 수"λ₯Ό λ³€μˆ˜ν™”ν•˜λ©΄ 곡간 λ³΅μž‘λ„κ°€ O(1)둜 κ°μ†Œλ  수 μžˆμŠ΅λ‹ˆλ‹€.
* 2) μ—°μ‚° 수 쀄이기
* λ‹€λ₯Έ λΉ λ₯Έ 풀이(1ms)λ₯Ό λ³΄λ‹ˆ 두 자리 숫자둜 ν•΄μ„ν•˜λŠ” κ²½μš°μ— 숫자둜 λ³€ν™˜ν•˜μ§€ μ•Šκ³  character만 λΉ„κ΅ν•΄μ„œ
* (s[i] == '1' || s[i] == '2' && s[i + 1] < '7') 10 <= x <= 26 인지 확인함. 이 경우 더 적은 연산을 μˆ˜ν–‰.
*/

0 comments on commit 8e221d8

Please sign in to comment.