-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #347 from jdalma/main
[์ ํ์ค] 2์ฃผ์ฐจ ๋ต์ ์ ์ถ
- Loading branch information
Showing
5 changed files
with
307 additions
and
0 deletions.
There are no files selected for viewing
56 changes: 56 additions & 0 deletions
56
construct-binary-tree-from-preorder-and-inorder-traversal/jdalma.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | ||
} | ||
} |