Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[정현준] 11주차 #549

Merged
merged 3 commits into from
Oct 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions binary-tree-maximum-path-sum/jdalma.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package leetcode_study

import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test
import kotlin.math.max

class `binary-tree-maximum-path-sum` {

/**
* TC: O(n), SC: O(log n)
*/
fun maxPathSum(root: TreeNode?): Int {
if (root == null) return 0
var max = root.`val` // 부모 노드와 2개의 자식 노드의 합을 전역 변수로 갱신한다.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사소한 내용이긴 한데, // 부모 노드와 2개의 자식 노드의 합을 전역 변수로 갱신한다. 라는 코멘트가 직관적으로 와닿진 않았습니다

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어떻게 설명하면 직관적일까요?? 조부모 노드와 연결된 간선을 제거한 노드의 합을 갱신한다 라고 필요한 이유를 설명하는 것이 괜찮을까요??

Copy link
Contributor

@obzva obzva Oct 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

우선 대안 없이 비평만 남긴 점 사과 드립니다
빠르게 리뷰 남겨드리고 싶은 생각에 너무 대충 코멘트만 달아버린 것 같네요..

제가 고민했던 포인트는 이거였습니다

  • 부모 노드와 2개의 자식 노드의 합을 전역 변수로 갱신한다는 정확하고 자세한 표현임
  • 하지만 dfs를 수행하며 maxPathSum을 갱신한다같은 표현과 비교했을 때, 한 번에 와닿지 않는다고 느꼈음 (과장된 비슷한 예시: 피자를 만든다 vs 밀가루 반죽 위에 토마토 페이스트를 바르고 치즈를 뿌리고 화덕에 굽는다)
  • 대신 dfs를 수행하며 maxPathSum을 갱신한다는 앞선 표현보다는 덜 자세하고 덜 엄밀한 표현임

자세한 알고리즘 전개는 함수를 보면 자연스레 알 수 있으니까 코멘트로는 dfs를 수행하며 maxPathSum을 갱신한다와 같은 가이드를 해주는게 더 좋다고 생각했는데요, 이건 전적으로 제 개인적인 의견이라 사실 스킵하셔도 되는 부분입니다 :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 추후에 해결한 문제를 볼 때 도움이 되도록 주석을 작성하려 하는데 다른 분도 잘 이해할 수 있다면 저도 금방 이해할 수 있을 거라고 생각되어서 다시 여쭤봤습니다 ㅎㅎ
뭔가 말씀을 들으니까 주석을 작성할 때 너무 세부적인 내용을 적은 것 같네요. 코드를 읽었을 때 알만한 정보보다는 윤곽을 제공하는 방향으로 작성해봐야겠네요 감사합니다~


fun dfs(node: TreeNode?): Int {
if (node == null) return 0

val left = max(dfs(node.left), 0)
val right = max(dfs(node.right), 0)

max = max(node.`val` + left + right, max)
return node.`val` + max(left, right) // 현재 노드와 2개의 자식 노드 중 최대의 값을 반환한다.
}

dfs(root)
return max
}

@Test
fun `이진 트리의 최대 경로 합을 반환한다`() {
maxPathSum(TreeNode.of(-10,9,20,null,null,15,7)) shouldBe 42
maxPathSum(TreeNode.of(1,9,20,null,null,15,7)) shouldBe 45
}
}
61 changes: 61 additions & 0 deletions graph-valid-tree/jdalma.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package leetcode_study

import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test

class `graph-valid-tree` {

/**
* TC: O(n), SC: O(n)
*/
fun validTree(nodeSize: Int, edges: Array<IntArray>): Boolean {
if (nodeSize - 1 != edges.size) {
return false
}

val visited = mutableSetOf<Int>()
val adj = List(nodeSize) { mutableListOf<Int>() }
for (e in edges) {
adj[e[0]].add(e[1])
adj[e[1]].add(e[0])
}

val queue = ArrayDeque<Int>().apply {
this.add(0)
}

while (queue.isNotEmpty()) {
val now = queue.removeFirst()
visited.add(now)
for (next in adj[now]) {
if (!visited.contains(next)) {
queue.add(next)
}
}
}

return nodeSize == visited.size
}

@Test
fun `노드가 트리의 조건을 만족하는지 여부를 반환한다`() {
validTree(5,
arrayOf(
intArrayOf(0,1),
intArrayOf(0,2),
intArrayOf(0,3),
intArrayOf(1,4)
)
) shouldBe true

validTree(5,
arrayOf(
intArrayOf(0,1),
intArrayOf(0,2),
intArrayOf(0,3),
intArrayOf(1,4),
intArrayOf(2,3),
)
) shouldBe false
}
}
59 changes: 59 additions & 0 deletions insert-interval/jdalma.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package leetcode_study

