• 剑指offer--字符串全排列/全组合


    题目:

    输入一个字符串,打印出该字符串中字符的所有排列。

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

    思路:

    把一个字符串看成两部分组成:第一部分为第一个字符,第二部分为后面的所有字符。

    求整个字符串的排列,可以看出两步:首先求所有可能出现在第一个位置的字符,即把第一个字符和后面的所有字符交换;然后固定第一个字符,求后面所有字符的排序。此时仍把后面的字符看成两部分,第一个字符和后面的字符,然后重复上述步骤。(递归)

    在后面的在线测试中,要求输入字符串可能有重复的字符,输出按照字典顺序。

    类似题目:

     1、输入一个含有8个数字的数组,判断有么有可能把这8个数字分别放到正方体的8个顶点上,使得正方体上三组相对的面上的4个顶点的和相等。

     思路:相当于求出8个数字的全排列,判断有没有一个排列符合题目给定的条件,即三组对面上顶点的和相等。

    2、N皇后问题:在8 X 8的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后不得处于同一行,同一列或者同意对角线上,求出所有符合条件的摆法。

    思路:由于8个皇后不能处在同一行,那么肯定每个皇后占据一行,这样可以定义一个数组A[8],数组中第i个数字,即A[i]表示位于第i行的皇后的列号。先把数组A[8]分别用0-7初始化,接下来对该数组做全排列,由于我们用0-7这7个不同的数字初始化数组,因此任意两个皇后肯定也不同列,那么我们只需要判断每个排列对应的8个皇后中是否有任意两个在同一对角线上即可,即对于数组的两个下标i和j,如果i-j==A[i]-A[j]或i-j==A[j]-A[i],则认为有两个元素位于了同一个对角线上,则该排列不符合条件。 

    //字符串的全排列
    //1. 把第一个字符与后面的所有字符进行交换。
    //2. 固定第一个字符,将第二个字符与后面字符进行交换。
    //3. 重复2操作,第一字符后移,将其交换
    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    //去掉重复的全排列
    //在[nBegin,nEnd)区间中是否有字符与下标为pEnd的字符相等  
    bool IsSwap(char* pBegin, char* pEnd)
    {
        char *p;
        for (p = pBegin; p < pEnd; p++)
        {
            if (*p == *pEnd)
                return false;
        }
        return true;
    }
    
    void sawp(char* s1, char* s2)
    {
        char temp = *s1;
        *s1 = *s2;
        *s2 = temp;
    }
    void Permutation(char* pstr, char* pBegin)
    {
        if (*pBegin == '') {
            static int num = 0;
            num++;
            cout << "" << num << "个全排列" << pstr << endl;
            //printf("%s
    ", pstr);
        }
        else {
            for (char* pCh = pBegin; *pCh != ''; ++pCh)
            {
                if (IsSwap(pBegin, pCh)) {
                sawp(pBegin, pCh);
                Permutation(pstr, pBegin + 1);
                sawp(pBegin, pCh);
                }
            }
        }
    }
    
    void permutation(char *str)
    {
        if (str == NULL)
        {
            return;
        }
        Permutation(str, str);
    }
    
    int main()
    {
        char a[64];
        int  n;
        cin >> a;
        n = strlen(a) - 1;
        permutation(a);
        system("pause");
        return 0;
    }

    全组合

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

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

    假设我们想在长度为n的字符串中求m个字符的组合。我们先从头扫描字符串的第一个字符。针对第一个字符,我们有两种选择:第一是把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选取m-1个字符;第二是不把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选择m个字符。这两种选择都很容易用递归实现。下面是这种思路的参考代码:

    //全组合
    #include<iostream>  
    #include<vector>  
    #include<cstring>  
    using namespace std;
    #include<assert.h>  
    
    void Combination(char *string, int number, vector<char> &result);
    
    void Combination(char *string)
    {
        assert(string != NULL);
        vector<char> result;
        int i, length = strlen(string);
        for (i = 1; i <= length; ++i)           //用for循环分开字符组合
            Combination(string, i, result);
    }
    
    void Combination(char *string, int number, vector<char> &result)
    {
        assert(string != NULL);
        if (number == 0)
        {
            static int num = 1;
            printf("第%d个组合	", num++);
    
            vector<char>::iterator iter = result.begin();
            for (; iter != result.end(); ++iter)
                printf("%c", *iter);
            printf("
    ");
            return;
        }
        if (*string == '')
            return;
        result.push_back(*string);
        Combination(string + 1, number - 1, result);
        result.pop_back();
        Combination(string + 1, number, result);
    }
    
    int main(void)
    {
        char str[] = "abc";
        Combination(str);
        system("pause");
        return 0;
    }

    转载请说明出处!
  • 相关阅读:
    OpenCV --- 2.4.8组件结构全解析
    综合博客
    设计模式之适配器模式
    android 面试题
    ANDROID 中设计模式的采用--结构型模式
    技术前线
    八大排序算法
    android 面试题
    Android控件——ViewPager
    Bugly
  • 原文地址:https://www.cnblogs.com/zengshangzhi/p/9305534.html
Copyright © 2020-2023  润新知