【剑指offer】字符串的组合

来源:互联网 发布:php 字符串大小写转换 编辑:程序博客网 时间:2024/05/16 04:38

转载请注明出处: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),从第一个字符开始扫描,每个字符有两种情况,要么被选中,要么不被选中,如果被选中,递归求解C(n-1, m-1)。如果未被选中,递归求解C(n-1, m)。不管哪种方式,n的值都会减少,递归的终止条件n=0或m=0。

    博主是刚开始尝试用递归去写,写了一个多小时都没写出来,桑心啊!除了操作二叉树写递归比较顺,其他好多地方用递归愣是憋不出来,尤其字符串操作。

    在何海涛博客下看到有人留言,给了个思路,觉得很不错,自己把代码写了出来。具体思路如下:

    开辟一个于字符串对应长度的int数组(char数组也可以,而且更节省空间),用该数组模拟二进制的加1操作,则该数组的元素只能为0或1,我们规定如果该数组某个位置处的元素是1,则字符串对应位置处的字符参与组合,如果为0,则字符串对应位置处的字符不参与组合,这样讲该int数组,从全0加到全1,便可得到字符串的全部组合。

    这里没有去除重复子串,也没按照字典序输出,如果要求按照字典序输出,并去掉重复子串的话,可以采取上道题目一样的办法,先将所有的字符串保存在字符串数组中,而后通过快排使数组中的字符串按照字典序排列,再在输出的时候,跳过重复的字符串。

    实现代码如下:

#include<stdio.h>#include<string.h>#include<stdlib.h>/*模拟二进制加1操作,当最高位要进位时,说明所有的位都是1,返回false,用char数组来模拟比int数组更省空间,这里必须传入数组长度len,由于我们CominationAll中将要传入的字符数组全部初始化为了'\0',如果在该函数内部用strlen计算的话,会得到len=0。*/bool Increment(char *BindAdd,int len){if(BindAdd == NULL)return false;BindAdd[len-1]++;int i;for(i=len-1;i>=0;i--){if(BindAdd[i] >= 2){if(i == 0){BindAdd[i]--;return false;}else{BindAdd[i] -= 2;BindAdd[i-1]++;}}elsebreak;}return true;}/*输出字符串的所有组合*/void CominationAll(char *str){if(str == NULL)return;int len = strlen(str);char *BindAdd = (char *)malloc(len*sizeof(char));if(BindAdd == NULL)exit(EXIT_FAILURE);memset(BindAdd,0,len*sizeof(char));while(Increment(BindAdd,len)){int i;for(i=0;i<len;i++){if(BindAdd[i] == 1)putchar(str[i]);}putchar('\n');}free(BindAdd);BindAdd = NULL;}int main(){char str[10];while(gets(str))CominationAll(str);return 0;}
    测试结果:



3 0
原创粉丝点击