使用递归算法解决字符的组合问题

原创 2006年06月09日 22:09:00

    前几天到ChinaUnix的Python版去闲逛,在http://bbs.chinaunix.net/viewthread.php?tid=757345&extra=page%3D2 发现了这个问题,原文如下:

    把一个字符串中所有字符的所有可能的组合打印出来(字符串中没有重复的字符),不考虑字符顺序('123'和'312'是一样的)
 

bleem1998已经写出了该问题的非递归的求解方法,基本思想就是按照组合的字符串的长度依次穷举.原来很容易懂.但是实现起来稍微麻烦一些,所以我找了一个比较简单的方法.

    我所采用了递归的方法来解决这个问题,也就是什么说的分冶策略,把一个字符的组合问题拆分成两个规模比较小的字符的组合问题,从而导致递归求解.拆分的方法如下:

    对于任意的满足题目条件的字符串,总是可以拆分成两个字符串:第一个字符a,和剩余的字符构成的字符串b. 例如字符串"12345"可以拆分成两个字符串"1"和"2345",对于原来的问题那么就转化成了:求字符串a中的所有字母的组合的字符串集合A,以及字符串b中的字符的组合的字符串的集合B,然后把这两个集合进行一个笛卡儿积运算A×B,把两个集合的字符串拼接起来构成一个新的字符串集合C,从而C就是求得所得的结果.对于集合A,显然就只要2个元素,因为a只有一个字符;而字符b相对于原来的字符串长度已经减少了1,同原来的问题的性质一样,因此可以递归调用原来的函数求解.

     整个求解的过程可以用一个二叉树来表示,而对于问题的描述可以用一个二元组(prefix,src)来表示,prefix表示已经拆分了的字符串,src表示有待于拆分的字符串.

    下面是规模为3的时候的二叉树表示图,问题的答案就是这个完全二叉树的叶接点的prefix字符串所组成的集合,包括空字符串,显然一共有2n个字符串(n表示字符串的长度)

    下面是我用Python写的一个求解的程序,就只有几行代码,很简洁,我确实被Python所折服了

def permute(str,prefix):
    if len(str) == 0:
        print prefix,
        return
    permute(str[1:],prefix)
    permute(str[1:],prefix+str[0])

permute('123','')

这是解答的结果,和上面二叉树来表示完全一致

 3 2 23 1 13 12 123

由于用Python的人并不是很多,所以我也用C写了个程序作为参考

#include <iostream>
#include <cstring>

#define BUFFER_SIZE 255

using namespace std;

void permute(char *src, char *prefix)
{
    char buf[BUFFER_SIZE];
    int len = strlen(prefix);

    if (strlen(src) == 0)
    {
        cout<<prefix<<" ";
        return;
    }
    strcpy(buf,prefix);
    permute(src+1, prefix);
    prefix[len] = *src;
    prefix[len+1] = '/0';
    permute(src+1, prefix);
}

int main(int argc,char argv)
{
    char buf[BUFFER_SIZE] = "";
    permute("12345",buf);
    return 0;
}

 

相比之下,这个程序看起来要复杂得多,远不入Python那么简洁,这就是Python的魅力所在.

另外stone.zh也提供了一个简洁的方法,不过我现在也没有看懂,因为我不知道yield到底是什么做什么用的,不知道有没有知道,顺便告诉一下,谢过了先.

def permute(str):
    for i in str:
        yield i;
        for j in permute(str[str.index(i)+1:]):
            yield i+j

for i in permute("12345"):
    print i,

 

与这个问题类似,"百度之星"中的初赛题目中也可以用这个方法来求解,只是这里的组合问题是菜的组合,而且组合的元素的个数也固定了.有兴趣可以试试,题目如下

出处见http://star.baidu.com/data/chusai/q2.html

饭团的烦恼

“午餐饭团”是百度内部参与人数最多的民间组织。
同一个部门的、同一所大学的、同一年出生的、使用同一种型号电脑的员工们总是以各种理由组织各种长期的、临时的饭团。
 

参加饭团,不仅可以以优惠的价格尝到更加丰富的菜式,还可以在吃饭的时候和同事们增进感情。
但是,随着百度的员工越来越多,各个饭团的管理变得繁杂起来。特别是为了照顾员工们越来越挑剔的胃,饭团的点菜负责人的压力也越来越大。现在,这个任务就交给“百度之星”了,因为,你将要为所有的百度饭团设计一个自动点菜的算法。
 

