-
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 #449 from jdalma/main
[์ ํ์ค] 5์ฃผ์ฐจ ๋ต์ ์ ์ถ
- Loading branch information
Showing
5 changed files
with
352 additions
and
0 deletions.
There are no files selected for viewing
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,66 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder | ||
import org.junit.jupiter.api.Test | ||
|
||
class `3sum` { | ||
|
||
fun threeSum(nums: IntArray): List<List<Int>> { | ||
return usingTwoPointer(nums) | ||
} | ||
|
||
/** | ||
* 1. ์ ์ ๋ฐฐ์ด์ ์ํํ๋ฉฐ ๋ชจ๋ ํ์ธํ๋ค. (์๊ฐ์ด๊ณผ) | ||
* TC: O(n^3), SC: O(n) | ||
*/ | ||
private fun usingIterative(nums: IntArray): List<List<Int>> { | ||
val result = mutableSetOf<List<Int>>() | ||
for (first in nums.indices) { | ||
for (second in first + 1 until nums.size) { | ||
for (third in second + 1 until nums.size) { | ||
if (nums[first] + nums[second] + nums[third] == 0) { | ||
result.add(listOf(nums[first], nums[second], nums[third]).sorted()) | ||
} | ||
} | ||
} | ||
} | ||
return result.toList() | ||
} | ||
|
||
/** | ||
* 2. ์ ๋ ฅ๋ฐ์ ์ ์ ๋ฐฐ์ด์ ์ ๋ ฌํ์ฌ ์ํํ๋ฉด์ ์์๋ฅผ ํฉ์ฐํ์ฌ 0๊ณผ ๋น๊ตํ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ์ค์ผ๋ก ํฌ ํฌ์ธํฐ์ ๊ฐ์ ์กฐ์ํ๋ค. | ||
* TC: O(n^2), SC: O(n) | ||
*/ | ||
private fun usingTwoPointer(nums: IntArray): List<List<Int>> { | ||
val sortedNumbers = nums.sorted() | ||
val result = mutableSetOf<List<Int>>() | ||
for (index in nums.indices) { | ||
var left = index + 1 | ||
var right = nums.size - 1 | ||
while (left < right) { | ||
val sum = sortedNumbers[index] + sortedNumbers[left] + sortedNumbers[right] | ||
if (sum == 0) { | ||
result.add(listOf(sortedNumbers[index], sortedNumbers[left], sortedNumbers[right])) | ||
left++ | ||
right-- | ||
} else if (sum < 0) { | ||
left++ | ||
} else { | ||
right-- | ||
} | ||
} | ||
} | ||
return result.toList() | ||
} | ||
|
||
@Test | ||
fun `์ ๋ ฅ๋ฐ์ ์ ์ ๋ฐฐ์ด์ ์ธ ๊ฐ์ ์์์ ํฉ์ด 0์ด ๋๋ ๋ฆฌ์คํธ๋ฅผ ๋ฐํํ๋ค`() { | ||
threeSum(intArrayOf(-1,0,1,2,-1,-4)) shouldContainExactlyInAnyOrder listOf( | ||
listOf(-1,-1,2), | ||
listOf(-1,0,1) | ||
) | ||
threeSum(intArrayOf(0,0,0)) shouldContainExactlyInAnyOrder listOf( | ||
listOf(0,0,0) | ||
) | ||
} | ||
} |
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,60 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
import kotlin.math.max | ||
|
||
class `best-time-to-buy-and-sell-stock` { | ||
|
||
fun maxProfit(prices: IntArray): Int { | ||
if (prices.size == 1) return 0 | ||
return usingKadaneAlgorithm(prices) | ||
} | ||
|
||
/** | ||
* 1. ๋ฐฉํฅ์ด ์กด์ฌํ๊ธฐ ๋๋ฌธ์ ํฌ ํฌ์ธํฐ๋ฅผ ํ์ฉํ์ฌ ์ฃผ์์ ํ ์ ์๋ ๊ฒฝ์ฐ๋ผ๋ฉด ์ต๋ ๊ฐ์ ๊ณ์ฐํ๊ณ ๋ง์ฝ ์ฐ ๊ฐ๊ฒฉ๋ณด๋ค ์ผ ๊ฐ๊ฒฉ์ ๋ง๋๋ฉด ๋ค์ ์ฐ๋ค | ||
* TC: O(n), SC: O(1) | ||
*/ | ||
private fun usingTwoPointer(prices: IntArray): Int { | ||
var (left, right) = 0 to 1 | ||
var maxProfit = 0 | ||
|
||
while (right < prices.size) { | ||
if (prices[left] < prices[right]) { | ||
maxProfit = max(prices[right] - prices[left], maxProfit) | ||
right++ | ||
} else if (prices[left] >= prices[right]) { | ||
left = right | ||
right++ | ||
} | ||
} | ||
|
||
return maxProfit | ||
} | ||
|
||
/** | ||
* 2. ์นด๋ฐ์ธ ์๊ณ ๋ฆฌ์ฆ์ ๋ณํ๋ ๋ฒ์ ์ผ๋ก ๊ฐ์ฅ ์ผ ๊ฒฝ์ฐ๋ฅผ buy์ ์ ์ฅํ๊ณ ํ์ฌ ์ต๋ ์์ต์ ์ด๊ณผํ๋ฉด ์ ๋ฐ์ดํธํ๋ค | ||
* TC: O(n), SC: O(1) | ||
*/ | ||
private fun usingKadaneAlgorithm(prices: IntArray): Int { | ||
var buy = prices[0] | ||
var maxProfit = 0 | ||
|
||
for (index in 1 until prices.size) { | ||
if (prices[index] < buy) { | ||
buy = prices[index] | ||
} else if (prices[index] - buy > maxProfit) { | ||
maxProfit = prices[index] - buy | ||
} | ||
} | ||
return maxProfit | ||
} | ||
|
||
@Test | ||
fun `์ฃผ์ด์ง ๊ฐ๊ฒฉ ๋ฐฐ์ด์ ํตํด ์ต๋์ ์์ต์ ๋ฐํํ๋ค`() { | ||
maxProfit(intArrayOf(3,3)) shouldBe 0 | ||
maxProfit(intArrayOf(7,6,5,4,3,2,1,0)) shouldBe 0 | ||
maxProfit(intArrayOf(7,1,5,3,6,4)) shouldBe 5 | ||
maxProfit(intArrayOf(1,2,4,2,5,7,2,4,9,0,9)) shouldBe 9 | ||
} | ||
} |
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,53 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder | ||
import org.junit.jupiter.api.Test | ||
|
||
class `group-anagrams` { | ||
|
||
fun groupAnagrams(strs: Array<String>): List<List<String>> { | ||
return usingArray(strs) | ||
} | ||
|
||
/** | ||
* 1. ์ ๋ ฅ๋ฐ์ ๋ฌธ์์ด๋ค์ ๋ฌธ์ ๋ฐฐ์ด๋ก ๋ณํํ์ฌ ์ ๋ ฌ๋ ๊ฒฐ๊ณผ๋ฅผ map ์ ํค๋ก ์ ํ์ฌ ํค ๊ธฐ์ค์ผ๋ก ๋ฌธ์์ด๋ค์ ๊ทธ๋ฃนํํ๋ค. | ||
* TC: O(n * k log(k)), SC: O(n) | ||
*/ | ||
private fun usingSort(strs: Array<String>): List<List<String>> { | ||
val map = strs.groupBy { it.toCharArray().sorted() } | ||
return map.values.toList() | ||
} | ||
|
||
/** | ||
* 2. ์ ๋ ฅ๋ฐ์ ๋ฌธ์์ด๋ค์ ์ํํ๋ฉฐ ๋ฌธ์์ด์ ๋ฌธ์ ๊ฐฏ์๋ฅผ ์นด์ดํธํ์ฌ ์ ๋๊ทธ๋จ์ธ์ง ๊ตฌ๋ณํ๋ค. | ||
* TC: O(n), SC: O(n) | ||
*/ | ||
private fun usingArray(strs: Array<String>): List<List<String>> { | ||
val map = strs.groupBy { it -> | ||
val counter = IntArray(26) | ||
for (ch in it) { | ||
counter[ch - 'a']++ | ||
} | ||
counter.joinToString(",") // ๊ตฌ๋ถ์๋ฅผ ๋ฃ์ง ์์ผ๋ฉด arrayOf("bdddddddddd","bbbbbbbbbbc") ํ ์ผ๋ฅผ ์คํจํจ | ||
} | ||
|
||
return map.values.toList() | ||
} | ||
|
||
@Test | ||
fun `์ ๋ ฅ๋ฐ์ ๋ฌธ์์ด๋ค์ ์ ๋๊ทธ๋จ ๊ธฐ์ค ๊ทธ๋ฃน๋ณ๋ก ๋ฐํํ๋ค`() { | ||
groupAnagrams(arrayOf("eat","tea","tan","ate","nat","bat")) shouldContainExactlyInAnyOrder listOf( | ||
listOf("tan","nat"), | ||
listOf("bat"), | ||
listOf("eat","tea","ate"), | ||
) | ||
groupAnagrams(arrayOf("cab","tin","pew","duh","may","ill","buy","bar","max","doc")) shouldContainExactlyInAnyOrder listOf( | ||
listOf("max"),listOf("buy"),listOf("doc"),listOf("may"),listOf("ill"), | ||
listOf("duh"),listOf("tin"),listOf("bar"),listOf("pew"),listOf("cab") | ||
) | ||
groupAnagrams(arrayOf("bdddddddddd","bbbbbbbbbbc")) shouldContainExactlyInAnyOrder listOf( | ||
listOf("bbbbbbbbbbc"), | ||
listOf("bdddddddddd") | ||
) | ||
} | ||
} |
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,82 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
|
||
class `implement-trie-prefix-tree` { | ||
|
||
/** | ||
* ์์ด ์๋ฌธ์๋ง ์ ๋ ฅ๋๋ค. | ||
*/ | ||
class Trie { | ||
|
||
private val node = Node() | ||
|
||
/** | ||
* TC: O(n), SC: O(n) | ||
*/ | ||
fun insert(word: String) { | ||
var now = node | ||
|
||
for (char in word) { | ||
val index = char - 'a' | ||
if (now.next[index] == null) { | ||
now.next[index] = Node() | ||
} | ||
now.next[index]?.apply { now = this } | ||
} | ||
now.isEnd = true | ||
} | ||
|
||
/** | ||
* TC: O(n), SC: O(1) | ||
*/ | ||
fun search(word: String): Boolean { | ||
var now = node | ||
|
||
for (char in word) { | ||
val index = char - 'a' | ||
if (now.next[index] == null) { | ||
return false | ||
} | ||
now.next[index]?.apply { now = this } | ||
} | ||
|
||
return now.isEnd | ||
} | ||
|
||
/** | ||
* TC: O(n), SC: O(1) | ||
*/ | ||
fun startsWith(prefix: String): Boolean { | ||
var now = node | ||
|
||
for (char in prefix) { | ||
val index = char - 'a' | ||
if (now.next[index] == null) { | ||
return false | ||
} | ||
now.next[index]?.apply { now = this } | ||
} | ||
|
||
return true | ||
} | ||
|
||
} | ||
|
||
@Test | ||
fun `์ ๋์ฌ ํธ๋ฆฌ๋ฅผ ๊ตฌํํ๋ผ`() { | ||
val trie = Trie() | ||
trie.insert("apple") | ||
trie.search("apple") shouldBe true | ||
trie.search("app") shouldBe false | ||
trie.startsWith("app") shouldBe true | ||
trie.insert("app") | ||
trie.search("app") shouldBe true | ||
} | ||
} | ||
|
||
private class Node { | ||
val next = Array<Node?>(26) { null } | ||
var isEnd = false | ||
} |
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,91 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
|
||
class `word-break` { | ||
|
||
fun wordBreak(s: String, wordDict: List<String>): Boolean { | ||
return usingDP(s, wordDict) | ||
} | ||
|
||
/** | ||
* 1. DFS ์ฌ์ฉ (์๊ฐ์ด๊ณผ) | ||
* TC: O(w^s * wordDict ๋จ์ด์ ๊ธธ์ด), SC: O(s) | ||
*/ | ||
private fun usingDFS(s: String, wordDict: List<String>): Boolean { | ||
|
||
fun recursion(s: String, wordDict: List<String>, index: Int): Boolean = | ||
if (index == s.length) true | ||
else { | ||
wordDict.map { word -> | ||
var result = false | ||
if (index + word.length < s.length + 1 && s.substring(index, index + word.length) == word) { | ||
result = recursion(s, wordDict, index + word.length) | ||
} | ||
result | ||
}.find { it } ?: false | ||
} | ||
|
||
return recursion(s, wordDict, 0) | ||
} | ||
|
||
/** | ||
* 2, ์ฌ์ ์ ๋ด๊ฒจ์๋ ๋ฌธ์์ด๋ค์ ๊ธฐ์ค์ผ๋ก ์ธ๋ฑ์ค๋ฅผ ์ฆ๊ฐ์ํค๋ฉด์ ๋ฌธ์์ด์ ์์ฑ์ํจ๋ค. ํ ๋ฒ ํ์ํ์ฌ ๋ฌธ์์ด์ ์์ฑ์ํค์ง ๋ชปํ ์ธ๋ฑ์ค๋ฅผ ์ ์ฅํ์ฌ ํด๋น ์ธ๋ฑ์ค๋ ๋ค์ ํ์ํ์ง ์๋๋ก ํ์ฌ ์ฑ๋ฅ์ ๊ฐ์ ํ๋ค. | ||
* TC: O(s * w * wordDict ๋จ์ด์ ๊ธธ์ด), SC: O(s) | ||
*/ | ||
private fun usingMemoizationDFS(s: String, wordDict: List<String>): Boolean{ | ||
|
||
fun dfs(s: String, wordDict: List<String>, index: Int, memo: MutableSet<Int>): Boolean { | ||
val len = s.length | ||
if(index == len) return true | ||
else if(memo.contains(index)) return false | ||
|
||
for (word in wordDict) { | ||
if (index + word.length < s.length + 1 && | ||
s.substring(index, index + word.length) == word && | ||
dfs(s, wordDict, index + word.length, memo)) { | ||
return true | ||
} | ||
} | ||
memo.add(index) | ||
return false | ||
} | ||
|
||
if(s.isEmpty()) return false | ||
return dfs(s, wordDict, 0, mutableSetOf()) | ||
} | ||
|
||
/** | ||
* 3. ๋ฌธ์์ด์ ๋๋ถํฐ 0๊น์ง ์ํํ๋ฉด์ ์ํํ๋ ๋ฒ์์ ๋ฌธ์์ด์ ๋ง๋ค ์ ์๋ค๋ฉด ํด๋น ์ธ๋ฑ์ค๋ฅผ true๋ก ๋ณํํ์ฌ ์ด์ ์ ์ฌ์ฉํ ์ฐ์ฐ์ ๊ฒฐ๊ณผ๋ฅผ ์ฌํ์ฉํ๋ค. | ||
* TC: O(s * w * wordDict ๋จ์ด์ ๊ธธ์ด) SC: O(s) | ||
*/ | ||
private fun usingDP(s: String, wordDict: List<String>): Boolean { | ||
val dp = BooleanArray(s.length + 1).apply { | ||
this[s.length] = true | ||
} | ||
|
||
for (index in s.length - 1 downTo 0) { | ||
for (word in wordDict) { | ||
if (dp[index]) break | ||
else if (index + word.length <= s.length && s.substring(index, index + word.length) == word) { | ||
dp[index] = dp[index + word.length] | ||
} | ||
} | ||
} | ||
return dp[0] | ||
} | ||
|
||
@Test | ||
fun `๋ฌธ์์ด๊ณผ ๋ฌธ์์ด ์ฌ์ ์ด ์ฃผ์ด์ก์ ๋ ๋ฌธ์์ด ์ฌ์ ์ ์ด์ฉํ์ฌ ๋ฌธ์์ด์ ์์ฑํ ์ ์์ผ๋ฉด ์ฐธ์ ๋ฐํํ๋ค`() { | ||
wordBreak("applepenapple", listOf("apple", "pen")) shouldBe true | ||
wordBreak("leetcode", listOf("leet", "co", "de")) shouldBe true | ||
wordBreak("abcd", listOf("a","abc","b","cd")) shouldBe true | ||
wordBreak("cars", listOf("car","ca","rs")) shouldBe true | ||
} | ||
|
||
@Test | ||
fun `๋ฌธ์์ด๊ณผ ๋ฌธ์์ด ์ฌ์ ์ด ์ฃผ์ด์ก์ ๋ ๋ฌธ์์ด ์ฌ์ ์ ์ด์ฉํ์ฌ ๋ฌธ์์ด์ ์์ฑํ ์ ์๋ค๋ฉด ๊ฑฐ์ง์ ๋ฐํํ๋ค`() { | ||
wordBreak("catsandog", listOf("cats", "dog", "sand", "and", "cat")) shouldBe false | ||
} | ||
} |