【LeetCode】 有序链表转换二叉搜索树

80 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第21天,点击查看活动详情

有序链表转换二叉搜索树

原题:leetcode-cn.com/problems/co…

描述

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

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

难度

中等

示例

输入: [-10, -3, 0, 5, 9]
输出:      0
         / \
       -3   9
       /   /
     -10  5
     [0, -3, 9, -10, null, 5]

思路

由于需要平衡,根节点的左子树和右子树节点个数就要比较接近,左右子树的高度差也会非常接近。将链表的中位数作为根节点,那么小于中位数的节点作为左子树的节点,大于中位数的节点作为右子树的节点,对于左右子节点同样使用相同的规则。这就可以使用分治的思想对链表进行分解,找出每个区间的中位数作为一个子树的根节点,递归构造左右子树。

要找出中间节点,可以使用快慢指针,初始化快指针 fast 和慢指针 slow 都指向链表的每一段的头节点,将 fast 指针右移 2 个节点,slow 指针右移 1 个节点,当 fast 指向链表的每一段的尾节点时,slow 指针就是中间节点。

中间节点作为根节点,递归构造左右子树。

中序遍历优化

在上诉思路中每次都要寻找中间节点,二叉搜索树中序遍历的结果就是有序链表的结果,我们可以利用中序遍历对上诉思路进行优化。首先计算出链表的长度,利用分治对长度进行分解,初始化一个全局的节点 gCurrent,初始值指向链表的头节点,每次构建树时以 gCurrent 的值构建树的根节点,然后指向下一个节点,即 gCurrent = gCurrent.next

代码

Rust

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
    pub val: i32,
    pub next: Option<Box<ListNode>>
}
​
impl ListNode {
    #[inline]
    fn new(val: i32) -> Self {
        ListNode { next: None, val }
    }
}
​
#[derive(Debug, PartialEq, Eq, code_rust_macro::InfixOrder)]
pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}
​
impl TreeNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        TreeNode { val, left: None, right: None }
    }
}
​
use std::rc::Rc;
use std::cell::RefCell;
​
pub struct Solution {}
​
impl Solution {
    pub fn sorted_list_to_bst(head: Option<Box<ListNode>>) -> Option<Rc<RefCell<TreeNode>>> {
        let length = Solution::get_length(head.as_ref());
        let (_, tree) = Solution::build_tree(head, 0, length - 1);
        tree
    }
    /// 分治 + 中序遍历构建二叉树
    fn build_tree(
        current: Option<Box<ListNode>>, start: i32, end: i32)
        -> (Option<Box<ListNode>>, Option<Rc<RefCell<TreeNode>>>) {
        if start > end {
            return (current, None)
        }
        // 中间下标,用来分解
        // (start + end) >> 1 也可以是一个中间下标
        let mid = (start + end + 1) >> 1;
        // 构建左子树
        let (current, left) = Solution::build_tree(current, start, mid - 1);
        if let Some(current) = current {
            // 中序遍历,等同于链表遍历
            let mut root = TreeNode::new(current.val);
            root.left = left;
            // 构建右子树
            let (current, right) = Solution::build_tree(current.next, mid + 1, end);
            root.right = right;
            return (current, Some(Rc::new(RefCell::new(root))));
        }
        (current, None)
    }
​
    fn get_length(mut head: Option<&Box<ListNode>>) -> i32 {
        let mut len = 0;
        while let Some(node) = head {
            head = node.next.as_ref();
            len += 1;
        }
        len
    }
}
#[test]
fn test_sorted_list_to_bst() {
    let mut node1 = Some(Box::new(ListNode::new(-10)));
    let mut node2 = Some(Box::new(ListNode::new(-3)));
    let mut node3 = Some(Box::new(ListNode::new(0)));
    let mut node4 = Some(Box::new(ListNode::new(5)));
    let node5 = Some(Box::new(ListNode::new(9)));
​
    node4.as_mut().unwrap().next = node5;
    node3.as_mut().unwrap().next = node4;
    node2.as_mut().unwrap().next = node3;
    node1.as_mut().unwrap().next = node2;
​
    let tree = Solution::sorted_list_to_bst(node1);
​
    tree.as_ref().unwrap().borrow().infix_order();
}

运行结果:

-10
-3
0
5
9

Go

