Skip to content

Commit ddcff99

Browse files
committed
Update some notes of tree and graph problems
1 parent 3aa0008 commit ddcff99

18 files changed

+326
-129
lines changed

leetcode/1022.sum-of-root-to-leaf-binary-numbers.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## [1022. Sum of Root To Leaf Binary Numbers](https://leetcode.com/problems/sum-of-root-to-leaf-binary-numbers/)
1+
# [1022. Sum of Root To Leaf Binary Numbers](https://leetcode.com/problems/sum-of-root-to-leaf-binary-numbers/)
22
## Clarification Questions
33
* No, it's clear from problem description.
44

@@ -14,6 +14,42 @@ Output:
1414
Input:
1515
Output:
1616
```
17+
18+
## Paths
19+
We can get all paths from root to leaf, and then calculate the sum of binary numbers.
20+
```kotlin
21+
private val paths = mutableListOf<List<Int>>()
22+
23+
fun sumRootToLeaf(root: TreeNode?): Int {
24+
dfs(root, LinkedList<Int>())
25+
var answer = 0
26+
for (path in paths) {
27+
var sum = 0
28+
for (i in 0 until path.size) {
29+
// 1, 1, 0, 1
30+
// <- i
31+
sum += path[path.size - 1 - i] * Math.pow(2.0, i.toDouble()).toInt()
32+
}
33+
answer += sum
34+
}
35+
return answer
36+
}
37+
38+
private fun dfs(root: TreeNode?, path: LinkedList<Int>) {
39+
if (root == null) return
40+
41+
path.addLast(root.`val`)
42+
if (root.left == null && root.right == null) {
43+
paths.add(ArrayList(path))
44+
}
45+
46+
dfs(root.left, path)
47+
dfs(root.right, path)
48+
path.removeLast()
49+
}
50+
```
51+
52+
## Recursive
1753
```kotlin
1854
private var sum = 0
1955

