Skip to content

Commit

Permalink
Merge pull request #347 from jdalma/main
Browse files Browse the repository at this point in the history
[์ •ํ˜„์ค€] 2์ฃผ์ฐจ ๋‹ต์•ˆ ์ œ์ถœ
  • Loading branch information
jdalma authored Aug 22, 2024
2 parents 8f47a65 + b02d06f commit ac59579
Show file tree
Hide file tree
Showing 5 changed files with 307 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package leetcode_study

import io.kotest.matchers.equals.shouldBeEqual
import org.junit.jupiter.api.Test

class `construct-binary-tree-from-preorder-and-inorder-traversal` {

/**
* preorder : ํ˜„์žฌ(๋ถ€๋ชจ) ๋…ธ๋“œ๋ถ€ํ„ฐ ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ, ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ
* inorder : ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ ๋ถ€ํ„ฐ ๋ถ€๋ชจ ๋…ธ๋“œ, ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ
*/
fun buildTree(preorder: IntArray, inorder: IntArray): TreeNode? {
val inorderIndices = inorder.withIndex().associate { it.value to it.index }
return traversal(preorder, inorder, inorderIndices)
}

/**
* preorder์—์„œ ์กฐํšŒํ•œ ๋ถ€๋ชจ ๋…ธ๋“œ์˜ ๊ฐ’์€ inorder์˜ ์ค‘๊ฐ„์— ์œ„์น˜ํ•œ๋‹ค.
* ๊ทธ ์ค‘๊ฐ„ ์œ„์น˜ ๊ธฐ์ค€์œผ๋กœ ์™ผ์ชฝ ๋…ธ๋“œ, ์˜ค๋ฅธ์ชฝ ๋…ธ๋“œ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์žฌ๊ท€์ ์œผ๋กœ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
* ์‹œ๊ฐ„๋ณต์žก๋„: O(n), ๊ณต๊ฐ„๋ณต์žก๋„: O(n)
*/
private fun traversal(
preorder: IntArray, inorder: IntArray, inorderIndices: Map<Int, Int>,
preStart: Int = 0, inStart: Int = 0, inEnd: Int = inorder.size - 1
): TreeNode? {
if (preStart > preorder.size - 1 || inStart > inEnd) {
return null
}
val value = preorder[preStart]
val rootIndexInInorder = inorderIndices[value]!!

return TreeNode(value).apply {
this.left = traversal(
preorder, inorder, inorderIndices,
preStart + 1, inStart, rootIndexInInorder - 1
)
this.right = traversal(
preorder, inorder, inorderIndices,
preStart + rootIndexInInorder - inStart + 1, rootIndexInInorder + 1, inEnd
)
}
}

@Test
fun `์ „์œ„ ์ˆœํšŒ, ์ค‘์œ„ ์ˆœํšŒ ์ˆœ์„œ์˜ ์ •์ˆ˜ ๋ฐฐ์—ด์„ ๊ธฐ์ค€์œผ๋กœ ์ด์ง„ํŠธ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•œ๋‹ค`() {
val actual = buildTree(intArrayOf(3,9,20,15,7), intArrayOf(9,3,15,20,7))!!
val expect = TreeNode.of(3,9,20,null,null,15,7)!!

actual shouldBeEqual expect

val actual1 = buildTree(intArrayOf(3,9,8,10,20,15,7), intArrayOf(8,9,10,3,15,20,7))!!
val expect1 = TreeNode.of(3,9,20,8,10,15,7)!!

actual1 shouldBeEqual expect1
}
}
62 changes: 62 additions & 0 deletions counting-bits/jdalma.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package leetcode_study

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

