算法练习-递归
文章目录
- 算法练习-递归
- 1 解题技巧
- 1.1 如何发现问题可以用递归来做
- 1.2编写递归的正确姿势
- 2 爬楼梯
- 2.1 题目
- 2.2 题解
- 3 细胞分裂
- 3.1 题目
- 3.2 题解
- 4 从尾到头打印链表
- 4.1 题目
- 4.2 题解
- 5 剑指 Offer 10- I. 斐波那契数列
- 5.1 题目
- 5.2 题解
- 6 剑指 Offer 10- II. 青蛙跳台阶问题
- 6.1 题目
- 6.2 题解
- 7 三步问题
- 7.1 题目
- 7.2 题解
- 7.2.1 递归(可能会超时)
- 7.2.2 非递归
- 7.2.3 非递归+优化(内存优化)
- 8 剑指 Offer 16. 数值的整数次方
- 8.1 题目
- 8.2 题解
- 9 递归乘法
- 9.1 题目
- 9.2 题解
1 解题技巧
1.1 如何发现问题可以用递归来做
- 规模更小的问题和规模更大的问题,解题思路相同,规模不同
- 利用子问题可以组合得到原问题的解
- 存在最小子问题,可以直接返回结果(存在递归终止条件)
1.2编写递归的正确姿势
可以假设子问题B、C已经解决,在此基础上再思考如何解决问题A
2 爬楼梯
链接:https://leetcode.cn/problems/climbing-stairs
2.1 题目
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
示例 1:
输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
- 1 阶 + 1 阶
- 2 阶
示例 2:
输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
- 1 阶 + 1 阶 + 1 阶
- 1 阶 + 2 阶
- 2 阶 + 1 阶
2.2 题解
class Solution {private int[] m;public int climbStairs(int n) {m = new int[n + 1];return f(n);}private int f(int n) {if (n == 1) {return 1;}if (n == 2) {return 2;}if (m[n] != 0) {return m[n];}m[n] = f(n - 1) + f(n - 2);return m[n];}
}
3 细胞分裂
3.1 题目
一个细胞的生命周期是3小时,1小时分裂一次,求n小时后容器内有多少个细胞。
细胞会在每个小时的开始分裂、死亡,并且先分裂后死亡
3.2 题解
当前时间细胞总数 = 分裂后的个数 - 死亡个数
f(n) = 2 * f(n - 1) - f(n - 4)
当前时间点,死亡的细胞个数,为三个小时前分裂出的净细胞个数,
而一个时间点分裂出来的净细胞个数等于前一个时间点的细胞个数
所以死亡个数为f(n - 4)
public int f(int n) {if (n == 0) return 1;if (n == 1) return 2;if (n == 2) return 4;if (n == 3) return 8;return 2 * f(n - 1) - f(n - 4);
}
4 从尾到头打印链表
链接:剑指 Offer 06. 从尾到头打印链表 - 力扣(LeetCode)
4.1 题目
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2]
输出:[2,3,1]
4.2 题解
/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/
class Solution {List<Integer> result = new ArrayList<>();public int[] reversePrint(ListNode head) {reverse(head);int[] resultArr = new int[result.size()];int i = 0;for (Integer j : result) {resultArr[i++] = j;}return resultArr;}public void reverse(ListNode head) {if (head == null) {return;}reverse(head.next);result.add(head.val);}
}
5 剑指 Offer 10- I. 斐波那契数列
链接:https://leetcode.cn/problems/fei-bo-na-qi-shu-lie-lcof
5.1 题目
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:1
示例 2:
输入:n = 5
输出:5
5.2 题解
class Solution {int mod = 1000000007;int[] m;public int fib(int n) {m = new int[n + 1];return f(n);}private int f(int n) {if (n == 0) return 0;if (n == 1) return 1;if (m[n] != 0) return m[n];m[n] = (f(n - 1) + f(n - 2)) % mod;return m[n];}
}
6 剑指 Offer 10- II. 青蛙跳台阶问题
链接:https://leetcode.cn/problems/qing-wa-tiao-tai-jie-wen-ti-lcof
6.1 题目
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:2
示例 2:
输入:n = 7
输出:21
示例 3:
输入:n = 0
输出:1
提示:
0 <= n <= 100
6.2 题解
class Solution {private int mod = 1000000007;private Map<Integer, Integer> memo = new HashMap<>();public int numWays(int n) {if (n == 0) return 1;if (n == 1) return 1;if (memo.containsKey(n)) {return memo.get(n);}int ret = (numWays(n-1)+numWays(n-2))%mod;memo.put(n, ret);return ret;}
}
7 三步问题
链接:https://leetcode.cn/problems/three-steps-problem-lcci
7.1 题目
三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模1000000007。
示例1:
输入:n = 3
输出:4
说明: 有四种走法
示例2:
输入:n = 5
输出:13
7.2 题解
7.2.1 递归(可能会超时)
class Solution {private int mod = 1000000007;private Map<Integer, Integer> m = new HashMap<>();public int waysToStep(int n) {if (n == 1) return 1;if (n == 2) return 2;if (n == 3) return 4;if (m.containsKey(n)) return m.get(n);int ret = ((waysToStep(n - 1) + waysToStep(n - 2)) % mod + waysToStep(n - 3)) % mod;m.put(n, ret);return ret; }
}
7.2.2 非递归
class Solution {public int waysToStep(int n) {int mod = 1000000007;if (n == 1) return 1;if (n == 2) return 2;if (n == 3) return 4;int[] dp = new int[n + 1];dp[1] = 1;dp[2] = 2;dp[3] = 4;for (int i = 4; i <= n; i++) {dp[i] = ((dp[i - 1] + dp[i - 2]) % mod + dp[i - 3]) % mod;}return dp[n];}
}
7.2.3 非递归+优化(内存优化)
class Solution {public int waysToStep(int n) {int mod = 1000000007;if (n == 1) return 1;if (n == 2) return 2;if (n == 3) return 4;int a = 1;int b = 2;int c = 4;int d = 0;for (int i = 4; i <= n; i++) {d = ((c + b) % mod + a) % mod;a = b;b = c;c = d;} return d;}
}
8 剑指 Offer 16. 数值的整数次方
链接:https://leetcode.cn/problems/shu-zhi-de-zheng-shu-ci-fang-lcof
8.1 题目
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。
示例 1:
输入:x = 2.00000, n = 10
输出:1024.00000
示例 2:
输入:x = 2.10000, n = 3
输出:9.26100
示例 3:
输入:x = 2.00000, n = -2
输出:0.25000
解释:2-2 = 1/22 = 1/4 = 0.25
8.2 题解
class Solution {public double myPow(double x, int n) {if (n == 0) return 1;if (n == 1) return x;if (n == -1) return 1/x;double h = myPow(x, n / 2);double mod = myPow(x, n % 2);return h * h * mod;}
}
9 递归乘法
链接:https://leetcode.cn/problems/recursive-mulitply-lcci
9.1 题目
递归乘法。 写一个递归函数,不使用 * 运算符, 实现两个正整数的相乘。可以使用加号、减号、位移,但要吝啬一些。
示例1:
输入:A = 1, B = 10
输出:10
示例2:
输入:A = 3, B = 4
输出:12
9.2 题解
class Solution {public int multiply(int A, int B) {if (B == 0) return 0;return A + multiply(A, B - 1);}
}
class Solution {public int multiply(int A, int B) {int n = Math.min(A, B);int k = Math.max(A, B);if (n == 1) {return k;}int h = multiply(n / 2, k);if (n % 2 == 1) {return h + h + k;} else {return h + h;}}
}