import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test
import kotlin.math.max
import kotlin.math.min

class `insert-interval` {

/**
* TC: O(n), SC: O(n)
*/
fun insert(intervals: Array<IntArray>, newInterval: IntArray): Array<IntArray> {
if (intervals.isEmpty()) return arrayOf(newInterval)
return justIterate(intervals, newInterval)
}

private fun justIterate(intervals: Array<IntArray>, newInterval: IntArray): Array<IntArray> {
val result = mutableListOf<IntArray>()
var new: IntArray? = newInterval

for (interval in intervals) {
if (new != null) {
if (new[1] < interval[0]) {
// new 범위가 더 앞에 있다
result.add(new)
result.add(interval)
new = null
} else if (new[0] > interval[1]) {
// new 범위가 더 뒤에 있어 다른 범위에 포함될 가능성이 있음
result.add(interval)
} else {
new[0] = min(new[0], interval[0])
new[1] = max(new[1], interval[1])
}
} else {
result.add(interval)
}
}
if (new != null) {
result.add(new)
}
return result.toTypedArray()
}

@Test
fun name() {
insert(
arrayOf(
intArrayOf(1,2),
intArrayOf(3,5),
intArrayOf(6,7),
intArrayOf(8,10),
intArrayOf(12,16)
),
intArrayOf(4,8)
) shouldBe arrayOf(intArrayOf(1,2), intArrayOf(3,10), intArrayOf(12,16))
}
}
22 changes: 22 additions & 0 deletions maximum-depth-of-binary-tree/jdalma.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package leetcode_study

import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test
import kotlin.math.max

class `maximum-depth-of-binary-tree` {

/**
* 이진 트리이기에 스택의 깊이가 차지하는 공간 복잡도는 log일 것
* TC: O(n), SC: O(log n)
*/
fun maxDepth(root: TreeNode?): Int {
return if (root == null) 0
else max(maxDepth(root.left) + 1, maxDepth(root.right) + 1)
}
Comment on lines +13 to +16
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

간결하고 좋네요!


@Test
fun `노드의 최대 깊이를 반환한다`() {
maxDepth(TreeNode.of(3,9,20,null,null,15,7)) shouldBe 3
}
}
98 changes: 98 additions & 0 deletions reorder-list/jdalma.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package leetcode_study

import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test

class `reorder-list` {

fun reorderList(root: ListNode?) {
if (root == null) return
usingTwoPointers(root)
}

/**
* TC: O(n), SC: O(n)
*/
private fun usingStack(input: ListNode) {
val tail = ArrayDeque<ListNode>().apply {
var node: ListNode? = input
while (node != null) {
this.add(node)
node = node.next
}
}

val dummy = ListNode(-1)
var node: ListNode = dummy
var head: ListNode = input
for (i in 0 until tail.size) {
if (i % 2 != 0) {
node.next = tail.removeLast()
} else {
node.next = head
head.next?.let { head = it }
}
node.next?.let { node = it }
}
node.next = null
}

/**
* TC: O(n), SC: O(1)
*/
private fun usingTwoPointers(input: ListNode) {
if (input.next == null) return

var slow: ListNode? = input
var fast: ListNode? = input
while (fast?.next != null && fast.next?.next != null) {
slow = slow?.next
fast = fast.next?.next
}

val firstHalfEnd = slow
var secondHalfStart = slow?.next
firstHalfEnd?.next = null

secondHalfStart = reverse(secondHalfStart)

var node1: ListNode? = input
var node2: ListNode? = secondHalfStart
while (node2 != null) {
val (next1, next2) = (node1?.next to node2?.next)
node1?.next = node2
node2.next = next1
node1 = next1
node2 = next2
}
}

private fun reverse(head: ListNode?): ListNode? {
var prev: ListNode? = null
var current = head
while (current != null) {
val next = current.next
current.next = prev
prev = current
current = next
}
return prev
}

@Test
fun `정렬된 리스트 노드의 참조 체이닝을 특정 순서로 재정렬한다`() {
val actual = ListNode.of(1,2,3,4,5).apply {
reorderList(this)
}
actual.`val` shouldBe 1
actual.next!!.`val` shouldBe 5
actual.next!!.next!!.`val` shouldBe 2
actual.next!!.next!!.next!!.`val` shouldBe 4
actual.next!!.next!!.next!!.next!!.`val` shouldBe 3
actual.next!!.next!!.next!!.next!!.next shouldBe null

ListNode.of(1,2,3,4,5,6).apply {
reorderList(this)
}
}
}