leetcode---递归

1137. 第 N 个泰波那契数

在这里插入图片描述

【代码一】超时

class Solution {
    public int tribonacci(int n) {
        if(n == 0){
            return 0;
        }
        if(n == 1 || n == 2){
            return 1;
        }
        return tribonacci(n-1) + tribonacci(n-2) + tribonacci(n-3);
    }
}

【代码二】通过—动态规划

class Solution {
    public int tribonacci(int n) {
        if(n == 0){
            return 0;
        }
        if(n == 1 || n == 2){
            return 1;
        }
        int[] dp = new int[n+1];
        dp[0] = 0;
        dp[1] = dp[2] = 1;
        for(int i = 3; i <= n; i++){
            dp[i] = dp[i-1] + dp[i-2] + dp[i-3];
        }
        return dp[n];
    }
}

【代码三】通过—记忆搜索

class Solution {
    private int[] dp; // 记忆数组
    public int tribonacci(int n) {
        if(n == 0){
            return 0;
        }
        if(n == 1 || n == 2){
            return 1;
        }
        dp = new int[n+1];
        dp[0] = 0;
        dp[1] = dp[2] = 1;
        for(int i = 3; i <= n; i++){
            dp[i] = -1;
        }
        return solve(n);
    }
    private int solve(int n){
        if(dp[n] == -1){
            dp[n] = solve(n-1) + solve(n-2) + solve(n-3);
        }
        return dp[n];
    }
}

【代码四】通过—三个变量直接递推

class Solution {
    public int tribonacci(int n) {
        if(n == 0){
            return 0;
        }
        if(n == 1 || n == 2){
            return 1;
        }
        // 直接用三个变量递推,类似于动态规划,但不记录中间结果
        int a = 0;
        int b = 1;
        int c = 1;
        int tmp;
        for(int i = 3; i <= n; i++){
            tmp = a + b + c;
            a = b;
            b = c;
            c = tmp;
        }
        return c;
    }
}

【代码五】通过—直接打表(利用题目数据范围)

class Solution {
    private int[] table = {
	    0, 1, 1, 2, 4, 7, 13, 24, 44, 81, 149, 274, 504, 927, 1705, 3136, 5768, 10609, 19513, 35890, 66012, 121415,223317, 410744, 755476, 1389537, 2555757, 4700770, 8646064, 15902591, 29249425, 53798080, 98950096, 181997601,334745777, 615693474, 1132436852, 2082876103};

    public int tribonacci(int n) {
        return table[n];
    }
}

938. 二叉搜索树的范围和

在这里插入图片描述
【代码一】通过—二叉搜索树遍历

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int rangeSumBST(TreeNode root, int L, int R) {
        if(root == null){
            return 0;
        }
        if(root.val < L){
            return rangeSumBST(root.right, L, R);
        }
        if(root.val > R){
            return rangeSumBST(root.left, L, R);
        }
        return rangeSumBST(root.left, L, R) + rangeSumBST(root.right, L, R) + root.val;
    }
}

【代码二】通过—普通二叉树遍历

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int rangeSumBST(TreeNode root, int L, int R) {
        if(root == null){
            return 0;
        }
        if(root.val < L || root.val > R){
            return rangeSumBST(root.right, L, R) + rangeSumBST(root.left, L, R);
        }
        return rangeSumBST(root.left, L, R) + rangeSumBST(root.right, L, R) + root.val;
    }
}

894. 所有可能的满二叉树

