代码随想录 | 刷题-回溯算法4
491.递增子序列
题解说这里用数组做哈希,效率会更高 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29class Solution {
public:
vector<vector<int>> result;
void findSS(vector<int>& nums, vector<int> path, int left){
unordered_set<int> used; // 当前层去重
for(int i = left; i<nums.size();i++){
if(used.find(nums[i]) != used.end())continue;
if(path.empty()){
path.push_back(nums[i]);
used.insert(nums[i]);
findSS(nums, path, i+1);
path.pop_back();
}else if(!path.empty() && nums[i]>=path.back()){
// if(i>left && nums[i-1] == nums[i])continue; // 重复元素不一定相邻
path.push_back(nums[i]);
result.push_back(path);
used.insert(nums[i]);
findSS(nums, path, i+1);
path.pop_back();
}
}
return;
}
vector<vector<int>> findSubsequences(vector<int>& nums) {
vector<int> path;
findSS(nums, path, 0);
return result;
}
};
46.全排列
- 索引限制错误:
- 使用
left参数限制选择范围,导致只能生成索引递增的子序列而非全排列 - 例如输入
[1,2,3]时,代码只能生成[1,2,3],无法生成[2,1,3]等排列
- 使用
- 缺少元素使用状态跟踪:
- 排列需要从所有未使用元素中选择,而不仅仅是当前索引后的元素
- 没有记录哪些元素已被使用,导致:
- 无法重新选择左侧元素
- 无法避免重复使用同一元素
- 递归逻辑错误:
- 每次递归都从
i+1开始,使得路径只能向右扩展 - 排列需要任意顺序组合,需能回头选择左侧元素
- 每次递归都从
1 | class Solution { |
47.全排列 II
1 | class Solution { |
51. N皇后
问题分析:
列起始位置错误:
1
for(int i = l; i<n; i++) // 错误:每行都应从0开始尝试所有列
赋值操作符错误:
1
li[i] == 1; // 应该是 =,不是 ==
皇后位置检查逻辑错误:
- 检查时使用
continue导致死循环,应记录检查结果后设置皇后位置1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65class Solution {
public:
vector<vector<string>> result;
void solve(vector<vector<int>>& cur, int n, int row) {
if (row == n) {
vector<string> solution;
for (auto& line : cur) {
string s;
for (int p : line) {
s.push_back(p == 1 ? 'Q' : '.');
}
solution.push_back(s);
}
result.push_back(solution);
return;
}
for (int col = 0; col < n; col++) { // 每行都尝试所有列
bool valid = true;
// 检查正上方
for (int r = 0; r < row; r++) {
if (cur[r][col] == 1) {
valid = false;
break;
}
}
if (!valid) continue;
// 检查左上对角线
int r = row - 1, c = col - 1;
while (r >= 0 && c >= 0) {
if (cur[r][c] == 1) {
valid = false;
break;
}
r--;
c--;
}
if (!valid) continue;
// 检查右上对角线
r = row - 1;
c = col + 1;
while (r >= 0 && c < n) {
if (cur[r][c] == 1) {
valid = false;
break;
}
r--;
c++;
}
if (!valid) continue;
// 放置皇后
vector<int> new_row(n, 0);
new_row[col] = 1; // 正确赋值
cur.push_back(new_row);
// 递归下一行(列从0开始)
solve(cur, n, row + 1);
// 回溯
cur.pop_back();
}
}
vector<vector<string>> solveNQueens(int n) {
vector<vector<int>> cur;
solve(cur, n, 0); // 从第0行开始
return result;
}
};
- 检查时使用
牛客acm模式 REAL492 数独(leetcode37解数独)
按照回溯算法的思路解决即可 注意递归函数需要传引用
- 遍历每一行每一列的格子,如果需要填入数字,就遍历1-9中哪些数字符合要求
- 符合要求的数字需要在每行,每列和每3*3小格子都没出现过
- 如果符合要求,则沿着这个分支继续递归,如果返回一个符合要求的板子,那么回溯函数返回true
- 重置当前格子为0
- 最里层的递归函数何时返回true false呢?
- false是当遍历完1-9所有数字,都没有出现一个true分支的时候
- true是遍历完每一行每一列的格子,都没有出现false的时候
1 |
|