class `counting-bits` {

fun countBits(n: Int): IntArray {
return usingDPAndLeastSignificantBit(n)
}

// 1. ์ž…๋ ฅ๋ฐ›์€ ์ •์ˆ˜๋งŒํผ ์ˆœํšŒํ•˜๋ฉฐ bit ์นด์šดํŠธ
// ์‹œ๊ฐ„๋ณต์žก๋„: O(n * log(n)), ๊ณต๊ฐ„๋ณต์žก๋„: O(1)
private fun usingBinary(n: Int): IntArray {
fun binary(n: Int): Int {
var calc = n
var count = 0
while(calc > 0) {
if (calc % 2 != 0) {
count++
}
calc /= 2
}
return count
}

return (0 .. n).map { binary(it) }.toIntArray()
}

// 2. MSB, ์ฆ‰ ์ตœ์ƒ์œ„ ๋น„ํŠธ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์‹ญ์ง„์ˆ˜๊ฐ€ ๋‘ ๋ฐฐ๊ฐ€ ๋ ๋•Œ๋งˆ๋‹ค MSB๋ฅผ ๊ฐฑ์‹ ํ•˜์—ฌ ์ด์ „์˜ ๊ฒฐ๊ณผ๋ฅผ ํ™œ์šฉ
// ์‹œ๊ฐ„๋ณต์žก๋„: O(n), ๊ณต๊ฐ„๋ณต์žก๋„: O(n)
private fun usingDPAndMostSignificantBit(n: Int): IntArray {
val dp = IntArray(n + 1)
var msb = 1

for (index in 1 .. n) {
if (index == msb shl 1) {
msb = index
}
dp[index] = 1 + dp[index - msb]
}

return dp
}

// 3. ์ตœํ•˜์œ„ ๋น„ํŠธ๋ฅผ ์ œ๊ฑฐํ•œ ๊ฒฐ๊ณผ๋ฅผ ์žฌํ™œ์šฉํ•œ๋‹ค. (์ตœํ•˜์œ„ ๋น„ํŠธ๋ฅผ ์ œ๊ฑฐํ•œ ๊ฒฐ๊ณผ) + (ํ˜„์žฌ ์‹ญ์ง„์ˆ˜์˜ ์ตœํ•˜์œ„๋น„ํŠธ)
// ์‹œ๊ฐ„๋ณต์žก๋„: O(n), ๊ณต๊ฐ„๋ณต์žก๋„: O(n)
private fun usingDPAndLeastSignificantBit(n: Int): IntArray {
val dp = IntArray(n + 1)
for (index in 1 .. n) {
dp[index] = dp[index shr 1] + (index and 1)
}

return dp
}

@Test
fun `์ •์ˆ˜๊ฐ€ ์ฃผ์–ด์ง€๋ฉด ๊ฐ i(0 ~ i)์— ๋Œ€ํ•ด ์ด์ง„ ํ‘œํ˜„์—์„œ 1์˜ ๊ฐœ์ˆ˜๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค`() {
countBits(2) shouldBe intArrayOf(0,1,1)
countBits(5) shouldBe intArrayOf(0,1,1,2,1,2)
}
}
95 changes: 95 additions & 0 deletions decode-ways/jdalma.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package leetcode_study

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

class `decode-ways` {

fun numDecodings(s: String): Int {
return usingOptimizedDP(s)
}

/**
* 1. ๋ฌธ์ž์—ด์˜ ์ฒซ ์ธ๋ฑ์Šค๋ถ€ํ„ฐ DFS๋กœ ํ™•์ธํ•˜๋ฉด์„œ ๊ฒฐ๊ณผ๋ฅผ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค. โ†’ ์‹œ๊ฐ„์ดˆ๊ณผ
* 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” ๋ฌธ์ž์—ด์€ ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ์— ๋ฐ”๋กœ 0์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๊ณ  ๊ทธ ๋’ค ์ˆซ์ž๋ถ€ํ„ฐ DFS๋ฅผ ์—ฐ์ด์–ด ์‹คํ–‰ํ•œ๋‹ค.
* ์‹œ๊ฐ„๋ณต์žก๋„: O(2^n), ๊ณต๊ฐ„๋ณต์žก๋„: O(n)
*/
private fun usingDfs(s: String): Int {
fun dfs(index: Int): Int =
if (index == s.length) 1
else if (s[index] == '0') 0
else if (index + 1 < s.length && (s[index] == '1' || (s[index] == '2' && s[index + 1] < '7')) )
dfs(index + 1) + dfs(index + 2)
else dfs(index + 1)

return dfs(0)
}

/**
* 2. 1๋ฒˆ ํ’€์ด์—์„œ ์ค‘๋ณต๋˜๋Š” ์—ฐ์‚ฐ์— top-down ๋ฐฉํ–ฅ์œผ๋กœ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ์ ์šฉ
* ์‹œ๊ฐ„๋ณต์žก๋„: O(n), ๊ณต๊ฐ„๋ณต์žก๋„: O(n)
*/
private fun usingMemoization(s: String): Int {
fun dfs(index: Int, mem: IntArray): Int {
println(index)
mem[index] = if (index == s.length) 1
else if (s[index] == '0') 0
else if (mem[index] != 0) mem[index]
else if (index + 1 < s.length && (s[index] == '1' || (s[index] == '2' && s[index + 1] < '7')) )
dfs(index + 1, mem) + dfs(index + 2, mem)
else dfs(index + 1, mem)

return mem[index]
}
return dfs(0, IntArray(s.length + 1) { 0 })
}

/**
* 3. ๋งˆ์ง€๋ง‰ ์ˆซ์ž๋ถ€ํ„ฐ bottom-up ๋ฐฉํ–ฅ DP
* ์‹œ๊ฐ„๋ณต์žก๋„: O(n), ๊ณต๊ฐ„๋ณต์žก๋„: O(n)
*/
private fun usingDP(s: String): Int {
val dp = IntArray(s.length + 1).apply {
this[s.length] = 1
}

(s.length - 1 downTo 0).forEach { index ->
if (s[index] == '0') dp[index] = 0
else if(index + 1 < s.length && (s[index] == '1' || (s[index] == '2' && s[index + 1] < '7')))
dp[index] = dp[index + 1] + dp[index + 2]
else dp[index] = dp[index + 1]
}

return dp[0]
}

/**
* 4. ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  DP ์ ์šฉ
* ์‹œ๊ฐ„๋ณต์žก๋„: O(n), ๊ณต๊ฐ„๋ณต์žก๋„: O(1)
*/
private fun usingOptimizedDP(s: String): Int {
var (memo, result) = 0 to 1

(s.length - 1 downTo 0).forEach { index ->
var tmp = if (s[index] == '0') 0 else result

if (index + 1 < s.length && (s[index] == '1' || (s[index] == '2' && s[index + 1] < '7'))) {
tmp += memo
}
memo = result
result = tmp
}

return result
}

@Test
fun `์ž…๋ ฅ๋ฐ›์€ ๋ฌธ์ž์—ด์˜ ๋””์ฝ”๋”ฉ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ์˜ ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค`() {
numDecodings("12") shouldBe 2
numDecodings("226") shouldBe 3
numDecodings("06") shouldBe 0
numDecodings("1011") shouldBe 2
numDecodings("10112266") shouldBe 8
numDecodings("1025") shouldBe 2
}
}
39 changes: 39 additions & 0 deletions encode-and-decode-strings/jdalma.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package leetcode_study

import io.kotest.matchers.equals.shouldBeEqual
import org.junit.jupiter.api.Test

