Skip to content

Commit fa13157

Browse files
committed
Add new binary tree problems
1 parent 14bea44 commit fa13157

27 files changed

+1240
-70
lines changed

leetcode/112.path-sum.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,6 @@ private fun dfs(root: TreeNode?, sum: Int) {
7171
```
7272

7373
* **Time Complexity**: `O(n)`.
74-
* **Space Complexity**: `O(n)`.
74+
* **Space Complexity**: `O(n)`.
75+
76+
> 只需要用给定和target减去节点值,最终结束条件判断target==0即可
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# [129. Sum Root to Leaf Numbers](https://leetcode.com/problems/sum-root-to-leaf-numbers/description/)
2+
3+
# Test Cases
4+
### Normal Cases
5+
```
6+
Input:
7+
1
8+
/ \
9+
2 3
10+
11+
Output: 12 + 13 = 25
12+
```
13+
### Edge / Corner Cases
14+
* Not full or complete binary tree
15+
```
16+
Input:
17+
2
18+
/ \
19+
3 4
20+
/ \
21+
5 7
22+
/
23+
1
24+
Output: 235 + 2371 + 24 = 2630
25+
```
26+
27+
## DFS
28+
For `2 -> 3 -> 5`, we traverse to build the number `235`:
29+
* Start from `0`.
30+
* At `2`, the number will become `0 * 10 + 2` -> `2`.
31+
* At `3`, the number will become `2 * 10 + 3` -> `23`.
32+
* At `5`, the number will become `23 * 10 + 5` -> `235`. And it's a leaf node, so we sum it.
33+
34+
![](https://assets.leetcode-cn.com/solution-static/129/fig1.png)
35+
> Source: https://leetcode.cn/problems/sum-root-to-leaf-numbers/solutions/464666/qiu-gen-dao-xie-zi-jie-dian-shu-zi-zhi-he-by-leetc/
36+
37+
Steps by steps:
38+
![](../media/129.sum-root-to-leaf-numbers-1.png)
39+
![](../media/129.sum-root-to-leaf-numbers-2.png)
40+
![](../media/129.sum-root-to-leaf-numbers-3.png)
41+
![](../media/129.sum-root-to-leaf-numbers-4.png)
42+
```kotlin
43+
fun sumNumbers(root: TreeNode?): Int {
44+
return dfs(root, 0)
45+
}
46+
47+
private fun dfs(root: TreeNode?, num: Int): Int {
48+
if (root == null) return 0
49+
var newNum = num * 10 + root.`val`
50+
51+
if (root.left == null && root.right == null) {
52+
return newNum
53+
}
54+
55+
val left = dfs(root.left, newNum)
56+
val right = dfs(root.right, newNum)
57+
return left + right
58+
}
59+
```
60+
61+
* **Time Complexity:** `O(n)`
62+
* **Time Complexity:** `O(h)`, where `h` is the height of the tree.
63+
64+
## Backtracking
65+
```kotlin
66+
private var sum = 0
67+
fun sumNumbers(root: TreeNode?): Int {
68+
dfs(root, ArrayDeque<Int>())
69+
return sum
70+
}
71+
72+
private fun dfs(root: TreeNode?, numbers: ArrayDeque<Int>) {
73+
if (root == null) return
74+
75+
numbers.addLast(root.`val`)
76+
if (root.left == null && root.right == null) {
77+
sum += numbers.toInt()
78+
numbers.removeLast()
79+
return
80+
}
81+
dfs(root.left, numbers)
82+
dfs(root.right, numbers)
83+
numbers.removeLast()
84+
}
85+
86+
private fun ArrayDeque<Int>.toInt(): Int {
87+
var num = 0
88+
for (i in 0 until this.size) {
89+
num = num * 10 + this[i]
90+
}
91+
return num
92+
}
93+
```
94+
95+
* **Time Complexity:** `O(n)`
96+
* **Time Complexity:** `O(n)`
97+
98+
## BFS
99+
For every node, we enqueue the current number and the node to the queue. If the node is a leaf node, we sum the number.
100+
101+
* For `2 -> 3 -> 5`, we traverse to build the number `235`:
102+
* We enqueue `(2 to 0)`.
103+
* At `2`, the number will become `0 * 10 + 2` -> `2`. We enqueue `(3 to 2)`.
104+
* At `3`, the number will become `2 * 10 + 3` -> `23`. We enqueue `(5 to 23)`.
105+
* At `5`, the number will become `23 * 10 + 5` -> `235`. And it's a leaf node, so we sum it.
106+
107+
```kotlin
108+
fun sumNumbers(root: TreeNode?): Int {
109+
if (root == null) return 0
110+
var totalSum = 0
111+
val queue = ArrayDeque<Pair<TreeNode, Int>>()
112+
queue.addLast(root to 0)
113+
while (queue.isNotEmpty()) {
114+
val pair = queue.removeFirst()
115+
val node = pair.first
116+
val sum = pair.second
117+
118+
val newSum = sum * 10 + node.`val`
119+
if (node.left == null && node.right == null) {
120+
totalSum += newSum
121+
continue
122+
}
123+
124+
if (node.left != null) {
125+
queue.addLast(node.left to newSum)
126+
}
127+
128+
if (node.right != null) {
129+
queue.addLast(node.right to newSum)
130+
}
131+
}
132+
return totalSum
133+
}
134+
```
135+
136+
* **Time Complexity:** `O(n)`
137+
* **Time Complexity:** `O(n)`, where `n` is the number of nodes in the tree.
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# [1339. Maximum Product of Splitted Binary Tree](https://leetcode.com/problems/maximum-product-of-splitted-binary-tree/description/)
2+
3+
## Postorder
4+
For a root node, how can we split into two subtrees to get the product of the sums of the subtrees?
5+
```js
6+
2
7+
/ \
8+
3 4
9+
10+
// Can split into two cases
11+
2 2
12+
\ or /
13+
3 4 3 4
14+
15+
= 3 * 6 or 5 * 4
16+
```
17+
If we split the left child, for example, then the product will be `3 * (2 + 4)`, which is `the sum of the left subtree` x `total sum - the left subtree`. (The same for the right child)
18+
19+
So for any root node, we can calculate the left subtree sum and the right subtree sum, and then
20+
* Split left = `sum(left) * (total sum - sum(left))`
21+
```js
22+
root
23+
\
24+
sum(left) sum(right)
25+
```
26+
* Split right = `(total sum - sum(right)) * sum(right)`
27+
```js
28+
root
29+
/
30+
sum(left) sum(right)
31+
```
32+
33+
We can use postorder to calculate the sum of the subtree and the total sum of the tree. Then we can calculate the product of the splitted tree for each node and update the maximum product.
34+
35+
```kotlin
36+
private val mod = 1000000000L + 7
37+
private var result = 0L
38+
private var total = 0L
39+
40+
fun maxProduct(root: TreeNode?): Int {
41+
total = sum(root)
42+
sum(root)
43+
return (result % mod).toInt()
44+
}
45+
46+
private fun sum(root: TreeNode?): Long {
47+
if (root == null) return 0L
48+
// 5
49+
// / \
50+
// 2 3
51+
// total = 10
52+
val left = sum(root.left) // 2
53+
val right = sum(root.right) // 3
54+
55+
val leftSplit = left * (total - left) // 2 * (10 - 2)
56+
val rightSplit = (total - right) * right // (10 - 3) * 3
57+
result = maxOf(result, maxOf(leftSplit, rightSplit))
58+
59+
return root.`val`.toLong()+ left + right
60+
}
61+
```
62+
63+
Or the same idea, we can split at root node:
64+
```js
65+
parent
66+
\
67+
X // split here
68+
\
69+
root sum(root)
70+
/ \
71+
left right
72+
73+
```kotlin
74+
private val mod = 1000000000L + 7
75+
private var result = 0L
76+
private var total = 0L
77+
78+
fun maxProduct(root: TreeNode?): Int {
79+
total = sum(root)
80+
sum(root)
81+
return (result % mod).toInt()
82+
}
83+
84+
private fun sum(root: TreeNode?): Long {
85+
if (root == null) return 0L
86+
val currentSum = root.`val` + sum(root.left) + sum(root.right)
87+
result = maxOf(result, currentSum * (total - currentSum))
88+
return currentSum
89+
}
90+
```
91+
92+
* **Time Complexity:** `O(n)`
93+
* **Space Complexity:** `O(n)`
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# [1448. Count Good Nodes in Binary Tree](https://leetcode.com/problems/count-good-nodes-in-binary-tree/description/)
2+
3+
## DFS
4+
We just trace the current maximum value from the root to the current node.
5+
6+
```kotlin
7+
fun goodNodes(root: TreeNode?): Int {
8+
return dfs(root, root.`val`)
9+
}
10+
11+
private fun dfs(root: TreeNode?, max: Int): Int {
12+
if (root == null) return 0
13+
var count = if (root.`val` >= max) 1 else 0
14+
15+
val nextMax = maxOf(max, root.`val`)
16+
count += dfs(root.left, nextMax)
17+
count += dfs(root.right, nextMax)
18+
return count
19+
}
20+
```
21+
22+
* **Time Complexity:** `O(n)` where `n` is the number of nodes in the tree.
23+
* **Space Complexity:** `O(h)` where `h` is the height of the tree.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# [1530. Number of Good Leaf Nodes Pairs](https://leetcode.com/problems/number-of-good-leaf-nodes-pairs/description/)
2+
3+
## Postorder
4+
We have to keep track of the number of leaf nodes with a particular distance for each root node.
5+
6+
> TODO: Add explanation and Kotlin code.
7+
8+
```python
9+
class Solution:
10+
def countPairs(self, root: TreeNode, distance: int) -> int:
11+
self.result = 0
12+
13+
# Helper function to perform DFS
14+
def dfs(node):
15+
# If it's a null node, return an empty list (no leaves)
16+
if not node:
17+
return [0] * (distance + 1)
18+
19+
# If it's a leaf node, return distance 1 (leaf nodes are distance 1 from themselves)
20+
if not node.left and not node.right:
21+
leaf_distances = [0] * (distance + 1)
22+
leaf_distances[1] = 1 # Leaf is at distance 1
23+
return leaf_distances
24+
25+
# Perform DFS on left and right children
26+
left_distances = dfs(node.left)
27+
right_distances = dfs(node.right)
28+
29+
# Count good pairs (pairs whose distance is <= given distance)
30+
for l_dist in range(1, distance + 1):
31+
for r_dist in range(1, distance + 1):
32+
if l_dist + r_dist <= distance:
33+
self.result += left_distances[l_dist] * right_distances[r_dist]
34+
35+
# Prepare the distance array for the current node
36+
current_distances = [0] * (distance + 1)
37+
for i in range(1, distance):
38+
current_distances[i + 1] = left_distances[i] + right_distances[i]
39+
40+
return current_distances
41+
42+
# Start DFS from root
43+
dfs(root)
44+
return self.result
45+
```

0 commit comments

Comments
 (0)