Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 4f06e7d

Browse files
update md files
1 parent e12416d commit 4f06e7d

27 files changed

+3263
-3
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# 17 : 电话号码的字母组合
2+
3+
## 📌题目详情
4+
5+
[leetcode-cn 题目地址](https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/)
6+
7+
📗Difficulty:**Medium**
8+
9+
🎯Tags:
10+
11+
+ [回溯](https://leetcode-cn.com/tag/backtracking/)
12+
13+
---
14+
15+
## 📃题目描述
16+
17+
给定一个仅包含数字 `2-9` 的字符串,返回所有它能表示的字母组合。
18+
19+
给出数字到字母的映射如下(与电话按键相同)。注意 `1` 不对应任何字母。
20+
21+
![字母映射](https://assets.ryantech.ltd/20201018201525.png)
22+
23+
24+
25+
**样例 1:**
26+
27+
```
28+
输入:"23"
29+
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
30+
```
31+
32+
33+
34+
- 尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。
35+
36+
37+
38+
****
39+
40+
## 🏹🎯解题思路
41+
42+
通过画出 递归树 ,可以看出此问题的一个 **全排列** 问题。是 [46. 全排列](https://leetcode-cn.com/problems/permutations/) 问题的修改版本,遍历的情况稍微复杂了一些些,仅此而已。
43+
44+
45+
46+
#### 代码实现
47+
48+
```java
49+
// 全排列问题
50+
public List<String> letterCombinations(String digits) {
51+
List<String> res = new ArrayList<>();
52+
53+
if (digits == null || digits.length() == 0) {
54+
return res;
55+
}
56+
57+
int len = digits.length();
58+
Deque<Character> path = new ArrayDeque<>();
59+
// 建立字母映射
60+
Map<Integer, char[]> map = new HashMap<>();
61+
map.put(2, new char[]{'a', 'b', 'c'});
62+
map.put(3, new char[]{'d', 'e', 'f'});
63+
map.put(4, new char[]{'g', 'h', 'i'});
64+
map.put(5, new char[]{'j', 'k', 'l'});
65+
map.put(6, new char[]{'m', 'n', 'o'});
66+
map.put(7, new char[]{'p', 'q', 'r', 's'});
67+
map.put(8, new char[]{'t', 'u', 'v'});
68+
map.put(9, new char[]{'w', 'x', 'y', 'z'});
69+
70+
dfs(digits, len, 0, map, path, res);
71+
72+
return res;
73+
}
74+
75+
private void dfs(String digits, int len, int depth, Map<Integer, char[]> map, Deque<Character> path, List<String> res) {
76+
// 递归结束的条件
77+
if (depth == len) {
78+
StringBuilder sb = new StringBuilder();
79+
for (char c : path) {
80+
sb.append(c);
81+
}
82+
res.add(sb.toString());
83+
return;
84+
}
85+
86+
char digit = digits.charAt(depth);
87+
char[] chars = map.get(Integer.parseInt(String.valueOf(digit)));
88+
// 全排列
89+
for (char aChar : chars) {
90+
path.addLast(aChar);
91+
dfs(digits, len, depth + 1, map, path, res); // 选取下一个字母
92+
path.removeLast();
93+
}
94+
}
95+
```
96+
97+
98+
99+
#### 复杂度分析
100+
101+
+ 时间复杂度:`O(3 ^ m * 4 ^ n)`
102+
+ 空间复杂度:`O(m + n)`
103+
104+
105+
106+
---
107+
108+
## 💡总结
109+
110+
111+
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# 216 : 组合总和 3
2+
3+
## 📌题目详情
4+
5+
[leetcode-cn 题目地址](https://leetcode-cn.com/problems/combination-sum-iii/)
6+
7+
📗Difficulty:**Medium**
8+
9+
🎯Tags:
10+
11+
+ [回溯](https://leetcode-cn.com/tag/backtracking/)
12+
13+
---
14+
15+
## 📃题目描述
16+
17+
找出所有相加之和为 `n``k` 个数的组合。组合中只允许含有 `1 - 9` 的正整数,并且每种组合中不存在重复的数字。
18+
19+
**说明:**
20+
21+
+ 所有数字都是正整数。
22+
+ 解集不能包含重复的组合。
23+
24+
25+
26+
**样例 1:**
27+
28+
```
29+
输入: k = 3, n = 7
30+
输出: [[1,2,4]]
31+
```
32+
33+
34+
35+
**样例 2:**
36+
37+
```
38+
输入: k = 3, n = 9
39+
输出: [[1,2,6], [1,3,5], [2,3,4]]
40+
```
41+
42+
43+
44+
****
45+
46+
## 🏹🎯解题思路
47+
48+
> [回溯 + 剪枝(Java)](https://leetcode-cn.com/problems/combination-sum-iii/solution/hui-su-jian-zhi-by-liweiwei1419/)
49+
50+
首先画出递归的树形图。
51+
52+
![树形图](https://assets.ryantech.ltd/20201018221151.png)
53+
54+
55+
56+
+ 尝试做减法,减到 `0` 就说明可能找到了一个符合题意的组合,但是题目对组合里元素的个数有限制,因此还需要对元素个数做判断;
57+
+ 如果减到负数,没有必要继续搜索下去;
58+
+ 由于结果集里的元素互不相同,因此下一层搜索的起点应该是上一层搜索的 `起点值 + 1`;
59+
+ 根据画出的递归树设计递归方法的参数。
60+
61+
62+
63+
64+
65+
#### 代码实现
66+
67+
```java
68+
public List<List<Integer>> combinationSum3(int k, int n) {
69+
List<List<Integer>> res = new ArrayList<>();
70+
71+
if (n <= 0 || k <= 0) {
72+
return res;
73+
}
74+
75+
int[] nums = new int[9];
76+
for (int i = 0; i < nums.length; i++) {
77+
nums[i] = i + 1;
78+
}
79+
80+
int len = nums.length;
81+
Deque<Integer> path = new ArrayDeque<>();
82+
dfs(nums, len, 0, n, k, path, res);
83+
84+
return res;
85+
}
86+
87+
private void dfs(int[] nums, int len, int begin, int n, int k, Deque<Integer> path, List<List<Integer>> res) {
88+
// 递归结束的条件
89+
if (n == 0 && path.size() == k) {
90+
res.add(new ArrayList<>(path));
91+
return;
92+
}
93+
94+
for (int i = begin; i < len; i++) {
95+
// 剪枝,如果下一个数字比 n 小,那么提前 break 搜索下一个数字
96+
if (n - nums[i] < 0) {
97+
break;
98+
}
99+
100+
path.addLast(nums[i]);
101+
dfs(nums, len, i + 1, n - nums[i], k, path, res); // 向后继续寻找
102+
path.removeLast();
103+
}
104+
}
105+
```
106+
107+
108+
109+
---
110+
111+
## 💡总结
112+
113+
114+
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# 377 : 组合总和4
2+
3+
## 📌题目详情
4+
5+
[leetcode-cn 题目地址](https://leetcode-cn.com/problems/combination-sum-iv/)
6+
7+
📗Difficulty:**Medium**
8+
9+
🎯Tags:
10+
11+
+ [回溯](https://leetcode-cn.com/tag/backtracking/)
12+
13+
---
14+
15+
## 📃题目描述
16+
17+
给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数。
18+
19+
20+
21+
**样例 1:**
22+
23+
```
24+
nums = [1, 2, 3]
25+
target = 4
26+
27+
所有可能的组合为:
28+
(1, 1, 1, 1)
29+
(1, 1, 2)
30+
(1, 2, 1)
31+
(1, 3)
32+
(2, 1, 1)
33+
(2, 2)
34+
(3, 1)
35+
36+
请注意,顺序不同的序列被视作不同的组合。
37+
38+
因此输出为 7。
39+
```
40+
41+
42+
43+
****
44+
45+
## 🏹🎯解题思路
46+
47+
参考前面的类似的几道组合的题目。给出这样的代码。
48+
49+
```java
50+
// DFS 剪枝
51+
// 无法解决题目,时间复杂度过高
52+
public List<List<Integer>> combinationSum4(int[] nums, int target) {
53+
List<List<Integer>> res = new ArrayList<>();
54+
55+
if (nums == null || nums.length == 0) {
56+
return res;
57+
}
58+
59+
Arrays.sort(nums);
60+
61+
if (nums[0] > target) {
62+
return res;
63+
}
64+
65+
int len = nums.length;
66+
Deque<Integer> path = new ArrayDeque<>();
67+
dfs(nums, len, target, path, res);
68+
69+
return res;
70+
}
71+
72+
private void dfs(int[] nums, int len, int target, Deque<Integer> path, List<List<Integer>> res) {
73+
if (target == 0) {
74+
res.add(new ArrayList<>(path));
75+
return;
76+
}
77+
78+
for (int i = 0; i < len; i++) {
79+
if (target - nums[i] < 0) {
80+
break;
81+
}
82+
83+
path.addLast(nums[i]);
84+
dfs(nums, len, target - nums[i], path, res);
85+
path.removeLast();
86+
}
87+
}
88+
```
89+
90+
虽然能过掉样例,但是遇到比较大的 `target` ,回溯需要的时间和空间就很高了,超出了运行的时间限制。
91+
92+
93+
94+
### 动态规划
95+
96+
> [动态规划](https://leetcode-cn.com/problems/combination-sum-iv/solution/dong-tai-gui-hua-python-dai-ma-by-liweiwei1419/)
97+
98+
首先给出递归的树形图。
99+
100+
![树形图](https://assets.ryantech.ltd/20201018222059.png)
101+
102+
103+
104+
![对动态规划的过程](https://assets.ryantech.ltd/20201018222121.png)
105+
106+
107+
108+
"动态规划"的两个步骤是思考"状态"以及"状态转移方程"。
109+
110+
1. 状态
111+
+ 对于"状态",我们首先思考能不能就用问题当中问的方式定义状态,上面递归树都画出来了。当然就用问题问的方式。
112+
+ `dp[i]` :对于给定的由正整数组成且不存在重复数字的数组,和为 `i` 的组合的个数。
113+
+ 思考输出什么?因为状态就是问题当中问的方式而定义的,因此输出就是最后一个状态 `dp[n]`
114+
2. 状态转移方程
115+
+ 由上面的树形图,可以很容易地写出状态转移方程:
116+
+ `dp[i] = sum{dp[i - num] for num in nums and if i >= num}`
117+
+ 注意:在 `0` 这一点,我们定义 `dp[0] = 1 `的,它表示如果 `nums` 里有一个数恰好等于 `target`,它单独成为 `1` 种可能。
118+
119+
120+
121+
#### 代码实现
122+
123+
```java
124+
// 动态规划
125+
public int combinationSum4(int[] nums, int target) {
126+
int[] dp = new int[target + 1];
127+
// 这个值被其它状态参考,设置为 1 是合理的
128+
dp[0] = 1;
129+
130+
for (int i = 1; i <= target; i++) {
131+
for (int num : nums) {
132+
if (num <= i) {
133+
dp[i] += dp[i - num];
134+
}
135+
}
136+
}
137+
return dp[target];
138+
}
139+
```
140+
141+
142+
143+
---
144+
145+
## 💡总结
146+
147+
148+

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /