开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第21天,点击查看活动详情。
有序链表转换二叉搜索树
描述
给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 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