含重复字符的字符串组合算法(深度优先搜索树递归实现)
2012-08-12 21:08
232 查看
今天研究了字符串的组合,和字符串的全排列不同的是,组合只考虑元素的个数而不考虑元素的排列顺序。对于不含重复字符的字符串全排列,笔者搜索到的最简单的算法如下所示,来源http://hi.baidu.com/%C2%AC%B1%C8%D0%A1%BE%AB%C1%E9/blog/item/21363d8912977fc09023d97d.html
即在串中没有相同字符时, 一个最简单的思路,设串长为n,把它和一个n位的二进制数关联起来,这个数从1跑到2^n时就跑遍了所有的字符的组合。
但是对于含重复字符时,上述方法是行不通的。笔者经过思考,对于含重复字符的字符串,可以这样遍历它的所有组合,例如acc这个字符串,这样求其组合,a,ac,acc,c,cc。也就是按照深度优先搜索其所有组合,其对应的搜索树如下图所示:
就是说,每一层节点包含字符串的长度是从1开始递增的,如果存在相同字符,则只取一次,按照深度优先搜索遍历,处理完所有字符时回溯、递归,即可求出所有组合。
为了方便判断回溯去掉的字符是否与待处理字符相同,预先对字符串进行了排序,当然如果不想排序,也可以通过容器将回溯掉的所有元素保存,再遍历是否和待处理字符相同即可。代码如下:
运行结果如下图所示:
void substr(char *str) { int i, j,n=strlen(str), m=1<<n, k; for(i=1; i<m;i++) { for(j=0,k=i; k>0; k>>=1, j++) if(k&0x01) putchar(str[j]); putchar('n');//此处应为'\n',原代码可能有错误 } }
即在串中没有相同字符时, 一个最简单的思路,设串长为n,把它和一个n位的二进制数关联起来,这个数从1跑到2^n时就跑遍了所有的字符的组合。
但是对于含重复字符时,上述方法是行不通的。笔者经过思考,对于含重复字符的字符串,可以这样遍历它的所有组合,例如acc这个字符串,这样求其组合,a,ac,acc,c,cc。也就是按照深度优先搜索其所有组合,其对应的搜索树如下图所示:
就是说,每一层节点包含字符串的长度是从1开始递增的,如果存在相同字符,则只取一次,按照深度优先搜索遍历,处理完所有字符时回溯、递归,即可求出所有组合。
为了方便判断回溯去掉的字符是否与待处理字符相同,预先对字符串进行了排序,当然如果不想排序,也可以通过容器将回溯掉的所有元素保存,再遍历是否和待处理字符相同即可。代码如下:
#include "stdafx.h" #include <stdio.h> #include <string.h> #include <iostream> #include <iomanip> #define MAXBUFFERSIZE 100 using namespace std; void zuhe(char d[],char s[], int i,int flag,int n); /* i : 输出字串的长度 flag : 当前处理字符的位置 n: 原始字符串的长度 */ void Sort(char s[]); int count2 = 0; char temp=' '; void main() { char s[MAXBUFFERSIZE]; char d[MAXBUFFERSIZE]; // input source string// cout<<"Input source string:"<<endl; gets(s); // 排序,排列并输出// Sort(s); ::temp=' '; zuhe( d, s, 0,0,strlen(s)); return; } void zuhe(char d[],char s[], int i,int flag,int n) { int j; if (flag<n) { for(j=flag ; j < n;j++ ) { if ( s[j] == ::temp ) //如果当前字符和回溯去掉的字符相同,则跳过该字符// { flag++; continue; } else { flag++; d[i] = s[j]; //把源串的一个字符赋给目的串// cout<<setw(2)<<++::count2<<":"; for (int k=0;k<=i;k++) cout<<d[k]; // 打印出其结果// cout<<endl; zuhe( d, s, i + 1,flag,n); // 递归调用// ::temp=d[i]; d[i] = ' '; // 回溯// } } } } // 冒泡排序// void Sort(char s[]) { int n = strlen(s); int i, j; char temp; for(i = 0; i < n - 1; i ++) for(j = i + 1; j < n; j ++) if(s[i] > s[j]) { temp = s[i]; s[i] = s[j]; s[j] = temp; } }
运行结果如下图所示:
相关文章推荐
- 尾单词长度、1 3 9 27 81 实现1-121任意算法、去除重复字符并排序、拼音转数字、按要求分解字符串
- 实现一个算法来判断一个字符串中的字符是否唯一(即没有重复).不能使用额外的数据结构。 (即只使用基本的数据结构)
- 寻找字符串中首次出现的不重复字符算法与c++实现
- C语言实现全排列(部分算法参考网友,可实现重复字符的组合)
- 算法学习(java实现之字符串篇)·····判断字符串是否没有重复字符
- 打印字符串的全字符组合的常用算法
- java统计字符串中重复【单个】字符的次数频次-使用字符数组实现
- 确定一个字符串的所有字符全都不同算法实现
- 实现一个算法检测字符串是否为唯一字符
- 请实现一个算法,确定一个字符串的所有字符是否全都不同。这里我们要求不允许使用额外的存储结构。
- 算法 输出字符串字符的任意组合
- java实现输出字符串中第一个出现不重复的字符详解
- 字符串操作(人民币转成大写/全角字符转半角字符/去掉字符串中重复的子字符串/过滤常见特殊字符/反过滤特殊字符/判断是不是合法手机/字符串匹配的算法)
- C++实现删除字符串中所有重复出现的字符
- 基本字符串压缩 利用字符重复出现的次数,编写一个方法,实现基本的字符串压缩功能。比如,字符串“aabcccccaaa”经压缩会变成“a2b1c5a3”。若压缩后的字符串没有变短,则返回原先的字符串。
- JavaScript实现查找字符串中第一个不重复的字符
- 字符串查找第一个不重复的字符的实现
- 请用Java实现一个算法:由a-z、0-9组成3位的字符密码,并打印所有可能的密码组合。
- 经典算法面试题目-设计算法移除字符串中重复的字符(1.3)
- 对于一个字符串,请设计一个高效算法,找到第一次重复出现的字符。 给定一个字符串(不一定全为字母)A及它的长度n。请返回第一个重复出现的字符。保证字符串中有重复字符,字符串的长度小于等于500。