字符串(集合)的全排列和子集
来源:互联网 发布:局域网问卷调查软件 编辑:程序博客网 时间:2024/05/20 07:58
<p>
学过回溯法和分支限界法之后,觉得对递归有了很好地理解,但是真让写集合(字符串)的子集和全排列的code时,一时又感觉手足无措。
</p>
<p>
<br />
</p>
<p>
全排列
</p>
<p>
基本的想法:将字符串或集合的第一个元素固定,然后让其加上剩余串集合的子集。然后从第二位开始,跟第一个字符交换,然后再固定一个字符,加上剩余串的子集。交换的想法非常巧妙,然后利用递归的思想。
</p>
<p>
基本的code如下:
</p>
<p>
void swap(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
}
/*先以某个字符打头,计算剩余所有字符的子集,然后在*/
void total_arrange(int *data, int cur, int ed)
{
if(cur >= ed){
for(int i = 0; i < ed; ++i){
cout<<data[i]<<" ";
}
cout<<endl;
}
else{
for(int i = cur; i < ed; ++i){
swap(&data[cur], &data[i]);//以data[i]打头,求剩余的子串的子集
total_arrange(data, cur + 1, ed);
swap(&data[cur], &data[i]);//以data[i]打头,求剩余的子串的子集
}
}
}
<br />
</p>
<p>
集合的子集基本的思想:可以从二项分布的思想去理解问题,n个特征,每个特征只有两种选择0-1,选择与否。从递归树的角度来看,是一个具有n+1层的完全二叉树,每个结点的分叉都有两种可能,0-1,即加入or不加入,这样每个叶子结点(共有2^n个叶子结点)都可以表示成长度为长度为n的0-1串。
</p>
<p>
具体的实现如下:
</p>
<p>
/*想象递归树,左边是加入,右边不加入,树的深度就是字符串的长度,
每个叶子结点就是一个0-1串,0代表不加入,1代表加入*/
void subset(const string str, bool *flag, int level)
{
if(level >= str.length()){//到达底层
for(int i = 0; i < str.length(); ++i){
if(flag[i] == true){
cout<<str[i];
}
}
cout<<endl;
}
else{
for(int i = level; i <= str.length(); ++i){//循环的结束条件要加等号,否则只打印部分结果
flag[i] = false;//选择分支
subset(str, flag, i + 1);//深度遍历
flag[i] = true;//回溯到上一层
}
}
}<br />
</p>
<p>
递归进行过程中,需要建立一个递归栈,存储程序跳转时的位置,如果递归层数一深,很容易出现栈溢出。根据上述的想法,我们可以用一个整数的每一位对应字符串中的每一位,0表示不加入,1表示加入。然后遍历一下这个整数的范围。
</p>
<p>
具体的实现如下:
</p>
<p>
/*一个字符串加入与否,可以使用0-1模拟*/
void subset1(const string str)
{
unsigned int len = str.length();
unsigned int slen = (1 << len) - 1;
for(unsigned int i = 0; i <= slen; ++i){
for(unsigned int j = 0; j < len; ++j){
if(i & (0x01 << j)){
cout<<str[j];
}
}
cout<<endl;
}
}
<br />
</p>
<p>
当然这样的做法是有一定问题的,unsigned int最多表示32位的整数,这样输入字符串的长度不能超过32,当然可以改成long long类型,最多也只能达到64位。不过可以自己定义进位表示,定义两个变量,一个表示另一个的高位,如果地位溢出,高位在操作。
</p>
学过回溯法和分支限界法之后,觉得对递归有了很好地理解,但是真让写集合(字符串)的子集和全排列的code时,一时又感觉手足无措。
</p>
<p>
<br />
</p>
<p>
全排列
</p>
<p>
基本的想法:将字符串或集合的第一个元素固定,然后让其加上剩余串集合的子集。然后从第二位开始,跟第一个字符交换,然后再固定一个字符,加上剩余串的子集。交换的想法非常巧妙,然后利用递归的思想。
</p>
<p>
基本的code如下:
</p>
<p>
void swap(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
}
/*先以某个字符打头,计算剩余所有字符的子集,然后在*/
void total_arrange(int *data, int cur, int ed)
{
if(cur >= ed){
for(int i = 0; i < ed; ++i){
cout<<data[i]<<" ";
}
cout<<endl;
}
else{
for(int i = cur; i < ed; ++i){
swap(&data[cur], &data[i]);//以data[i]打头,求剩余的子串的子集
total_arrange(data, cur + 1, ed);
swap(&data[cur], &data[i]);//以data[i]打头,求剩余的子串的子集
}
}
}
<br />
</p>
<p>
集合的子集基本的思想:可以从二项分布的思想去理解问题,n个特征,每个特征只有两种选择0-1,选择与否。从递归树的角度来看,是一个具有n+1层的完全二叉树,每个结点的分叉都有两种可能,0-1,即加入or不加入,这样每个叶子结点(共有2^n个叶子结点)都可以表示成长度为长度为n的0-1串。
</p>
<p>
具体的实现如下:
</p>
<p>
/*想象递归树,左边是加入,右边不加入,树的深度就是字符串的长度,
每个叶子结点就是一个0-1串,0代表不加入,1代表加入*/
void subset(const string str, bool *flag, int level)
{
if(level >= str.length()){//到达底层
for(int i = 0; i < str.length(); ++i){
if(flag[i] == true){
cout<<str[i];
}
}
cout<<endl;
}
else{
for(int i = level; i <= str.length(); ++i){//循环的结束条件要加等号,否则只打印部分结果
flag[i] = false;//选择分支
subset(str, flag, i + 1);//深度遍历
flag[i] = true;//回溯到上一层
}
}
}<br />
</p>
<p>
递归进行过程中,需要建立一个递归栈,存储程序跳转时的位置,如果递归层数一深,很容易出现栈溢出。根据上述的想法,我们可以用一个整数的每一位对应字符串中的每一位,0表示不加入,1表示加入。然后遍历一下这个整数的范围。
</p>
<p>
具体的实现如下:
</p>
<p>
/*一个字符串加入与否,可以使用0-1模拟*/
void subset1(const string str)
{
unsigned int len = str.length();
unsigned int slen = (1 << len) - 1;
for(unsigned int i = 0; i <= slen; ++i){
for(unsigned int j = 0; j < len; ++j){
if(i & (0x01 << j)){
cout<<str[j];
}
}
cout<<endl;
}
}
<br />
</p>
<p>
当然这样的做法是有一定问题的,unsigned int最多表示32位的整数,这样输入字符串的长度不能超过32,当然可以改成long long类型,最多也只能达到64位。不过可以自己定义进位表示,定义两个变量,一个表示另一个的高位,如果地位溢出,高位在操作。
</p>
0 0
- 字符串(集合)的全排列和子集
- 求集合的子集、全排列总结
- 全排列以及集合的子集
- 求集合子集,和全排列的递归算法实现(c++,Dev C++调试通过)
- 子集(全排列的延伸)
- 子集和全排列问题
- 回溯法 求集合全排列、子集
- 代码--C++全排列和子集的实现
- 【C语言】递归实现元素的全排列和子集
- 字符串的全排列和全组合
- 求数组的全部子集 && 全排列
- 集合的全排列
- 集合元素的排列与子集
- 全排列、子集
- 剑指offer 面试题28 字符串的排列与集合的所有子集
- 字符串的全排列和组合算法
- 字符串的全排列和组合算法
- 字符串的全排列和组合算法
- DG下手工处理v$archive_gap方法
- invalid use of non-static member function ‘void Date::init(int, int, int)’
- KVC-键值编码
- linux文件链接
- 二分图
- 字符串(集合)的全排列和子集
- 下载好一个android软件之后,怎样自动提示安装?
- Hadoop状态转移图生成
- Struts2框架_03
- 利用批处理启动cygwin到指定的目录.
- Mac OS X terminal命令收集
- mui update.json 中文乱码
- PHP--导出excel乱码问题的解决方案
- DG日志不应用,GAP,主备切换解决思路与办法