剑指offer 38 字符串的排列

字符的全排列

题目描述

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

输入描述:

输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

思路:

1、把字符串分为两部分:一部分是字符串的第一个字符;另一部分是第一个字符以后的所有字符,称为剩余字符,接下来递归求剩余字符的全排列,直到遇到‘\0’.

2、用第一个字符和后面的字符逐个交换,再执行1,直到遇到‘\0’

递归代码:

class Solution {
public:
    vector<string> Permutation(string str) {
        vector<string>st;
        if(str.size()==0)
            return st;
        Permutation(st,str,0);
        sort(st.begin(),st.end());
        return st;
    }
     void Permutation(vector<string> &array, string str, int begin)//遍历第begin位的所有可能性
    {
        if(begin==str.size()-1)
            array.push_back(str);//只剩一个元素未排列时
        for(int i=begin; i<str.size();i++)
        {
           if(i!=begin && str[i]==str[begin])//有重复字符时,跳过
            continue;
            swap(str[i], str[begin]);//当i==begin时,也要遍历其后面的所有字符;
                                    //当i!=begin时,先交换,使第begin位取到不同的可能字符,再遍历后面的字符
            Permutation(array, str, begin+1);//遍历其后面的所有字符;
             
            swap(str[i], str[begin]);//为了防止重复的情况,还需要将begin处的元素重新换回来
        }
    }

字符的组合

题目:输入一个字符串,输出该字符串中字符的所有组合。举个例子,如果输入abc,它的组合有a、b、c、ab、ac、bc、abc。

上面我们详细讨论了如何用递归的思路求字符串的排列。同样,本题也可以用递归的思路来求字符串的组合。

思路:同样是用递归求解。可以考虑求长度为n的字符串中m个字符的组合,设为C(n,m)。原问题的解即为C(n, 1), C(n, 2),...C(n, n)的总和。对于求C(n, m),从第一个字符开始扫描,每个字符有两种情况,要么被选中,要么不被选中,如果被选中,递归求解C(n-1, m-1)。如果未被选中,递归求解C(n-1, m)。不管哪种方式,n的值都会减少,递归的终止条件n=0或m=0。

//函数功能 : 从一个字符串中选m个元素  
//函数参数 : pStr为字符串, m为选的元素个数, result为选中的  
//返回值 :   无  
void Combination_m(char *pStr, int m, vector<char> &result)  
{  
    if(pStr == NULL || (*pStr == '\0'&& m != 0))  
        return;  
    if(m == 0) //递归终止条件  
    {  
        for(unsigned i = 0; i < result.size(); i++)  
            cout<<result[i];  
        cout<<endl;  
        return;  
    }  
    //选择这个元素  
    result.push_back(*pStr);  
    Combination_m(pStr + 1, m - 1, result);  
    result.pop_back();  
    //不选择这个元素  
    Combination_m(pStr + 1, m, result);  
}  
//函数功能 : 求一个字符串的组合  
//函数参数 : pStr为字符串  
//返回值 :   无  
void Combination(char *pStr)  
{  
    if(pStr == NULL || *pStr == '\0')  
        return;  
    int number = strlen(pStr);  
    for(int i = 1; i <= number; i++)  
    {  
        vector<char> result;  
        Combination_m(pStr, i, result);  
    }  
}  

字符串全排列扩展----八皇后问题
    题目:在8×8的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后不得处在同一行、同一列或者同一对角斜线上。下图中的每个黑色格子表示一个皇后,这就是一种符合条件的摆放方法。请求出总共有多少种摆法。


扫描二维码关注公众号,回复: 1647100 查看本文章

    这就是有名的八皇后问题。解决这个问题通常需要用递归,而递归对编程能力的要求比较高。因此有不少面试官青睐这个题目,用来考察应聘者的分析复杂问题的能力以及编程的能力。

由于八个皇后的任意两个不能处在同一行,那么这肯定是每一个皇后占据一行。于是我们可以定义一个数组ColumnIndex[8],数组中第i个数字表示位于第i行的皇后的列号。先把ColumnIndex的八个数字分别用0-7初始化,接下来我们要做的事情就是对数组ColumnIndex做全排列。由于我们是用不同的数字初始化数组中的数字,因此任意两个皇后肯定不同列。我们只需要判断得到的每一个排列对应的八个皇后是不是在同一对角斜线上,也就是数组的两个下标i和j,是不是i-j==ColumnIndex[i]-Column[j]或者j-i==ColumnIndex[i]-ColumnIndex[j]。

关于排列的详细讨论,详见上面的讲解。
接下来就是写代码了。思路想清楚之后,编码并不是很难的事情。下面是一段参考代码:

#include<iostream>  
using namespace std;  
  
int g_number = 0;  
void Permutation(int * , int  , int );  
void Print(int * , int );  
  
void EightQueen( )  
{  
    const int queens = 8;  
    int ColumnIndex[queens];  
    for(int i = 0 ; i < queens ; ++i)  
        ColumnIndex[i] = i;    //初始化  
    Permutation(ColumnIndex , queens , 0);  
}  
  
bool Check(int ColumnIndex[] , int length)  
{  
    int i,j;  
    for(i = 0 ; i < length; ++i)  
    {  
        for(j = i + 1 ; j < length; ++j)  
        {  
            if( i - j == ColumnIndex[i] - ColumnIndex[j] || j - i == ColumnIndex[i] - ColumnIndex[j])   //在正、副对角线上  
                return false;  
        }  
    }  
    return true;  
}  
void Permutation(int ColumnIndex[] , int length , int index)  
{  
    if(index == length)  
    {  
        if( Check(ColumnIndex , length) )   //检测棋盘当前的状态是否合法  
        {  
            ++g_number;  
            Print(ColumnIndex , length);  
        }  
    }  
    else  
    {  
        for(int i = index ; i < length; ++i)   //全排列  
        {  
            swap(ColumnIndex[index] , ColumnIndex[i]);  
            Permutation(ColumnIndex , length , index + 1);  
            swap(ColumnIndex[index] , ColumnIndex[i]);  
        }  
    }  
}  
  
void Print(int ColumnIndex[] , int length)  
{  
    printf("%d\n",g_number);  
    for(int i = 0 ; i < length; ++i)  
        printf("%d ",ColumnIndex[i]);  
    printf("\n");  
}  
  
int main(void)  
{  
    EightQueen();  
    return 0;  
}  
转载:http://zhedahht.blog.163.co
题目:输入两个整数n和m,从数列1,2,3...n中随意取几个数,使其和等于m,要求列出所有的组合。

[cpp] view plain copy
#include <iostream>  
#include <list>  
using namespace std;  
list<int> list1;  
void find_factor(int sum,int n)  
{  
    //递归出口  
    if(n<=0||sum<=0)  
        return;  
    //输出找到的数  
    if(sum==n)  
    {  
        list1.reverse();  
        for(list<int>::iterator iter=list1.begin();iter!=list1.end();iter++)  
            cout<<*iter<<"+";  
        cout<<n<<endl;  
        list1.reverse();  
    }  
    list1.push_front(n);  
    find_factor(sum-n,n-1);//n放在里面  
    list1.pop_front();  
    find_factor(sum,n-1);//n不放在里面  
}  
  
int main(void)  
{  
    int sum,n;  
    cin>>sum>>n;  
    cout<<"所有可能的序列,如下:"<<endl;  
    find_factor(sum,n);  
    return 0;  
}  

猜你喜欢

转载自blog.csdn.net/weixin_41413441/article/details/80645777