1.回溯总结 主要参考下面的题目,代码随想 ,还有labuladong ,这个类型的主要思路就是,找
到结束条件,然后就是进行选择,放入之后,就再次进行放出
1 2 3 4 5 6 7 8 9 10 11 result = [] def backtrack(路径, 选择列表):     if 满足结束条件:         result.add(路径)         return          for 选择 in 选择列表:         做选择         backtrack(路径, 选择列表)         撤销选择 
 
包含下面几个题目
46全排列 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 class  Solution  {public :    vector<vector<int >> ans;     vector<int > res;     vector<bool > st;     vector<vector<int >> permute (vector<int >& nums) {         st=vector <bool > (nums.size ());         dfs (nums,0 );         return  ans;     }     void  dfs (vector<int > &nums,int  u)  {         if (u==nums.size ()){             ans.push_back (res);             return ;         }         for  (int  i = 0 ; i < nums.size (); ++i) {             if  (!st[i]){                 st[i]=true ;                 res.push_back (nums[i]);                 dfs (nums,u+1 );                 res.pop_back ();                 st[i]=false ;             }         }     } }; 
 
首先还是使用ans进行保存,使用st进行验证,u代表成功的个数,当为n,就是可以进行添加,从0开始进行访问所有的值
51.N皇后 这个题目就是进行求解,他的check条件就是列上没有,,斜线上没有,斜线就是当前的点(x-1,y-1),(x-1,y+1),检查这些值有没有,没有就放,
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 class  Solution  {public :    vector<vector<string>> ans;     vector<string> res;     vector<vector<string>> solveNQueens (int  n) {         res=vector <string>(n,string (n,'.' ));         dfs (n,0 );         return  ans;     }     void  dfs (int  n,int  u)  {         if (n==u){             ans.push_back (res);             return  ;         }         for  (int  i = 0 ; i < n; ++i) {             if (isok (u,i)){                 res[u][i]='Q' ;                 dfs (n,u+1 );                 res[u][i]='.' ;             }         }     } bool  isok (int  u,int  i)  {                          int  n=res.size ();     for  (int  j = 0 ; j <=u; ++j) {         if (res[j][i]=='Q' )return  false ;     }          for  (int  j = u-1 ,k=i-1 ; j>=0 &&k>=0  ; j--,k--) {         if (res[j][k]=='Q' )return  false ;     }     for  (int  j = u-1 ,k=i+1 ; j>=0 &&k<n ; j--,k++) {         if (res[j][k]=='Q' )return  false ;     }     return  true ;     } }; 
 
112路径总和 从根节点开始寻找,两种dfs方式,一种就是在for循环里面进行回溯,还有一种在最开始进行回溯。
这个就是在里面进行回溯,因为是直接开始减的,所以,不需要把target还原
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class  Solution  {public :    bool  hasPathSum (TreeNode* root, int  targetSum)   {         if  (!root)return  false ;         return  dfs (root,targetSum-root->val);     }     bool  dfs (TreeNode* root,int  target)  {         if  (target==0 &&!root->left&&!root->right){             return  true ;         }         if (root->left){             bool  left= dfs (root->left,target-root->left->val);             if  (left)return  true ;         }         if (root->right){             if (dfs (root->right,target-root->right->val)){                 return  true ;             }         }         return  false ;     } }; 
 
140.单词拆分 这个题目还是回溯,本质就是对i从u开始,进行截取,然后,看是不是在指点里面
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 class  Solution  {public :    unordered_map<string,int > rec;     vector<string> ans;     string path;     vector<string> wordBreak (string s, vector<string>& wordDict)   {         for (auto  word:wordDict){             rec[word]++;         }         dfs (s,0 );         return  ans;     }     void  dfs (string s,int  u)  {         if (u==s.size ()){             path.pop_back ();                          ans.push_back (path);             path+=" " ;             return ;         }         if (u>s.size ()){             return ;         }         for  (int  i = u; i <s.size () ; ++i) {             auto  t=s.substr (u,i-u+1 );             if (rec.find (t)!=rec.end ()){                 auto  x=path;                 path+=t+" " ;                 dfs (s,i+1 );                 path=x;             }         }     } }; 
 
