【leetcode-二叉树遍历】验证/恢复二叉搜索树 / 二叉搜索树中的众数/第K小的元素 / 二叉树中第二小的节点

验证二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:

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

示例 1:
输入:
在这里插入图片描述
输出: true

示例 2:
输入:
在这里插入图片描述
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4

中序遍历

class Solution {
    private 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);
    }
}

递归

class Solution {
    public boolean isValidBST(TreeNode root) {
        return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }

    public boolean isValidBST(TreeNode root, long min, long max) {
        if (root == null)
            return true;
        if (root.val <= min || root.val >= max)
            return false;
        return isValidBST(root.left, min, root.val) && isValidBST(root.right, root.val, max);
    }
}

恢复二叉搜索树

给你二叉搜索树的根节点 root ,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。
进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用常数空间的解决方案吗?

示例 1:
在这里插入图片描述
输入:root = [1,3,null,null,2]
输出:[3,1,null,null,2]
解释:3 不能是 1 左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。

示例 2:
在这里插入图片描述
输入:root = [3,1,4,null,null,2]
输出:[2,1,4,null,null,3]
解释:2 不能在 3 的右子树中,因为 2 < 3 。交换 2 和 3 使二叉搜索树有效。

中序遍历,数组存储

class Solution {
    public void recoverTree(TreeNode root) {
        List<TreeNode> list = new ArrayList<TreeNode>();
        inorder(root, list);
        TreeNode wrong1 = null, wrong2 = null;
        for (int i = 0; i < list.size() - 1; i++) {
            if (list.get(i).val > list.get(i + 1).val) {
                wrong1 = list.get(i + 1);
                if (wrong2 == null)
                    wrong2 = list.get(i);
            }
        }
        int tmp = wrong1.val;
        wrong1.val = wrong2.val;
        wrong2.val = tmp;
    }

    public void inorder(TreeNode root, List<TreeNode> list) {
        if (root == null)
            return;
        inorder(root.left, list);
        list.add(root);
        inorder(root.right, list);
    }
}

中序遍历,存储节点

class Solution {
    private TreeNode wrong1 = null;
    private TreeNode wrong2 = null;
    private TreeNode pre = null;
    private int count = 0;
    public void recoverTree(TreeNode root) {
        inorder(root);
        
        int tmp = wrong1.val;
        wrong1.val = wrong2.val;
        wrong2.val = tmp;
    }

    public void inorder(TreeNode root) {
        if (count >= 2 || root == null)
            return;
        inorder(root.left);
        if (pre == null) {
            pre = root;
        } else {
            if (pre.val > root.val) {
                count++;
                wrong1 = root;
                if (wrong2 == null)
                    wrong2 = pre;
            }
            pre = root;
        }
        inorder(root.right);
    }
}

莫里斯遍历

可以做到 O(1) 的空间复杂度去遍历一棵树。

class Solution {
    public void recoverTree(TreeNode root) {
        if(root==null)
			return;
        
        TreeNode wrong1 = null, wrong2 = null;
		TreeNode pre = null, node = null;
        while(root!=null) {
            if(root.left != null) {
                node = root.left;
                while(node.right != null && node.right != root) 
                    node = node.right;
                if(node.right == null) {
                    node.right = root;
                    root = root.left;
                } else {
                    if(pre != null && pre.val > root.val) {
                        wrong1 = root;
                        if(wrong2 == null)
                            wrong2 = pre;
                    }
                    pre = root;
                    node.right = null;
                    root = root.right;
                }
            } else {
				if(pre != null && pre.val > root.val) {
					wrong1 = root;
                    if(wrong2 == null)
                        wrong2 = pre;
				}
				pre = root;
				root = root.right;
			}
        }
        int tmp = wrong1.val;
        wrong1.val = wrong2.val;
        wrong2.val = tmp;
    }
}

二叉搜索树中第K小的元素

给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。

示例 1:
在这里插入图片描述
输入:root = [3,1,4,null,2], k = 1
输出:1

