LeetCode刷题 day29

目录

  • [1. 恢复二叉搜索树](#1. 恢复二叉搜索树)
  • [2. 有序链表转换二叉搜索树](#2. 有序链表转换二叉搜索树)

1. 恢复二叉搜索树

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

示例 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 使二叉搜索树有效。

思路

中序遍历后能得到二叉搜索树的升序排列,如果有两个位置交换了顺序,分两种情况,一是相邻位置交换顺序,则中序遍历后只有一个位置是x>y(x在y前面),二是不相邻位置交换顺序,则中序遍历后会有两个位置是x>y。这里通过一个语句即可满足这两种情况

java 复制代码
# pred表示中序遍历中的前驱节点,root表示当前节点
# 第一次遇到时,x,y都会被赋值
# 第二次遇到时,y会被赋值,x不会
# 以1 2 3 4 5 6 7 为例
# 交换相邻元素 1 2 4 3 5 6 7
# 遍历完后 x=4 y=3 
# 交换不相邻元素 1 6 3 4 5 2 7
# 遍历完后 x=6 y=2
if(pred != null && root.val<pred.val){
	y=root;
	if(x==null){
		x = pred;
	}
}

因此最简单的做法是中序遍历,得到整个升序数组,再找出非升序的位置即可。但空间复杂度会是 O ( n ) O(n) O(n),这里 n n n是树的节点数,为了减小空间复杂度,可以采用Morris遍历,将空间复杂度降为 O ( 1 ) O(1) O(1)

java 复制代码
/**
 * 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) {
        TreeNode x = null,y = null,pred = null, predecessor = null;
        while(root!=null){
            if(root.left!=null){
                //第一次先建立当前节点与左子树的前驱联系
                //并遍历左子树
                //第二次进来时遍历当前节点,并且消除前驱联系
                //建立前驱节点
                predecessor = root.left;
                while(predecessor.right!=null&&predecessor.right!=root){
                    predecessor = predecessor.right; 
                }
                if(predecessor.right==null){//建立前驱节点连接
                    predecessor.right = root;
                    root = root.left;
                }else{
                    //遍历当前节点
                    if(pred!=null&&root.val<pred.val){
                        y = root;
                        if(x==null){
                            x = pred;
                        }
                    }
                    pred = root;
                    predecessor.right = null;
                    root = root.right;
                }
            }else{
                //遍历当前节点
                if(pred!=null&&root.val<pred.val){
                    y = root;
                    if(x==null){
                        x = pred;
                    }
                }
                pred = root;
                //所有节点均有右子节点,因为前面已经建立了前驱联系
                root = root.right;
            }
        }
        swap(x,y);
    }

    public void swap(TreeNode x, TreeNode y){
        int temp = x.val;
        x.val = y.val;
        y.val = temp;
    }
}

时间复杂度: O ( n ) O(n) O(n) n是节点个数

空间复杂度: O ( 1 ) O(1) O(1)

2. 有序链表转换二叉搜索树

给定一个单链表的头节点 head ,其中的元素 按升序排序 ,将其转换为 平衡 二叉搜索树。

示例 1:

输入: head = -10,-3,0,5,9

输出: 0,-3,9,-10,null,5

解释: 一个可能的答案是0,-3,9,-10,null,5,它表示所示的高度平衡的二叉搜索树。

示例2:

输入: head = \[\]

输出: \[\]

思路

平衡二叉搜索树左右节点数相差不大,可以先找到中间节点,然后把中间点的左边作为左子树,右边作为右子树。这里可以拟合中序遍历的思想,中序遍历的结果就是链表的结果。先遍历左子树,遍历完左子树,再访问当前节点,再遍历右子树

java 复制代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
/**
 * 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 {
    ListNode globalHead;
    public TreeNode sortedListToBST(ListNode head) {
        int len = getLength(head);
        globalHead = head;
        return buildTree(0,len-1);
    }
    public int getLength(ListNode head){
        int res = 0;
        while(head!=null){
            res++;
            head = head.next;
        }
        return res;
    }
    public TreeNode buildTree(int left,int right){
        if(left>right){
            return null;
        }
        //先占个位置,模拟中序遍历
        TreeNode root = new TreeNode();
        int mid = (left+right+1)/2;
        root.left = buildTree(left,mid-1);
        //左子树都遍历完了,再给当前节点赋值,此时globalHead就处在当前节点位置
        root.val = globalHead.val;
        globalHead = globalHead.next;
        root.right = buildTree(mid+1,right);
        return root;
    }
}

时间复杂度: O ( n ) O(n) O(n) n是节点个数

空间复杂度: O ( 1 ) O(1) O(1)

相关推荐
4154111 小时前
MyBatis-Plus + PostGIS 实战(1.1):Geometry 字段在 Swagger 中的优雅展示
java·mybatis·postgis
embrace_the_sunhaha1 小时前
卡尔曼滤波理解
算法
极客先躯2 小时前
高级java每日一道面试题-2026年04月05日-实战篇[Docker]-如何排查容器 OOM 的问题?
java·运维·docker·容器·内存溢出·高级面试
带娃的IT创业者2 小时前
监控并非安全:当隐私成为技术的祭品
java·开发语言·安全·数据安全·监控·隐私保护·加密技术
叩码以求索2 小时前
使用next数组加速匹配过程
java·数据结构·算法
余额瞒着我当琳2 小时前
C++ 基础核心概念精讲:引用、内联与 nullptr
java·开发语言·c++
名字还没想好☜3 小时前
Go 内存逃逸分析:什么时候变量跑到堆上
开发语言·算法·性能优化·golang·go·内存逃逸
li星野3 小时前
滑动窗口五题通关:从食堂打饭到上下文窗口——算法与大模型的内存管理哲学
算法