Skip to content

Commit a3c9195

Browse files
authored
Merge pull request #538 from jdalma/main
[정현준] 10주차
2 parents afb1e8a + 7444507 commit a3c9195

File tree

5 files changed

+371
-0
lines changed

5 files changed

+371
-0
lines changed

course-schedule/jdalma.kt

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
6+
class `course-schedule` {
7+
8+
/**
9+
* TC: O(node + edge), SC: O(node + edge)
10+
*/
11+
fun canFinish(numCourses: Int, prerequisites: Array<IntArray>): Boolean {
12+
if (prerequisites.isEmpty()) return true
13+
14+
return usingTopologySort(numCourses, prerequisites)
15+
}
16+
17+
private fun usingTopologySort(numCourses: Int, prerequisites: Array<IntArray>): Boolean {
18+
val adj = List(numCourses) { mutableListOf<Int>() }
19+
val degree = IntArray(numCourses)
20+
for (e in prerequisites) {
21+
val (course, pre) = e[0] to e[1]
22+
adj[pre].add(course)
23+
degree[course]++
24+
}
25+
26+
val queue = ArrayDeque<Int>().apply {
27+
degree.forEachIndexed { index, i ->
28+
if (i == 0) {
29+
this.add(index)
30+
}
31+
}
32+
}
33+
34+
var answer = 0
35+
while (queue.isNotEmpty()) {
36+
val now = queue.removeFirst()
37+
answer++
38+
39+
queue.addAll(adj[now].filter { --degree[it] == 0 })
40+
}
41+
42+
return answer == numCourses
43+
}
44+
45+
@Test
46+
fun `코스의 개수와 코스 간 의존성을 전달하면 코스를 완료할 수 있는지 여부를 반환한다`() {
47+
canFinish(5,
48+
arrayOf(
49+
intArrayOf(0,1),
50+
intArrayOf(0,2),
51+
intArrayOf(1,3),
52+
intArrayOf(1,4),
53+
intArrayOf(3,4)
54+
)
55+
) shouldBe true
56+
canFinish(5,
57+
arrayOf(
58+
intArrayOf(1,4),
59+
intArrayOf(2,4),
60+
intArrayOf(3,1),
61+
intArrayOf(3,2)
62+
)
63+
) shouldBe true
64+
canFinish(2, arrayOf(intArrayOf(1, 0))) shouldBe true
65+
canFinish(2, arrayOf(intArrayOf(1, 0), intArrayOf(0, 1))) shouldBe false
66+
canFinish(20,
67+
arrayOf(
68+
intArrayOf(0,10),
69+
intArrayOf(3,18),
70+
intArrayOf(5,5),
71+
intArrayOf(6,11),
72+
intArrayOf(11,14),
73+
intArrayOf(13,1),
74+
intArrayOf(15,1),
75+
intArrayOf(17,4)
76+
)
77+
) shouldBe false
78+
}
79+
}

invert-binary-tree/jdalma.kt

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
6+
class `invert-binary-tree` {
7+
8+
fun invertTree(root: TreeNode?): TreeNode? {
9+
if (root == null) return null
10+
11+
return usingStack(root)
12+
}
13+
14+
/**
15+
* TC: O(n), SC: O(n)
16+
*/
17+
private fun usingDFS(node: TreeNode?): TreeNode? {
18+
if (node == null) return null
19+
20+
val (left, right) = node.left to node.right
21+
node.left = usingDFS(right)
22+
node.right = usingDFS(left)
23+
24+
return node
25+
}
26+
27+
/**
28+
* TC: O(n), SC: O(n)
29+
*/
30+
private fun usingStack(node: TreeNode): TreeNode {
31+
val stack= ArrayDeque<TreeNode>().apply {
32+
this.add(node)
33+
}
34+
35+
while (stack.isNotEmpty()) {
36+
val now = stack.removeLast()
37+
val tmp = now.left
38+
now.left = now.right
39+
now.right = tmp
40+
41+
now.left?.let { stack.add(it) }
42+
now.right?.let { stack.add(it) }
43+
}
44+
return node
45+
}
46+
47+
@Test
48+
fun `전달된 노드의 하위 노드들의 반전된 값을 반환한다`() {
49+
val actual = TreeNode.of(4,2,7,1,3,6,9)
50+
val expect = TreeNode.of(4,7,2,9,6,3,1)
51+
invertTree(actual) shouldBe expect
52+
53+
val actual1 = TreeNode.of(1,2)
54+
val expect1 = TreeNode.of(1,null,2)
55+
56+
invertTree(actual1) shouldBe expect1
57+
}
58+
}

