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)

相关推荐
蓝斯49730 分钟前
[原创]《C#高级GDI+实战:从零开发一个流程图》第章:增加贝塞尔曲线,上、下、左、右连接点
java·c#·流程图
前端工作日常43 分钟前
我学习到的Java 的 Service 分层:itf 和 impl 到底是什么?
java·后端
都叫我大帅哥1 小时前
Spring @Transactional 注解完全指南
java·spring
Java成神之路-2 小时前
G1 垃圾回收器 :SATB + TAMS核心机制深度解析
java·jvm
前端工作日常2 小时前
我学习到的JIT即时编译与机器码缓存失效
java·后端
带刺的坐椅2 小时前
Solon 的 10 种 HTTP 服务器:改一行依赖,换一个引擎
java·solon·jetty·undertow·mcp-server·htttp
luj_17682 小时前
星火科技助力边远地区防病攻坚
c语言·开发语言·c++·经验分享·算法
xcLeigh3 小时前
Go入门:变量声明的五种方式详解
java·开发语言·golang
AI大模型-小华3 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
Mark_ZP4 小时前
【锁1】Synchronized vs ReentrantLock区别
java