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

原创 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

相关文章推荐

采用递归算法实现任意字符的全排列问题

本文考虑了存在相同字符的情况。 实现效果: 输入1212,得到以下字符串: 1212 1221 1122 2112 2121 2211 相关代码: import java.ut...
  • youtui
  • youtui
  • 2016年08月30日 22:11
  • 513

我的Java开发学习之旅------>使用循环递归算法把数组里数据数组合全部列出

面试题如下:把一个数组里的数组合全部列出,比如1和2列出来为1,2,12,21。 (面试题出自《Java程序员面试宝典》) 代码如下: import java.util.Arrays; impo...

java 解决 汉诺塔问题(递归算法)

import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Exercise6_37 e...

数据结构 - 用递归算法解决实际问题

实验题目:编写一个程序exp5-2.cpp,求解背包问题:设有不同价值、不同重量的物品n件,求从这n件物品中选取一部分物品的方案,使选中物品的总重量不超过指定的限制重量,但选中物品的总价值最大。源码:...

排列和组合的非递归算法的C语言实现

2008-11-28 09:56 #include #include //从n个元素的数组a中,取m个元素的组合 bool zuhe(char a[],int n,int m) ...

组合的两种递归算法

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

关于二叉树非递归算法使用的栈问题

/*有一个问题,一直没有解决,单步调试发现已正常入栈的元素,为什么Pop出来的栈元素为1,打印到屏幕上就是一个笑脸?*/#include #include "bitree.h" using name...

组合的递归算法

组合的递归算法。
  • zjweii
  • zjweii
  • 2011年02月16日 21:00
  • 713

递归算法(求n的加法组合,将一个整数拆分成多个整数相加的形式, O(N)时间,O(N)空间)4.0版

网上的多种解法比较复杂,本文用递归方法,22行代码搞定。时间和空间复杂度已经降到最低!   //n give the sum of a list,and start give the first nu...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用递归算法解决字符的组合问题
举报原因:
原因补充:

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