jump-game/jdalma.kt

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
import kotlin.math.max
6+
7+
class `jump-game` {
8+
9+
fun canJump(nums: IntArray): Boolean {
10+
return usingGreedy(nums)
11+
}
12+
13+
/**
14+
* TC: O(n), SC: O(1)
15+
*/
16+
private fun usingGreedy(nums: IntArray): Boolean {
17+
var reachable = 0
18+
for (index in nums.indices) {
19+
if (index > reachable) return false
20+
reachable = max(reachable, index + nums[index])
21+
}
22+
23+
return true
24+
}
25+
26+
/**
27+
* TC: O(n^2), SC: O(n)
28+
*/
29+
private fun usingMemoization(nums: IntArray): Boolean {
30+
val memo = IntArray(nums.size) { -1 }
31+
fun dfs(now: Int): Boolean {
32+
if (now >= nums.size - 1) {
33+
return true
34+
} else if (memo[now] != -1) {
35+
return memo[now] != 0
36+
}
37+
for (next in 1 .. nums[now]) {
38+
if (dfs(now + next)) {
39+
memo[now] = 1
40+
return true
41+
}
42+
}
43+
memo[now] = 0
44+
return false
45+
}
46+
return dfs(0)
47+
}
48+
49+
@Test
50+
fun `첫 번째 인덱스에서 마지막 인덱스에 도달할 수 있는지 여부를 반환한다`() {
51+
canJump(intArrayOf(2,3,1,1,4)) shouldBe true
52+
canJump(intArrayOf(3,2,1,0,4)) shouldBe false
53+
}
54+
}

