暴力递归1

第17次课

第一题:打印一个字符串的所有子序列
采用决策树的方式,要么选这个字母,要么不选这个字母,当完成一条支路的选择后,把选好的字符串装好,继续进行下面的支路的选择;
主函数提供字符串给子函数,子函数将字符串转成字节数组,先往递归函数中传入一个空字符串,递归进入第一重,index = 0,执行第一条递归,不选择该位置的字符,即不选择a,递归进入第二重;index = 1,不选择该位置的字符,即不选择b,进入第三重;index = 2,不选择该位置的字符,即不选择c,进入第四重;index = 3,满足if条件," "加入ans后,break掉第四重递归,回到第三重;index = 2,第三重的第一条递归已经执行完毕,即不选c,下面进入第二条递归语句,即选c,进入第四重;index = 3, 满足if条件,"c"加入ans,break掉,退回到第三重递归;index = 2,第三重递归已经执行完毕,退出,回到第二重递归;index = 1,至此,第二重递归已经执行完第一句递归,下面执行第二条递归。。循环往复,直至打印完所有的子序列;

第二题:打印一个字符串的所有不重复子序列
用Set

第三题:打印一个字符串的全排列
解法1:选择第一个字符,保存,删除之后,进行第二重递归,即在删除之后的字符串(它其实转化为了集合)中进行第二个字符的选择,第一次递归完成后,进行第二次递归;选择最开始的字符串的第二个字符,进行同样的操作。。。
为了后面的清除现场,将字符串转化为ArrayList (它是剩余字符集合),将它、已选择的路径和最终结果ans传入递归函数当中,如果剩余字符数为0,则把路径加到ans里,如果还剩,则记录下当前字符,从ArrayList里面删去它,将新的剩余字符集合传入递归里,同时(path + 当前字符)传入path里,ans照常,然后将删去的字符加入ArrayList里面(目的是要让递归函数从删去后的字符集合中进行选择,而for循环的下一次选择,则要从最开始的字符串中的第二个字符开始选择,那时必须保证字符串是完好如初的),这就是恢复现场;
注意:ArrayList把元素remove掉之后,后一个会补上前一个的位置,abc删去第二个就变成了ac,大小是2;
(垃圾递归)

解法2:
第零重递归,index = 0,i = 0,它自己交换,交换后,abc,进入第一递归;index = 1,i = 1,它和自己交换,abc,进入第二重递归;index = 2,i = 2,它和自己交换,abc,进入第三重递归;index = 3,满足条件,abc加入ans,退出第三重递归;index = 2,i = 2,它和自己交换,abc,i = 3,跳出for,退出第二重递归;index = 1,i = 1,它和自己交换,交换后,abc,新的一轮for,i = 2,index= 1,1和2交换,acb,进入第二重递归;index = 2,i = 2,它和自己交换,进入第三重递归;满足条件,acb写入ans,退出第三重递归;以此类推。。。
如果index == 字符串长度,代表已经不可以再选择了,就把选择好的字符串放进ans中;

该解法有很多冗余步骤,比如到达最后一个有效递归时,两行交换代码就显得很冗余了

第四题:上述过程实现不重复的全排列
方案:在递归函数上增加一个boolean表,当有新的字符需要交换时就交换,不是新的字符就不交换
解释:对于一个串abaacd,0和0交换,a第一次用,锁住;0和1交换,b第一次用,锁住;0和3交换,a已经被用过了,跳开,0和4交换,a已经被用过了,跳开。
每次是用一个字符进行全排列的时候,都相当于在第一重递归里,把该位置的字符放在首位置上去,但是由于要去重,所以只要是之前已经被放在首位置上过的字符,就不该再次放在首位置上。

(该解法使用了剪枝技巧,即在递归分支诞生之前就将其裁剪掉,而之前使用的set方法是在所有分支都递归完成之后进行选择性存储,显然,论速度,剪枝快于set)

第五题:不额外申请数据结构,用递归逆序一个栈
思路:采用双重递归
第一递归功能:将栈底的元素弹出,然后让剩余的元素压下来
第二递归功能:翻转整个栈

第一递归的实现:将栈传递到第一重递归中,栈顶元素弹出并接收,栈判空,是则返回栈顶元素,否则,将新的栈传入第二重递归,抓取它的返回值,把栈顶元素压入栈,返回第二递归返回的值

第二递归的实现:栈判空,空即返回;栈传入第一递归中,抓取它的返回值,栈传入第二递归,将第一递归的返回值压入栈。
(注意第一递归和第一重递归)(结合例子来看会更容易理解)

口诀:子序全排栈(柳枝柳絮,孩子上体育课站队,拿筒子来装柳絮)

子序列:决策、放(set) (老师拿扩音器、后面孩子弯曲柳枝弹前面的孩子)
全排列:向右交换,剪枝 (向右看齐,脚很缓慢地动,柳枝太长,剪掉)
栈:双重,取栈底,往下压 (拿了两个筒子重在一起,把底部的物品拿出来,把柳絮往下压)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值