Skip to content

Commit

Permalink
Merge pull request #449 from jdalma/main
Browse files Browse the repository at this point in the history
[์ •ํ˜„์ค€] 5์ฃผ์ฐจ ๋‹ต์•ˆ ์ œ์ถœ
  • Loading branch information
jdalma authored Sep 14, 2024
2 parents 41435c7 + 15f9259 commit 004452c
Show file tree
Hide file tree
Showing 5 changed files with 352 additions and 0 deletions.
66 changes: 66 additions & 0 deletions 3sum/jdalma.kt
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)
)
}
}
60 changes: 60 additions & 0 deletions best-time-to-buy-and-sell-stock/jdalma.kt
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
}
}
53 changes: 53 additions & 0 deletions group-anagrams/jdalma.kt
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")
)
}
}
82 changes: 82 additions & 0 deletions implement-trie-prefix-tree/jdalma.kt
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
}
91 changes: 91 additions & 0 deletions word-break/jdalma.kt
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
}
}

0 comments on commit 004452c

Please sign in to comment.