饭团点菜的需求如下:
1.经济是我们要考虑的一个因素,既要充分利用百度员工的午餐补助,又不能铺张浪费。因此,我们希望最后的人均费用越接近12元越好。
2.菜式丰富是我们要考虑的另一个因素。为简单起见,我们将各种菜肴的属性归结为荤菜,素菜,辛辣,清淡,并且每个菜只能点一次。
3.请谨记,百度饭团在各大餐馆享受8折优惠
 

输入要求:
1.输入数据第一行包含三个整数N,M,K(0<N<=16,0<M<=N,0<K<=12),分别表示菜单上菜的数目,饭团需要点的菜的数目,就餐的人数;
2.紧接着N行,每行的格式如下:
菜名(长度不超过20个字符) 价格(原价,整数) 是否荤菜(1表示是,0表示否) 是否辛辣(1表示是,0表示否);
3.第N+2行是 a b c d 四个整数,分别表示需要点的荤菜,素菜,辛辣,清淡菜的数目。例:
3 2 2
水煮鱼 30 1 1
口水鸡 18 1 1
清炖豆腐 12 0 0
1 1 1 1
样例:in.txt
 

输出要求:
对于每组测试数据,输出数据包含M+1行,前M行每行包含一个菜名(按菜名在原菜单的顺序排序)。第M+1行是人均消费,结果保留两位小数。例:
口水鸡
清炖豆腐
12.00
样例:out.txt

组合的两种递归算法

组合就是从n个物品中任意选择m个组成一组,下面两种递归算法都可以求出不同的组合,如果待选物品当中有重复的,比如说下面代码中an = new char[]{'1','2','3','4','5'} 变成...
  • silent_strings
  • silent_strings
  • 2015年09月08日 11:00
  • 2694

硬币面值组合的算法题解

方法一 转自http://www.cnblogs.com/python27/archive/2013/09/05/3303721.html 动态规划的方法,是将m*n(m表示硬币的种类,n表示所要组...
  • styyzxjq2009
  • styyzxjq2009
  • 2014年07月16日 16:59
  • 3770

众数问题(递归)

【众数问题】 «问题描述: 给定含有n个元素的多重集合S,每个元素在S中出现的次数称为该元素的重数。多重 集S中重数最大的元素称为众数。 例如,S={1,2,2,2,3,5}。 多重集S的众...
  • QuinnQin
  • QuinnQin
  • 2017年05月30日 22:10
  • 342

众数问题(递归分治策略)

所谓众数,就是对于给定的含有N个元素的多重集合,每个元素在S中出现次数最多的成为该元素的重数, 多重集合S重的重数最大的元素成为众数。例如:S={1,2,2,2,3,5},则多重集S的众数是2,其重...
  • GuoZLH
  • GuoZLH
  • 2016年03月07日 08:30
  • 4661

C++ 全排列和组合算法(递归)

全排列: 设待排列的数组为a[n],任意时刻将其分为0~s-1和s~n-1两端。 其中,0~s-1是已经选择的区间,s~n-1是待选择的区间,每次选择s~n-1的一个与s为的数交换 #include...
  • Kirk0316
  • Kirk0316
  • 2013年09月23日 18:02
  • 854

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

排列组合递归和非递归算法总结篇
  • u012309042
  • u012309042
  • 2014年09月04日 23:05
  • 2118

汉诺塔问题的递归解法与非递归解法(堆栈解法)

1.非递归解法,使用堆栈主要是将问题分解为三个,从后向前压进堆栈,再依次解决#include using namespace std; const int Maxsize = 100; typede...
  • qq_40540973
  • qq_40540973
  • 2017年11月13日 22:15
  • 66

递归算法解决因式分解(java版)

最近在复习数据结构与算法相关的知识点,
  • u012754897
  • u012754897
  • 2014年05月23日 14:18
  • 1754

递归处理全排列问题的两种方法

#include #include #include #include #include #include #include using namespace std; void permutati...
  • qq_22194315
  • qq_22194315
  • 2017年01月10日 13:27
  • 212

兔子繁殖问题 - 两种递归思路

兔子繁殖问题 - 两种递归思路 有一对兔子出生,从第三月起,每个月生一对兔子,出生的兔子也是第三月起每个月生一对兔子,请问2年后,共有多少只兔子? 分析思路—— 斐波那契...
  • linfeng24
  • linfeng24
  • 2014年05月17日 09:42
  • 1254
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用递归算法解决字符的组合问题
举报原因:
原因补充:

(最多只允许输入30个字)