zoukankan      html  css  js  c++  java
  • 55. 2种方法求字符串的组合[string combination]

    【本文链接】

    http://www.cnblogs.com/hellogiser/p/string-combination.html

    题目】

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

    分析

    在之前的博文28.字符串的排列[StringPermutation]中讨论了如何用递归的思路求字符串的排列。同样,本题也可以用递归的思路来求字符串的组合。


     【递归法求组合】

    可以考虑求长度为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。

    【代码】

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
     
    // 55_StringCombination.cpp : Defines the entry point for the console application.
    //
    /*
        version: 1.0
        author: hellogiser
        blog: http://www.cnblogs.com/hellogiser
        date: 2014/5/24
    */


    #include "stdafx.h"
    #include <vector>
    #include <iostream>
    using namespace std;

    // print string combination
    void Print(vector<char> &result)
    {
        vector<
    char>::const_iterator iterBegin = result.begin();
        vector<
    char>::const_iterator iterEnd = result.end();

        
    for (; iterBegin != iterEnd; ++ iterBegin)
            printf(
    "%c", *iterBegin);
        printf(
    " ");
    }

    // get string combination recursively
    // choose m chars from str
    void Combination(char *str, unsigned int m, vector<char> &result)
    {
        
    if(NULL == str || (*str == '' && m > 0))
            
    return;

        
    // base cases
        if (m == 0)
        {
            
    // we have got a combination,print it
            Print(result);
            
    return;
        }
        
    // (1)choose current char
        result.push_back(*str);
        
    // choose m-1 chars from remaining n-1 chars
        Combination(str + 1, m - 1, result);

        
    // (2) not choose current char
        result.pop_back();
        
    // choose m chars from remaining n-1 chars
        Combination(str + 1, m, result);
    }

    // string combination
    void StringCombination(char *str)
    {
        
    if(NULL == str || *str == '')
            
    return;
        
    int len = strlen(str);
        vector<
    char> result;
        
    for (int i = 1; i <= len; ++i)
            Combination(str, i, result);
    }

    void test_base(char *str)
    {
        StringCombination(str);
        printf(
    "--------------------- ");
    }

    void test_case1()
    {
        
    char str[] = "";
        test_base(str);
    }

    void test_case2()
    {
        
    char str[] = "a";
        test_base(str);
    }

    void test_case3()
    {
        
    char str[] = "abc";
        test_base(str);
    }

    void test_main()
    {
        test_case1();
        test_case2();
        test_case3();
    }

    int _tmain(int argc, _TCHAR *argv[])
    {
        test_main();
        
    return 0;
    }
    /*
    ---------------------
    a
    ---------------------
    a
    b
    c
    ab
    ac
    bc
    abc
    ---------------------
    */

    由于组合可以是1个字符的组合,2个字符的组合……一直到n个字符的组合,因此在函数void StringCombination(char *str)中,需要一个for循环。另外,用一个vector来存放选择放进组合里的字符。


     【位运算求组合】

    另外本题还有一个巧妙的思路,可以从位运算出发求组合。用一个二进制数字,来决定字符的取舍,某一位为1,则取对应的字符,若为0则不取,就能够实现字符组合。

    例如对于“abc”,长度为3,则共有7种组合可能。让num 从1自增到7,跟字符的每一位进行判断,是否取舍。

    比如:num=1,即001时:

    (1)j指向第1个字符,(a>>j)&1==1,则取a;

    (2)j指向第2个字符,(a>>j)&1==0,则舍弃b;

    (3)j指向第3个字符,(a>>j)&1==0,则舍弃c;

    此次组合的字符串为a;

    以此类推。

    当num=7,即111时:

    (1)j指向第1个字符,(a>>j)&1==1,则取a;

    (2)j指向第2个字符,(a>>j)&1==1,则取b;

    (3)j指向第3个字符,(a>>j)&1==1,则取c;

    此次组合的字符串为abc;

    那么当num依次取完所有的值,就可以得到所有的字符串组合。

    【代码】

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    /*
        version: 1.0
        author: hellogiser
        blog: http://www.cnblogs.com/hellogiser
        date: 2014/5/24
    */

    void StringCombinationUsingBitwise(char *str)
    {
        
    // use bitwise operations to get string combination
        if(NULL == str || *str == '')
            
    return;
        
    int len = strlen(str);
        
    if (len >= 32)
            
    return;
        
    int sum = 1 << len;
        
    for (int i = 1; i < sum; ++i)
        {
            
    for (int j = 0; j < len; j++)
            {
                
    if ((i >> j) & 0x1)
                {
                    
    // choose char at str[j]
                    printf("%c", str[j]);
                }
            }
            printf(
    " ");
        }
    }

    相对于 【递归法求组合】【位运算求组合】速度更快,其时间复杂度为T=n*2n,但是n不能超过32.

    【注意】

    多谢“路上的脚印”的提醒,该算法只能适用于字符串中字符都不相同的情形。如果有相同字符,则不再适合,需要进一步修正。

    【参考】

    http://zhedahht.blog.163.com/blog/static/2541117420114172812217/

    http://zhuyanfeng.com/archives/3246

    http://blog.csdn.net/hackbuteer1/article/details/7462447

    http://blog.csdn.net/wuzhekai1985/article/details/6643127

     【本文链接】

    http://www.cnblogs.com/hellogiser/p/string-combination.html

    个人学习笔记,欢迎拍砖!---by hellogiser

    Author: hellogiser
    Warning: 本文版权归作者和博客园共有,欢迎转载,但请保留此段声明,且在文章页面明显位置给出原文连接。Thanks!
    Me: 如果觉得本文对你有帮助的话,那么【推荐】给大家吧,希望今后能够为大家带来更好的技术文章!敬请【关注】
  • 相关阅读:
    北航 2012 秋季 软件工程课 M2 要求
    现代软件工程讲义 7 设计阶段 Spec
    软件工程讲义 0 微博上的软件工程
    现代软件工程讲义 8 软件的血型
    北航 2012 秋季 现代软件工程 两人结对 作业要求
    现代软件工程讲义 6 用户调研
    现代软件工程 2012 北航 项目复审模板
    北航 2012 秋季 现代软件工程 团队项目要求
    现代软件工程 学生阅读、思辨和调查作业
    现代软件工程讲义 5 团队合作的阶段
  • 原文地址:https://www.cnblogs.com/hellogiser/p/string-combination.html
Copyright © 2011-2022 走看看