求子集序列:
解题思路:
- 已知原集合的数据位数为N,则可以通过二进制比对原来集合,二进制位为1则输出集合上的该位数据,为0则空,二进制的01排序规律与子集的输出一致
- 由集合的位数可以判断出二进制的范围 0 ~(1<<N)
- 第一重循环:for (int i = 0; i < (1 << n); i++)
- 由二进制的0 1 判断当前集合的该位数字是否输出
- 第二重循环判断集合每一位进行比较:for (int j = 0; j < N; j++)
- 二层循环判断循环位是否输出:if (i & (1 << j))
- cout << str[j] << " ";
- 有一个集合由A-Z这26个字母组成,前N位的子集输出,打印这个集合的所有子集,每个子集一行,写C代码实现,不能使用递归
void Subset(string str, int n)
//有一个集合由A-Z这26个字母组成,前N位的子集输出
//打印这个集合的所有子集,每个子集一行,写C代码实现,不能使用递归
{for (int i = 0; i < (1 << n); i++){for (int j = 0; j < n; j++){if (i & (1 << j))cout << str[j] << " ";}cout << endl;}
}
int main()
{string str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";Subset(str, 6);return 0;
}
2.给你一个整数数组 nums ,数组中的元素互不相同 。返回该数组所有可能的子集
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
class Solution {
public:vector<vector<int>> subsets(vector<int>& nums) {vector<vector<int>>v;vector<int>tmp;int n=nums.size();for(int i=0;i<(1<<n);i++){tmp.clear();for(int j=0;j<n;j++){if(i&(1<<j))tmp.push_back(nums[j]);}v.push_back(tmp);}return v;}
};
求数据的全排列:
函数:bool next_permutation(起始迭代器,结束迭代器);
在调用 next_permutation 之前,你需要确保 nums 是按字典序排列的(升序或降序都可以,但通常选择升序),因为 next_permutation 会生成给定序列的下一个排列。如果 nums 不是有序的,那么第一次调用 next_permutation 将不会得到正确的结果。
我们知道有一全排列的函数可以直接使用,该函数返回可否继续排列的bool值
int main()
{vector<int>v{ 1,2,3,4 };do {for (auto it : v)cout << it << " ";cout << endl;} while (next_permutation(v.begin(), v.end()));return 0;
}
自己实现算法解析:
//解题精髓:
一个数字:本身一个
两个数字:{1,2}->{1,2},{2,1}
三个数字:{1,2,3}->{1,{2,3}}{2,{}} {3,{}}四个数字:{1,2,3,4}->{1,{2,3,4}}{2,{}} {3,{}}{4,{}}
划分大边距到小边距 的交换
当交换距离为1时,表示当前唯一,无需交换,插入数组
从大边距缩减,并且大边距可以通过交换,得到所有可能性
class Solution {
public:void swap(int&a,int&b){int tmp=a;a=b;b=tmp;}vector<vector<int>> _permute(vector<vector<int>>&v,vector<int>& nums,int b,int e){if(e-b==1)v.push_back(nums);else{for(int i=b;i<e;i++){swap(nums[b],nums[i]);_permute(v,nums,b+1,e);swap(nums[b],nums[i]);}}return v;}vector<vector<int>> permute(vector<int>& nums){//自己实现:vector<vector<int>>v;return _permute(v,nums,0,nums.size());}//调用函数实现:// vector<vector<int>> permute(vector<int>& nums) {// vector<vector<int>> v;// sort(nums.begin(),nums.end());// do{// v.push_back(nums);// }while(next_permutation(nums.begin(),nums.end()));// return v;// }
};
N皇后:
N*N 的棋盘上,有N位皇后,但是!两两皇后不能在同一行、同一列、同一对角线!
解题思路:
- N行N列中,存放N位皇后
- 我们尝试在一行中的每个位置放置皇后,并判断该位置是否与先前的其他皇后冲突
- 冲突判断,所有皇后不在同一列:v[j] == v[i],一对角线:abs(v[i] - v[j]) == (i - j)
- 我们只关心不冲突的情况下,冲突时则回溯到上一级,继续for()判断这一行下一列位置
- 不冲突时,默认这一行该位置已经确定,递归调用处理下一行需要确定的位置_solveNQueens(s,v,n,in+1)
- 当我们确定了所有N皇后位置时,则插入vector<vector<string>>&s
class Solution {
public:bool Checkpos(vector<int>& v, int in) { for (int i = 1; i <= in; i++) { for (int j = i-1; j>=0; j--) { // 修改循环条件以避免越界 if (v[j] == v[i] || abs(v[i] - v[j]) == (i - j)) { return true; } } } return false; }void To_string(vector<vector<string>>&s,vector<int>v){vector<string>t(v.size(),string(v.size(),'.'));for(int i=0;i<v.size();i++){t[i][v[i]]='Q'; }s.push_back(t);}void _solveNQueens(vector<vector<string>>&s,vector<int>&v,int n,int in){for(int i=0;i<n;i++){if(in<n)v[in]=i;if(!Checkpos(v,in)){if(in==n-1)To_string(s,v);else_solveNQueens(s,v,n,in+1);}}return ;}vector<vector<string>> solveNQueens(int n) {vector<vector<string>>s;vector<int>v(n);_solveNQueens(s,v,n,0);return s;}
};
矩阵中的路径
class Solution {vector<vector<int>>f = { {1,0},{-1,0},{0,1},{0,-1} };
public:bool _exist(vector<vector<char>>& board, string word, vector<vector<bool>>& visited,int i, int j, int len) {if (len == word.size()){return true;}visited[i][j] = true;for (int k = 0; k < f.size(); k++){int h = f[k][0] + i;int l = f[k][1] + j;if (h >= 0 && h < board.size() && l >= 0 && l < board[0].size()){if (board[h][l] == word[len] && visited[h][l] == false)if (_exist(board, word, visited, h, l, len + 1))return true;}}visited[i][j] = false; // 回溯,标记为未访问 return false;}bool exist(vector<vector<char>>& board, string word) {int h = board.size();int l = board[0].size();vector<vector<bool>>visited(h, vector<bool>(l, false));for (int i = 0; i < h; i++){for (int j = 0; j < l; j++){if (board[i][j] == word[0]){if (word.size() == 1)return true;if (_exist(board, word, visited, i, j, 1))return true;}}}return false;}
};
我们需要关注每次访问后对被访问结点作标记,但是未访问成功后,需要撤除标记
以及在找到完整的word语句后,递归调用的返回值,依次返回给上一级直到原始调用层