7月11日的五题

95. 不同的二叉搜索树 II

Difficulty: 中等

给定一个整数 n,生成所有由 1 … n 为节点所组成的 二叉搜索树

示例:

输入:3
输出:
[
  [1,null,3,2],
  [3,2,null,1],
  [3,1,null,null,2],
  [2,1,3],
  [1,null,2,null,3]
]
解释:
以上的输出对应以下 5 种不同结构的二叉搜索树:

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

提示:

  • 0 <= n <= 8
Solution:递归,以其中一个值为根节点,其两边的值就是左右子树,注意当 L > R时,需要添加null
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */


 /*思路:
        1. 就是把L,R看成是二叉搜索树中序遍历的左右边界
        2.枚举每个点为root,递归两边。返回的集合中都是合法的左子树或者右子树
        3.root和集合中的左右子树分别拼接一下即可
*/

class Solution {
     public List<TreeNode> generateTrees(int n) {
        
        if(n < 1) return new ArrayList<>();
        return dfs(1,n);
    }


    public List<TreeNode> dfs(int L, int R){
        List<TreeNode> res = new ArrayList<>();
        if(L > R){
            res.add(null);
            return res;
        }

        for(int i=L; i<=R; i++){  //分别为根节点
            
            List<TreeNode> left = dfs(L, i-1);
            List<TreeNode> right = dfs(i+1, R);
            for(TreeNode l: left){
                for(TreeNode r: right){
                    TreeNode head = new TreeNode(i);
                    head.left = l;
                    head.right = r;
                    res.add(head);
                }
            }
        }
        return res;
    }
   

}

96. 不同的二叉搜索树

Difficulty: 中等

给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?

示例:

输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3
Solution:对比上一题。找规律 :

当n = 3时:

  1. 以1根节点 f(3) += f(0)*f(2)
  2. 以2为根节点:f(3) += f(1)*f(1)
  3. 以3位根结点:f(3) += f(2)*f(0)
    其中f(0) = 1,f(1) = 1, f(2) = 2;所以f(3) = f(0)*f(2) + f(1)*f(1) + f(2)*f(0) = 5
    同理 f(4) = f(0)*f(3) + f(1)*f(2) + f(2)*f(1) + f(3)*f(0) = 14
    f(n) = f(0)*f(n-1) + f(1)*f(n-2) + f(2)*f(n-3) +…+ f(n-1)*f(0)
class Solution {
    public int numTrees(int n) {

        if(n<=0) return 0;
        if(n == 1) return 1;
        if(n == 2) return 2;

        int[] dp = new int[n+1];
        dp[0] = 1;
        dp[1] = 1;
        dp[2] = 2;
        
        for(int i=3; i<=n; i++){
            dp[i] = 0;
            for(int j=0; j<=i-1; j++){
                dp[i] += dp[j]*dp[i-1-j];
            }
        }
        return dp[n];
    }


}

97. 交错字符串

Difficulty: 困难

给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1s2 交错组成的。

示例 1:

输入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
输出: true

示例 2:

输入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
输出: false
Solution:动态规划,boolean dp[i][j]表示s1的前i个字符,s2的前j个字符,是否可以组合成s3的前(i+j)个字符
class Solution {
    public boolean isInterleave(String s1, String s2, String s3) {
        
        int len1 = s1.length(), len2 = s2.length(), len3 = s3.length();
        if(len3<0 || (len1+len2)!=len3) return false;

        boolean[][] dp = new boolean[len1+1][len2+1];
        dp[0][0] = true;

        for(int i=0; i<=len1; i++){
            for(int j=0; j<=len2; j++){
                if(i==0 && j==0) continue;
                else if(i==0){
                    if(s2.charAt(j-1) == s3.charAt(j-1)) dp[0][j] = dp[0][j-1];
                }
                else if(j==0){
                    if(s1.charAt(i-1) == s3.charAt(i-1)) dp[i][0] = dp[i-1][0];
                }
                else{
                    dp[i][j] = (s1.charAt(i-1)==s3.charAt(i+j-1) && dp[i-1][j]) || 
                                (s2.charAt(j-1)==s3.charAt(i+j-1) && dp[i][j-1]);
                }
            }
        }
        return dp[len1][len2];

    }

}

98. 验证二叉搜索树

Difficulty: 中等

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

假设一个二叉搜索树具有如下特征:

  • 节点的左子树只包含小于当前节点的数。
  • 节点的右子树只包含大于当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

示例 1:

输入:
    2
   / \
  1   3
输出: true

示例 2:

输入:
    5
   / \
  1   4
     / \
    3   6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
     根节点的值为 5 ,但是其右子节点值为 4 。
Solution:中序遍历是否递增,非递归遍历(借助栈)
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isValidBST(TreeNode root) {
        List<Integer> num = new ArrayList<>();
        List<TreeNode> stack = new ArrayList<>();

        TreeNode cur = root;
        while(cur!=null || !stack.isEmpty()){
            if(cur != null){
                stack.add(cur);
                cur = cur.left;
            }
            else{
                cur = stack.remove(stack.size()-1);
                if(!num.isEmpty() && num.get(num.size()-1) >= cur.val) 
                    return false;
                num.add(cur.val);
                cur = cur.right;
            }
        }
        return true;
    }
}

99. 恢复二叉搜索树

Difficulty: 困难

二叉搜索树中的两个节点被错误地交换。

请在不改变其结构的情况下,恢复这棵树。

示例 1:

输入: [1,3,null,null,2]

   1
  /
 3
  \
   2

输出: [3,1,null,null,2]

   3
  /
 1
  \
   2

示例 2:

输入: [3,1,4,null,null,2]

  3
 / \
1   4
   /
  2

输出: [2,1,4,null,null,3]

  2
 / \
1   4
   /
  3

进阶:

  • 使用 O(n) 空间复杂度的解法很容易实现。
  • 你能想出一个只使用常数空间的解决方案吗?
Solution:中序遍历之后,找到逆序对,如果只有一对,则两个数直接交换,如果有两对,则交换这两对数最左边和最右边。
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */

 //交换只需要交换两个值就可以了
class Solution {
    public void recoverTree(TreeNode root) {
        if(root == null) return;
        List<TreeNode> nodeList = new ArrayList<>();
        midSort(root, nodeList);


        int i1 = 0, i2 = 0; //需要交换的位置
        int count = 0; //逆序对的个数
        int len = nodeList.size();
        for(int i=0; i<len; i++){
            if(i<len-1 && nodeList.get(i).val>nodeList.get(i+1).val){
                if(count == 0){
                    i1 = i;
                    i2 = i+1;
                    count++;
                }
                else{
                    i2 = i+1;
                    break;
                }
                //System.out.println(i1+","+i2);
            }
        }

        //System.out.println(nodeList.get(i1).val +","+ nodeList.get(i2).val);
        //交换值
        int temp = nodeList.get(i1).val;
        nodeList.get(i1).val = nodeList.get(i2).val;
        nodeList.get(i2).val = temp;
    }

   //中序遍历
    public void midSort(TreeNode root, List<TreeNode> nodeList){
        if(root == null) return;
        midSort(root.left, nodeList);
        nodeList.add(root);
        midSort(root.right, nodeList);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值