字符串排列组合问题

一.全排列无重复字符

#include<stdio.h>
#include<string.h>

char buf[1024];

void func(int index);
void swap(int index1,int index2);
int main()
{
    memset(buf,0,sizeof(buf));
    sprintf(buf,"abc");
    func(0);
    return 0;
}

void func(int index)
{
    if(index == strlen(buf)-1)
    {
        printf("%s\n",buf);
    }
    else
    {
        for(int i=index;i<strlen(buf);i++)//注意这里i是从index开始的,这里做的决策是每个剩余的字符都可能做index位
        {
            swap(index,i);
            func(index+1);
            swap(index,i);
        }
    }
}
void swap(int index1,int index2)
{
    char temp = buf[index1];
    buf[index1] = buf[index2];
    buf[index2] = temp;
}

二.全排列有重复字符

由于全排列就是从第一个数字起每个数分别与它后面的数字交换。我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这二个数就不交换了。如122,第一个数与后面交换得212、221。然后122中第二数就不用与第三个数交换了,但对212,它第二个数与第三个数是不相同的,交换之后得到221。与由122中第一个数与第三个数交换所得的221重复了。所以这个方法不行。

换种思维,对122,第一个数1与第二个数2交换得到212,然后考虑第一个数1与第三个数2交换,此时由于第三个数等于第二个数,所以第一个数不再与第三个数交换。再考虑212,它的第二个数与第三个数交换可以得到解决221。此时全排列生成完毕。
这样我们也得到了在全排列中去掉重复的规则——去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换。

#include<stdio.h>
#include<string.h>

char buf[1024];

void func(int index);
void swap(int index1,int index2);
bool isSwap(int index1,int index2);
int main()
{
    memset(buf,0,sizeof(buf));
    sprintf(buf,"abb");
    func(0);
    return 0;
}

void func(int index)
{
    if(index == strlen(buf)-1)
    {
        printf("%s\n",buf);
    }
    else
    {
        for(int i=index;i<strlen(buf);i++)
        {
            if(isSwap(index,i))
            {
                swap(index,i);
                func(index+1);
                swap(index,i);
            }
        }
    }
}
void swap(int index1,int index2)
{
    char temp = buf[index1];
    buf[index1] = buf[index2];
    buf[index2] = temp;
}
bool isSwap(int index1,int index2)//判断前面是否已经有与buf[index2]相同的字符
{
    if(index1 == index2)
        return true;
    else
    {
        for(int i=index1;i<index2;i++)
        {
            if(buf[i] == buf[index2])
            {
                return false;
            }
        }
        return true;
    }
}

三.从m个字符中取n个组合,如abc的组合有a、bc、ab、ac、bc、abc

方法一:利用位运算来实现求组合,例如:对于字符序列“abc”,让其与1-7的二进制相与,每次输出对应二进制为1的那几位,即可输出全部组合。

#include<stdio.h>
#include<string.h>

char buf[1024];

void func();

int main()
{
    memset(buf,0,sizeof(buf));
    sprintf(buf,"abb");
    func();
    return 0;
}

void func()
{
    int n = strlen(buf);
    if(n > 31)
    {
        return;
    }
    for(int i=1;i<(1<<n);i++)
    {
        for(int j=0;j<n;j++)
        {
            if((1<<j)&i)
            {
                printf("%c",buf[j]);
            }
        }
        printf("\n");
    }
}

方法二:先决定选几个字符,再遍历字符串,依次做两种决策:第i个字符在结果中;第i个字符不在结果中,最后看字符数是否与开始选定的值相等

代码略

四.八皇后问题

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

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

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

#include<stdio.h>
#include<string.h>

int buf[8];

void func(int index);
void swap(int index1,int index2);
bool isLegal();
int main()
{
    memset(buf,0,sizeof(buf));
    for(int i=0;i<8;i++)
    {
        buf[i] = i;
    }
    func(0);
    return 0;
}

