可重复排列

可重复排列
键盘输入一个仅由小写字母组成的字符串,输出以该串中任取M个字母的所有排列

及排列总数(输入数据均不需判错)。

此题是由全排列问题转变而来,不同之处在于:一个字符串中可能有相同的字符,导

致可能出现重复的排列。例如从字符串‘aab’中取2个字符的排列只有三种:‘aa’、‘ab’、

‘ba’。如何去掉那些可能重复的排列呢?一种想法就是每产生一种不同的排列就记录下

来,以便让以后产生的排列进行比较判重。这种想法显然没有考虑到随着字符串长度的增

加,排列将会多得无法记录,而且这种判重方法在效率上也会很低。最好有一种方法能在

产生排列的过程中就能将重复的去掉。先看一看全排列的递归过程:

PROCEDUREWork(k);

BEGIN

IFk=m十1

THEN打印结果

ELSEFORi←1TO字符串长度nDO

IFi<>e〔1〕,e[2〕…e[k-1]

THEN

BEGIN

e〔k〕←i;

Workk十1);

END;

END;

让我们来分析产生重复的原因。考虑从字符串‘aab’中取2个字符的排列。当e〔1]从

1变到2时,字符串中的字符却没有变,都是‘a’。这样我们只要在改变e〔k]时,判断其对

应的字符是否也改变。即在上面的过程的循环中加一句判断(设字符串为s):IFs[i]<>

s[e[k]]THEN…;这当然只是一个粗略的想法,我们仅仅用上面的例子就能发现问题:

程序在对e[k〕的每一次赋值之前都要进行一次判断,而不是我们预想的在改变e[k]时才

进行判重。我们用一个布尔型的局部变量First来记录是否是对e[k]进行第一次赋值。修

改后的程序如下:

PROCEDUREWork(k);

BEGIN

First←True;

IFk=m十1

THEN打印结果

ELSEFORi←1TO字符串长度nDO

IF(i<>e〔1〕,e〔2〕…e[k-1]AND

(FirstORs〔i[<>s〔e[k]])

THEN

BEGIN

e[k]←i;

First←False;

Work(k十1);

END;

END;

很多选手的程序到此就为止了,可是它还有一个致命的错误:我们在判重时假定这个

字符串中的字符已经排好顺序,即相同的字符已经连在一起。事实上并不是这样,输入的

字符串中的字符排列是任意的,需要我们在递归之前作一次排序的初始化才能保证程序

运行得正确。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值