一、合法括号
初始定义“()”是一个可消除的合法括号,此时设m=1。当m增加为2时,要在此基础上新增加一对括号,但是新生成括号对要求是可完全消除的(即从左到右,相邻的左右括号可以消除),也就是消除完是空串。求m=n时,有多少符合条件的串?
递归:
# include<iostream>
# include<string>
# include<vector>
# include<set>
using namespace std;
set<string> Brackets(int n) {
set<string>cur_str;
if (n == 1) {
cur_str.insert("()");
return cur_str;
}
set<string>new_str = Brackets(n - 1);
for (auto it = new_str.begin(); it != new_str.end(); it++) {
cur_str.insert("()" + *it);
cur_str.insert(*it + "()");
cur_str.insert("(" + *it + ")");
}
return cur_str;
}
int main(void) {
int n;
cin>> n;
set<string>ans;
ans=Brackets(n);
for (auto it = ans.begin(); it != ans.end(); it++) {
cout << *it << endl;
}
return 0;
}
对于当前次操作来说,一共有三类方法:左,右,包
(1)放在cur的左边
(2)放在cur的右边
(3)包住cur
迭代:
# include<iostream>
# include<string>
# include<vector>
# include<set>
using namespace std;
int main(void) {
int n;
cin>> n;
set<string>cur_str;
cur_str.insert("()");
for (int i = 1; i < n; i++) {
set<string>new_str;
for (auto it = cur_str.begin(); it != cur_str.end(); it++) {
new_str.insert("()" + *it);
new_str.insert(*it + "()");
new_str.insert("(" + *it + ")");
}
cur_str=new_str;
}
for (auto it = cur_str.begin(); it != cur_str.end(); it++) {
cout << *it << endl;
}
return 0;
}
二、子集个数(组合问题)
求一个集合的子集?
递归:
#include<iostream>
#include<set>
#include<vector>
#include<algorithm>
using namespace std;
set<set<int>> GetSet(vector<int>& arr, int n, int curIndex) {
set<set<int>> new_set;
if (curIndex == 0) {
set<int>emotyJ= {};
set<int>firstJ = { arr[0] };
new_set.insert(emotyJ); // 插入空集合
new_set.insert(firstJ); // 插入第一个元素的集合
return new_set;
}
set<set<int>> cur_set = GetSet(arr, n, curIndex - 1);
// 将之前的子集加入到 new_set 中
for (auto a : cur_set) {
new_set.insert(a); // 插入当前集合
set<int> cur = a; // 复制当前集合
cur.insert(arr[curIndex]); // 插入当前索引的元素
new_set.insert(cur); // 插入新的集合
}
return new_set;
}
set<set<int>> ChildSet(vector<int>& arr) {
sort(arr.begin(), arr.end());
return GetSet(arr, arr.size(), arr.size() - 1);
}
int main(void) {
vector<int> arr = { 1, 2, 3,4};
set<set<int>> ans = ChildSet(arr);
int n = ans.size();
cout << "子集个数:" << n << endl;
// 输出子集
for (auto sub_set : ans) {
cout << "{ ";
for (auto elem : sub_set) {
cout << elem << " ";
}
cout << "}" << endl;
}
return 0;
}
无非就是加不加新元素
迭代:
#include<iostream>
#include<set>
#include<vector>
#include<algorithm>
using namespace std;
set<set<int>> GetSet(vector<int>& arr, int n, int curIndex) {
set<set<int>> cur_set;
set<int> empty_set = {};
cur_set.insert(empty_set);
for (int i = 0; i < n; i++) {
set<set<int>> new_set;
// 将之前的子集加入到 new_set 中
for (auto a : cur_set) {
new_set.insert(a); // 插入当前集合
set<int> cur = a; // 复制当前集合
cur.insert(arr[i]); // 插入当前索引的元素
new_set.insert(cur); // 插入新的集合
}
cur_set=new_set;
}
return cur_set;
}
set<set<int>> ChildSet(vector<int>& arr) {
sort(arr.begin(), arr.end());
return GetSet(arr, arr.size(), arr.size() - 1);
}
int main(void) {
vector<int> arr = { 1, 2, 3, 4};
set<set<int>> ans = ChildSet(arr);
int n = ans.size();
cout << "子集个数:" << n << endl;
// 输出子集
for (auto sub_set : ans) {
cout << "{ ";
for (auto elem : sub_set) {
cout << elem << " ";
}
cout << "}" << endl;
}
return 0;
}
与上面类似
位运算迭代法:
无非就是取或者不取
#include<iostream>
#include<set>
#include<vector>
#include<algorithm>
using namespace std;
set<set<int>> GetSet(vector<int>& arr, int n, int curIndex) {
set<set<int>> res;
for (int i = 0; i < (1 << n); i++) {
set<int>cur;
int val = i;
int index = curIndex;
if (val == 0) {
res.insert(cur);
continue;
}
while (val >0) {
if (val & 1) {
cur.insert(arr[index]);
}
val >>= 1;
index--;
}
res.insert(cur);
}
return res;
}
set<set<int>> ChildSet(vector<int>& arr) {
sort(arr.begin(), arr.end());
return GetSet(arr, arr.size(), arr.size() - 1);
}
int main(void) {
vector<int> arr = { 1, 2, 3};
set<set<int>> ans = ChildSet(arr);
int n = ans.size();
cout << "子集个数:" << n << endl;
// 输出子集
for (auto sub_set : ans) {
cout << "{ ";
for (auto elem : sub_set) {
cout << elem << " ";
}
cout << "}" << endl;
}
return 0;
}
三、排列序列(排列问题)
每个都要取,但是只能取一次
递归:
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
vector<string> GetChild(int n,int curIndex){
vector<string> now;
vector<string> cur;
if (curIndex == 1) {
now.push_back("1");
cur=now;
return cur;
}
cur=GetChild(n, curIndex - 1);
for (string temp : cur) {
now.push_back(temp + to_string(curIndex));
now.push_back(to_string(curIndex) + temp);
for (int j = 1; j < temp.size(); j++) {
now.push_back(temp.substr(0, j) + to_string(curIndex) + temp.substr(j));
}
}
cur = now;
return cur;
}
int main(void) {
int n,k;
cin >> n>>k;
// 获取子集
vector<string>ans = GetChild(n,n); // 存放子集的数组
//排序
sort(ans.begin(), ans.end());
// 输出子集个数
int n_ = ans.size();
cout << "子集个数:" << n_ << endl;
// 输出子集
for (auto sub_set : ans) {
cout << sub_set << endl;
}
cout<<endl;
// 输出第k个子集
cout << ans[k - 1];
return 0;
}
和上次说的一样,递归其实就是老板思维,我只需要看最后一次就行了,其他的由员工去完成。
对于当前次操作来说,一共有三类方法。
- (1)放在cur的前面
- (2)放在cue的后面
- (3)插在cur的中间(cur.size()-1个间隔)
和合法括号有点类似。
迭代:
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
vector<string> GetChild(int n) {
vector<string> cur;
cur.push_back("1");
for (int i = 2; i <= n; i++) {
vector<string> now;
for (string temp : cur) {
now.push_back(temp + to_string(i));
now.push_back(to_string(i) + temp);
for (int j = 1; j < temp.size(); j++) {
now.push_back(temp.substr(0, j) + to_string(i) + temp.substr(j));
}
}
cur = now;
}
return cur;
}
int main(void) {
int n,k;
cin >> n>>k;
// 获取子集
vector<string>ans = GetChild(n); // 存放子集的数组
//排序
sort(ans.begin(), ans.end());
// 输出子集个数
int n_ = ans.size();
cout << "子集个数:" << n_ << endl;
// 输出子集
for (auto sub_set : ans) {
cout << sub_set << endl;
}
cout<<endl;
// 输出第k个子集
cout << ans[k - 1];
return 0;
}
主要就是将递归的过程用循环代替,其余没有什么改变。
不要忘了排序,保证最后结果是字典序。
另一种迭代思路:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<vector<int>> GetChild(int n) {
int row = n;
vector<vector<int>> cur;
for (int i = 0; i < row; i++) {
vector<int> temp(n, 0);
temp[i] = 1;
cur.push_back(temp);
}
for (int i = 2; i <= n; i++) {
vector<vector<int>> now;
vector<int> temp;
for (int j = 0; j < cur.size(); j++) {
for (int k = 0; k < n; k++) {
temp = cur[j];
if (temp[k] == 0) {
temp[k] = i;
now.push_back(temp);
}
}
}
cur = now;
}
return cur;
}
int main(void) {
int n,k;
cin >> n>>k;
// 获取子集
vector<vector<int>>ans = GetChild(n); // 存放子集的数组
//排序
sort(ans.begin(), ans.end());
// 输出子集个数
int n_ = ans.size();
cout << "子集个数:" << n_ << endl;
// 输出子集
for (auto sub_set : ans) {
cout << "{ ";
for (auto elem : sub_set) {
cout << elem << " ";
}
cout << "}" << endl;
}
// 输出第k个子集
for (auto elem : ans[k - 1]) {
cout << elem;
}
return 0;
}
这种迭代法控制的是数字的位置,而不是当前数字是哪个。
通过枚举所有数字可能的位置来求排列。