LeetCode 递归篇(70、22、98、104)

70. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。

  1. 1 阶 + 1 阶
  2. 2 阶
    示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。

  1. 1 阶 + 1 阶 + 1 阶
  2. 1 阶 + 2 阶
  3. 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;
    }
}
posted @ 2020-07-02 21:10  gg12138  阅读(133)  评论(0编辑  收藏  举报