-
Notifications
You must be signed in to change notification settings - Fork 53
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 #390 from jdalma/main
[์ ํ์ค] 3์ฃผ์ฐจ ๋ต์ ์ถ๊ฐ
- Loading branch information
Showing
5 changed files
with
294 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,32 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
|
||
class `climbing-stairs` { | ||
|
||
/** | ||
* 1. bottom-up ๋ฐฉ์์ผ๋ก ๊ฐ๋ฅํ ๊ฒฝ์ฐ์ ์๋ฅผ ๋์ ํ๋ค. | ||
* TC: O(n), SC: O(n) | ||
*/ | ||
fun climbStairs(n: Int): Int { | ||
val dp = IntArray(n + 1).apply { | ||
this[1] = 1 | ||
if (n >= 2) this[2] = 2 | ||
} | ||
|
||
for (num in 3 .. n) { | ||
dp[num] = dp[num - 1] + dp[num - 2] | ||
} | ||
|
||
return dp[n] | ||
} | ||
|
||
@Test | ||
fun `์ ๋ ฅ๋ฐ์ ๋ชฉํฏ๊ฐ์ 1๊ณผ 2๋ง ๋ํ์ฌ ๋๋ฌํ ์ ์๋ ๊ฒฝ์ฐ์ ์๋ฅผ ๋ฐํํ๋ค`() { | ||
climbStairs(1) shouldBe 1 | ||
climbStairs(2) shouldBe 2 | ||
climbStairs(3) shouldBe 3 | ||
climbStairs(4) shouldBe 5 | ||
} | ||
} |
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,122 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
import java.util.ArrayDeque | ||
import kotlin.math.min | ||
|
||
class `coin-change` { | ||
|
||
fun coinChange(coins: IntArray, amount: Int): Int { | ||
return topDown(coins, amount) | ||
} | ||
|
||
/** | ||
* 1. ๋ชจ๋ ์ฝ์ธ์ ๋ฐ๋ณต์ ์ผ๋ก ์ฌ์ฉํ๋ฉด์ 0์์ ๋๋ฌํ๋ฉด ๊ทธ ๋์ step ์ค ์ต์๊ฐ์ ๋ฐํํ๋ค. | ||
* TC: O(coins^amount), SC: O(amount) | ||
*/ | ||
private fun bruteForce(coins: IntArray, amount: Int): Int { | ||
fun dfs(coins: IntArray, remain: Int, step: Int): Int = | ||
if (remain < 0) Int.MAX_VALUE | ||
else if (remain == 0) step | ||
else coins.map { dfs(coins, remain - it, step + 1) }.min() | ||
|
||
val result = dfs(coins, amount, 0) | ||
return if (result == Int.MAX_VALUE) -1 else result | ||
} | ||
|
||
/** | ||
* 2. ๋ชจ๋ ์ฝ์ธ๋ค์ ์ข ๋ฅ๋ณ๋ก ๋์ ํ๋ฉด์ ๊ฐ์ฅ ๋นจ๋ฆฌ ๋ชฉํฏ๊ฐ์ ๋๋ฌํ๋ ์ฝ์ธ์ ์๋ฅผ ๋ฐํํ๋ค. | ||
* TC: O(amount * coins), SC: O(amount) | ||
*/ | ||
private fun bfs(coins: IntArray, amount: Int): Int { | ||
if (amount == 0) return 0 | ||
|
||
val visited = BooleanArray(amount + 1) { false } | ||
val queue = ArrayDeque<Int>().apply { | ||
this.offer(0) | ||
} | ||
|
||
var coinCount = 0 | ||
while (queue.isNotEmpty()) { | ||
var size = queue.size | ||
while (size-- > 0) { | ||
val sum = queue.poll() | ||
if (sum == amount) return coinCount | ||
else if (sum < amount && !visited[sum] ) { | ||
visited[sum] = true | ||
for (coin in coins) { | ||
queue.offer(sum + coin) | ||
} | ||
} | ||
} | ||
coinCount++ | ||
} | ||
return -1 | ||
} | ||
|
||
/** | ||
* 3. ๋ฐ๋ณต๋๋ ์ฐ์ฐ์ DP๋ฅผ ํ์ฉํ์ฌ bottom-up์ผ๋ก ํด๊ฒฐ | ||
* 1์๋ถํฐ ๋ชฉํฏ๊ฐ๊น์ง ๊ฐ ๊ฐ์น๋ฅผ ๊ตฌ์ฑํ๊ธฐ ์ํ ์ต์ ์ฝ์ธ์ ๋์ ํ๋ฉด์ ๋ชฉํฏ๊ฐ์ ๊ตฌ์ฑํ๋ ์ต์ ์ฝ์ธ ๊ฐ์๋ฅผ ๊ตฌํ๋ ๊ฒ์ด๋ค. | ||
* TC: O(amount*coins), SC: O(amount) | ||
*/ | ||
private fun bottomUp(coins: IntArray, amount: Int): Int { | ||
val dp = IntArray(amount + 1) { 10000 + 1 }.apply { | ||
this[0] = 0 | ||
} | ||
|
||
for (target in 1 .. amount) { | ||
coins.forEach { coin -> | ||
if (coin <= target) { | ||
dp[target] = min(dp[target], dp[target - coin] + 1) | ||
} | ||
} | ||
} | ||
|
||
return if (dp[amount] == 10001) -1 else dp[amount] | ||
} | ||
|
||
/** | ||
* 4. ๋ชฉํ๊ธ์ก๋ถํฐ ์ฝ์ธ๋งํผ ์ฐจ๊ฐํ์ฌ 0์์ ๋๋ฌํ๋ฉด ๋ฐฑํธ๋ํน์ผ๋ก DP ๋ฐฐ์ด์ ๊ฐฑ์ ํ๋ค | ||
* TC: O(amount * coins), SC: O(amount) | ||
*/ | ||
private fun topDown(coins: IntArray, amount: Int): Int { | ||
fun recursive(coins: IntArray, remain: Int, dp: IntArray): Int { | ||
if (remain == 0) return 0 | ||
else if (remain < 0) return -1 | ||
else if (dp[remain] != 10001) return dp[remain] | ||
|
||
var minCoins = 10001 | ||
coins.forEach { coin -> | ||
val result = recursive(coins, remain - coin, dp) | ||
if (result in 0 until minCoins) { | ||
minCoins = result + 1 | ||
} | ||
} | ||
dp[remain] = if (minCoins == 10001) -1 else minCoins | ||
return dp[remain] | ||
} | ||
|
||
if (amount < 1) return 0 | ||
return recursive(coins, amount, IntArray(amount + 1) { 10000 + 1 }) | ||
} | ||
|
||
@Test | ||
fun `์ฝ์ธ์ ์ข ๋ฅ์ ๋ชฉํ๊ฐ์ ์ ๋ ฅํ๋ฉด ๋ชฉํฏ๊ฐ์ ๊ตฌ์ฑํ๋ ์ฝ์ธ์ ์ต์ ๊ฐ์๋ฅผ ๋ฐํํ๋ค`() { | ||
coinChange(intArrayOf(1,2,5), 11) shouldBe 3 | ||
coinChange(intArrayOf(1,3,5), 15) shouldBe 3 | ||
coinChange(intArrayOf(5,3,1), 15) shouldBe 3 | ||
coinChange(intArrayOf(1,2), 4) shouldBe 2 | ||
coinChange(intArrayOf(2,5,10,1), 27) shouldBe 4 | ||
} | ||
|
||
@Test | ||
fun `์ฝ์ธ์ ์ข ๋ฅ๋ก ๋ชฉํ๊ฐ์ ์์ฑํ ์ ์๋ค๋ฉด -1์ ๋ฐํํ๋ค`() { | ||
coinChange(intArrayOf(2), 3) shouldBe -1 | ||
} | ||
|
||
@Test | ||
fun `๋ชฉํฏ๊ฐ์ด 0์ด๋ผ๋ฉด 0์ ๋ฐํํ๋ค`() { | ||
coinChange(intArrayOf(1,2,3), 0) shouldBe 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,46 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
|
||
class `combination-sum` { | ||
|
||
/** | ||
* ํ๋ณด์๋ฅผ ์ค๋ณต์ผ๋ก ์ฌ์ฉํ ์ ์๊ธฐ์ 0๋ถํฐ ํ๋ณด์๋ค์ ๋์ ํ๋ฉด์ target๋ณด๋ค ํฌ๋ฉด ํ์ถํ๋ ๋ฐฉ์์ด๋ค. | ||
* ๋ง์ฝ target๊ณผ ๋์ผํ๋ค๋ฉด ๋์ ํ ๋ ์ฌ์ฉ๋ ํ๋ณด์๋ค์ numbers์ ์ ์ฅํด๋๊ธฐ์ ๊ฒฐ๊ณผ์ ๋ณต์ฌํ๋ค. | ||
* ์๊ฐ๋ณต์ก๋: O(n^t), ๊ณต๊ฐ๋ณต์ก๋: O(t) | ||
*/ | ||
fun combinationSum(candidates: IntArray, target: Int): List<List<Int>> { | ||
|
||
fun backtracking(candidates: IntArray, target: Int, result: MutableList<List<Int>>, numbers: MutableList<Int>, start: Int, total: Int) { | ||
if (total > target) return | ||
else if (total == target) { | ||
result.add(numbers.toList()) | ||
} else { | ||
(start until candidates.size).forEach { | ||
numbers.add(candidates[it]) | ||
backtracking(candidates, target, result, numbers, it, total + candidates[it]) | ||
numbers.removeLast() | ||
} | ||
} | ||
} | ||
|
||
val result = mutableListOf<List<Int>>() | ||
backtracking(candidates, target, result, mutableListOf(), 0, 0) | ||
return result | ||
} | ||
|
||
@Test | ||
fun `์ ๋ ฅ๋ฐ์ ์ ์ ๋ฆฌ์คํธ๋ฅผ ์ฌ์ฉํ์ฌ ๋ชฉํฏ๊ฐ์ ๋ง๋ค์ด๋ผ ์ ์๋ ๋ชจ๋ ๊ฒฝ์ฐ๋ฅผ ๋ฆฌ์คํธ๋ก ๋ฐํํ๋ค`() { | ||
combinationSum(intArrayOf(2,3,6,7), 7) shouldBe listOf( | ||
listOf(2,2,3), | ||
listOf(7) | ||
) | ||
combinationSum(intArrayOf(2,3,5), 8) shouldBe listOf( | ||
listOf(2,2,2,2), | ||
listOf(2,3,3), | ||
listOf(3,5) | ||
) | ||
combinationSum(intArrayOf(2), 1) shouldBe listOf() | ||
} | ||
} |
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,38 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
|
||
class `product-of-array-except-self` { | ||
|
||
fun productExceptSelf(nums: IntArray): IntArray { | ||
return usingPrefixSum(nums) | ||
} | ||
|
||
/** | ||
* ๊ฐ ์ธ๋ฑ์ค์ ์ ,ํ๋ฅผ ๋์ ๊ณฑ์ ํฉํ์ฌ ์ด์ ์ฐ์ฐ ๊ฒฐ๊ณผ๋ฅผ ์ฌํ์ฉํ๋ค. | ||
* ์๊ฐ๋ณต์ก๋: O(n), ๊ณต๊ฐ๋ณต์ก๋: O(n) | ||
*/ | ||
private fun usingPrefixSum(nums: IntArray): IntArray { | ||
val toRight = Array(nums.size) { 1 } | ||
val toLeft = Array(nums.size) { 1 } | ||
|
||
(0 until nums.size - 1).forEach { | ||
toRight[it + 1] = toRight[it] * nums[it] | ||
} | ||
(nums.size - 1 downTo 1).forEach { | ||
toLeft[it - 1] = toLeft[it] * nums[it] | ||
} | ||
|
||
return nums.indices | ||
.map { toRight[it] * toLeft[it] } | ||
.toIntArray() | ||
} | ||
|
||
@Test | ||
fun `์ ๋ ฅ๋ฐ์ ๋ฐฐ์ด์ ์ํํ๋ฉฐ ์๊ธฐ ์์ ์ ์ ์ธํ ๋๋จธ์ง ์์๋ค์ ๊ณฑํ ๊ฐ์ ๋ฐฐ์ด๋ก ๋ฐํํ๋ค`() { | ||
productExceptSelf(intArrayOf(2,3,4,5)) shouldBe intArrayOf(60,40,30,24) | ||
productExceptSelf(intArrayOf(1,2,3,4)) shouldBe intArrayOf(24,12,8,6) | ||
productExceptSelf(intArrayOf(-1,1,0,-3,3)) shouldBe intArrayOf(0,0,9,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,56 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
|
||
class `two-sum` { | ||
|
||
fun twoSum(nums: IntArray, target: Int): IntArray { | ||
return usingMapOptimized(nums, target) | ||
} | ||
|
||
/** | ||
* 1. map์ ํ์ฉ | ||
* TC: O(n), SC: O(n) | ||
*/ | ||
private fun usingMap(nums: IntArray, target: Int): IntArray { | ||
val map = nums.withIndex().associate { it.value to it.index } | ||
|
||
nums.forEachIndexed { i, e -> | ||
val diff: Int = target - e | ||
if (map.containsKey(diff) && map[diff] != i) { | ||
return map[diff]?.let { | ||
intArrayOf(it, i) | ||
} ?: intArrayOf() | ||
} | ||
} | ||
return intArrayOf() | ||
} | ||
|
||
/** | ||
* 2. map์ ๋ชจ๋ ๊ฐ์ ์ด๊ธฐํํ ํ์๊ฐ ์๊ธฐ์, nums๋ฅผ ์ํํ๋ฉฐ ํ์ธํ๋ค. | ||
* TC: O(n), SC: O(n) | ||
*/ | ||
private fun usingMapOptimized(nums: IntArray, target: Int): IntArray { | ||
val map = mutableMapOf<Int, Int>() | ||
|
||
for (index in nums.indices) { | ||
val diff = target - nums[index] | ||
if (map.containsKey(diff)) { | ||
return map[diff]?.let { | ||
intArrayOf(it, index) | ||
} ?: intArrayOf() | ||
} | ||
map[nums[index]] = index | ||
} | ||
|
||
return intArrayOf() | ||
} | ||
|
||
@Test | ||
fun `์ ์ ๋ฐฐ์ด๊ณผ ๋ชฉํฏ๊ฐ์ ์ ๋ ฅ๋ฐ์ ๋ชฉํฏ๊ฐ์ ๋ง๋ค ์ ์๋ ์ ์ ๋ฐฐ์ด์ ์์๋ค ์ค ๋ ๊ฐ์ ์์์ ์ธ๋ฑ์ค๋ฅผ ๋ฐํํ๋ค`() { | ||
twoSum(intArrayOf(2,7,11,15), 9) shouldBe intArrayOf(0,1) | ||
twoSum(intArrayOf(3,2,4), 6) shouldBe intArrayOf(1,2) | ||
twoSum(intArrayOf(3,3), 6) shouldBe intArrayOf(0,1) | ||
} | ||
} |