在这里插入图片描述在这里插入图片描述在这里插入图片描述
【代码一】通过—暴力递归

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<TreeNode> allPossibleFBT(int N) {
        /**
            确定是什么问题重要。。整棵树是”满二叉树“,以每个节点为根的子树也是”满二叉树“,
            这就是递归了。。
            节点总数是N,首先N必定是奇数,递归结束条件易定,N为偶数或N=1。递归拆解子问题
            FBT(N) = {x >= 1 && x < N, 递归左子树FBT(x),递归右子树FBT(N-1-x),1->根 
        */
        List<TreeNode> ans = new ArrayList<>();
        
        if(N == 1){
            ans.add(new TreeNode(0));
            return ans;
        }
        if(N % 2 == 0){
            return ans;
        }
        
        for(int x = 1; x < N; x += 2){
            List<TreeNode> leftT = allPossibleFBT(x);
            List<TreeNode> rightT = allPossibleFBT(N-1-x);
            for(TreeNode l : leftT){
                for(TreeNode r : rightT){
                    TreeNode root = new TreeNode(0);
                    root.left = l;
                    root.right = r;
                    ans.add(root);
                }
            }
        }
        return ans;
    }
}

【代码二】通过—记忆化搜索

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    
    private Map<Integer, List<TreeNode> > map = new HashMap<>();
    
    public List<TreeNode> allPossibleFBT(int N) {
        /**
            确定是什么问题重要。。整棵树是”满二叉树“,以每个节点为根的子树也是”满二叉树“,
            这就是递归了。。
            节点总数是N,首先N必定是奇数,递归结束条件易定,N为偶数或N=1。递归拆解子问题
            FBT(N) = {x >= 1 && x < N, 递归左子树FBT(x),递归右子树FBT(N-1-x),1->根 
        */
        
        if(map.containsKey(N)){
            return map.get(N);
        }
        
        List<TreeNode> ans = new ArrayList<>();
        
        if(N == 1){
            ans.add(new TreeNode(0));
            return ans;
        }
        if(N % 2 == 0){
            return ans;
        }
        
        for(int x = 1; x < N; x += 2){
            List<TreeNode> leftT = allPossibleFBT(x);
            List<TreeNode> rightT = allPossibleFBT(N-1-x);
            for(TreeNode l : leftT){
                for(TreeNode r : rightT){
                    TreeNode root = new TreeNode(0);
                    root.left = l;
                    root.right = r;
                    ans.add(root);
                }
            }
        }
        map.put(N, ans);
        return ans;
    }
}

783. 二叉搜索树结点最小距离

在这里插入图片描述在这里插入图片描述
【代码一】通过—欠妥暴力思路
遍历出来,搞成一个数组,排序,遍历一遍比较搞定。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private List<Integer> list = new ArrayList<>();
    public int minDiffInBST(TreeNode root) {
        dfs(root);
        Collections.sort(list, new Comparator<Integer>(){
           public int compare(Integer x, Integer y){
               return x - y;
           } 
        });
        int min = Integer.MAX_VALUE;
        for(int i = 1; i < list.size(); i++){
            if(list.get(i) - list.get(i-1) < min){
                min = list.get(i) - list.get(i-1);
            }
        }
        return min;
    }
    private void dfs(TreeNode root){
        if(root != null){
            list.add(root.val);
            dfs(root.left);
            dfs(root.right);
        }
    }
}

【代码二】通过—利用二叉搜索树性质,边遍历边比较

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private TreeNode pre = null;
    private int min = Integer.MAX_VALUE;
        
    public int minDiffInBST(TreeNode root) {
        dfs(root);
        return min;
    }
    private void dfs(TreeNode root){
        if(root != null){
            dfs(root.left);
            if(pre != null){
                min = min > root.val - pre.val ? root.val - pre.val : min;
            }
            pre = root;
            dfs(root.right);
        }
    }
}

779. 第K个语法符号

在这里插入图片描述在这里插入图片描述

【代码一】超时—暴力递归

class Solution {
    public int kthGrammar(int N, int K) {
        String s = f(N);
        return s.charAt(K-1) - '0';
    }
    private String f(int N){
        if(N == 1){
            return "0";
        }
        String s = f(N-1);
        String obj = "";
        for(int i = 0; i < s.length(); i++){
            obj += s.charAt(i) == '0' ? "01" : "10";
        }
        return obj;
    }
}