17.电话组合 还不是组合一样,放入字符串里面
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 class  Solution  {public :    vector<string> ans;     string strs[10 ] = {             "" , "" , "abc" , "def" ,             "ghi" , "jkl" , "mno" ,             "pqrs" , "tuv" , "wxyz" ,     };     string path;     vector<string> letterCombinations (string digits)   {         if  (digits.empty ())return  ans;         dfs (digits,0 );         return  ans;     }     void  dfs (string digits,int  u)  {         if (u==digits.size ()){             ans.push_back (path);             return ;         }         if (u>digits.size ())return ;         int  n=digits[u]-'0' ;         for  (int  i = 0 ; i < strs[n].size (); ++i) {             path.push_back (strs[n][i]);             dfs (digits,u+1 );             path.pop_back ();         }     } }; 
 
22.括号生成 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 class  Solution  {public :    vector<string> ans;     string path;     unordered_map<char ,int > rec;     vector<string> generateParenthesis (int  n)   {         dfs (n,0 );         return  ans;     }     void  dfs (int  n,int  u)  {         if (u==2 *n){             ans.push_back (path);             return ;         }         if (rec.find ('(' )==rec.end ()||rec['(' ]<n){             path+='(' ;             rec['(' ]++;             dfs (n,u+1 );             path.pop_back ();             rec['(' ]--;         }         if  (rec.find (')' )==rec.end ()||rec[')' ]<rec['(' ]){             path+=')' ;             rec[')' ]++;             dfs (n,u+1 );             path.pop_back ();             rec[')' ]--;         }     } }; 
 
两个剪纸,一个是长度都是n,括号,还有一个就是右括号小于左的
39.组合总和 这个就是组合数,使用i到u进行遍历,然后还有一个就是,直接从i开始,不是i+1
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 class  Solution  {public :    vector<vector<int >> ans;     vector<int > path;     vector<vector<int >> combinationSum (vector<int >& candidates, int  target) {         sort (candidates.begin (),candidates.end ());         dfs (candidates,target,0 );         return  ans;     }     void  dfs (vector<int > &nums,int  u,int  index)  {         if  (u==0 ){             ans.push_back (path);             return ;         }         if  (index==nums.size ())return ;         if (u<0 )return ;         for  (int  i = index; i < nums.size (); ++i) {             path.push_back (nums[i]);             dfs (nums,u-nums[i],i);             path.pop_back ();         }     } }; 
 
