Skip to content

Commit 943d558

Browse files
committed
Add solution 823
1 parent 8bb84f2 commit 943d558

26 files changed

+1029
-662
lines changed

README.md

Lines changed: 465 additions & 460 deletions
Large diffs are not rendered by default.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package leetcode
2+
3+
import (
4+
"sort"
5+
)
6+
7+
const mod = 1e9 + 7
8+
9+
// 解法一 DFS
10+
func numFactoredBinaryTrees(arr []int) int {
11+
sort.Ints(arr)
12+
numDict := map[int]bool{}
13+
for _, num := range arr {
14+
numDict[num] = true
15+
}
16+
dict, res := make(map[int][][2]int), 0
17+
for i, num := range arr {
18+
for j := i; j < len(arr) && num*arr[j] <= arr[len(arr)-1]; j++ {
19+
tmp := num * arr[j]
20+
if !numDict[tmp] {
21+
continue
22+
}
23+
dict[tmp] = append(dict[tmp], [2]int{num, arr[j]})
24+
}
25+
}
26+
cache := make(map[int]int)
27+
for _, num := range arr {
28+
res = (res + dfs(num, dict, cache)) % mod
29+
}
30+
return res
31+
}
32+
33+
func dfs(num int, dict map[int][][2]int, cache map[int]int) int {
34+
if val, ok := cache[num]; ok {
35+
return val
36+
}
37+
res := 1
38+
for _, tuple := range dict[num] {
39+
a, b := tuple[0], tuple[1]
40+
x, y := dfs(a, dict, cache), dfs(b, dict, cache)
41+
tmp := x * y
42+
if a != b {
43+
tmp *= 2
44+
}
45+
res = (res + tmp) % mod
46+
}
47+
cache[num] = res
48+
return res
49+
}
50+
51+
// 解法二 DP
52+
func numFactoredBinaryTrees1(arr []int) int {
53+
dp := make(map[int]int)
54+
sort.Ints(arr)
55+
for i, curNum := range arr {
56+
for j := 0; j < i; j++ {
57+
factor := arr[j]
58+
quotient, remainder := curNum/factor, curNum%factor
59+
if remainder == 0 {
60+
dp[curNum] += dp[factor] * dp[quotient]
61+
}
62+
}
63+
dp[curNum]++
64+
}
65+
totalCount := 0
66+
for _, count := range dp {
67+
totalCount += count
68+
}
69+
return totalCount % mod
70+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package leetcode
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
)
7+
8+
type question823 struct {
9+
para823
10+
ans823
11+
}
12+
13+
// para 是参数
14+
// one 代表第一个参数
15+
type para823 struct {
16+
arr []int
17+
}
18+
19+
// ans 是答案
20+
// one 代表第一个答案
21+
type ans823 struct {
22+
one int
23+
}
24+
25+
func Test_Problem823(t *testing.T) {
26+
27+
qs := []question823{
28+
29+
{
30+
para823{[]int{2, 4}},
31+
ans823{3},
32+
},
33+
34+
{
35+
para823{[]int{2, 4, 5, 10}},
36+
ans823{7},
37+
},
38+
}
39+
40+
fmt.Printf("------------------------Leetcode Problem 823------------------------\n")
41+
42+
for _, q := range qs {
43+
_, p := q.ans823, q.para823
44+
fmt.Printf("【input】:%v 【output】:%v\n", p, numFactoredBinaryTrees(p.arr))
45+
}
46+
fmt.Printf("\n\n\n")
47+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# [823. Binary Trees With Factors](https://leetcode.com/problems/binary-trees-with-factors/)
2+
3+
4+
## 题目
5+
6+
Given an array of unique integers, `arr`, where each integer `arr[i]` is strictly greater than `1`.
7+
8+
We make a binary tree using these integers, and each number may be used for any number of times. Each non-leaf node's value should be equal to the product of the values of its children.
9+
10+
Return *the number of binary trees we can make*. The answer may be too large so return the answer **modulo** `109 + 7`.
11+
12+
**Example 1:**
13+
14+
```
15+
Input: arr = [2,4]
16+
Output: 3
17+
Explanation: We can make these trees: [2], [4], [4, 2, 2]
18+
```
19+
20+
**Example 2:**
21+
22+
```
23+
Input: arr = [2,4,5,10]
24+
Output: 7
25+
Explanation: We can make these trees: [2], [4], [5], [10], [4, 2, 2], [10, 2, 5], [10, 5, 2].
26+
```
27+
28+
**Constraints:**
29+
30+
- `1 <= arr.length <= 1000`
31+
- `2 <= arr[i] <= 10^9`
32+
33+
## 题目大意
34+
35+
给出一个含有不重复整数元素的数组,每个整数均大于 1。我们用这些整数来构建二叉树,每个整数可以使用任意次数。其中:每个非叶结点的值应等于它的两个子结点的值的乘积。满足条件的二叉树一共有多少个?返回的结果应模除 10 * 9 + 7。
36+
37+
## 解题思路
38+
39+
- 首先想到的是暴力解法,先排序,然后遍历所有节点,枚举两两乘积为第三个节点值的组合。然后枚举这些组合并构成树。这里计数的时候要注意,左右孩子如果不是对称的,左右子树相互对调又是一组解。但是这个方法超时了。原因是,暴力枚举了很多次重复的节点和组合。优化这里的方法就是把已经计算过的节点放入 `map` 中。这里有 2 层 `map`,第一层 `map` 记忆化的是两两乘积的组合,将父亲节点作为 `key`,左右 2 个孩子作为 `value`。第二层 `map` 记忆化的是以 `root` 为根节点此时二叉树的种类数,`key``root``value` 存的是种类数。这样优化以后,DFS 暴力解法可以 runtime beats 100%。
40+
- 另外一种解法是 DP。定义 `dp[i]` 代表以 `i` 为根节点的树的种类数。dp[i] 初始都是 1,因为所有节点自身可以形成为自身单个节点为 `root` 的树。同样需要先排序。状态转移方程是:
41+
42+
$$dp[i] = \sum_{j<i, k<i}^{}dp[j] * dp[k], j * k = i$$
43+
44+
最后将 `dp[]` 数组中所有结果累加取模即为最终结果,时间复杂度 O(n^2),空间复杂度 O(n)。
45+
46+
## 代码
47+
48+
```go
49+
package leetcode
50+
51+
import (
52+
"sort"
53+
)
54+
55+
const mod = 1e9 + 7
56+
57+
// 解法一 DFS
58+
func numFactoredBinaryTrees(arr []int) int {
59+
sort.Ints(arr)
60+
numDict := map[int]bool{}
61+
for _, num := range arr {
62+
numDict[num] = true
63+
}
64+
dict, res := make(map[int][][2]int), 0
65+
for i, num := range arr {
66+
for j := i; j < len(arr) && num*arr[j] <= arr[len(arr)-1]; j++ {
67+
tmp := num * arr[j]
68+
if !numDict[tmp] {
69+
continue
70+
}
71+
dict[tmp] = append(dict[tmp], [2]int{num, arr[j]})
72+
}
73+
}
74+
cache := make(map[int]int)
75+
for _, num := range arr {
76+
res = (res + dfs(num, dict, cache)) % mod
77+
}
78+
return res
79+
}
80+
81+
func dfs(num int, dict map[int][][2]int, cache map[int]int) int {
82+
if val, ok := cache[num]; ok {
83+
return val
84+
}
85+
res := 1
86+
for _, tuple := range dict[num] {
87+
a, b := tuple[0], tuple[1]
88+
x, y := dfs(a, dict, cache), dfs(b, dict, cache)
89+
tmp := x * y
90+
if a != b {
91+
tmp *= 2
92+
}
93+
res = (res + tmp) % mod
94+
}
95+
cache[num] = res
96+
return res
97+
}
98+
99+
// 解法二 DP
100+
func numFactoredBinaryTrees1(arr []int) int {
101+
dp := make(map[int]int)
102+
sort.Ints(arr)
103+
for i, curNum := range arr {
104+
for j := 0; j < i; j++ {
105+
factor := arr[j]
106+
quotient, remainder := curNum/factor, curNum%factor
107+
if remainder == 0 {
108+
dp[curNum] += dp[factor] * dp[quotient]
109+
}
110+
}
111+
dp[curNum]++
112+
}
113+
totalCount := 0
114+
for _, count := range dp {
115+
totalCount += count
116+
}
117+
return totalCount % mod
118+
}
119+
```

website/content/ChapterFour/0800~0899/0821.Shortest-Distance-to-a-Character.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,5 @@ func min(a, b int) int {
7979
----------------------------------------------
8080
<div style="display: flex;justify-content: space-between;align-items: center;">
8181
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0800~0899/0820.Short-Encoding-of-Words/">⬅️上一页</a></p>
82-
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0800~0899/0826.Most-Profit-Assigning-Work/">下一页➡️</a></p>
82+
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0800~0899/0823.Binary-Trees-With-Factors/">下一页➡️</a></p>
8383
</div>
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# [823. Binary Trees With Factors](https://leetcode.com/problems/binary-trees-with-factors/)
2+
3+
4+
## 题目
5+
6+
Given an array of unique integers, `arr`, where each integer `arr[i]` is strictly greater than `1`.
7+
8+
We make a binary tree using these integers, and each number may be used for any number of times. Each non-leaf node's value should be equal to the product of the values of its children.
9+
10+
Return *the number of binary trees we can make*. The answer may be too large so return the answer **modulo** `109 + 7`.
11+
12+
**Example 1:**
13+
14+
```
15+
Input: arr = [2,4]
16+
Output: 3
17+
Explanation: We can make these trees: [2], [4], [4, 2, 2]
18+
```
19+
20+
**Example 2:**
21+
22+
```
23+
Input: arr = [2,4,5,10]
24+
Output: 7
25+
Explanation: We can make these trees: [2], [4], [5], [10], [4, 2, 2], [10, 2, 5], [10, 5, 2].
26+
```
27+
28+
**Constraints:**
29+
30+
- `1 <= arr.length <= 1000`
31+
- `2 <= arr[i] <= 10^9`
32+
33+
## 题目大意
34+
35+
给出一个含有不重复整数元素的数组,每个整数均大于 1。我们用这些整数来构建二叉树,每个整数可以使用任意次数。其中:每个非叶结点的值应等于它的两个子结点的值的乘积。满足条件的二叉树一共有多少个?返回的结果应模除 10 * 9 + 7。
36+
37+
## 解题思路
38+
39+
- 首先想到的是暴力解法,先排序,然后遍历所有节点,枚举两两乘积为第三个节点值的组合。然后枚举这些组合并构成树。这里计数的时候要注意,左右孩子如果不是对称的,左右子树相互对调又是一组解。但是这个方法超时了。原因是,暴力枚举了很多次重复的节点和组合。优化这里的方法就是把已经计算过的节点放入 `map` 中。这里有 2 层 `map`,第一层 `map` 记忆化的是两两乘积的组合,将父亲节点作为 `key`,左右 2 个孩子作为 `value`。第二层 `map` 记忆化的是以 `root` 为根节点此时二叉树的种类数,`key``root``value` 存的是种类数。这样优化以后,DFS 暴力解法可以 runtime beats 100%。
40+
- 另外一种解法是 DP。定义 `dp[i]` 代表以 `i` 为根节点的树的种类数。dp[i] 初始都是 1,因为所有节点自身可以形成为自身单个节点为 `root` 的树。同样需要先排序。状态转移方程是:
41+
42+
$$dp[i] = \sum_{j<i, k<i}^{}dp[j] * dp[k], j * k = i$$
43+
44+
最后将 `dp[]` 数组中所有结果累加取模即为最终结果,时间复杂度 O(n^2),空间复杂度 O(n)。
45+
46+
## 代码
47+
48+
```go
49+
package leetcode
50+
51+
import (
52+
"sort"
53+
)
54+
55+
const mod = 1e9 + 7
56+
57+
// 解法一 DFS
58+
func numFactoredBinaryTrees(arr []int) int {
59+
sort.Ints(arr)
60+
numDict := map[int]bool{}
61+
for _, num := range arr {
62+
numDict[num] = true
63+
}
64+
dict, res := make(map[int][][2]int), 0
65+
for i, num := range arr {
66+
for j := i; j < len(arr) && num*arr[j] <= arr[len(arr)-1]; j++ {
67+
tmp := num * arr[j]
68+
if !numDict[tmp] {
69+
continue
70+
}
71+
dict[tmp] = append(dict[tmp], [2]int{num, arr[j]})
72+
}
73+
}
74+
cache := make(map[int]int)
75+
for _, num := range arr {
76+
res = (res + dfs(num, dict, cache)) % mod
77+
}
78+
return res
79+
}
80+
81+
func dfs(num int, dict map[int][][2]int, cache map[int]int) int {
82+
if val, ok := cache[num]; ok {
83+
return val
84+
}
85+
res := 1
86+
for _, tuple := range dict[num] {
87+
a, b := tuple[0], tuple[1]
88+
x, y := dfs(a, dict, cache), dfs(b, dict, cache)
89+
tmp := x * y
90+
if a != b {
91+
tmp *= 2
92+
}
93+
res = (res + tmp) % mod
94+
}
95+
cache[num] = res
96+
return res
97+
}
98+
99+
// 解法二 DP
100+
func numFactoredBinaryTrees1(arr []int) int {
101+
dp := make(map[int]int)
102+
sort.Ints(arr)
103+
for i, curNum := range arr {
104+
for j := 0; j < i; j++ {
105+
factor := arr[j]
106+
quotient, remainder := curNum/factor, curNum%factor
107+
if remainder == 0 {
108+
dp[curNum] += dp[factor] * dp[quotient]
109+
}
110+
}
111+
dp[curNum]++
112+
}
113+
totalCount := 0
114+
for _, count := range dp {
115+
totalCount += count
116+
}
117+
return totalCount % mod
118+
}
119+
```
120+
121+
122+
----------------------------------------------
123+
<div style="display: flex;justify-content: space-between;align-items: center;">
124+
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0800~0899/0821.Shortest-Distance-to-a-Character/">⬅️上一页</a></p>
125+
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0800~0899/0826.Most-Profit-Assigning-Work/">下一页➡️</a></p>
126+
</div>

website/content/ChapterFour/0800~0899/0826.Most-Profit-Assigning-Work.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,6 @@ func maxProfitAssignment(difficulty []int, profit []int, worker []int) int {
109109

110110
----------------------------------------------
111111
<div style="display: flex;justify-content: space-between;align-items: center;">
112-
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0800~0899/0821.Shortest-Distance-to-a-Character/">⬅️上一页</a></p>
112+
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0800~0899/0823.Binary-Trees-With-Factors/">⬅️上一页</a></p>
113113
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0800~0899/0828.Count-Unique-Characters-of-All-Substrings-of-a-Given-String/">下一页➡️</a></p>
114114
</div>

0 commit comments

Comments
 (0)