回溯法
###优先队列 priority_queue<int,vector<int>,greater<int>> que;//升序,小顶堆
还有一种结构体内重载
struct Status {
int val;
ListNode *ptr;
bool operator < (const Status &rhs) const {
return val > rhs.val;
}
};
priority_queue <Status> q;
###位运算 负数取余1判断奇偶,只能用&1不能用%。同时如果先判断偶数注意括号,if((n&1) == 0)
###集合查询, if(uset.find(nums[i]) != uset.end())//去重
###图遍历 unordered_map<int,int> map;
第一种 注意这里x是指针,->取值
###队列有que,size()方法,层序遍历 q.push(x) q.pop() q.front() q.back() q.empty()
###字符串也有push_back(0),pop_back()方法,17题
###字符串找子串,s.find("123");s.find("123",0);第一个参数子串;第二个参数查找的起始位置
###字符串反转自身,reverse(s.begin(),s.end())
###string切割, s.substr(pos, len)
###数字转字符串 string s = to_string(num);
###字符串转数字 int num = stoi(s);
###vector全局声明定义会报错expected parameter declarator vector<int>father(200); ,全局声明,主函数里定义。vector<int>a;a = vector<int>(n,0);
###vector转字符串 Str.assign(Vec.begin(), Vec.end());
###vector反转自身,reverse(vec.begin(),vec.end())
回溯法去重,排序+if(nums[i]!=nums[i-1]),太好用了!
性能:本质是穷举,最多剪枝一下
可以解决的问题:排列,组合,切割,子集,棋盘
理解:N叉树
模板:
void back(){
if()
return;
for(){
back();
撤销结果;
}
}
77. 组合 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<vector<int>> result; 4 vector<int> path; 5 void back(int n,int k,int index){ 6 if(path.size()==k){ 7 result.push_back(path); 8 return ; 9 } 10 for(int i=index;i<=n;i++){ 11 path.push_back(i); 12 back(n,k,i+1); 13 path.pop_back(); 14 } 15 } 16 vector<vector<int>> combine(int n, int k) { 17 back(n,k,1); 18 return result; 19 } 20 };
216. 组合总和 III - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<int>path; 4 vector<vector<int>> result; 5 void back(int k,int n,int start){ 6 if(n==0&&k==path.size()){ 7 result.push_back(path); 8 return ; 9 } 10 for(int i=start;i<=9;i++){ 11 path.push_back(i); 12 n-=i; 13 back(k,n,i+1); 14 path.pop_back(); 15 n+=i; 16 } 17 } 18 vector<vector<int>> combinationSum3(int k, int n) { 19 back(k,n,1); 20 return result; 21 } 22 };
17. 电话号码的字母组合 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 string path; 4 vector<string> result; 5 unordered_map<char, string> map{ 6 {'0', ""}, {'1',""}, {'2', "abc"}, 7 {'3',"def"}, {'4',"ghi"}, {'5',"jkl"}, 8 {'6',"mno"}, {'7',"pqrs"},{'8',"tuv"}, 9 {'9',"wxyz"} 10 }; 11 void back(string digits,int i){ 12 if(path.size()==digits.size()){ 13 result.push_back(path); 14 return ; 15 } 16 for(int j=0;j<map[digits[i]].size();j++){ 17 path.push_back(map[digits[i]][j]); 18 back(digits,i+1); 19 path.pop_back(); 20 } 21 } 22 23 vector<string> letterCombinations(string digits) { 24 if(digits.size()==0) 25 return result; 26 back(digits,0); 27 return result; 28 } 29 };
39. 组合总和 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int sum; 4 vector<int> path; 5 vector<vector<int>> result; 6 void back(vector<int>& candidates, int target){ 7 if(sum>target)//没这个溢出啥的 8 return; 9 if(sum==target){//去重 10 int flag = 1; 11 vector<int> temp = path; 12 sort(temp.begin(),temp.end()); 13 for(int i=0;i<result.size();i++){ 14 if(result[i]==temp) 15 flag = 0; 16 } 17 if(flag) 18 result.push_back(temp); 19 return ; 20 } 21 for(int i=0;i<candidates.size();i++){ 22 sum+=candidates[i]; 23 path.push_back(candidates[i]); 24 back(candidates,target); 25 sum-=candidates[i]; 26 path.pop_back(); 27 } 28 } 29 vector<vector<int>> combinationSum(vector<int>& candidates, int target) { 30 back(candidates,target); 31 return result; 32 } 33 };
1 class Solution { 2 public: 3 int sum; 4 vector<int> path; 5 vector<vector<int>> result; 6 void back(vector<int>& candidates, int target,int startIndex){ 7 if(sum>target)//没这个溢出啥的 8 return; 9 if(sum==target){// 10 result.push_back(path); 11 return ; 12 } 13 for(int i=startIndex;i<candidates.size();i++){ 14 sum+=candidates[i]; 15 path.push_back(candidates[i]); 16 back(candidates,target,i); 17 sum-=candidates[i]; 18 path.pop_back(); 19 } 20 } 21 vector<vector<int>> combinationSum(vector<int>& candidates, int target) {//元素是否重复选取,就是startIndex是i还是i+1这么传递 22 back(candidates,target,0); 23 return result; 24 } 25 };
40. 组合总和 II - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<int> path; 4 vector<vector<int>> result; 5 int sum; 6 void back(vector<int>& candidates, int target,int startIndex){ 7 if(sum == target){ 8 result.push_back(path); 9 return ; 10 } 11 for(int i=startIndex;i<candidates.size()&&sum+candidates[i]<=target;i++){//这道题因为有重复元素,所以要去重了耶 12 if(i>startIndex&&candidates[i] == candidates[i-1]) 13 continue; 14 path.push_back(candidates[i]); 15 sum+=candidates[i]; 16 back(candidates,target,i+1); 17 path.pop_back(); 18 sum-=candidates[i]; 19 } 20 } 21 vector<vector<int>> combinationSum2(vector<int>& candidates, int target) { 22 // 首先把给candidates排序,让其相同的元素都挨在一起。 23 sort(candidates.begin(), candidates.end()); 24 back(candidates,target,0); 25 return result; 26 } 27 };
131. 分割回文串 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<string> path; 4 vector<vector<string>> result; 5 bool istrue(string &s,int start,int end){ 6 for(int i=start,j=end;i<j;i++,j--){ 7 if(s[i]!=s[j]){ 8 return false; 9 } 10 } 11 return true; 12 } 13 void back(string &s,int startIndex){ 14 if(startIndex==s.size()){ 15 result.push_back(path); 16 return; 17 } 18 for(int i=startIndex;i<s.size();i++){ 19 if(istrue(s,startIndex,i)){ 20 string str = s.substr(startIndex,i-startIndex+1); 21 path.push_back(str); 22 back(s,i+1); 23 path.pop_back(); 24 } 25 } 26 } 27 vector<vector<string>> partition(string s) { 28 back(s,0); 29 return result ; 30 } 31 };
93. 复原 IP 地址 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<string>result; 4 string path; 5 void backtrace(string& s,int cnt,int startIndex){ 6 if(cnt==4 ){ 7 if(startIndex==s.size()) 8 result.push_back(path); 9 return ; 10 } 11 for(int i=startIndex;i<s.size();i++){ 12 int len = i-startIndex+1; 13 if(len>3)//超出范围剪枝 14 return ; 15 if(s[startIndex]=='0' && i!=startIndex) //不合法IP地址有前缀0 16 return; 17 if(len==3 && s.substr(startIndex,len)>"255") //不合法IP地址过大,字符串比较太精髓了 18 return; 19 path+=s.substr(startIndex,len); 20 if(cnt!=3) 21 path.push_back('.'); 22 backtrace(s,cnt+1,i+1); 23 path = path.substr(0,path.size()-len); 24 if(cnt!=3) 25 path = path.substr(0,path.size()-1); 26 } 27 } 28 vector<string> restoreIpAddresses(string s) { 29 backtrace(s,0,0); 30 return result; 31 } 32 };
78. 子集 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<vector<int>> result; 4 vector<int> path; 5 void back(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 back(nums,i+1); 13 path.pop_back(); 14 } 15 } 16 vector<vector<int>> subsets(vector<int>& nums) { 17 back(nums,0); 18 return result; 19 } 20 };
90. 子集 II - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<int> path; 4 vector<vector<int>> result; 5 void back(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 back(nums,i+1); 16 path.pop_back(); 17 } 18 } 19 vector<vector<int>> subsetsWithDup(vector<int>& nums) { 20 sort(nums.begin(),nums.end()); 21 back(nums,0); 22 return result; 23 } 24 };
491. 递增子序列 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<int> path; 4 vector<vector<int>> result; 5 void back(vector<int>& nums,int startIndex){//[1,2,3,1,1,1] 去重完犊子了,这个不能排序哈哈哈,所以不能nums[i]==nums[i-1]这样了, 6 if(path.size()>=2){ 7 result.push_back(path); 8 } 9 unordered_set<int> uset; // 使用set对本层元素进行去重 10 for(int i=startIndex;i<nums.size();i++){ 11 if(path.size()!=0&&nums[i]<path.back())//递增 12 continue ; 13 if(uset.find(nums[i]) != uset.end())//去重 14 continue ; 15 uset.insert(nums[i]); 16 path.push_back(nums[i]); 17 back(nums,i+1); 18 path.pop_back(); 19 } 20 } 21 22 vector<vector<int>> findSubsequences(vector<int>& nums) { 23 back(nums,0); 24 return result; 25 } 26 };
46. 全排列 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<int> path; 4 vector<vector<int>> result; 5 void back(vector<int>& nums,vector<bool>&used){ 6 if(path.size() == nums.size()){ 7 result.push_back(path); 8 return ; 9 } 10 for(int i=0;i<nums.size();i++){ 11 if(used[i]) 12 continue ; 13 used[i] = true; 14 path.push_back(nums[i]); 15 back(nums,used); 16 used[i] = false; 17 path.pop_back(); 18 } 19 } 20 vector<vector<int>> permute(vector<int>& nums) { 21 vector<bool>used(nums.size(),false); 22 back(nums,used); 23 return result; 24 } 25 };
51. N 皇后 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<vector<string>> result; 4 bool isValid(int n,int row,int col,vector<string> path){ 5 for(int i=0;i<row;i++){//列 6 if(path[i][col]=='Q') 7 return false; 8 } 9 for(int i=row-1,j=col-1;i>=0&&j>=0;i--,j--){//45度往左上 10 if(path[i][j]=='Q') 11 return false; 12 } 13 for(int i=row-1,j=col+1;i>=0&&j<n;i--,j++){//45度往左上 14 if(path[i][j]=='Q') 15 return false; 16 } 17 return true; 18 } 19 void back(int n,int num,vector<string>& path){ 20 if(num == n){ 21 result.push_back(path); 22 return ; 23 } 24 for(int col=0;col<n;col++){//列 25 if(!isValid(n,num,col,path)) 26 continue ; 27 path[num][col] = 'Q'; 28 back(n,num+1,path); 29 path[num][col] = '.'; 30 } 31 } 32 vector<vector<string>> solveNQueens(int n) { 33 vector<string> path(n, string(n, '.'));//初始化n行n列都为. 34 back(n,0,path); 35 return result; 36 } 37 };
37. 解数独 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 bool isValid(int row, int col, char val, vector<vector<char>>& board) { 4 for (int i = 0; i < 9; i++) { // 判断行里是否重复 5 if (board[row][i] == val) { 6 return false; 7 } 8 } 9 for (int j = 0; j < 9; j++) { // 判断列里是否重复 10 if (board[j][col] == val) { 11 return false; 12 } 13 } 14 int startRow = (row / 3) * 3;//这里求九方格起始位置也很巧 15 int startCol = (col / 3) * 3; 16 for (int i = startRow; i < startRow + 3; i++) { // 判断9方格里是否重复 17 for (int j = startCol; j < startCol + 3; j++) { 18 if (board[i][j] == val ) {//判断的是当前加入进去的数有没有和之前的数冲突,初始数独肯定有效。所以不要判断每个数不超过1次 19 return false; 20 } 21 } 22 } 23 return true; 24 } 25 bool back(vector<vector<char>>& board){ 26 for(int i=0;i<9;i++){ 27 for(int j=0;j<9;j++){ 28 if(board[i][j]!='.') 29 continue; 30 for(char k='1';k<='9';k++){ 31 if(isValid(i,j,k,board)){ 32 board[i][j] = k; 33 back(board)//只有一种解,所以找到了就不用回溯,主要是结果是board,不是自定义的 34 board[i][j] = '.'; 35 } 36 } 37 } 38 } 39 return true;//没有i,j循环完了,棋盘遍历完了,答案出来了。 40 } 41 void solveSudoku(vector<vector<char>>& board) { 42 back(board); 43 } 44 };