求字符串所有组合

本文介绍字符串的排列与组合算法,包括去重排列、字符组合、正方体顶点和相等问题及八皇后问题的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

字符串的去重排列
从第一个数字起每个数分别与它后面非重复出现的数字交换。

#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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值