示例 2:
在这里插入图片描述
输入:root = [5,3,6,2,4,null,null,1], k = 3
输出:3

迭代

class Solution {
    public int kthSmallest(TreeNode root, int k) {
        Deque<TreeNode> stack = new LinkedList<>();
        while (root != null || !stack.isEmpty()) {
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            if (0 == --k)
                return root.val;
            root = root.right;
        }
        return 0;
    }
}

递归

class Solution {
    public int kthSmallest(TreeNode root, int k) {
        return inorder(root, k, new ArrayList<Integer>()).get(k - 1);
    }

    private List<Integer> inorder(TreeNode root, int k, List<Integer> list) {
        if (root == null || list.size() == k)
            return list;

        inorder(root.left, k, list);
        list.add(root.val);
        inorder(root.right, k, list);
        return list;
    }
}

二叉搜索树中的众数

给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。

假定 BST 有如下定义:

  • 结点左子树中所含结点的值小于等于当前结点的值
  • 结点右子树中所含结点的值大于等于当前结点的值
  • 左子树和右子树都是二叉搜索树

例如:
给定 BST [1,null,2,2],
在这里插入图片描述
返回[2].

提示:如果众数超过1个,不需考虑输出顺序

中序遍历

class Solution {
    private List<Integer> result = new ArrayList<>();
    private int count = 0, cur_val = 0, max_count = 0;
    public int[] findMode(TreeNode root) {
        inorder(root);
        int[] ans = new int[result.size()];
        for (int i = 0; i < result.size(); i++)
            ans[i] = result.get(i);
        return ans;
    }

    private void inorder(TreeNode node) {
        if (node == null)
            return;

        inorder(node.left);
        int val = node.val;
        if (val == cur_val) {
            count++;
        } else {
            cur_val = val;
            count = 1;
        }

        if (count == max_count)
            result.add(val);
        else if (count > max_count) {
            result.clear();
            result.add(val);
            max_count = count;
        }
        inorder(node.right);
    }
}

Morris遍历

class Solution {
    private int cur_val = 0, count = 0, maxCount = 0;
    private List<Integer> answer = new ArrayList<Integer>();

    public int[] findMode(TreeNode root) {
        TreeNode cur = root, pre = null;
        while (cur != null) {
            if (cur.left == null) {
                update(cur.val);
                cur = cur.right;
                continue;
            }

            for (pre = cur.left; pre.right != null && pre.right != cur; pre = pre.right);

            if (pre.right == null) {
                pre.right = cur;
                cur = cur.left;
            } else {
                pre.right = null;
                update(cur.val);
                cur = cur.right;
            }
        }

        int[] result = new int[answer.size()];
        for (int i = 0; i < answer.size(); ++i) 
            result[i] = answer.get(i);
        return result;
    }

    private void update(int x) {
        if (x == cur_val) {
            ++count;
        } else {
            count = 1;
            cur_val = x;
        }

        if (count == maxCount) {
            answer.add(x);
        } else if (count > maxCount) {
            maxCount = count;
            answer.clear();
            answer.add(x);
        }
    }
}

二叉树中第二小的节点

给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么该节点的值等于两个子节点中较小的一个。
更正式地说,root.val = min(root.left.val, root.right.val) 总成立。
给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。

示例 1:
在这里插入图片描述
输入:root = [2,2,5,null,null,5,7]
输出:5
解释:最小的值是 2 ,第二小的值是 5 。

示例 2:
在这里插入图片描述
输入:root = [2,2,2]
输出:-1
解释:最小的值是 2, 但是不存在第二小的值。

递归

class Solution {
    private int result = -1;
    public int findSecondMinimumValue(TreeNode root) {
        if (root == null)
            return result;

        if (root.left != null && root.left.val != root.right.val) {
            int larger = Math.max(root.left.val, root.right.val);
            result = result == -1 ? larger : Math.min(result, larger);
            findSecondMinimumValue(root.left.val > root.right.val ? root.right : root.left);
        } else {
            findSecondMinimumValue(root.left);
            findSecondMinimumValue(root.right);
        }
        return result;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值