【代码二】通过—找规律

class Solution {
    public int kthGrammar(int N, int K) {
        // 与其说递归,不如说是找规律。。
        // 第N行前一半和第N-1行完全一样。
        // 第N行后一半和第N-1行完全相反。
        if(N == 1){
            return 0;
        }
        int len = (1 << (N-2)); // 第N行长度
        if(K <= len){
            return kthGrammar(N-1, K);
        }
        return 1 - kthGrammar(N-1, K-len); // 0转成1,1转成0
    }
}

【代码三】通过—借助二叉树

class Solution {
    public int kthGrammar(int N, int K) {
        // 看成是二叉树
        // 0的左孩子是0,右孩子是1。1与之相反。K的奇偶可定左孩子还是右孩子
        // 关键问题就是找父亲是1还是0,递归往上走。
        // 树的每层都是从1开始数
        // K为偶数时,kthGrammar(N, K)的父亲是kthGrammar(N, K/2)
        // K为奇数时,kthGrammar(N, K)的父亲是kthGrammar(N, (K+1)/2)
        if(N == 1){
            return 0;
        }
        if(K % 2 == 0){
            return 1 - kthGrammar(N-1, K/2);
        }else{
            return kthGrammar(N-1, (K+1)/2);
        }
    }
}

698. 划分为k个相等的子集

在这里插入图片描述
【代码一】通过—暴力回溯

class Solution {
    public boolean canPartitionKSubsets(int[] nums, int k) {
        // 回溯法。
        // 先对数组求和得sum及最大值max,
        // 1.若sum%k != 0 || max > sum/k(此max无法放入任一个桶),返回false
        // 2.搞成K个桶,每个桶初始值都是0,尝试每个数依次放入不同桶中,如果所有桶
        //   都能达到sum/k,就返回true。尝试所有情况都不行,那就返回false
        
        int sum = 0;
        int max = 0; // 因为nums[i]>0
        for(int i = 0; i < nums.length; i++){
            sum += nums[i];
            max = max < nums[i] ? nums[i] : max;
        }
        if(sum % k != 0 || max > sum/k){
            return false;
        }
        int[] bucket = new int[k];
        Arrays.fill(bucket, 0);
        return backtrack(nums, k, bucket, sum/k, 0);
    }
    // cur ---> 尝试放当前值nums[cur]放入某个桶
    private boolean backtrack(int[] nums, int K, int[] bucket, int avg, int cur){
        if(cur >= nums.length){ // 已经尝试放完了所有的值到K个桶中
            return true;
        }
        for(int i = 0; i < K; i++){
            // 某值nums[cur]满足啥标准才放入桶bucket[i]中,这是关键
            if(bucket[i] + nums[cur] <= avg){
                bucket[i] += nums[cur]; // TODO,若需记录实际每个桶中有哪些值,可以在这里记录
                // dfs,直至搜出一条路,或不满足回退
                if(backtrack(nums, K, bucket, avg, cur+1)){
                    return true;
                }else{
                    bucket[i] -= nums[cur];
                }
            }
        }
        // 已经尝试所有情况,都没有返回true,说明没有解
        return false;
    }
}

687. 最长同值路径

在这里插入图片描述在这里插入图片描述
【代码一】通过—二叉树递归遍历
参考资料链接

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private int ans;
    
    public int longestUnivaluePath(TreeNode root) {
        ans = 0;
        len(root);
        return ans;
    }
    // 记录以某个节点作为根,包含根的左右单侧最长路径
    private int len(TreeNode root){
        if(root == null){
            return 0;
        }
        int left = len(root.left);
        int right = len(root.right);
        int leftL = 0, rightL = 0;
        if(root.left != null && root.val == root.left.val){
            leftL = left + 1;
        }
        if(root.right != null && root.val == root.right.val){
            rightL = right + 1;
        }
        ans = Math.max(ans, leftL + rightL);
        return Math.max(leftL, rightL);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值