1. 介绍递归和动态规划
暴力递归:
- 把
问题转化为规模缩小了的同类问题的子问题
. - 有明确的的不需要继续进行递归的条件(base case也就是递归的出口,例如
当节点为空之类的
). - 有当得到了子问题结果之后的决策过程.
- 不记录每一个子问题的解.
动态规划(就是为了优化暴力递归):
- 从暴力递归中来.
- 将每一个子问题的解记录下来,避免重复计算.
- 把暴力递归的过程,抽象成状态表达.
- 并且存在化简形式表达,使其更加简洁地可能.
我们直接上题目练习,动态规划就是一个尝试的过程,不断去尝试其规律,说白了就是一种感觉哈哈哈哈,这就要自己多练习了
题目1. 求n!的结果
思路:
- 不递归就通过一个for循环,直接从1开始乘,一直乘到n结束.
- 递归的话就把
求n的阶乘
看作求n*(n-1的阶乘)
,然后一直乘到1就结束.
求n的阶乘代码
2. 题目2. 汉诺塔问题
如果有n层,那么时间复杂度为O(2^n);
汉诺塔来源:
相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如下图)。
游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好,在算法中就是通过最少的步骤实现这个目标,然后打印出实现步骤。
操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。
***思路:***我刚开始有三个杆(left, middle, right),刚开始n个盘子都在左边杆上,目标就是把所有盘子移到右边去.
- 把
1~n-1
个盘子移动到middle杆上,然后把from杆中最下面的盘子移动到right杆上去.
- 把
1~n-1
个盘子从middle杆移到right杆中去.
汉诺塔问题代码
3. 题目3. 打印一个字符串的全部子序列,包括空字符串
3.1. 区分子序列和子串
例如:一个字符串 awbcdewgh
他的子串:awbc、awbcd、awbcde等
很多个子串 ,但是都是连续在一起 .
他的子序列:abc 、abcd、 abcde等
很多个子序列 ,但是 子序列中的字符在字符串中不一定是连在一起的,而是删除其中若干个, 但是子序列一定是单调的(即字符之间ASCII单调递增或单调递减,相对顺序不能改变)
所以 子串!=子序列
思路:
刚开始是空字符
,但是不是null哈就是每次走到一个字符,我都有两种选择
:一个是我当前的字符(刚开始是空字符)去和后面的字符做拼接,还有一个是我当前的字符不去和后面的字符做拼接.(可以画个图,就跟二叉树差不多
,然后结束条件就是到了叶节点)
打印字符串的子序列代码
题目4.母牛每年可以生一头母牛,新出生的母牛成长三年后(也就是第四年开始)
也能每年生一头母牛,假设不会死,求N年后,母牛的数量
例如:
这种方法的时间复杂度为O(N)
母牛问题代码
4. 题目4
题目如图:
思路:暴力递归,时间复杂度比较高,因为会发生有的位置重复计算比如两次经过(1,1)
这个点,如下面的代码
最短路径递归代码
5. 题目5:给你一个正数数组arr和一个正整数aim,如果可以任意选择arr中的数字,能不能累加得到aim,返回true或者false
***思路:跟求子序列的思路差不多,就是我们在遍历数组的时候,每个数都有两种选择,一种是和后面的数相加
,另一种是不和后面的数相加
,当遍历结束之后,比较各种情况的结果,如果存在与aim相同的结果,那么返回true,反之返回false