merge-k-sorted-lists/jdalma.kt

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
import java.lang.RuntimeException
6+
7+
class `merge-k-sorted-lists` {
8+
9+
data class ListNode(var `val`: Int) {
10+
var next: ListNode? = null
11+
12+
companion object {
13+
fun of(vararg `val`: Int): ListNode {
14+
val dummy = ListNode(-1)
15+
var prev = dummy
16+
for (v in `val`) {
17+
prev.next = ListNode(v)
18+
prev = prev.next ?: throw RuntimeException()
19+
}
20+
return dummy.next ?: throw RuntimeException()
21+
}
22+
}
23+
}
24+
25+
fun mergeKLists(lists: Array<ListNode?>): ListNode? {
26+
return if (lists.isEmpty()) null
27+
else if (lists.size == 1) lists.first()
28+
else mergeDivideAndConquer(lists)
29+
}
30+
31+
/**
32+
* TC: O(lists.size * ListNode.size), SC: O(1)
33+
*/
34+
private fun usingBruteForce(lists: Array<ListNode?>): ListNode? {
35+
val dummy = ListNode(-1)
36+
var prev = dummy
37+
38+
while (true) {
39+
var minNode: ListNode? = null
40+
var minIndex = -1
41+
42+
for (index in lists.indices) {
43+
val curr = lists[index] ?: continue
44+
if (minNode == null || curr.`val` < minNode.`val`) {
45+
minNode = curr
46+
minIndex = index
47+
}
48+
}
49+
prev.next = minNode ?: break
50+
prev = prev.next ?: throw RuntimeException()
51+
52+
lists[minIndex] = minNode.next
53+
}
54+
55+
return dummy.next
56+
}
57+
58+
/**
59+
* TC: O(lists.size * ListNode.size), SC: O(1)
60+
*/
61+
private fun mergeLists(lists: Array<ListNode?>): ListNode? {
62+
fun merge(node1: ListNode?, node2: ListNode?): ListNode? {
63+
val dummy = ListNode(-1)
64+
var prev = dummy
65+
var (n1, n2) = node1 to node2
66+
while (n1 != null && n2 != null) {
67+
if (n1.`val` < n2.`val`) {
68+
prev.next = n1
69+
n1 = n1.next
70+
} else {
71+
prev.next = n2
72+
n2 = n2.next
73+
}
74+
prev.next?.let { prev = it }
75+
}
76+
prev.next = n1 ?: n2
77+
return dummy.next
78+
}
79+
for (index in 1 until lists.size) {
80+
lists[0] = merge(lists[0], lists[index])
81+
}
82+
return lists[0]
83+
}
84+
85+
/**
86+
* TC: O(lists.size * ListNode.size), SC: O(lists.size)
87+
*/
88+
private fun mergeDivideAndConquer(lists: Array<ListNode?>): ListNode? {
89+
fun merge(node1: ListNode?, node2: ListNode?): ListNode? {
90+
val dummy = ListNode(-1)
91+
var prev = dummy
92+
var (n1, n2) = node1 to node2
93+
while (n1 != null && n2 != null) {
94+
if (n1.`val` < n2.`val`) {
95+
prev.next = n1
96+
n1 = n1.next
97+
} else {
98+
prev.next = n2
99+
n2 = n2.next
100+
}
101+
prev.next?.let { prev = it }
102+
}
103+
prev.next = n1 ?: n2
104+
return dummy.next
105+
}
106+
107+
fun divideAndConquer(lists: Array<ListNode?>, s: Int, e: Int): ListNode? {
108+
if (s > e) return null
109+
else if (s == e) return lists[s]
110+
111+
val mid = (s + e) / 2
112+
val left = divideAndConquer(lists, s, mid)
113+
val right = divideAndConquer(lists, mid + 1, e)
114+
return merge(left, right)
115+
}
116+
117+
return divideAndConquer(lists, 0, lists.size - 1)
118+
}
119+
120+
@Test
121+
fun `전달받은 노드들을 정렬하고 병합된 결과를 반환한다`() {
122+
mergeKLists(
123+
arrayOf(
124+
ListNode.of(1,4,5),
125+
ListNode.of(1,3,4),
126+
ListNode.of(2,6)
127+
)
128+
) shouldBe ListNode.of(1,1,2,3,4,4,5,6)
129+
}
130+
}
+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
6+
class `search-in-rotated-sorted-array` {
7+
8+
/**
9+
* O(log n)만큼의 시간만으로 해결해야 한다.
10+
* nums 배열은 정렬되어있지만 순환된 배열이므로 target 을 찾기 위한 일반적인 이분 탐색으로는 해결할 수 없다.
11+
* TC: O(log n), SC: O(1)
12+
*/
13+
fun search(nums: IntArray, target: Int): Int {
14+
var (low, high) = 0 to nums.size - 1
15+
16+
while (low + 1 < high) {
17+
val mid = (low + high) / 2
18+
19+
if (nums[mid] == target) {
20+
return mid
21+
}
22+
if (nums[low] <= nums[mid]) {
23+
if (target in nums[low] .. nums[mid]) {
24+
high = mid
25+
} else {
26+
low = mid
27+
}
28+
} else {
29+
if (target in nums[mid] .. nums[high]) {
30+
low = mid
31+
} else {
32+
high = mid
33+
}
34+
}
35+
}
36+
return when (target) {
37+
nums[low] -> low
38+
nums[high] -> high
39+
else -> -1
40+
}
41+
}
42+
43+
@Test
44+
fun `배열에서 타겟의 인덱스를 반환한다`() {
45+
search(intArrayOf(4,5,6,7,0,1,2), 0) shouldBe 4
46+
search(intArrayOf(4,5,6,7,0,1,2), 3) shouldBe -1
47+
search(intArrayOf(2,3,4,5,6,0,1), 1) shouldBe 6
48+
search(intArrayOf(1,2,3,4,5,6,7), 6) shouldBe 5
49+
}
50+
}

0 commit comments

Comments
 (0)