一. 八皇后问题
第一种解法将棋盘的所有格子都初始化为‘.’, 定义递归函数为前l-1行的格子已经排好(给定排面的情况下), 从第l层开始继续排得到的八皇后搜索结果。具体做法是从第l行的每一个列逐列尝试,如果不冲突则加入,再进行l+1的问题求解,求解完后进行回溯。空间复杂度为O(N*N)
class Solution { public: int totalNQueens(int n) { vector<vector<int>> round(n, vector<int>(n, 0)); int total = 0; btsearch(round, 0, n, total); return total; } private: void btsearch(vector<vector<int>> &round, int t, int n, int &total) { if (t == n) { total++; return; } for (int i = 0; i < n; i++) { if (isok(round, t, i)) { round[t][i] = 1; btsearch(round, t+1, n, total); round[t][i] = 0; } } } bool isok(const vector<vector<int>>round, int t, int j) { int n = round.size(); for (int c=0; c<t; c++) { if (round[c][j] == 1) return false; } for (int r=0; r<j; r++) { if (round[t][r] == 1) return false; } // 45 o for (int c=t-1, r=j+1; c>=0 && r<n; c--, r++) { if (round[c][r] == 1) return false; } // 135 o for (int c=t-1, r=j-1; c>=0 && r>=0; c--, r-- ) { if (round[c][r] == 1) return false; } // nqueque = 4。 return true; } };
class Solution { public: int totalNQueens(int n) { vector<vector<int>> round(n, vector<int>(n, 0)); int total = 0; btsearch(round, 0, n, total); return total; } private: void btsearch(vector<vector<int>> &round, int t, int n, int &total) { if (t == n) { total++; return; } for (int i = 0; i < n; i++) { if (isok(round, t, i)) { round[t][i] = 1; btsearch(round, t+1, n, total); round[t][i] = 0; } } } bool isok(const vector<vector<int>>round, int t, int j) { int n = round.size(); for (int c=0; c<t; c++) { if (round[c][j] == 1) return false; } for (int r=0; r<j; r++) { if (round[t][r] == 1) return false; }
第二种方法类似,不过可以将格子表示成一个一维数组,第i个元素的值j表示将皇后放在第i行第j列
二. Permutation
对一个数组进行全排列,无重复元素,定义递归函数为前i-1个元素全排列已经排好, 将第i个元素以及后面的元素进行全排列。过程为从第i个元素到最后一个元素轮流放在第i个位置上, 然后对第i+1个元素以及后续元素进行全排列。
class Solution { public: vector<vector<int>> permute(vector<int>& nums) { vector<vector<int>> res; permutehelper(nums, 0, res); return res; } private: void permutehelper(vector<int>&nums, int l, vector<vector<int>> &res){ if (l == nums.size()) { res.push_back(nums);} for (int i = l; i < nums.size(); i++) { swap(nums[l], nums[i]); permutehelper(nums, l+1, res); swap(nums[i], nums[l]); } } };
若有重复,则先进行sort, 并且轮流当头那部分相同的数字只能出现一次,
class Solution { public: vector<vector<int>> permuteUnique(vector<int>& nums) { vector<vector<int>> res; sort(nums.begin(), nums.end()); helper(nums, 0, res); return res; } private: void helper(vector<int>& nums, int l, vector<vector<int>> &res) { if (l == nums.size()) res.push_back(nums); set<int> vis; for (int i=l; i< nums.size(); i++) { if (vis.count(nums[i])) continue; vis.insert(nums[i]); swap(nums[l], nums[i]); helper(nums, l+1, res); swap(nums[i], nums[l]); } } };
三. 整数拆分
输入一个整数n,输出这个整数的所有划分方法,例如对于4,我们可以得到:4、3+1、2+1+1、1+1+1+1这四种划分方案。
为了使得有相同数字不同顺序组成的方案记作一种方案,我们另m表示当前整数划分方案中最大的数字,curSum表示当前方案已经构成的和,如果curSum==n则输出当前方案,否则尝试从m到1加入到方案中,并递归调用,注意回溯时,需要删除之前添加的数字。
void IntSplitPrint(int n, int m, int curSum, vector<int> & cur) { if( curSum == n ) { for( int i = 0 ; i < cur.size() ; i++ ) { cout<<cur[i]<<" "; } cout<<endl; } else { for( int i = m ; i > 0 ; i-- ) { if( i + curSum <= n ) { cur.push_back(i); IntSplitPrint(n, i, curSum + i, cur); cur.pop_back(); } } } }
四. CombineSum
在一组数字中,寻找子数组,使子数组的元素和为target的所有组合,求罗列所有组合,或求解组合总数,或求解最少使用的组合中元素个数(找零钱问题leetcode322)
求一个数组中所有的和等于target的组合。要求:
1.每个数可以用多次
2.没有重复的组合
3.一个组合中的所有的数是升序排列的
class Solution { public: vector<vector<int>> combinationSum(vector<int>& candidates, int target) { vector<vector<int>> res; vector<int> out; btsearch(candidates, 0, target, out, res); return res; } void btsearch(vector<int> candidates, int l, int target, vector<int> &out, vector<vector<int>>&res) { if (target < 0) { return; } if (target == 0) { res.push_back(out); return; } for (int i = l ; i< candidates.size(); i++) { out.push_back(candidates[i]); btsearch(candidates, i, target - candidates[i], out, res); out.pop_back(); } } };
五. CombineSumII
求一个数组中所有的和等于target的组合。要求:
1.每个数最多只能使用一次
2.没有重复的组合
3.一个组合中的所有的数是升序排列的
class Solution { public: vector<vector<int> > combinationSum2(vector<int> &num, int target) { vector<vector<int> > res; vector<int> out; sort(num.begin(), num.end()); combinationSum2DFS(num, target, 0, out, res); return res; } void combinationSum2DFS(vector<int> &num, int target, int start, vector<int> &out, vector<vector<int> > &res) { if (target < 0) return; else if (target == 0) res.push_back(out); else { for (int i = start; i < num.size(); ++i) { if (i > start && num[i] == num[i - 1]) continue; out.push_back(num[i]); combinationSum2DFS(num, target - num[i], i + 1, out, res); out.pop_back(); } } } };
六. subsets
https://www.cnblogs.com/TenosDoIt/p/3451902.html
给定一个整数的set, 给出所有的子set。无重复数字。每一个元素有选择放或者不放两种选择。
class Solution { public: vector<vector<int>> subsets(vector<int>& nums) { vector<vector<int>> res; vector<int> out; helper(nums, 0, out, res); return res; } private: void helper(vector<int>nums, int l, vector<int>&out, vector<vector<int>>&res) { if (l == nums.size()) { res.push_back(out); return; } out.push_back(nums[l]); helper(nums, l+1, out, res); out.pop_back(); helper(nums, l+1, out, res); } };