void func(int index)
{
    if(index == 7)
    {
        if(isLegal())
        {
            for(int i=0;i<7;i++)
            {
                printf("%d,",buf[i]);
            }
            printf("%d\n",buf[7]);
        }
    }
    for(int i=index;i<8;i++)
    {
        swap(i,index);
        func(index+1);
        swap(i,index);
    }
}
void swap(int index1,int index2)
{
    if(index1==index2)
    {
        return;
    }
    else
    {
        int temp = buf[index1];
        buf[index1] = buf[index2];
        buf[index2] = temp;
    }

}
bool isLegal()
{
    for(int i=0;i<7;i++)
    {
        for(int j=i+1;j<8;j++)
        {
            if((i-j) == (buf[i]-buf[j]) || (i-j) == (buf[j]-buf[i]))
            {
                return false;
            }
        }
    }
    return true;
}

字符串排列组合问题

时间: 2024-08-11 15:00:45

字符串排列组合问题的相关文章

字符串排列组合算法

第二个算法是我笔试题遇到的,当时没有做出来,在网上看到别人写的算法,感觉太精妙了,就在这里分享出来. 全排列 所谓全排列,就是打印出字符串中所有字符的所有排列.例如输入字符串abc,则打印出 a.b.c 所能排列出来的所有字符串 abc.acb.bac.bca.cab 和 cba . #include<stdio.h> #include<string.h> static int number=0; void Swap(char *a ,char *b) { char temp =

字符串排列组合

输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 结果请按字母顺序输出. <?php class Test{ /** * arr 元素数组, * m 从arr 中选择的元素个数 * isRepeat arr中的元素是否可以重复(默认重复) * b 中间变量 * n 等于第一次调用时的 m * res 存放结果 */ public static function combi

打印任意字符串排列组合

#include <iostream>#include <string> using namespace std; void swap(string& s,int i,int j){ char a = s[i]; s[i] = s[j]; s[j] = a;} void myPrint(string& s, size_t index){ if (index >= s.size()) { cout << s << endl; return

字符串的排列组合

1.字符串的组合 字符串的组合,有字符串abc,它的所有组合为a,b,c,ab,ac,abc.求字符串的组合可以使用递归的方法,程序如下: void print(string &s,int start,vector<char> &t) { if(start==s.size()) { return ; } int i=0; for(i=start;i<s.size();++i) { t.push_back(s[i]); //使用递归+回溯的方法求组合 vector<c

字符串的排列组合总结

问题1 :输入一个字符串,打印出该字符串中字符的所有排列.例如输入字符串abc,则输出由字符a.b.c所能排列出来的所有字符串abc.acb.bac.bca.cab和cba. 思路:这是个递归求解的问题.递归算法有四个特性:(1)必须有可达到的终止条件,否则程序将陷入死循环:(2)子问题在规模上比原问题小:(3)子问题可通过再次递归调用求解:(4)子问题的解应能组合成整个问题的解. 对于字符串的排列问题.如果能生成n - 1个元素的全排列,就能生成n个元素的全排列.对于只有1个元素的集合,可以直

9.9递归和动态规划(五)——确定某字符串的所有排列组合

/** * 功能:确定某字符串的所有排列组合. */ 注意:不考虑重复字符.若考虑重复字符,只需在加入permulations时去掉重复的字符串即可. /** * 思路:元素由少到多,将新的元素塞进所有字符串中间的任意可能位置. * @param str * @return */ public static ArrayList<String> getPerms(String str){ if(str==null) return null; ArrayList<String> per

编写一个方法,确定某字符串的所有排列组合

public static ArrayList<String> getPerms(String str) { if(str==null) return null; ArrayList<String> permutations=new ArrayList<String>(); if(str.length()==0)//终止条件 { permutations.add(""); return permutations; } char first=str.c

排列组合递归和非递归算法总结篇

#include <iostream> #include <string> #include <math.h> #include <vector> #include <algorithm> using namespace std; //method1 bool flag[5] ; int arr[5] = {1,2,3,4,5}; int len = sizeof(arr)/sizeof(int); void Comb(int n,int cou

【剑指offer】字符串的组合

转载请注明出处:http://blog.csdn.net/ns_code/article/details/26405471 剑指offer上的拓展题目,输入一个字符串,输出该字符串的字符的所有组合,比如输入字符串: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),从第一个字符开始扫描,每个字符有两种