递归思想之尝试法(汉诺塔问题,字符串所有子序列)

递归思想的,其实是一种尝试的思想,而我们一般的思想,总是想通过每一步明确的步骤来实现,而不是尝试!这是想学好递归需要进行的思路转换。

n!问题

先来个最简单的。这个问题,很多人都喜欢通过1乘以2乘以3一直乘到n来解决,这是标准的人类思路,每一步我都需要知道确定的结果,比较符合人类的思维。
但是这个的递归解法呢,其实就充分证明了尝试在递归中的重要性。
递归思路:求n!,可以先由n乘以n-1!至于n-1怎么求,不知道,先尝试走一步再说,先尝试把原问题划分成更小的子问题,然后找到这个问题的最小规模时的状态,返回就可以了。
代码

public int get(int n){
	if(n==1){
		return 1;
	}
	return n*get(n-1);
}

汉诺塔问题

题目描述
有三个杆子,第一个在左边,第二个在中间,第三个在右边。然后左边杆子上有从上到下依次增大的卡片。每次只能取出并放置一张卡片,并且任何时候任何杆子上的卡牌都不能是大的在上小的在下,必须任何时间都是大牌在下。
现在,给你一个左边是N层的汉诺塔,请求出将左边杆子上的所有卡牌移动到右边杆子上的过程?
思路分析
递归第一步,不要死磕细节,我们尝试把问题划分成更小的问题来解决。尝试一下把问题划分成n-1的规模,如何实现?
1.把n-1的卡牌从左边杆子移动到中间的帮助杆子上。
2.把左边杆子上剩下的最后一个放到右边杆子上。
3.把中间的帮助杆子上的n-1放到右边杆子上。
然后呢?此时我们仍然不知道n-1是如何从左边放到中间的帮助杆子上的,对吧?那么,n-1时的问题,是不是就变成了把n-1个卡牌,从左边杆子上放到中间,此时,右边的杆子是不是就可以当作帮助杆子了?这个问题最难想明白的地方在于,杆子是不是只是个杆子啊?中间的并不一定一直都是help杆子,对吧?当把左边n-1放中间这一步,是不是中间就变成了目标杆子了?此时空余出来的右边杆子,是不是就能当作help使用了?
此时,我们是不是把n的问题成功划分成n-1了?然后,我们也成功给出了n-1的解决办法,对吧?然后,n-1就可以继续递归到n-2了,没问题吧?最后再考虑一下终点,终点值就是n==1的时候,就剩最后一个了,直接转移就可以了,不需要帮助的杆子了。此时递归的过程不就写出来了吗?
因此,前面的分析中可以看出,每个杆子并不是一直都固定的功能,当n-1时,是要把左边的n-1放入中间,此时中间的杆子就成目标杆子了,右边空出来了,可以当作help杆子。因此,递归代码中,我们不能写死哪个杆子是什么功能,我们的递归函数中,传入的参数分别为被转移from,目标to,帮助help,然后每次递归时,不同杆子可能会充当不同的角色。
汉诺塔问题时间复杂度为2的n次方再减1,就是2的n次方。

代码

    public static void proccess(int n,String from,String help,String to){
        if(n==1){
            System.out.println("把"+from+"的"+n+"移动到"+to);
        }else {
            proccess(n-1,from,to,help);//把n-1移动到中间,此时help成了目标地址
            System.out.println("把"+from+"的"+n+"移动到"+to);//打印将最后一个从左边放到右边
            proccess(n-1,help,from,to);//最后,再将help中放入右边
        }
    }

打印一个字符串的全部子序列

子序列不同于子串,这里需要注意。
题目要求就是给一个字符串,比如abc,请打印出所有可能子子序列,包括空格。
例如:abc,所有子序列:a、b、c、ab、ac、bc、abc、空格.
思路分析
此题怎么尝试?
我们把字符串拆分成字符数组,然后呢?我们把问题再次化简成n-1的问题,是不是就变成了:第一个字符与后面n-1的子序列的拼接?
因此,第一个字符,可以有,也可以没有,对吧?这就是第一个字符的所有情况,然后,在每种情况下,拼接上后面n-1的递归结果,就是递归过程。
代码:

    public static void printAllSub(char[] chars,int index,String str){
        if(chars.length==index){
            System.out.println(str);
            return ;
        }
        printAllSub(chars,index+1,str);
        printAllSub(chars,index+1,str+chars[index]);
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值