109. 有序链表转换二叉搜索树
给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:
给定的有序链表: [-10, -3, 0, 5, 9],
一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:
方法 1:递归+数组
想法
题目中最重要的要求是需要利用链表中的节点,构建一颗高度平衡的二叉搜索树,好消息是链表中的元素是升序的。
众所周知,一棵二叉搜索树是一棵有根二叉树并且对于所有节点满足特殊的性质:对于树中任意一个点,它的权值必然 ≥ 所有左子树节点的权值, ≤ 所有右子树节点的权值。因为二叉树具有递归的子结构,二叉搜索树也同理:所有子树也是二叉搜索树。
当前方法和下一个方法的主要思路是:
**给定列表中的中间元素将会作为二叉搜索树的根,该点左侧的所有元素递归的去构造左子树,同理右侧的元素构造右子树。**这必然能够保证最后构造出的二叉搜索树是平衡的。
算法
方法1: 遍历链表,将值存入数组,数组值为二叉树的中序遍历值,使用递归还原。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode sortedListToBST(ListNode head) {
//1.遍历链表,使用数组保留节点升序值
List<Integer> list = new ArrayList<>();
ListNode p = head;
while(p != null){
list.add(p.val);
p = p.next;
}
2.递归构建二叉树,链表值为中序遍历结果
return buildBST(list, 0, list.size()-1);
}
public TreeNode buildBST(List<Integer> list, int start, int end){
if(start > end){
return null;
}
int mid = (start + end) / 2;
TreeNode root = new TreeNode(list.get(mid));
root.left = buildBST(list, start, mid-1);
root.right = buildBST(list, mid+1, end);
return root;
}
}
方法二:中序遍历模拟,快慢指针+递归
想法
我们知道,二叉树有三种不同的遍历方法:
- 前序遍历
- 中序遍历
- 后序遍历
中序遍历一棵二叉搜索树会有一个非常有趣的结论。
中序遍历一棵二叉搜索树的结果是得到一个升序序列。
这个方法模拟了二叉搜索树的构造过程,因为我们已经获得有序的链表,所以自然的产生了这样的想法。
在描述算法之前,先看一下中序遍历是如何获得有序值的。
基于解决这个问题的中序遍历的思想:
我们知道中序遍历最左边的元素一定是给定链表的头部,类似地下一个元素一定是链表的下一个元素,以此类推。这是肯定的,因为给定的初始链表保证了升序排列。
算法
public TreeNode sortedListToBST(ListNode head) {
if (head == null) return null;
return helper(head, null);
}
private TreeNode helper(ListNode head, ListNode tail) {
if (head == tail) return null;
//初始化快慢指针
ListNode slow = head, fast = head;
while (fast != tail && fast.next != tail) {
slow = slow.next;
fast = fast.next.next;
}
//慢指针指向中点节点
TreeNode root = new TreeNode(slow.val);
root.left = helper(head, slow);
root.right = helper(slow.next, tail);
return root;
}