LeetCode 递归篇(70、22、98、104)
70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
- 1 阶 + 1 阶
- 2 阶
示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
- 1 阶 + 1 阶 + 1 阶
- 1 阶 + 2 阶
- 2 阶 + 1 阶
思路
//动态规划 二维矩阵
//递归,即斐波那契数列 可以有以下四个解法
//找最近重复性???
solution1 傻递归
//45阶时超时
class Solution {
public int climbStairs(int n) {
if (n<=2) return n;
else return climbStairs(n-1) + climbStairs(n-2);
}
}
solution2 迭代
class Solution {
public int climbStairs(int n) {
if (n<=2) return n;
int a = 1,b=2;
while(n-->2){ //运行与后面的数的差次数
int sum= a + b;
a = b;
b = sum;
}
return b;
}
}
solution3 高级递归
//自顶向下 对计算过的进行保存
class Solution {
int[] cache = new int[100];
public int climbStairs(int n) {
if (n<=2) return n;
else if (cache[n] != 0) return cache[n];
else return cache[n] = climbStairs(n-1) + climbStairs(n-2);
}
}
solution3 动态规划
//从下到上至要抵达的台阶
class Solution {
public int climbStairs(int n) {
int[] cache = new int[n+1];
cache[1] = 1;
cache[0] = 1;
for (int i = 2;i<=n;i++){
cache[i] = cache[i-1]+cache[i-2];
}
return cache[n];
}
}
22. 括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例:
输入:n = 3
输出:[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
思路
//递归 不断生成左右括号
//递归1 生成全部情况,过滤掉不合法的情况
//递归2 一边生成符号,一边保留格式正常的
//找最小重复性
solution 1
class Solution {
private List<String> result;
public List<String> generateParenthesis(int n) {
result = new ArrayList<>();
_generate(0, 2*n, "");
return result;
}
private void _generate(int curr,int n,String s){
//停止递归
if (curr == n) {
_filter(s);
return;
}
//当前层
//下一层
_generate(curr+1,n,s+'(');
_generate(curr+1,n,s+')');
}
private void _filter(String s){
Stack<Character> st = new Stack<>();
for (char c : s.toCharArray()){
if(c == '(') st.push(c);
else {
if (!st.isEmpty()){
st.pop();
}else {
return;
}
}
}
if (st.isEmpty()) result.add(s);
}
}
solution 2
class Solution {
private List<String> result;
public List<String> generateParenthesis(int n) {
result = new ArrayList<>();
_generate(0,0,n,"");
return result;
}
private void _generate(int left,int right,int n,String s){
//抵达最后一层,停止递归
if (left == n && right == n) {
result.add(s);
return;
}
//当前层
//下一层
// 左括号数量大于右括号数量时,添加右括号
if (left < n) {
_generate(left+1,right,n,s+'(');
}
if (left > right) {
_generate(left,right+1,n,s + ")");
}
}
}
class Solution {
public List<String> generateParenthesis(int n) {
List<String> result = new ArrayList<>();
_generate(result,0,0, 2*n, "");
return result;
}
private void _generate(List<String> result,int left,int right,int max,String s){
if (s.length() == max) {
result.add(s);
return;
}
if (left < max/2) _generate(result,left+1,right,max,s+'(');
if (right < left) _generate(result,left,right+1,max,s+')');
}
}
98. 验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:
2
/
1 3
输出: true
示例 2:
输入:
5
/
1 4
/
3 6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4 。
错误思路
//没有考虑是整个子树的比较而不只是结点的比较
class Solution {
public boolean isValidBST(TreeNode root) {
if (root == null) return true;
//终止条件
if (root.left == null && root.right == null) return true;
//当前层
if (root.left != null && root.left.val >= root.val) return false;
if (root.right != null && root.right.val <= root.val) return false;
return isValidBST(root.left) && isValidBST(root.right);
}
}
思路整理
//思路1:传入根结点进入递归(错) 传入结点对应树的最小和最大值(对)
//思路2:中序遍历为升序即true
solution1递归
class Solution {
public boolean isValidBST(TreeNode root) {
return helper(root,null,null);
}
public boolean helper(TreeNode root,Integer low,Integer up){
//终止层
if (root == null) return true;
//当前层
if (low!=null && root.val <= low) return false;
if (up!=null && root.val >= up) return false;
//下一层
return helper(root.left,low,root.val) && helper(root.right,root.val,up);
}
}
solution2 中序遍历
class Solution {
public boolean isValidBST(TreeNode root) {
Stack<TreeNode> st = new Stack<>();
double inorder = -Double.MAX_VALUE;
while(!st.isEmpty() || root != null){
while(root!=null){
st.push(root);
root = root.left;
}
root = st.pop();
if (root.val <= inorder) return false;
inorder = root.val;//取左子树为最小值
root = root.right;//遍历右子树
}
return true;
}
}
// 甜姨解法
class Solution {
long pre = Long.MIN_VALUE;
public boolean isValidBST(TreeNode root) {
if (root == null) return true;
//访问左子树(递归到底)
if (!isValidBST(root.left)) return false;
//访问当前结点
if (root.val<=pre) return false;
pre = root.val;
//访问右子树
return isValidBST(root.right);
}
}
104. 二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回它的最大深度 3 。
思路
//递归1、(如果有子树就加1并递归下一层)
//迭代1 深度优先
//迭代2 广度优先
solution1 递归
class Solution {
public int maxDepth(TreeNode root) {
if (root == null) return 0;
return helper(root,1);
}
public int helper(TreeNode root,int max) {
if (root.left == null && root.right == null) return max;
//当前层 和下一层
int left = 0;
int right = 0;
if (root.left != null) left = helper(root.left, max+1);
if (root.right != null) right = helper(root.right,max+1);
return Math.max(right,left);
}
}
//简洁版
class Solution {
public int maxDepth(TreeNode root) {
if (root == null) return 0;
else {
int left = maxDepth(root.left);
int right = maxDepth(root.right);
return Math.max(left,right)+1;
}
}
}
// 无敌版
class Solution {
public int maxDepth(TreeNode root) {
return root == null?0:Math.max(maxDepth(root.right),maxDepth(root.left))+1;
}
}
solution2 迭代
class Solution {
public int maxDepth(TreeNode root) {
TreeNode node = root;
Stack<TreeNode> nodest = new Stack<>();
Stack<Integer> depthst = new Stack<>();
int max = 0;
int depth = 1;
while (node !=null || nodest.size() > 0){
if (node!=null) {
nodest.push(node);
depthst.push(depth);
node = node.left;
depth++;
}else{
//当前结点为空,即该左树结束
node = nodest.pop();
depth = depthst.pop();
if(depth>max) max = depth;
// 遍历右子树
node = node.right;
depth++;
}
}
return max;
}
}
企鹅号:1272420336,一起学习,一起进步~