标签:
题目描述:输入一个字符串,打印出该字符串中字符的所有排列,例如输入"abc",输出"abc","acb","bac","bca","cab","cba"
解法一:递归实现
类似于图的深度遍历搜索求全路径的算法,每次交换两个数,并输出,按照递归的方法,如求abcd的全排序,1:先求abcd后面的bcd全排列(同样先求b后面cd的全排列,然后b与后面的元素依次交换);2:求ab交换后的bacd后面的acd全排列(同样先求a后面cd的全排列,然后a与后面的元素依次交换);3:先ac交换后的cbad后面的bad全排列(同样先求b后面ad的全排列,然后b与后面的元素依次交换);4:求ad交换后的dbca后面的bca全排列(同样先求b后面ca的全排列,然后b与后面的元素依次交换)。
时间复杂度为O(n!)。
#include <iostream>
#include <string>
using namespace std;
void AllPermutation(string &str, int start, int end){
if(start == end){
cout << str << endl;
return;
}
int i;
for(i = start; i <= end; i++){
swap(str[start], str[i]);
AllPermutation(str, start+1, end);
swap(str[start], str[i]);
}
}
int main(){
string str;
while(cin >> str){
if(str.size() == 0)//字符串长度为0直接返回
break;
AllPermutation(str, 0, str.size()-1);
}
return 0;
}解法二:按字典序排列#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
void AllPermutation(char *str, int num){
int i, j;
//输出当前序列
for(i = 0; i < num; ++i)
cout << str[i];
cout << endl;
//寻找下一字典序序列
//寻找i
for(i = num-2; i >= 0; --i)
if(str[i] < str[i+1])
break;
//递归结束条件:跳出递归,说明此时str中字符串完全降序
if(i < 0)
return;
//寻找j
for(j = num-1; j >= i+1; --j)
if(str[j] > str[i])
break;
//交换i,j所对应元素,并将下标i后面的字符串逆置
swap(str[i], str[j]);
reverse(str+i+1, str+num); //和sort函数一样为标准函数模板调用
AllPermutation(str, num);
}
int main(){
char str[110];
while(cin >> str){
int num = 0;
while(str[num]) ++num; //注意别写成while(str[num++]);
if(num == 0)//字符串长度为0直接返回
break;
sort(str, str+num);//注意要先排序
AllPermutation(str, num);
}
return 0;
}
举一反三:
1,字典序的所有排列:已知输入字符串的各个字符是不同的,按照字典序输出它的所有组合。如输入aa,则输出aa,ab,ba,bb。#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int j;
char str[110], ans[110];
void Access(int cur, int num){
while(ans[cur] == str[num-1]){
ans[cur] = str[0];
--cur;
}
int i;
for(i = 0; i < num; i++)
if(ans[cur] == str[i])
break;
ans[cur] = str[i+1];
j = 0;
}
void AllPermutation(int num){
int i;
//先输出当前字符串
for(i = 0; i < num; ++i)
cout << ans[i];
cout << endl;
//临界条件
int flag = 0;
for(i = 0; i < num; ++i)
if(ans[i] != str[num-1])
flag = 1;
if(!flag)
return;
//交换ans[num-1],str[j]
if(ans[num-1] < str[num-1])
ans[num-1] = str[j];
else
Access(num-1, num);
++j;
if(j == num)
j = 0;
AllPermutation(num);
}
int main(){
while(cin >> str){
int num = 0;
while(str[num]) ++num; //注意别写成while(str[num++]);
if(num == 0)//字符串长度为0直接返回
break;
sort(str, str+num);
int i;
for(i = 0; i < num; ++i)
ans[i] = str[0];
j = 1;
AllPermutation(num);
}
return 0;
}
2,字符的所有组合:如输入“abc”,输出"a","b","c","ab","ac","bc","abc"。
解法一:我们要分开求长度为1的组合,长度为2的组合,...,长度为n的组合。先考虑其中一种情况,如长度为k时的情况,这个时候我们又可以分为两种情况进行考虑:#include <iostream>
#include <vector>
using namespace std;
vector<char> result;
int num;
void Combination(char *str, int pos, int k){
if(pos == num && k != 0)//有两种返回条件:临界条件
return;
if(k == 0){
vector<char>::iterator iter = result.begin();
for( ; iter < result.end(); ++iter)
cout << *iter;
cout << endl;
return; //此时也需返回,否则str[pos]=str[num]可能未定义
}
result.push_back(str[pos]);
Combination(str, pos+1, k-1); //从字符串下标pos+1起的后面选择剩余的k-1个字符
result.pop_back();
Combination(str, pos+1, k); //从字符串下标pos+1起的后面选择剩余的k个字符
}
int main(){
char str[110];
while(cin >> str){
num = 0;
while(str[num]) num++;
if(num == 0) break;
int i;
for(i = 1; i <= num; ++i)
Combination(str, 0, i);
}
return 0;
}解法二:以abc为例,若三个字符a,b,c分别对应一个二进制数的第0,1,2位,则可用二进制001代表"a",二进制010代表"b",二进制011代表"ab",二进制100代表"c",...111代表"abc",换句话说,1~7中的任何一个数字正好对应原字符串的一个组合。#include <iostream>
#include <cmath>
using namespace std;
void Combination(char *str, int n){
int num = (int)pow(2.0, n) - 1;
int i, j;
for(i = 1; i <= num; ++i){
for(j = 0; j < n; j++){
if(i & (1 << j)) //注意:&是按位与,&&是逻辑与(整体逻辑判断)
cout << str[j];
}
cout << endl;
}
}
int main(){
char str[110];
while(cin >> str){
int n = strlen(str);
Combination(str, n);
}
return 0;
}
相关题目:
1,求正方体对面顶点和相等数组:输入一个含有8个数字的数组分别置于正方体的8个顶点上,使得正方体三组相对的面上的4个顶点和都相等,即:#include <iostream>
using namespace std;
bool IsEqual(int nums[]){
int sum1 = nums[0] + nums[1] + nums[2] + nums[3];
int sum2 = nums[4] + nums[5] + nums[6] + nums[7];
int sum3 = nums[0] + nums[2] + nums[4] + nums[6];
int sum4 = nums[1] + nums[3] + nums[5] + nums[7];
int sum5 = nums[0] + nums[1] + nums[4] + nums[5];
int sum6 = nums[2] + nums[3] + nums[6] + nums[7];
if(sum1 == sum2 && sum3 == sum4 && sum5 == sum6)
return true;
else
return false;
}
void AllPermutation(int *nums, int start, int end){
if(start == end){
if(IsEqual(nums)){
int i;
for(i = 0; i <= end; ++i)
cout << nums[i] << " ";
cout << endl;
}
return;
}
int i;
for(i = start; i <= end; i++){
swap(nums[start], nums[i]);
AllPermutation(nums, start+1, end);
swap(nums[start], nums[i]);
}
}
int main(){
int nums[110], n;
while(cin >> nums[0]){ //输入8个数表示正方体的8个顶点
int i;
for(i = 1; i <= 7; ++i)
cin >> nums[i];
AllPermutation(nums, 0, 7);
}
return 0;
}2,八皇后问题#include <iostream>
#include <string>
using namespace std;
bool IsNoDiag(int *nums){
int i, j;
for(int i = 0; i < 8; i++){
for(int j = i + 1; j < 8; j++){
if(i - j == nums[i] - nums[j] || i - j == nums[j] - nums[i])
return false;
}
}
return true;;
}
void AllPermutation(int *nums, int start, int end){
//临界条件
if(start == end){
if(IsNoDiag(nums)){
int i;
for(i = 0; i <= end; ++i)
cout << "(" << i << ", " << nums[i] << ")" << " ";
cout << endl;
}
return;
}
//下次递归
int i;
for(i = start; i <= end; ++i){
swap(nums[start], nums[i]);
AllPermutation(nums, start+1, end);
swap(nums[start], nums[i]);
}
}
int main(){
int nums[8] = {0, 1, 2, 3, 4, 5, 6, 7};
AllPermutation(nums, 0, 7);
}
《编程之法》1.3字符串的全排列,组合,重复排列,八皇后问题
标签:
原文地址:http://blog.csdn.net/qibofang/article/details/51920444