字符串全排列问题分析

本文探讨了字符串全排列问题,从问题描述到深入分析,包括状态与解的定义、如何求解、状态转换及代码实现。文章还详细讲解了如何通过优化处理重叠子问题、减少状态数量和状态转移开销,最终尝试将递归实现转化为非递归方式,以提高效率。
摘要由CSDN通过智能技术生成

今天晚上和一个同学讨论了下字符串全排列的问题,发现了一些自己没有发现过的点,感觉这个问题虽然简单,但是其实要写的漂亮,其实还是有一些难度,要解决整个问题需要经历的分析过程其实还是挺漫长的。所以就做一个小结,把一些其他的知识点也串上,讲讲我是如何去分析这个问题的。


问题描述

字符串全排列问题
输入:一个非空字符串,例如“abc”,“a”,“abcdefg”。
输出:这个字符串所有不重复的排列,例如对于“abc”,就有“abc”,“acb”,“bac”,“bca”,“cab”,“cba”,这六个。

问题分析

首先看我们给出的求解思路:

状态与解的描述

这里我们先说明一下状态,状态可以简单理解成我们的“解”,但是,需要注意的是,这个解可能是一个完全解,也可以是一个部分解。这东西的定义对我们的求解分析有什么作用?我们来一点点分析。

对于我们的全排列问题,我们使用下划线来表示进行全排列的字符串的范围,例如,“ abcdef”表示需要对整个字符串进行排序,而“ab cdef”则表示需要对后4个字符进行全排序,前2个字符不需要排序。
这种带有下划线的字符串就是我们的一个状态。

那为什么这种表示可以说它是一个“解”,我们看下图,对于字符串“ abc”的全排列,我们可以是看成是,分别以a,b,c开头的三个排列问题,即“a bc”,“b ac”,“c ba”,这样不断的分解下去,我们可以发现整个树的最底层其实就是我们所希望的解。

将整个树的非叶子节点看成不分解,叶子节点看成是完全解,两者的并集就是我们所描述的所有状态。



注:我自己也不知道这样描述状态是不是准确,因为状态这玩意玄之又玄,怎么说都感觉不在着力点上。

如何求解

知道了上述的这个图,那求解的思路就很自然了,只要遍历这棵树即可,这里需要注意的两点就是:
这里必须遍历这棵树,因为完全解处在所有叶子节点上,没有走完所有叶子节点,无法获取到所有的解。
这里也不可能使用递推的思路去求解这个问题,因为我们的起点只可能在树的根部,无法直接跳跃到叶子,当然,反过来思考,如果我们可以字节获得叶子节点,何必需要这个树呢(当然,有些强词夺理了)。

状态转换

有了上述的分析,我们接下来面对的问题就是,如何去遍历这棵树了。
遍历树,能够想到的无非就是所谓的什么先序遍历、中序遍历、后续遍历这些。这些技术说白了都是基于递归技术实现,所以我们第一反应就是使用递归去遍历这棵树。
但是问题在于我们事先是没有构建好这棵树的,所以这个现在问题的关键点就变成了如何从一个节点跳转到另外一个节点,也就是不同的状态间是如何转换的。
这里的解决方法可以看下图,我们通过一个swap操作,就可以做到了,图中只画了其中的一层,其他层次之间的转移操作也是一样的。
所以,我们这里的状态转移开销=交换两个元素所带来的开销



如何用代码描述状态

认真观察上面的图,我们很容易发现,每个状态我们可以分解成两个部分”不带下划线的字母串+带有下划线的字母串“,两者之间可谓泾渭分明,所以我们可以只使用一个下标值表示这两者的分界线即可。
所以设定i为首个下划线字母在整个字符串中的下标值。所以我们的函数就可以写成:


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值