-
Notifications
You must be signed in to change notification settings - Fork 120
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
[정현준] 11주차 #549
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,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개의 자식 노드의 합을 전역 변수로 갱신한다. | ||
|
||
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 | ||
} | ||
} |
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,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 | ||
} | ||
} |
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,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)) | ||
} | ||
} |
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,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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
} | ||
} |
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,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) | ||
} | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
사소한 내용이긴 한데,
// 부모 노드와 2개의 자식 노드의 합을 전역 변수로 갱신한다.
라는 코멘트가 직관적으로 와닿진 않았습니다There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
어떻게 설명하면 직관적일까요??
조부모 노드와 연결된 간선을 제거한 노드의 합을 갱신한다
라고 필요한 이유를 설명하는 것이 괜찮을까요??There was a problem hiding this comment.
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을 갱신한다
와 같은 가이드를 해주는게 더 좋다고 생각했는데요, 이건 전적으로 제 개인적인 의견이라 사실 스킵하셔도 되는 부분입니다 :)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제가 추후에 해결한 문제를 볼 때 도움이 되도록 주석을 작성하려 하는데 다른 분도 잘 이해할 수 있다면 저도 금방 이해할 수 있을 거라고 생각되어서 다시 여쭤봤습니다 ㅎㅎ
뭔가 말씀을 들으니까 주석을 작성할 때 너무 세부적인 내용을 적은 것 같네요. 코드를 읽었을 때 알만한 정보보다는 윤곽을 제공하는 방향으로 작성해봐야겠네요 감사합니다~