这个就是从i即系开始,可以重复使用 
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 class Solution { public:     vector<vector<int>> ans;     vector<int> path;          vector<vector<int>> combinationSum(vector<int>& c, int target) {             dfs(c,0,target);             return ans;     }     void dfs(vector<int>& c,int u,int target ){         // u代表当前循环到哪一个了数字呢         // 考虑边界         if(target==0){             ans.push_back(path);             return;         }         if(u==c.size()){             return;             // 直接返回         }         // 接下来就是放入放出         for(int i=0;i*c[u]<=target;i++){             dfs(c,u+1,target-i*c[u]);             path.push_back(c[u]);             // 这是选择加入一个后,再对后面的进行加入             // target-i*c[u]是加入当前的次数,u+1是下一个值              // 回复现场                                    }         for(int i=0;i*c[u]<=target;i++){             path.pop_back();         }              } }; 
 
这个代码很不错,因为是先dfs然后再push,为什么了,因为先dfs,代表选0个当前的,之后放入一个,就是选了一个dfs,而且是在dfs之后选择下一个值,而且,target因为是没有变,所以直接减去i*cu 
698.划分k个相等的子集 首先的先决条件就是sum数组的和可以整除k,而且最后一个数,一定小于平均数。之后就是进行回溯,代码思路,使用dfs(nums,avg,k,u)
含义就是当avg为0的时候,可以进行k-1(表示又有一组满足了,然后u从开始进行寻找,avg再次恢复到初始值)
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 class Solution { public:     vector<vector<int>> ans;     vector<int>path;     vector<bool> st;     int t;     int avg;     bool canPartitionKSubsets(vector<int>& nums, int k) {          auto sum=accumulate(nums.begin(),nums.end(),0);         if(sum%k!=0)return false;         st=vector<bool>(nums.size(),false);         int target=sum/k;         if (nums.back()>target)return false; //         t=k;         avg=target;         sort(nums.begin(),nums.end());         return dfs(nums,target,0,0);     }     bool  dfs(vector<int> &nums,int target,int index,int u){         if(u==t)return true; //        cout<<u;         if(target==0)return dfs(nums,avg,0,u+1); //        if(target<0)return false;         for (int i = index; i < nums.size(); ++i) {             if(!st[i]&&target-nums[i]>=0){                 st[i]=true; //                path.push_back(nums[i]);                 if(dfs(nums,target-nums[i],i+1,u)){                     return true;                 }                 st[i]=false; //                path.pop_back();                     //排好序了的,如果当前都没办法减少到0,后面就不可能                 if (target==avg)return false;             }         }         return false;     } }; 
 
if (target==avg)return false;重要剪纸,当表示值不变还是avg,就表示后面更不可能进行减少值,因为后面的都比当前值大,target会一直不变,所以不能选择,直接失败 
77.组合数 组合数,就是进行选择,首先进行排序,i到u开始,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class  Solution  {public :    vector<vector<int >> ans;     vector<int > rec;     vector<bool >st;     vector<vector<int >> combine (int  n, int  k) {         st=vector <bool > (n+1 ,false );         dfs (n,k,1 );         return  ans;     }     void  dfs (int  n,int  k,int  u)  {         if (!k){             ans.push_back (rec);             return ;         }         for  (int  i = u; i < n+1 ; ++i) {             rec.push_back (i);             dfs (n,k-1 ,i+1 );             rec.pop_back ();         }     } }; 
 
78,幂集 就是返回所有的选择,直接在上面的进行手动设置k
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 class  Solution  {public :    vector<vector<int >> ans;     vector<int > rec;     vector<vector<int >> subsets (vector<int >& nums) {         sort (nums.begin (),nums.end ());         for  (int  i = 0 ; i <=nums.size (); ++i) {             dfs (nums,i,0 );         }         return  ans;     }     void  dfs (vector<int > &nums,int  k,int  u)  {         if (!k){             ans.push_back (rec);             return ;         }         for  (int  i = u; i < nums.size (); ++i) {             rec.push_back (nums[i]);             dfs (nums,k-1 ,i+1 );             rec.pop_back ();         }     } }; 
 
40.组合综合 进行筛选,而且不能含有重复的,首先进行选择就是i到u,去重就是要使用那个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 class  Solution  {public :    vector<int > path;     vector<vector<int >> ans;     vector<vector<int >> combinationSum2 (vector<int >& candidates, int  target) {         sort (candidates.begin (),candidates.end ());         dfs (candidates,target,0 );         return  ans;     }     void  dfs (vector<int > &nums,int  target,int  u)  {         if (target==0 ){             ans.push_back (path);             return ;         }         if (u>=nums.size ())return ;         for  (int  i = u; i < nums.size (); ++i) {             if (nums[i]>target)return ;             if  (i>u&&nums[i]==nums[i-1 ])continue ;             path.push_back (nums[i]);             dfs (nums,target-nums[i],i+1 );             path.pop_back ();         }     } }; 
 
if (i>u&&nums[i]==nums[i-1])continue;去重代码,不需要使用st,来表示,因为后面都是没有访问的
216.组合综合 还是之前一样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class  Solution  {public :vector<int > path; vector<vector<int >> ans;     vector<vector<int >> combinationSum3 (int  k, int  n) {         dfs (1 ,k,n);         return  ans;     }     void  dfs (int  start,int  k,int  n)  {         if (!k){             if (!n)ans.push_back (path);         }else  if (k){                          for (int  i=start;i<=9 ;i++){                 if (n>=i){                     path.push_back (i);                     dfs (i+1 ,k-1 ,n-i);                     path.pop_back ();                 }             }         }          } }; 
 
131.分割回文串 还是之前一样,check条件就是是不是会问,如果是true,直接返回
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 class  Solution  {public :    vector<vector<string>> ans;     vector<string> path;     vector<vector<string>> partition (string s) {         dfs (s,0 );         return  ans;     }     void  dfs (string s,int  u)  {         if (u==s.size ()) {             ans.push_back (path);             return ;         }         for  (int  i = u; i < s.size (); ++i) {             auto  x=s.substr (u,i-u+1 );             if (is_ok (x)){                 path.push_back (x);                 dfs (s,i+1 );                 path.pop_back ();             }         }     }     bool  is_ok (string s)  {         auto  x=s;         reverse (s.begin (),s.end ());         return  x==s;     } }; 
 
93复原ip地址 这个首先是对于0,直接继续,而且,一共只有4个小数点,最后一个在加入的时候去除,之后就是普通的回溯
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 class  Solution  {public :    int  start;     int  end;     vector<string> ans;     string path;     vector<string> restoreIpAddresses (string s)   {         start=0 ,end=255 ;         dfs (s,4 ,0 );         return  ans;     }     void  dfs (string s,int  times,int  u)  {                           if  (!times&&u==s.size ()){             path.pop_back ();             ans.push_back (path);             return ;         }         if  (times<0 )return ;         if (u>=s.size ())return ;         if (s[u]=='0' ){             path+="0." ;             dfs (s,times-1 ,u+1 );             return  ;         }else {             for  (int  i = u; i < s.size (); ++i) {                 if  (i-u+1 >3 )return ;                 auto  x=s.substr (u,i-u+1 );                 auto  t= stoi (x);                 if (t<=255 ){                     auto  back=path;                     path+=x+"." ;                     dfs (s,times-1 ,i+1 );                     path=back;                 }             }         }     } }; 
 
对于签到0的优化方法就是把循环的下一位变成u+1,不是s.size 
1 2 3 4 int  n=u+1 ;        if (s[u]!='0' )n=s.size ();                     for  (int  i = u; i < n; ++i) { 
 
90子集 这个就是进行去重,直接看是不是相等,然后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 class  Solution  {public :    vector<vector<int >> ans;     vector<int > path;     vector<vector<int >> subsetsWithDup (vector<int >& nums) {         sort (nums.begin (),nums.end ());         for  (int  i = 0 ; i <=nums.size (); ++i) {             dfs (nums,i,0 );         }         return   ans;     }     void  dfs (vector<int > &nums,int  n,int  u)  {         if (n==0 ){             ans.push_back (path);             return ;         }         if (u>=nums.size ())return ;         if (n<0 )return ;         for  (int  i =u; i < nums.size (); ++i) {             if (i>u&&nums[i]==nums[i-1 ])continue ;             path.push_back (nums[i]);             dfs (nums,n-1 ,i+1 );             path.pop_back ();         }     } }; 
 
因为都是排序了的,后面一定没有访问,所以不用st
47全排列 进行去重,这个就是需要st数组,因为从是排列,而且需要进行去重,所以是从0开始的,需要st
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 class  Solution  {public :    vector<vector<int >> ans;     vector<int > path;     vector<bool > st;     vector<vector<int >> permuteUnique (vector<int >& nums) {         sort (nums.begin (),nums.end ());         path= vector <int >(nums.size ());         st= vector <bool >(nums.size ());         dfs (nums,0 );         return  ans;     }     void  dfs (vector<int >& nums,int  u )  {         if (u==nums.size ()){             ans.push_back (path);             return ;         }         for (int  i=0 ;i<nums.size ();i++){             if (!st[i]){             if (i&&nums[i-1 ]==nums[i]&&!st[i-1 ])continue ;                              st[i] = true ;                 path[u] = nums[i];                 dfs (nums, u + 1 );                 st[i] = false ;             }         }     } }; 
 
491递增子序列 因为没有排序,不能排序,所以只能使用set来进行作为
本人思路,就是对所有n的n从2到size进行遍历,然后加进去,使用set去除
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 class  Solution  {public :    vector<vector<int >> ans;     vector<int > path;     set<vector<int >> s;     vector<vector<int >> findSubsequences (vector<int >& nums) {         for  (int  i = 2 ; i <=nums.size (); ++i) {             dfs (nums,i,0 );         }         return  ans;     }     void  dfs (vector<int >& nums,int  n,int  u)  {         if (n==0 ){             if (s.find (path)==s.end ()){                 ans.push_back (path);                 s.insert (path);             }             return ;         }         if (u==nums.size ())return ;         for  (int  i = u; i <nums.size () ; ++i) {             if (path.empty ()||nums[i]>=path.back ()){                 path.push_back (nums[i]);                 dfs (nums,n-1 ,i+1 );                 path.pop_back ();             }         }     } }; 
 
2.小结 上面的几个经典题目,一个去重,前面相等直接跳过
1 if(i>u&&num[i]==num[i-1])continue 
 
第二个就是前导0的问题,一般是只能用做单独的0,那么距离就是u+1
1 2 3 int n=s.size(); if(s[i]=='0')n=u+1: for(int i=u;i<n;i++) 
 
第三个就是排列组合,排列的话就是从0开始,设置st数组.
组合的就是从u开始,去重和上面是一样的