/**
* ์ธ์ฝ”๋”ฉ๊ณผ ๋””์ฝ”๋”ฉ์„ ํ•ด๊ฒฐํ•  ๋•Œ ๊ตฌ๋ถ„์ž๋ฅผ 256๊ฐœ์˜ ASCII ๋ฌธ์ž ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
* ์‹œ๊ฐ„๋ณต์žก๋„: O(n), ๊ณต๊ฐ„๋ณต์žก๋„: O(1)
*/
class `encode-and-decode-strings` {

private val DELIMITER = ":"

fun encode(strings: List<String>): String {
return strings.joinToString(separator = "") { e -> "${e.length}$DELIMITER$e" }
}

fun decode(string: String): List<String> {
var index = 0
val result = mutableListOf<String>()
while (index < string.length) {
val delimiterIndex = string.indexOf(DELIMITER, startIndex = index)
val size = string.substring(index, delimiterIndex).toInt()
result.add(string.substring(delimiterIndex + 1, delimiterIndex + size + 1))
index = delimiterIndex + size + 1
}
return result
}

@Test
fun `๋ฌธ์ž์—ด ๋ชฉ๋ก์„ ํ•˜๋‚˜์˜ ๋ฌธ์ž์—ด๋กœ ์ธ์ฝ”๋”ฉํ•œ๋‹ค`() {
encode(listOf("leet","co:de","l:o:v:e","you")) shouldBeEqual "4:leet5:co:de7:l:o:v:e3:you"
}

@Test
fun `๋ฌธ์ž์—ด์„ ๋ฌธ์ž์—ด ๋ชฉ๋ก์œผ๋กœ ๋””์ฝ”๋”ฉํ•œ๋‹ค`() {
decode("4:leet5:co:de7:l:o:v:e3:you") shouldBeEqual listOf("leet","co:de","l:o:v:e","you")
}
}
55 changes: 55 additions & 0 deletions valid-anagram/jdalma.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package leetcode_study

import org.junit.jupiter.api.Test

class `valid-anagram` {

fun isAnagram(s: String, t: String): Boolean {
return usingArray(s, t)
}

// 1. ๋‘ ๋ฌธ์ž์—ด์„ ์ •๋ ฌํ•˜์—ฌ ๋น„๊ตํ•œ๋‹ค.
// ์‹œ๊ฐ„๋ณต์žก๋„: O(n * log(n)), ๊ณต๊ฐ„๋ณต์žก๋„: O(n)
private fun usingSort(s: String, t: String): Boolean {
val sorted1 = s.toCharArray().apply { this.sort() }
val sorted2 = t.toCharArray().apply { this.sort() }

return sorted1.contentEquals(sorted2)
}

// 2. ๋ฐฐ์—ด์— ๋ฌธ์ž ์ˆ˜ ๊ฐ€๊ฐ
// ์‹œ๊ฐ„๋ณต์žก๋„: O(n), ๊ณต๊ฐ„๋ณต์žก๋„: O(n)
private fun usingArray(s: String, t: String): Boolean {
if (s.length != t.length) {
return false
}

/* ํ•ด์‹œ๋งต ์‚ฌ์šฉ
val map: Map<Char, Int> = mutableMapOf<Char, Int>().apply {
(s.indices).forEach { index ->
this[s[index]] = this.getOrDefault(s[index], 0) + 1
this[t[index]] = this.getOrDefault(t[index], 0) - 1
}
}
return map.values.find { it > 0 } == null
*/

return IntArray(26).apply {
for (index in s.indices) {
this[s[index] - 'a'] = this[s[index] - 'a'] + 1
this[t[index] - 'a'] = this[t[index] - 'a'] - 1
}
}.find { it > 0 } == null
}

@Test
fun `์ž…๋ ฅ๋ฐ›์€ ๋‘ ๋ฌธ์ž์—ด์ด ์• ๋„ˆ๊ทธ๋žจ์ด๋ผ๋ฉด ์ฐธ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค`() {
isAnagram("anagram", "nagaram")
isAnagram("test", "estt")
}

@Test
fun `์ž…๋ ฅ๋ฐ›์€ ๋‘ ๋ฌธ์ž์—ด์ด ์• ๋„ˆ๊ทธ๋žจ์ด ์•„๋‹ˆ๋ผ๋ฉด ๊ฑฐ์ง“์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค`() {
isAnagram("cat", "rat")
}
}

0 comments on commit ac59579

Please sign in to comment.