java leetcode之[动态规划 中等]99. 恢复二叉搜索树

这篇博客主要介绍了如何解决LeetCode上的问题——恢复二叉搜索树。作者提供了两种解题方案,分别是暴力版和优化版。暴力版通过中序遍历找到不合规的节点并交换,而优化版则通过标记第一次和第二次下降的节点来提高效率。在遍历过程中,使用栈辅助中序遍历,并用一个列表记录节点,以便进行节点值的比较和交换。
摘要由CSDN通过智能技术生成

题目的链接在这里:https://leetcode-cn.com/problems/recover-binary-search-tree/


题目大意

给你二叉搜索树的根节点 root ,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。

进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用常数空间的解决方案吗?


一、示意图

在这里插入图片描述

二、解题思路

中序遍历 

暴力版

代码如下:

/**
 * 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 {
    int count=400;
    public  void recoverTree(TreeNode root) {
        List<TreeNode> list=new ArrayList<>();
        //先进行中序遍历
        //就必须是 这个节点和他前一个节点的比较就行了
        if(root==null){
            return;
        }
        //使用栈进行中序遍历
        Stack<TreeNode> stack=new Stack<>();
        TreeNode temp=root;
        while (temp!=null||!stack.isEmpty()){
            //一直递归到他最左边的值
            while (temp!=null){
                /**
                 * 一直找到最左边的
                 */
                stack.push(temp);
                //那就这里不判断
           /*     if(temp.left!=null){
                    if(temp.left.val>temp.val){
                        //直接不合规
                        swap(temp.left,temp);
                        //说明不能return
                        return;
                    }else{
                        temp=temp.left;
                    }
                }else {
                    temp = temp.left;
                }*/
                temp = temp.left;
            }
            //直接设置一个数组来存这些好了
            //现在temp就是指向null 而栈顶元素就是当前最左边的了
            if(!stack.isEmpty()){
                //这里就进行一次和上一个的查找
                //这里要进行一次查重
                temp=stack.pop();
               // System.out.println("temp.val = " + temp.val);
                if(list.size()!=0){
                    //说明他存在上一个 问题只可能出现在这
                    TreeNode l=list.get(list.size()-1);
                    //System.out.println(".va = " +l.val);
                    //让l和这个temp进行对比
                    if(temp.val<l.val){
                        //说明违规 就需要换位置
                        swap(temp,l);

                        //说明这边是不能return的 他们两个换号之后 list最
                        list.add(temp);
                        //然后指向
                    }
                    else{
                        //那就正常进行
                        list.add(temp);
                    }
                }
                //这个temp就在最左边的这个
                else {
                    list.add(temp);
                }
                //这里的问题吧 需要让3和右边最左边的数相比较 和他前一个节点的比较
                //temp这个时候是一个树的最左子树 他的前一个 那就和他后一个进行比较也行吧
     /*           if(temp.right!=null){
                    TreeNode te=temp.right;
                    //先和最右边的最左边进行比较
                    while (te.left!=null){
                        te=te.left;
                    }
                    //te就是指向右子树的最左边
                    if(te.val<temp.val){
                        //说明违规了
                        swap(te,temp);
                        return;
                    }
                    //说明这个点还存在右子树
                    //先进行判断
                    if(temp.right.val<temp.val){
                        //说明违规 直接进行交换
                        swap(temp.right,temp);
                        return;
                    }else{*/
         /*               //那就正常
                        temp=temp.right;
                    }
                }
                else{
                    //也是正常
                    temp=temp.right;
                }*/
                temp=temp.right;
                //System.out.println("temp.right.val = " + temp.right.val);
            }
            
            //要么就是在需要来一遍
            
        }
        count--;
        if(count!=0){
            recoverTree(root);
        }

    }

    private  void swap(TreeNode right, TreeNode temp) {
        //交换的代码 交换的是值
        int t=right.val;
        right.val=temp.val;
        temp.val=t;
    }
}

在这里插入图片描述

优化版

代码如下:

/**
 * 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 {
        /**
         * 可能会出现要交换好几次 所以记录 第一个下降前和第二个下降后的元素兑换
         * @param root
         */
        public  void recoverTree(TreeNode root) {
            TreeNode pre = null;
            TreeNode ord= null;
            TreeNode te=null;
            boolean flag=true;
            List<TreeNode> list=new ArrayList<>();
            //先进行中序遍历
            //就必须是 这个节点和他前一个节点的比较就行了
            if(root==null){
                return;
            }
            //使用栈进行中序遍历
            Stack<TreeNode> stack=new Stack<>();
            TreeNode temp=root;
            while (temp!=null||!stack.isEmpty()){
                //一直递归到他最左边的值
                while (temp!=null){
                    /**
                     * 一直找到最左边的
                     */
                    stack.push(temp);
                    temp = temp.left;
                }
                if(!stack.isEmpty()){
                    //这里就进行一次和上一个的查找
                    //这里要进行一次查重
                    temp=stack.pop();
                    //   System.out.println("temp.val = " + temp.val);
                    if(list.size()!=0){
                        //说明他存在上一个 问题只可能出现在这
                        TreeNode l=list.get(list.size()-1);
                        //   System.out.println(".va = " +l.val);
                        //让l和这个temp进行对比
                        if(temp.val<l.val){
                            //这里不交换 而是做标记
                            if(flag){
                                //万一只进行一次交换
                                //说明是第一次交换 那就记录第一次交换中的前一个数组也就是这个3
                                pre=l;
                                te=temp;
                                flag=false;
                            }else{
                                //说明不是第一次交换 那就把第二次交换的后一个也进行标记
                                ord=temp;
                            }
                        }
                        else{
                            //那就正常进行
                            list.add(temp);
                        }
                    }
                    //这个temp就在最左边的这个
                    else {
                        list.add(temp);
                    }

                    temp=temp.right;
                    //System.out.println("temp.right.val = " + temp.right.val);
                }

                //要么就是在需要来一遍

            }
            //直到这里再交换 就需要把两次交换还是一次交换的统计出来
            if(ord!=null) {
                swap(pre, ord);
            }else{
                swap(pre,te);
            }


        }

        private  void swap(TreeNode right, TreeNode temp) {
            //交换的代码 交换的是值
            int t=right.val;
            right.val=temp.val;
            temp.val=t;
        }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值