LeetCode109——有序链表转换二叉搜索树

2022年2月8日 · 292 字 · 2 分钟

题目

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

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

示例:

给定的有序链表: [-10, -3, 0, 5, 9],

一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:

      0
     / \
   -3   9
   /   /
 -10  5

思路

转换为数组

转换为数组后解法跟前面一道题一样。


// 链表转换为数组,复用108解法
func sortedListToBST(head *ListNode) *TreeNode {
	if head == nil {
		return nil
	}
	list := listToArray(head)
	return helper(list, 0, len(list)-1)
}

func listToArray(head *ListNode) []int {
	result := []int{}
	for head != nil {
		result = append(result, head.Val)
		head = head.Next
	}
	return result
}

func helper(nums []int, start, end int) *TreeNode {
	if start > end {
		return nil
	}
	// 取得根
	rootIndex := (start + end) / 2
	rootValue := nums[rootIndex]
	root := &TreeNode{Val: rootValue}
	root.Left = helper(nums, start, rootIndex-1)
	root.Right = helper(nums, rootIndex+1, end)
	return root
}

链表操作

我们遍历到中间节点后,将链表拆分为[左部分,中间点,右部分]即可复用逻辑,而且无额外空间占用

单链表是无法直到中间点在哪里的,因此我们需要先遍历一次,获取链表长度,除以2就是中间的index。

// 1. 遍历一遍链表得到链表长度,算出中间节点index
// 2. 再次遍历链表,拆分为三段
// 1. 起点到中间节点的上一个节点:左子链表
// 2. 中间节点
// 3. 中间节点的下一个节点到链表末尾:右子链表
// 3. 将中间节点作为树根,利用左右子链表,递归构建左右子树,然后挂到根节点
func sortedListToBST(head *ListNode) *TreeNode {
	if head == nil {
		return nil
	}
	return helper(head)
}


func helper(head *ListNode) *TreeNode {
	if head == nil {
		return nil
	}
	if head.Next == nil {
		return &TreeNode{Val: head.Val}
	}
	// 获取链表总长度
	length := 0
	p := head
	for p != nil {
		length++
		p = p.Next
	}
	middle := length / 2 // 取得中间点位置
	// 再次遍历到中间点
	var (
		prev = head      // 指向中间点的上一个节点
		curr = head.Next // 指向中间点
	)
	var (
		left  *ListNode // 左子链表头结点
		right *ListNode // 右子链表头结点
	)
	index := 0
	for curr != nil {
		// index是prev的下标,因此定位到middle的前一个
		if index == middle-1 {
			// 找到中点,将中点和右子链表连接打断
			right = curr.Next
			curr.Next = nil
			// 将左子链表和中点连接打断
			prev.Next = nil
			left = head
			break
		}
		prev = curr
		curr = curr.Next
		index++
	}
	// 此时我们拥有left,curr,right 三个链表,开始递归组合
	root := &TreeNode{Val: curr.Val}
	root.Left = helper(left) // 给你一条链表,给我构建一个树出来
	root.Right = helper(right)
	return root
}