leetcode/114.flatten-binary-tree-to-linked-list.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,18 @@ private fun preorder(root: TreeNode?, list: MutableList<TreeNode>) {
101101
* **Space Complexity**: `O(n)`.
102102

103103
## Preorder + Relink
104-
Use the template of preorder iterative traversal, and for every node, we have some extra steps:
104+
Use the template of preorder iterative traversal, and for every node, we relink the current node:
105105
1. We relink the right subtree after the right most node of left child.
106106
2. Move left child to right child.
107107
3. Clear left child.
108108
4. Go to next node.
109109

110+
![](../media/114.preorder+relink-1.png)
111+
![](../media/114.preorder+relink-2.png)
112+
![](../media/114.preorder+relink-3.png)
113+
110114
```kotlin
115+
// Follow the template of preorder traversal.
111116
fun flatten(root: TreeNode?): Unit {
112117
if (root == null) return
113118
val stack = Stack<TreeNode>()
@@ -119,12 +124,15 @@ fun flatten(root: TreeNode?): Unit {
119124

120125
if (right != null) stack.push(right)
121126
if (left != null) {
122-
// Start of extra steps
123-
val rightMost = subtreeLast(left)
124-
rightMost.right = right
127+
// Start of relink
128+
val rightMost: TreeNode? = left
129+
while (rightMost?.right != null) {
130+
rightMost = rightMost.right
131+
}
132+
rightMost?.right = right
125133
node.right = left
126134
node.left = null
127-
// End of extra steps
135+
// End of relink
128136

129137
stack.push(left)
130138
}
@@ -202,6 +210,7 @@ private fun subtreeLast(root: TreeNode?): TreeNode? {
202210
}
203211
```
204212

213+
### Dry Run (Postorder with Pointers)
205214
```kotlin
206215
1
207216
/ \

leetcode/116.populating-next-right-pointers-in-each-node.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Output:
2323
### Edge / Corner Cases
2424
* Empty or single node tree
2525

26+
## BFS
2627
```kotlin
2728
fun connect(root: Node?): Node? {
2829
if (root == null) return null
@@ -44,7 +45,32 @@ fun connect(root: Node?): Node? {
4445
* **Time Complexity**: `O(n)`.
4546
* **Space Complexity**: `O(n)`.
4647

47-
### Space Optimal
48+
49+
## Recursive
50+
```kotlin
51+
/**
52+
* 1
53+
* / \
54+
* 2 3
55+
* / \ / \
56+
* 4 5 6 7
57+
*/
58+
fun connect(root: Node?): Node? { // connect(1)
59+
if (root == null) return null
60+
dfs(root.left, root.right) // dfs(2, 3)
61+
return root
62+
}
63+
64+
fun dfs(left: Node?, right: Node?) { // dfs(2, 3)
65+
if (left == null || right == null) return
66+
left.next = right
67+
dfs(left.left, left.right) // 4 -> 5
68+
dfs(left.right, right.left) // 5 -> 6
69+
dfs(right.left, right.right) // 6 -> 7
70+
}
71+
```
72+
73+
## Space Optimal
4874
> TODO: `O(1)` space complexity.
4975
5076
> Take a look at another solution (using the `next` pointer just built): https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/solution/tian-chong-mei-ge-jie-dian-de-xia-yi-ge-you-ce-2-4/

leetcode/1325.delete-leaves-with-a-given-value.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Output: []
5959
```
6060

6161
## Recursive
62-
**Idea!!** Postorder, for problem statement `Note that once you delete a leaf node with value target, if its parent node becomes a leaf node and has the value target, it should also be deleted`, so we have to process the child first, when we've done, we check the root to see if that becomes the leaf and if to delete or not.
62+
For problem statement `Note that once you delete a leaf node with value target, if its parent node becomes a leaf node and has the value target, it should also be deleted`, so we have to process the children first, then we should use postorder traversal, as we finish traversing the children, we check the root to see if that becomes the leaf and if to delete or not.
6363

6464
```kotlin
6565
fun removeLeafNodes(root: TreeNode?, target: Int): TreeNode? {

leetcode/230.kth-smallest-element-in-a-bst.md

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Output:
2626
* The inorder traversal of BST is in the ascending order, so we can traverse the BST in inorder and increment the index until it reaches `k`.
2727

2828
```kotlin
29+
// Iterative
2930
fun kthSmallest(root: TreeNode?, k: Int): Int {
3031
if (root == null) -1
3132
val stack = Stack<TreeNode>()
@@ -43,6 +44,26 @@ fun kthSmallest(root: TreeNode?, k: Int): Int {
4344
}
4445
return -1
4546
}
47+
48+
// Recursive
49+
private var i = 0
50+
private var result = -1
51+
52+
fun kthSmallest(root: TreeNode?, k: Int): Int {
53+
inorder(root, k)
54+
return result
55+
}
56+
57+
private fun inorder(root: TreeNode?, k: Int) {
58+
if (root == null) return
59+
inorder(root.left, k)
60+
i++
61+
if (i == k) {
62+
result = root.`val`
63+
return
64+
}
65+
inorder(root.right, k)
66+
}
4667
```
4768

4869
* **Time Complexity**: `O(h + k)`, `h` for stack and k-th elements.
@@ -76,17 +97,29 @@ private fun count(root: TreeNode?): Int {
7697
}
7798
```
7899

79-
* **Time Complexity**: `O(h)`.
100+
* **Time Complexity**: `O(n^2)` if we don't precompute the count, or `O(n)` if we precompute and preserve the count of nodes in each node.
80101
* **Space Complexity**: `O(h)`.
81102

82-
> Why do we search for `k - leftCount - 1`-th element in the right subtree?
103+
Why do we search for `k - leftCount - 1`-th element in the right subtree?
83104
```js
84-
k = 7
85-
5 leftCount(5) = 4 < 7 - 1, so we search in right subtree.
86-
/ \
87-
3 8 kthSmallest(8, 7 - 4 - 1 = 2), we search the 2nd smallest in the subtree 8.
88-
/ \ /
89-
1 4 6
90-
\ \
91-
2 7
105+
k = 5
106+
leftCount(5) = 4
107+
108+
5 // start from 5 to search 5th smallest element
109+
/ \
110+
3 7
111+
/ \ / \
112+
2 4 6 8
113+
/
114+
1
115+
116+
k = 6
117+
118+
5 // start from 5 to search 6th smallest element
119+
/ \
120+
3 7 // start from 7 to search 6 - 4 - 1 = 1th smallest element
121+
/ \ / \
122+
2 4 6 8
123+
/
124+
1
92125
```

0 commit comments

Comments
 (0)