Skip to content

Commit

Permalink
Merge pull request #390 from jdalma/main
Browse files Browse the repository at this point in the history
[์ •ํ˜„์ค€] 3์ฃผ์ฐจ ๋‹ต์•ˆ ์ถ”๊ฐ€
  • Loading branch information
jdalma authored Aug 30, 2024
2 parents 93fe432 + 42cf39c commit a4ee01e
Show file tree
Hide file tree
Showing 5 changed files with 294 additions and 0 deletions.
32 changes: 32 additions & 0 deletions climbing-stairs/jdalma.kt
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
}
}
122 changes: 122 additions & 0 deletions coin-change/jdalma.kt
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
}
}
46 changes: 46 additions & 0 deletions combination-sum/jdalma.kt
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()
}
}
38 changes: 38 additions & 0 deletions product-of-array-except-self/jdalma.kt
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)
}
}
56 changes: 56 additions & 0 deletions two-sum/jdalma.kt
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)
}
}

0 comments on commit a4ee01e

Please sign in to comment.