【LeetCode】14.回溯算法系列
总目录:
0.理论基础
0.1.要点
(0)如果解决一个问题有多个步骤,每一个步骤有多种方法,题目又要我们找出所有的方法,那肯定要穷举,可以使用回溯算法。
(1)回溯是递归的副产品,只要有回溯就会有递归。
(2)回溯法也可以叫做回溯搜索法,它是一种穷举搜索的方式,效率慢。一些问题只能通过穷举解决,可以通过适当的剪枝来加快效率。
(3)回溯法解决的问题都可以抽象为树形结构。因为回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度,都构成的树的深度。
0.2.问题类型
常见问题类型:
(1)组合问题:N个数里面按一定规则找出k个数的集合
(2)切割问题:一个字符串按一定规则有几种切割方式
(3)子集问题:一个N个数的集合里有多少符合条件的子集
(4)排列问题:N个数按一定规则全排列,有几种排列方式
(5)棋盘问题:N皇后,解数独等等
0.3.方法模板
for循环横向遍历,递归纵向遍历,回溯不断调整结果集
1 void backtracking(参数) { 2 if (终止条件) { 3 存放结果; 4 return; 5 }
6 7 for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) { 8 处理节点; 9 backtracking(路径,选择列表); // 递归 10 回溯,撤销处理结果 11 } 12 }
1.组合
1.1.问题描述
给定两个整数 n
和 k
,返回范围 [1, n]
中所有可能的 k
个数的组合。
你可以按任何顺序返回答案。
1.2.要点
树形结构,深度搜索
剪枝:数量超过k的跳过
1.3.代码实例

1 class Solution { 2 private: 3 vector<vector<int>> result; 4 vector<int> path; 5 void backtracking(int n, int k, int startIndex) { 6 if (path.size() == k) { 7 result.push_back(path); 8 return; 9 } 10 for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) { // 优化的地方 11 path.push_back(i); // 处理节点 12 backtracking(n, k, i + 1); 13 path.pop_back(); // 回溯,撤销处理的节点 14 } 15 } 16 public: 17 18 vector<vector<int>> combine(int n, int k) { 19 backtracking(n, k, 1); 20 return result; 21 } 22 };
2.组合总和3
2.1.问题描述
找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:
(1)只使用数字1到9;
(2)每个数字最多使用一次 ;
返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。
链接:https://leetcode.cn/problems/combination-sum-iii
2.2.要点
在普通组合问题上添加一个总和匹配的目标
剪枝:总和超过n、数量超过k的跳过
2.3.代码实例

1 class Solution { 2 private: 3 vector<vector<int>> ret; 4 vector<int> temp; 5 int curSum=0,targetSum=0,targetCnt=0; 6 void backTracking(int start){ 7 if(curSum>targetSum){ 8 return; 9 } 10 if(temp.size()==targetCnt){ 11 if(curSum==targetSum){ 12 ret.push_back(temp); 13 } 14 return; 15 } 16 17 for(int i=start;i<=(9-(targetCnt-temp.size())+1);i++){ 18 temp.push_back(i); 19 curSum+=i; 20 backTracking(i+1); 21 temp.pop_back(); 22 curSum-=i; 23 } 24 } 25 26 public: 27 vector<vector<int>> combinationSum3(int k, int n) { 28 targetSum=n; 29 targetCnt=k; 30 backTracking(1); 31 return ret; 32 } 33 };
3.电话号码的字母组合
3.1.问题描述
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
链接:https://leetcode.cn/problems/letter-combinations-of-a-phone-number
3.2.要点
全排列组合
3.3.代码实例

1 class Solution { 2 private: 3 vector<string> code{"","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"}; 4 vector<string> ret; 5 string srcStr; 6 int tgtLen=0; 7 string temp; 8 void backTracking(int start){ 9 if(temp.length()==tgtLen){ 10 ret.emplace_back(temp); 11 return; 12 } 13 14 //防止code访问越界 15 if(start>=tgtLen){ 16 return; 17 } 18 int codeId=srcStr[start]-'1'; 19 if(codeId<0||codeId>9){ 20 return; 21 } 22 string curCode=code[codeId]; 23 for(auto& c:curCode){ 24 temp+=c; 25 backTracking(start+1); 26 temp=temp.substr(0,temp.length()-1); 27 } 28 } 29 public: 30 vector<string> letterCombinations(string digits) { 31 srcStr=digits; 32 tgtLen=digits.length(); 33 if(tgtLen<=0){ 34 return ret; 35 } 36 37 backTracking(0); 38 return ret; 39 } 40 };
4.组合总和1
4.1.问题描述
给你一个 无重复元素 的正整数数组 candidates 和一个目标正整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。
链接:https://leetcode.cn/problems/combination-sum
4.2.要点
特点是允许原地踏步、不允许后退
4.3.代码实例

1 class Solution { 2 private: 3 vector<vector<int>> ret; 4 vector<int> temp; 5 int curSum=0; 6 int tgtSum=0; 7 int dataLen=0; 8 int stage=0; 9 void backTracking(vector<int>& candidates,int start){ 10 if(curSum>tgtSum){ 11 return; 12 } 13 if(curSum==tgtSum){ 14 ret.push_back(temp); 15 return; 16 } 17 for(int i=start;i<dataLen;i++){ 18 curSum+=candidates[i]; 19 temp.push_back(candidates[i]); 20 backTracking(candidates,i); 21 curSum-=candidates[i]; 22 temp.pop_back(); 23 } 24 } 25 26 public: 27 vector<vector<int>> combinationSum(vector<int>& candidates, int target) { 28 tgtSum=target; 29 dataLen=candidates.size(); 30 backTracking(candidates,0); 31 32 return ret; 33 } 34 };
5.组合总和2
5.1.问题描述
给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
链接:https://leetcode.cn/problems/combination-sum-ii
5.2.要点
重点要求:集合(数组candidates)有重复元素,但还不能有重复的组合.
为了跳过重复元素造成的重复组合,有固定的范式:
(1)排序;
(2)在循环中使用以下代码,也就是不允许在广度上重复、允许在深度上重复:
if(i>start&&candidates[i]==candidates[i-1]){ continue; }
5.3.代码实例

1 class Solution { 2 private: 3 vector<vector<int>> ret; 4 vector<int> temp; 5 int curSum=0; 6 int tgtSum=0; 7 int dataLen=0; 8 void backTracking(vector<int>& candidates,int start){ 9 if(curSum>tgtSum){ 10 return; 11 } 12 if(curSum==tgtSum){ 13 ret.push_back(temp); 14 return; 15 } 16 for(int i=start;i<dataLen;i++){ 17 if(i>start&&candidates[i]==candidates[i-1]){ 18 continue; 19 } 20 21 curSum+=candidates[i]; 22 temp.push_back(candidates[i]); 23 backTracking(candidates,i+1); 24 curSum-=candidates[i]; 25 temp.pop_back(); 26 } 27 } 28 29 public: 30 vector<vector<int>> combinationSum2(vector<int>& candidates, int target) { 31 tgtSum=target; 32 dataLen=candidates.size(); 33 sort(candidates.begin(),candidates.end()); 34 backTracking(candidates,0); 35 36 return ret; 37 } 38 };
6.分割回文串
6.1.问题描述
给你一个字符串 s
,请你将s
分割成一些子串,使每个子串都是 回文串 。返回 s
所有可能的分割方案。
回文串 是正着读和反着读都一样的字符串。
链接:https://leetcode.cn/problems/palindrome-partitioning/
6.2.要点
先画树状图,再依次解决以下几个问题:
(1)切割问题可以抽象为组合问题
(2)如何模拟那些切割线
(3)切割问题中递归如何终止
(4)在递归循环中如何截取子串
(5)如何判断回文
6.3.代码实例

1 class Solution { 2 private: 3 vector<vector<string>> result; 4 vector<string> path; // 放已经回文的子串 5 void backtracking (const string& s, int startIndex) { 6 // 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了 7 if (startIndex >= s.size()) { 8 result.push_back(path); 9 return; 10 } 11 for (int i = startIndex; i < s.size(); i++) { 12 //指定段不是回文 13 if (!isPalindrome(s, startIndex, i)){ 14 continue; 15 } 16 17 // 获取[startIndex,i]在s中的子串,回文串 18 string str = s.substr(startIndex, i - startIndex + 1); 19 path.push_back(str); 20 21 backtracking(s, i + 1); // 寻找i+1为起始位置的子串 22 path.pop_back(); // 回溯过程,弹出本次已经填在的子串 23 } 24 } 25 bool isPalindrome(const string& s, int start, int end) { 26 for (int i = start, j = end; i < j; i++, j--) { 27 if (s[i] != s[j]) { 28 return false; 29 } 30 } 31 return true; 32 } 33 public: 34 vector<vector<string>> partition(string s) { 35 result.clear(); 36 path.clear(); 37 backtracking(s, 0); 38 return result; 39 } 40 };
7.复原IP地址
7.1.问题描述
有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。
例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效 IP 地址。
给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
链接:https://leetcode.cn/problems/restore-ip-addresses
7.2.要点
切割问题,切一段判断一段
本问题主要是判断的规则较细
7.3.代码实例

1 #include <string> 2 using namespace std; 3 class Solution { 4 private: 5 vector<string> ret; 6 string temp; 7 int pointCnt=0; 8 void backTracking(string& s,int startIndex){ 9 if(startIndex>=s.length()){ 10 if(pointCnt<4){ 11 return; 12 } 13 temp.pop_back();//去掉最后一个句号 14 ret.push_back(temp); 15 temp.push_back('.'); 16 return; 17 } 18 19 for(int i=startIndex;i<s.length();i++){ 20 if(pointCnt==3){ 21 i=s.length()-1; 22 } 23 if(!isPartOfIp(s,startIndex,i)){ 24 continue; 25 } 26 27 temp+=s.substr(startIndex,(i-startIndex+1)); 28 temp+='.'; 29 pointCnt++; 30 31 backTracking(s,i+1); 32 33 temp.pop_back(); 34 pointCnt--; 35 while(temp.length()>0&&temp[temp.length()-1]!='.'){ 36 temp.pop_back(); 37 } 38 } 39 40 } 41 bool isPartOfIp(string s,int start,int end){ 42 //检查数据长度在1~3之间 43 if((end-start+1)<=0||(end-start+1)>3){ 44 return false; 45 } 46 //检查非法字符 47 for(int i=start;i<=end;i++){ 48 if(s[i]<'0'||s[i]>'9'){ 49 return false; 50 } 51 } 52 //是否超限 53 if(end>start&&s[start]=='0'){ 54 return false; 55 } 56 int num=atoi(s.substr(start,(end-start+1)).c_str()); 57 if(num>255){ 58 return false; 59 } 60 61 return true; 62 } 63 public: 64 vector<string> restoreIpAddresses(string s) { 65 if (s.size() < 4 || s.size() > 12) return ret; // 算是剪枝了 66 backTracking(s,0); 67 return ret; 68 } 69 };
8.子集1
8.1.问题描述
给你一个整数数组 nums
,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
链接:https://leetcode.cn/problems/subsets/
8.2.要点
1掩码
通过bit位来表示某数字是否出现在集合中,遍历全排列组合的空间
2回溯法
观察树结构,注意“取节点而不是取叶子”这个概念
8.3.代码实例
掩码

1 class Solution { 2 public: 3 vector<int> t; 4 vector<vector<int>> ans; 5 6 vector<vector<int>> subsets(vector<int>& nums) { 7 int n = nums.size(); 8 for (int mask = 0; mask < (1 << n); ++mask) { 9 t.clear(); 10 for (int i = 0; i < n; ++i) { 11 if (mask & (1 << i)) { 12 t.push_back(nums[i]); 13 } 14 } 15 ans.push_back(t); 16 } 17 return ans; 18 } 19 };
回溯

1 class Solution { 2 private: 3 vector<vector<int>> result; 4 vector<int> path; 5 void backtracking(vector<int>& nums, int startIndex) { 6 result.push_back(path); // 收集子集,要放在终止添加的上面,否则会漏掉自己 7 if (startIndex >= nums.size()) { // 终止条件可以不加 8 return; 9 } 10 for (int i = startIndex; i < nums.size(); i++) { 11 path.push_back(nums[i]); 12 backtracking(nums, i + 1); 13 path.pop_back(); 14 } 15 } 16 public: 17 vector<vector<int>> subsets(vector<int>& nums) { 18 result.clear(); 19 path.clear(); 20 backtracking(nums, 0); 21 return result; 22 } 23 };
9.子集2
9.1.问题描述
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
链接:https://leetcode.cn/problems/subsets-ii
9.2.要点
回溯,仅添加一个横向搜索时的去重操作
9.3.代码实例

1 class Solution { 2 private: 3 vector<vector<int>> result; 4 vector<int> path; 5 void backtracking(vector<int>& nums, int startIndex) { 6 result.push_back(path); // 收集子集,要放在终止添加的上面,否则会漏掉自己 7 if (startIndex >= nums.size()) { // 终止条件可以不加 8 return; 9 } 10 for (int i = startIndex; i < nums.size(); i++) { 11 if(i>startIndex&&nums[i]==nums[i-1]){ 12 continue; 13 } 14 path.push_back(nums[i]); 15 backtracking(nums, i + 1); 16 path.pop_back(); 17 } 18 } 19 public: 20 vector<vector<int>> subsetsWithDup(vector<int>& nums) { 21 result.clear(); 22 path.clear(); 23 sort(nums.begin(),nums.end()); 24 backtracking(nums, 0); 25 return result; 26 } 27 };
10.全排列
10.1.问题描述
给定一个不含重复数字的数组 nums
,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
链接:https://leetcode.cn/problems/permutations/
10.2.要点
出现过的元素不能再被遍历到,标志位来记录使用情况。
10.3.代码实例
基于标志位的

1 class Solution { 2 public: 3 vector<vector<int>> result; 4 vector<int> path; 5 void backtracking (vector<int>& nums, vector<bool>& used) { 6 // 此时说明找到了一组 7 if (path.size() == nums.size()) { 8 result.push_back(path); 9 return; 10 } 11 for (int i = 0; i < nums.size(); i++) { 12 if (used[i] == true) continue; // path里已经收录的元素,直接跳过 13 used[i] = true; 14 path.push_back(nums[i]); 15 backtracking(nums, used); 16 path.pop_back(); 17 used[i] = false; 18 } 19 } 20 vector<vector<int>> permute(vector<int>& nums) { 21 result.clear(); 22 path.clear(); 23 vector<bool> used(nums.size(), false); 24 backtracking(nums, used); 25 return result; 26 } 27 };
基于交换的

1 class Solution { 2 public: 3 vector<vector<int>> result; 4 //vector<int> path; 5 void backtracking (vector<int>& nums, int start) { 6 // 此时说明找到了一组 7 if (start >= nums.size()) { 8 result.push_back(nums); 9 return; 10 } 11 for (int i = start; i < nums.size(); ++i) { 12 swap(nums[start],nums[i]); 13 backtracking(nums, start+1); 14 swap(nums[start],nums[i]); 15 } 16 } 17 vector<vector<int>> permute(vector<int>& nums) { 18 result.clear(); 19 backtracking(nums,0); 20 return result; 21 } 22 };
11.带重复的全排列
11.1.问题描述
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
示例 1:
输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]
链接:https://leetcode.cn/problems/permutations-ii
11.2.要点
要注意是不允许在树枝上重复还是不允许在树层间重复
11.3.代码实例

1 class Solution { 2 public: 3 vector<vector<int>> result; 4 vector<int> path; 5 void backtracking (vector<int>& nums, vector<bool>& used) { 6 // 此时说明找到了一组 7 if (path.size() == nums.size()) { 8 result.push_back(path); 9 return; 10 } 11 for (int i = 0; i < nums.size(); i++) { 12 // used[i - 1] == true,说明同一树枝nums[i - 1]使用过 13 // used[i - 1] == false,说明同一树层nums[i - 1]使用过 14 // 如果同一树层nums[i - 1]使用过则直接跳过 15 if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) { 16 continue; 17 } 18 if (used[i] == true) continue; // path里已经收录的元素,直接跳过 19 used[i] = true; 20 path.push_back(nums[i]); 21 backtracking(nums, used); 22 path.pop_back(); 23 used[i] = false; 24 } 25 } 26 vector<vector<int>> permuteUnique(vector<int>& nums) { 27 result.clear(); 28 path.clear(); 29 vector<bool> used(nums.size(), false); 30 31 sort(nums.begin(),nums.end()); 32 backtracking(nums, used); 33 return result; 34 } 35 };
12.递增子序列
12.1.问题描述
给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。
数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。
链接:https://leetcode.cn/problems/non-decreasing-subsequences
12.2.要点
注意,这里不能排序,前面已经用过的去重方法不再适用。
因此要想在层中去重得用特殊一点的方法,如哈希查询是否某元素已使用过
12.3.代码实例

1 // 版本一 2 class Solution { 3 private: 4 vector<vector<int>> result; 5 vector<int> path; 6 void backtracking(vector<int>& nums, int startIndex) { 7 if (path.size() > 1) { 8 result.push_back(path); 9 // 注意这里不要加return,要取树上的节点 10 } 11 unordered_set<int> uset; // 使用set对本层元素进行去重 12 for (int i = startIndex; i < nums.size(); i++) { 13 if ((!path.empty() && nums[i] < path.back()) 14 || uset.find(nums[i]) != uset.end()) { 15 continue; 16 } 17 uset.insert(nums[i]); // 记录这个元素在本层用过了,本层后面不能再用了 18 path.push_back(nums[i]); 19 backtracking(nums, i + 1); 20 path.pop_back(); 21 } 22 } 23 public: 24 vector<vector<int>> findSubsequences(vector<int>& nums) { 25 result.clear(); 26 path.clear(); 27 backtracking(nums, 0); 28 return result; 29 } 30 };
13.重新安排行程问题——暂略
13.1.问题描述
111
13.2.要点
222
13.3.代码实例
333
14.N皇后问题
14.1.问题描述
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
链接:https://leetcode.cn/problems/n-queens
14.2.要点
回溯尝试问题,判断是否冲突即可
14.3.代码实例

1 class Solution { 2 private: 3 int dim=0; 4 vector<vector<string>> ret; 5 vector<vector<bool>> flags; 6 void backTracking(int row){ 7 //到达一组的边界 8 if(row>=dim){ 9 save(); 10 return; 11 } 12 13 for(int i=0;i<dim;i++){ 14 if(hasConflict(row,i)){ 15 continue; 16 } 17 flags[row][i]=true; 18 backTracking(row+1); 19 flags[row][i]=false; 20 } 21 } 22 void save(){ 23 vector<string> sln; 24 string temp; 25 for(int i=0;i<dim;i++){ 26 for(int j=0;j<dim;j++){ 27 temp+=flags[i][j]?'Q':'.'; 28 } 29 sln.push_back(temp); 30 temp.clear(); 31 } 32 ret.push_back(sln); 33 } 34 bool hasConflict(const int row,const int col){ 35 //检查行,没必要 36 37 //检查列 38 for(int i=0;i<dim;i++){ 39 if(i!=row && flags[i][col]){ 40 return true; 41 } 42 } 43 44 int tgtRow=row,tgtCol=col; 45 //检查1条斜线 46 while(tgtRow>=0 && tgtCol>=0){ 47 tgtRow--; 48 tgtCol--; 49 } 50 tgtRow++;tgtCol++; 51 while(tgtRow<dim && tgtCol<dim){ 52 if(tgtRow!=row && tgtCol!=col){ 53 if(flags[tgtRow][tgtCol]){ 54 return true; 55 } 56 } 57 tgtRow++; 58 tgtCol++; 59 } 60 61 //检查另一条斜线 62 tgtRow=row,tgtCol=col; 63 while(tgtRow<dim && tgtCol>=0){ 64 tgtRow++; 65 tgtCol--; 66 } 67 tgtRow--;tgtCol++; 68 while(tgtRow>=0 && tgtCol<dim){ 69 if(tgtRow!=row && tgtCol!=col){ 70 if(flags[tgtRow][tgtCol]){ 71 return true; 72 } 73 } 74 tgtRow--; 75 tgtCol++; 76 } 77 78 return false; 79 } 80 public: 81 vector<vector<string>> solveNQueens(int n) { 82 dim=n; 83 flags.resize(n,vector<bool>(n,false)); 84 backTracking(0); 85 return ret; 86 } 87 };
15.解数独问题
15.1.问题描述
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
(1)数字 1-9
在每一行只能出现一次。
(2)数字 1-9
在每一列只能出现一次。
(3)数字 1-9
在每一个以粗实线分隔的 3x3
宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 '.'
表示。
15.2.要点
一般的回溯问题是一个二维树状搜索空间,数独问题是一个树状的三维搜索空间。在m行n列上取x。横向遍历时需要2个for循环的嵌套
15.3.代码实例

1 class Solution { 2 private: 3 bool backtracking(vector<vector<char>>& board) { 4 for (int i = 0; i < board.size(); i++) { // 遍历行 5 for (int j = 0; j < board[0].size(); j++) { // 遍历列 6 if (board[i][j] == '.') { 7 for (char k = '1'; k <= '9'; k++) { // (i, j) 这个位置放k是否合适 8 if (isValid(i, j, k, board)) { 9 board[i][j] = k; // 放置k 10 if (backtracking(board)) return true; // 如果找到合适一组立刻返回 11 board[i][j] = '.'; // 回溯,撤销k 12 } 13 } 14 return false; // 9个数都试完了,都不行,那么就返回false 15 } 16 } 17 } 18 return true; // 遍历完没有返回false,说明找到了合适棋盘位置了 19 } 20 bool isValid(int row, int col, char val, vector<vector<char>>& board) { 21 for (int i = 0; i < 9; i++) { // 判断行里是否重复 22 if (board[row][i] == val) { 23 return false; 24 } 25 } 26 for (int j = 0; j < 9; j++) { // 判断列里是否重复 27 if (board[j][col] == val) { 28 return false; 29 } 30 } 31 int startRow = (row / 3) * 3; 32 int startCol = (col / 3) * 3; 33 for (int i = startRow; i < startRow + 3; i++) { // 判断9方格里是否重复 34 for (int j = startCol; j < startCol + 3; j++) { 35 if (board[i][j] == val ) { 36 return false; 37 } 38 } 39 } 40 return true; 41 } 42 public: 43 void solveSudoku(vector<vector<char>>& board) { 44 backtracking(board); 45 } 46 };
16.总结
xxx.问题
xxx.1.问题描述
111
xxx.2.要点
222
xxx.3.代码实例
333