type ListNode struct {
    Val int
    Next *ListNode
}
​
type TreeNode struct {
    Val int
    Left *TreeNode
    Right *TreeNode
}
​
func sortedListToBST(head *ListNode) *TreeNode {
    // return buildTree(head, nil)
    length := getLength(head)
    gCurrent = head
    return buildTree2(0, length - 1)
}
​
// 构建平衡二叉树
func buildTree(head *ListNode, tail *ListNode) *TreeNode {
    if head == tail {
        return nil
    }
    middleNode := getMiddleNode(head, tail)
    // 链表的中间节点作为树的根节点
    root := &TreeNode{Val: middleNode.Val}
    // 构建左子树
    root.Left = buildTree(head, middleNode)
    // 构建右子树
    root.Right = buildTree(middleNode.Next, tail)
    return root
}
​
// 获取中间节点
func getMiddleNode(head *ListNode, tail *ListNode) *ListNode {
    fast, slow := head, head
    for fast != tail && fast.Next != tail {
        // 快指针走两个节点
        fast = fast.Next
        fast = fast.Next
        // 慢指针走一个节点
        slow = slow.Next
    }
    return slow
}
​
var gCurrent *ListNode
// 分治+中序遍历构建二叉树
func buildTree2(start, end int) *TreeNode {
    if start > end {
        return nil
    }
    root := &TreeNode{}
    // 中间下标,用来分解
    // (start + end) >> 1 也可以是一个中间下标
    mid := (start + end + 1) >> 1
    // 构建左子树
    root.Left = buildTree2(start, mid - 1)
    // 中序遍历,等同于链表遍历
    root.Val = gCurrent.Val
    gCurrent = gCurrent.Next
    // 构建右子树
    root.Right = buildTree2(mid + 1, end)
    return root
}
​
func getLength(head *ListNode) int {
    l := 0
    current := head
    for current != nil {
        current = current.Next
        l++
    }
    return l
}
​
func infixOrder(node *TreeNode) {
    if node == nil {
        return
    }
    infixOrder(node.Left)
    fmt.Println(node.Val)
    infixOrder(node.Right)
}
func TestSortedListToBST(t *testing.T) {
    node1 := &ListNode{Val: -10}
    node2 := &ListNode{Val: -3}
    node3 := &ListNode{Val: 0}
    node4 := &ListNode{Val: 5}
    node5 := &ListNode{Val: 9}
    node1.Next = node2
    node2.Next = node3
    node3.Next = node4
    node4.Next = node5
​
    tree := sortedListToBST(node1)
​
    infixOrder(tree)
}

运行结果:

-10
-3
0
5
9

Java

public class Main {
​
    public static class ListNode {
        public int val;
        public ListNode next;
        public ListNode(int val) { this.val = val; }
    }
​
    public static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode(int val) { this.val = val; }
    }
​
    public static TreeNode sortedListToBST(ListNode head) {
        // return buildTree(head, null);
        gCurrent = head;
        int length = getLength(head);
        return buildTree2(0, length - 1);
    }
​
    /**
     * 构建平衡二叉树
     */
    public static TreeNode buildTree(ListNode head, ListNode tail) {
        if (head == tail) {
            return null;
        }
        ListNode middleNode = getMiddleNode(head, tail);
        // 链表的中间节点作为树的根节点
        TreeNode root = new TreeNode(middleNode.val);
        // 构建左子树
        root.left = buildTree(head, middleNode);
        // 构建右子树
        root.right = buildTree(middleNode.next, tail);
        return root;
    }
​
    /**
     * 获取中间节点
     */
    public static ListNode getMiddleNode(ListNode head, ListNode tail) {
        ListNode fast = head, slow = head;
        while (fast != tail && fast.next != tail) {
            // 快指针走两个节点
            fast = fast.next;
            fast = fast.next;
            // 慢指针走一个节点
            slow = slow.next;
        }
        return slow;
    }
​
    public static int getLength(ListNode head) {
        int l = 0;
        ListNode current = head;
        while (current != null) {
            current = current.next;
            l++;
        }
        return l;
    }
​
    public static ListNode gCurrent = null;
​
    /**
     * 分治+中序遍历构建二叉树
     */
    public static TreeNode buildTree2(int start, int end) {
        if (start > end) {
            return null;
        }
        TreeNode root = new TreeNode(0);
        // 中间下标,用来分解
        // (start + end) >> 1 也可以是一个中间下标
        int mid = (start + end) >> 1;
        // 构建左子树
        root.left = buildTree2(start, mid - 1);
        // 中序遍历,等同于链表遍历
        root.val = gCurrent.val;
        gCurrent = gCurrent.next;
        // 构建右子树
        root.right = buildTree2(mid + 1, end);
        return root;
    }
​
    public static void infixOrder(TreeNode node) {
        if (node == null) {
            return;
        }
        infixOrder(node.left);
        System.out.println(node.val);
        infixOrder(node.right);
    }
​
    public static void main(String[] args) {
        ListNode node1 = new ListNode(-10);
        ListNode node2 = new ListNode(-3);
        ListNode node3 = new ListNode(0);
        ListNode node4 = new ListNode(5);
        ListNode node5 = new ListNode(9);
        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;
​
        TreeNode tree = sortedListToBST(node1);
​
        infixOrder(tree);
    }
}

运行结果:

-10
-3
0
5
9