字符串的去重排列
从第一个数字起每个数分别与它后面非重复出现的数字交换。
#include<iostream>
using namespace std;
#include<assert.h>
//在[nBegin,nEnd-1]区间中是否有字符与下标为pEnd的字符相等
bool IsSwap(char* pBegin , char* pEnd)
{
char *p;
for(p = pBegin ; p < pEnd ; p++)
{
if(*p == *pEnd)
return false;
}
return true;
}
void Permutation(char* pStr , char *pBegin)
{
assert(pStr);
if(*pBegin == '\0')
{
static int num = 1; //局部静态变量,用来统计全排列的个数
printf("第%d个排列\t%s\n",num++,pStr);
}
else
{
for(char *pCh = pBegin; *pCh != '\0'; pCh++) //第pBegin个数分别与它后面的数字交换就能得到新的排列
{
if(IsSwap(pBegin , pCh))
{
swap(*pBegin , *pCh);
Permutation(pStr , pBegin + 1);
swap(*pBegin , *pCh);
}
}
}
}
int main(void)
{
char str[] = "baa";
Permutation(str , str);
return 0;
}
字符的所有组合
http://www.wengweitao.com/qiu-zi-fu-de-suo-you-zu-he-he-suo-you-pai-lie.html
题目描述: 输入三个字符a、b、c,组合有:a, b, c , ab, ac, bc, abc。
题目分析: 字符串的组合与排列不同,当交换字符串中的两个字符时,虽然能得到两个不同的排列,但却是一个组合。比如ab和ba是两个排列,但是一个组合。 假设输入n个字符,则这n个字符能构成长度为1的组合、长度为2的组合、……、长度为n的组合。在求n个字符组成长度为m的组合的时候,与字符串全排列的求解思想类似,我们可以把这n个字符分为两个部分:第一个字符和剩余的其他所有的n-1个字符。这个时候可以分为两种情况:
如果组合里包含第一个字符,则从所有剩余n-1个字符里选取m-1个字符;
如果组合里不包含第一个字符,则下一步在剩余的n-1个字符选取m个字符。
也就是说,我们可以把求n个字符组成长度为m的组合问题分解成两个子问题,分别求n-1个字符串长度为m-1的组合,以及求n-1个字符的长度为m的组合。这两个子问题都可以用递归方式解决。
代码实现:
void Combination(char* str)
{
if(str == NULL)
return;
int length = strlen(str);
vector<char> result;
for(int i = 1; i <= length; i++)
CombinationCore(str, i, result);
}
void CombinationCore(char* str, int number, vector<char>& result) {
if(number == 0)
{
vector<char>::iterator iter = result.begin();
for(; iter != result.end(); ++iter)
cout << *iter;
cout << endl;
return;
}
if(*str == '\0')
return;
// n-1个字符串中,选取number-1个字符
result.push_back(*str);
CombinationCore(str+1, number-1, result);
// n-1个字符串中,选取number个字符
result.pop_back();
CombinationCore(str+1, number, result);
}
另外,还有另一种思路可以求解——基于位图。 假设一共有n个字符,则可能的组合结果共有2^n-1种。 以输入3个字符a、b、c为例: 3个字符,可以用3个位来表示,从右到左的每一位分别用来代表a、b、c,该位为1表示取该元素,该位为0表示不取该元素。例如如组合a表示为001,组合b表示为010,组合ac表示为101,组合abc表示为111,而000是没有意义的,所以总共的结果就是2^n-1种。
因此,我们可以从值1开始循环到2^n-1,输出每个值所代表的组合即可。
void Combination2(char *str) {
if(str == NULL)
return;
int i,j,temp;
int length = strlen(str);
int n = 1 << length; //n为2^n-1(111)
for(i = 1; i < n; i++) { // 依次输出值1到2^n-1所代表值的组合
for(j = 0; j < length; j++) { // 判断第j位是否为1
temp = i;
if(temp & (1<<j))
cout << *(str+j);
}
cout << endl;
}
}
相关题目
求正方体对面顶点和相等数组
问题描述: 输入一个含有8个数字的数组,判断有没有可能把这8个数字分别放到正方体的8个顶点上,使得正方体上三组相对的面上的4个顶点的和都相等。
问题分析: 我们可以求出这8个数字的全排列,然后从中找出是否符合题目条件的排列。即先得到a1、a2、a3、a4、a5、a6、a7和a8这8个数字的所有排列,然后判断有没有某个排列符合条件:
a1+a2+a3+a4=a5+a6+a7+a8
a1+a3+a5+a7=a2+a4+a6+a8
a1+a2+a5+a6=a3+a4+a7+a8
代码
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 swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
void CubicEqualExist(int *numbers, int* begin) {
if(numbers == NULL || begin == NULL)
return;
if(*begin == '\0') {
bool result = IsEqual(numbers);
if(result) {
for(int i = 0; i < length; i++)
cout << numbers[i];
cout << endl;
}
}
else {
for(int* i = begin; *i != '\0'; ++i) {
swap(begin, i);
CubicEqualExist(numbers, begin+1);
swap(begin, i);
}
}
}
八皇后问题
问题描述: 在8 X 8的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后不得处于同一行,同一列或者同一对角线上,求出所有符合条件的摆法。
问题分析: 任意两个皇后不得处于同一行,由此可得每个皇后都单独占据一行。我们可以定义一个数组ColumnIndex[8],其中ColumnIndex[i]表示处在第i行的皇后在ColumnIndex[i]列,例如ColumnIndex1 = 3 表示处在第1行的皇后在第3列上。 接下来,分别用0~7这8个数字对ColumnIndex进行初始化。注意,此时所有的皇后不同行也不同列。 因此,我们只需要对ColumnIndex数组进行全排列,判断每一个排列所对应的8个皇后的位置是否在对角线上,也就是对于数组下表i,j,是不是 i-j==ColumnIndex[i]-ColumnIndex[j],或者 j-i=ColumnIndex[i]-ColumnIndex[j]。
代码实现:
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
bool IsRight(int* ColumnIndex, int length) {
bool result = true;
for(int i = 0; i < length; i++)
for(int j = i + 1; j < length; j++)
if(i - j == ColumnIndex[i] - ColumnIndex[j] || i - j == ColumnIndex[j] - ColumnIndex[i]) {
result = false;
break;
}
return result;
}
void Permutation(int* ColumnIndex, int* pBegin,int length) {
if(*pBegin=='\0') {
bool result = IsRight(ColumnIndex, length);
if(result) {
for(int i = 0; i < length; i++)
cout << ColumnIndex[i];
cout << endl;
}
}
for(int *i = pBegin; *i != '\0'; i++) {
swap(pBegin,i);
Permutation(ColumnIndex, begin+1);
swap(pBegin,i);
}
}
void EightQueens() {
int ColumnIndex[8] = {0, 1, 2, 3, 4, 5, 6, 7};
Permutation(ColumnIndex, ColumnIndex,8);
}