Open azl397985856 opened 2 years ago
class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
if not head:
return head
pre ,slow , quick = None,head,head
while quick and quick.next:
pre = slow
slow = slow.next
quick = quick.next.next
#print(pre==head)
if pre:
pre.next = None
a = TreeNode(slow.val)
if quick == slow:
return a
a.left = self.sortedListToBST(head)
a.right = self.sortedListToBST(slow.next)
return a
先去做了108 Convert Sorted Array to Binary Search Tree
class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
def buildBSTfromList(nums,l,r) -> TreeNode:
if l>r:
return None
m = l + (r-l)//2
root = TreeNode(nums[m])
root.left = buildBSTfromList(nums,l,m-1)
root.right = buildBSTfromList(nums,m+1,r)
return root
res = []
while head:
res.append(head.val)
head = head.next
return buildBSTfromList(res,0,len(res)-1)
时间:On / 空间:On
思路我有了,但是代码一直没搞明白 / 答案参考了评论区,官方题解 / 还是要多多学习 /
class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
if not head:
return head
pre = None
slow = head
fast = head
# 找中间节点
while fast and fast.next:
fast = fast.next.next
pre = slow
slow = slow.next
# 如果slow = head的情况:
if pre:
pre.next = None
node = TreeNode(slow.val)
if slow == fast:
return node
node.left = self.sortedListToBST(head)
node.right = self.sortedListToBST(slow.next)
return node
令 n 为链表长度。 /
时间复杂度:递归树的深度为 logn,每一层的基本操作数为 n,因此总的时间复杂度为O(nlogn)O /
空间复杂度:空间复杂度为O(logn)O
思路:参考官方题解,由于链表已经排序了,所以以寻找到链表的中点,以链表中点为界限,中点左边是二叉搜索树的左孩子们,中点的右边是二叉树的右孩子们。进行递归地构造。 寻找链表的中点当然就用快慢指针法就好啦。 TreeNode sortedListToBST(ListNode head) { if(head==nullptr) return nullptr; return sortedListToBST(head,nullptr); } TreeNode sortedListToBST(ListNode head, ListNode tail) { if(head==tail) return nullptr; ListNode slow=head; ListNode fast=head; //寻找链表中点,以中点为界构造二叉树 while(fast!=tail && fast->next!=tail) { fast=fast->next->next; slow=slow->next; } TreeNode root=new TreeNode(slow->val); root->left=sortedListToBST(head,slow); root->right=sortedListToBST(slow->next,tail); return root; } 复杂度分析: 时间复杂度为O(nlogn) 空间复杂度为O(logn)
双指针找终点
class Solution {
public TreeNode sortedListToBST(ListNode head) {
return build(head, null);
}
//[start, end)
TreeNode build(ListNode start, ListNode end){
if(start == end){
return null;
}
ListNode mid = findMid(start, end);
TreeNode root = new TreeNode(mid.val);
root.left = build(start, mid);
root.right = build(mid.next, end);
return root;
}
//two pointers
ListNode findMid(ListNode start, ListNode end){
ListNode slow = start, fast = start;
while (fast != end && fast.next != end){
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
}
Use the list middle value as root, then recursively build the tree. Note the base case where only one element left in the recursion and should return node.
class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
value = []
while head:
value.append(head.val)
head = head.next
def convertBST(l, r):
if l > r: return None
mid = (l + r) // 2
node = TreeNode(value[mid])
if l == r: return node # base case
node.left = convertBST(l, mid - 1)
node.right = convertBST(mid + 1, r)
return node
return convertBST(0, len(value)-1)
O(n) time and space
线索: BST + 高度平衡. 意味着左右两边的节点个数一致. 自然想到用递归的解法,
递归函数的定义: 返回一个高度平衡的BST.
递归函数的思路: 先找到中间点, 递归地把中间点的左边 接到中间点的left. 把中间点的右边 接到中间点的right.
易错点: 每次递归调用时, 左侧的部分需要"剪断". 既, 应该剪断左侧部分与当前中间点的联系. pre.next = None
不然会进入死循环.
class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
if not head:
return None
if not head.next:
return TreeNode(head.val)
# Find mid first
slow, fast = head, head
dummy = TreeNode()
dummy.next = head
pre = dummy
while fast and fast.next:
pre = pre.next
slow = slow.next
fast = fast.next.next
# Slow is mid or left_mid
root = TreeNode(slow.val)
pre.next = None
root.left = self.sortedListToBST(head)
root.right = self.sortedListToBST(slow.next)
return root
O(NlogN) - 每一层是操作数N * 层数logN
O(logN): 递归树的高度
根据二叉搜索树的性质,升序链表的中间节点一定是一个局部二叉搜索子树的根。因此,可以先找到链表的中间节点,然后再递归构建树结构。
class Solution {
public TreeNode sortedListToBST(ListNode head) {
return binaryCreate(head, null);
}
public TreeNode binaryCreate(ListNode l, ListNode r) {
if (l == null || l == r)
return null;
if (l.next == null || r == l.next)
return new TreeNode(l.val);
ListNode slow = l;
ListNode fast = l;
while (fast != r && fast.next != r) {
slow = slow.next;
fast = fast.next.next;
}
TreeNode root = new TreeNode(slow.val);
root.left = binaryCreate(l, slow);
root.right = binaryCreate(slow.next, r);
return root;
}
}
寻找中间节点的位置,左右节点递归
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
if not head:
return head
pre = ListNode()
slow = head
fast = head
while fast and fast.next:
fast = fast.next.next
pre = slow
slow = slow.next
if pre:
pre.next = None
node = TreeNode(slow.val)
if slow == fast:
return node
node.left = self.sortedListToBST(head)
node.right = self.sortedListToBST(slow.next)
return node
时间 O(nlog(n)) \ 空间 O(log(n))
1.利用双指针找到链表的中间节点作为root 2.利用中间节点断开链表 3.分别在左右两部分链表进行从步骤1开始递归操作
var sortedListToBST = function(head) {
if (head == null) {
return null;
}
let pre = null;
let slow = fast = head;
while (fast != null && fast.next != null) {
pre = slow;
slow = slow.next;
fast = fast.next.next;
}
if (pre != null) {
pre.next = null;
} else {
head = null;
}
const next = slow.next;
slow.next = null;
const root = new TreeNode(slow.val);
root.left = sortedListToBST(head);
root.right = sortedListToBST(next);
return root;
};
思路 找中点后递归 + 中序遍历
代码
class Solution {
public:
ListNode* h;
TreeNode* sortedListToBST(ListNode* head) {
//if(!head ) return head;
h = head;
int n = 0;
for(auto p = head; p; p = p->next) n ++;
return build(0, n - 1);
}
TreeNode* build(int l, int r) {
if(l > r) return nullptr;
TreeNode *root = new TreeNode();
int mid = (l + r +1) >> 1;
root->left = build(l, mid - 1);
root->val = h->val;
h = h->next;
root->right = build(mid + 1, r);
return root;
}
};
复杂度
时间复杂度:O(nlogn)
空间复杂度: O(logn)
public class Solution {
public TreeNode sortedListToBST(ListNode head) {
if(head==null) return null;
return toBST(head,null);
}
public TreeNode toBST(ListNode head, ListNode tail){
ListNode slow = head;
ListNode fast = head;
if(head==tail) return null;
while(fast!=tail&&fast.next!=tail){
fast = fast.next.next;
slow = slow.next;
}
TreeNode thead = new TreeNode(slow.val);
thead.left = toBST(head,slow);
thead.right = toBST(slow.next,tail);
return thead;
}
class Solution { public TreeNode sortedListToBST(ListNode head) { if(head == null ) return null; if(head.next == null) return new TreeNode(head.val); ListNode pre = null, slow = head, fast = head; while(fast!= null && fast.next != null) { pre = slow; slow = slow.next; fast = fast.next.next; } TreeNode root = new TreeNode(slow.val); pre.next = null; root.left = sortedListToBST(head); root.right = sortedListToBST(slow.next); return root;
}
}
有二种基本思路:
func sortedListToBST(head *ListNode) *TreeNode {
var buildBST func([]int) *TreeNode
buildBST = func(data []int) *TreeNode {
if data == nil || len(data) == 0 {return nil}
rootIdx := len(data) / 2
root := &TreeNode{Val: data[rootIdx]}
if rootIdx > 0 {
root.Left = buildBST(data[:rootIdx])
}
if rootIdx < len(data) - 1 {
root.Right = buildBST(data[rootIdx + 1:])
}
return root
}
var arr []int
for head != nil {
arr = append(arr, head.Val)
head = head.Next
}
return buildBST(arr)
}
复杂度分析
先找出链表的中点 然后再建树 (中点就是树的根)
时间复杂度: O(NlogN)
空间复杂度: O(logN)
class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
def findmid(start, end):
slow = start
fast = start
while fast != end and fast.next != end:
slow = slow.next
fast = fast.next.next
return slow
def buildtree(start, end):
if start == end:
return
mid = findmid(start, end)
root = TreeNode(mid.val) #root = TreeNode(findmid(start, end).val)
root.left = buildtree(start, mid)
root.right = buildtree(mid.next, end)
return root
return buildtree(head, None)
递归找中点作为根节点创建二叉树,有两种方式:
class Solution {
public TreeNode sortedListToBST(ListNode head) {
List<Integer> list = new ArrayList<>();
while (head != null) {
list.add(head.val);
head = head.next;
}
return buildTree(0, list.size() - 1, list);
}
TreeNode buildTree(int left, int right, List<Integer> list) {
if (left > right) {
return null;
}
int mid = left + (right - left + 1) / 2;
TreeNode root = new TreeNode(list.get(mid));
root.left = buildTree(left, mid - 1, list);
root.right = buildTree(mid + 1, right, list);
return root;
}
}
Thoughts
Split the linkedlist intor three parts:
Code
public TreeNode sortedListToBST(ListNode head) {
if (head == null) {
return null;
} else if (head.next == null) {
return new TreeNode(head.val);
}
ListNode fast = head;
ListNode slow = head;
ListNode pre = slow;
while (fast != null && fast.next != null) {
pre = slow; // pre is the previous node of slow
slow = slow.next;
fast = fast.next.next;
}
TreeNode root = new TreeNode(slow.val);
root.right = sortedListToBST(slow.next);
slow.next = null;
pre.next = null;
root.left = sortedListToBST(head);
return root;
}
Complexity
快慢指针找中位数+递归建树;
class Solution {
public:
//快慢指针找中位数,递归确定树的结构,从根节点开始
//左闭右开,因为链表,上一个节点不好找
//1、找中位数,在链表中,快慢指针
ListNode* findMid(ListNode* left,ListNode* right){
ListNode* low=left;
ListNode* fast=left;
while(fast!=right && fast->next!=right){
fast=fast->next->next;
low=low->next;
}
return low;
}
//2、形成递归,依次构建树节点
TreeNode* findRoot(ListNode* left,ListNode* right){
//递归结束条件
if(left==right){
return nullptr;
}
ListNode* mid=findMid(left,right);
TreeNode* root=new TreeNode(mid->val);//mid是链表节点指针,用值创建根节点
root->left=findRoot(left,mid);//左闭右开
root->right=findRoot(mid->next,right);
return root;
}
TreeNode* sortedListToBST(ListNode* head) {
return findRoot(head,nullptr);
}
};
找到中间节点,构造二叉搜索树
const sortedListToBST = (head) => {
const arr = [];
while (head) { // 将链表节点的值逐个推入数组arr
arr.push(head.val);
head = head.next;
}
// 根据索引start到end的子数组构建子树
let buildBST = function(start,end) {
if (start>end) return null
let mid = (start+end) >>> 1
let root = new TreeNode(arr[mid])
root.left = buildBST(start,mid-1)
root.right = buildBST(mid+1,end)
return root
}
return buildBST(0,arr.length-1)
};
时间复杂度: O(nlogn)
空间复杂度: O(logn)
rust版本,递归数组,取中间节点,构建bst
use std::cell::RefCell;
use std::rc::Rc;
impl Solution {
pub fn sorted_list_to_bst(mut head: Option<Box<ListNode>>) -> Option<Rc<RefCell<TreeNode>>> {
let mut stack = Vec::new();
// 收集链表节点值
while let Some(node) = head {
stack.push(node.val);
head = node.next;
}
Solution::s(&stack[..])
}
pub fn s(nums: &[i32]) -> Option<Rc<RefCell<TreeNode>>> {
let mut n = nums.len();
if n == 0 {
return None;
}
let mid = n / 2;
let mut node = TreeNode::new(nums[mid]);
// 递归创建左子树
node.left = Solution::s(&nums[..mid]);
// 递归创建右子树
node.right = Solution::s(&nums[mid + 1..]);
Some(Rc::new(RefCell::new(node)))
}
}
Recursive. For every list, use fast-slow pointers to find the mid one as root. Do the same for left half of the list; Do the same for the right half.
class Solution {
public TreeNode sortedListToBST(ListNode head) {
if (head == null) {
return null;
}
if (head.next == null) {
return new TreeNode(head.val);
}
ListNode fast = head;
ListNode slow = head;
ListNode preMid = null;
while (fast != null && fast.next != null) {
fast = fast.next;
fast = fast.next;
preMid = slow;
slow = slow.next;
}
preMid.next = null;
TreeNode root = new TreeNode(slow.val);
root.left = sortedListToBST(head);
root.right = sortedListToBST(slow.next);
return root;
}
}
Time: O(NlogN) Space: O(logN) for recursion.
用recursion来做,先找到中点,然后左半边和右半边都call自己来construct
public TreeNode sortedListToBST(ListNode head) {
if(head == null) return null;
return constructBST(0, checkLength(head) - 1, head);
}
private int checkLength(ListNode head){
if(head == null) return 0;
return checkLength(head.next) + 1;
}
private TreeNode constructBST(int start, int end, ListNode head){
if(start > end) return null;
int mid = start + (end - start) / 2;
ListNode temp = head;
for(int i = 0; i < mid; i++){
temp = temp.next;
}
TreeNode root = new TreeNode(temp.val);
root.left = constructBST(start, mid - 1, head);
root.right = constructBST(mid + 1, end, head);
return root;
}
Time: O(n), 因为要遍历所有节点找到长度,再找到中点;\ Space: O(logn), 每次同时call左右,recursion的次数是树的高度。
Idea
Use vector to facilitate calculations in left and right branches via a mid point
Code
class Solution {
public:
vector<int>v;
TreeNode*balance(vector<int>v){
if(v.size()==0){
return NULL;
}
if(v.size()==1){
return new TreeNode(v[0]);
}
int mid = v.size()/2;
TreeNode* node = new TreeNode(v[mid]);
vector<int>lnode(v.begin(), v.begin()+mid);
vector<int>rnode(v.begin()+mid+1, v.end());
node->left = balance(lnode);
node->right = balance(rnode);
return node;
}
TreeNode* sortedListToBST(ListNode* head) {
while(head){
v.push_back(head->val);
head=head->next;
}
return balance(v);
}
};
Complexity
Time:
Memory:
recursive method to create tree -> sortedListBST(ListNode head)
- if head = null, return null
- find mid Node: call getMid(head)
- create root with value of mid.val
- if head = mid, just return root
- root.left = recursive call sortedListToBST(head)
- root.right = recursive call sortedListToBST(mid.next)
Find mid and break previous links ->getMid(ListNode head)
- initialize slow, fast, prev to head
- while (fast not null && fast.next not null)
- prev = slow;
-slow = slow.next;
- fast = fast.next.next;
-break the link if prev != null
-return slow
public TreeNode sortedListToBST(ListNode head) {
if(head == null) return null;
ListNode mid = getMid(head);
TreeNode root = new TreeNode(mid.val);
if(head == mid)
return root;
root.left = sortedListToBST(head);
root.right = sortedListToBST(mid.next);
return root;
}
public ListNode getMid(ListNode head){
ListNode fast = head;
ListNode slow = head;
ListNode prev = head;
while(fast != null && fast.next != null){
prev = slow;
slow = slow.next;
fast = fast.next.next;
}
//break the link before the mid point
if(prev != null)
prev.next = null;
return slow;
}
复杂度分析
var sortedListToBST = function (head) {
if (!head) return null;
return dfs(head, null);
};
function dfs(head, tail) {
if (head == tail) return null;
let fast = head;
let slow = head;
while (fast != tail && fast.next != tail) {
fast = fast.next.next;
slow = slow.next;
}
let root = new TreeNode(slow.val);
root.left = dfs(head, slow);
root.right = dfs(slow.next, tail);
return root;
}
快慢指针找链表中点,然后通过递归得到左子树和右子树。
class Solution {
public TreeNode sortedListToBST(ListNode head) {
if(head == null) {
return null;
}
if(head != null && head.next == null) {
return new TreeNode(head.val);
}
ListNode dummy = head;
ListNode slow = head;
ListNode fast = head;
ListNode pre = null;
while(fast != null && fast.next != null) {
pre = slow;
slow = slow.next;
fast = fast.next.next;
}
pre.next = null;
TreeNode root = new TreeNode(slow.val);
root.left = sortedListToBST(dummy);
root.right = sortedListToBST(slow.next);
return root;
}
}
复杂度
class Solution {
public TreeNode sortedListToBST(ListNode head) {
if (head == null) return null;
if (head.next == null) return new TreeNode(head.val);
int count = 0;
ListNode cur = head;
while (cur!= null){
cur = cur.next;
count++;
}
cur = head;
for (int i = 0; i< count/2-1; i++){
cur = cur.next;
}
TreeNode root = new TreeNode(cur.next.val);
root.right= sortedListToBST(cur.next.next);
cur.next = null;
root.left = sortedListToBST(head);
return root;
}
}
//TC: O(N logN) where N is the length of the linked list.
//SC: O(Log N) on call stack, and O(N) on the heap.
用双指针方法来找出链表的中间元素, 断开中间元素左边的链表部分 作为左子树,同理右半边为右子树。
class Solution {
public TreeNode sortedListToBST(ListNode head) {
if(head == null) return null;
ListNode mid = findMid(head);
TreeNode root = new TreeNode(mid.val);
if(head == mid){
return root;
}
root.left = sortedListToBST(head);
root.right = sortedListToBST(mid.next);
return root;
}
private ListNode findMid(ListNode head){
ListNode s = head, p = null, f = head;
while(f!=null && f.next!=null){
p = s;
s = s.next;
f = f.next.next;
}
if(p!=null){
p.next = null;
}
return s;
}
}
-TC: O(N logN) -SC: O(Log N)
4.9
思路:
快慢指针起初都指向头结点,分别一次走两步和一步,当快指针走到尾节点时,慢指针正好走到链表的中间。断成两个链表,分而治之。
代码:
#快慢指针法
class Solution:
def sortedListToBST(self, head: ListNode) -> TreeNode:
if not head:
return head
pre, slow, fast = None, head, head
while fast and fast.next:
fast = fast.next.next
pre = slow #保存slow前一个节点,因为链表没有前驱指针
slow = slow.next
if pre: #如果pre有值,则slow左边有节点
pre.next = None #切断pre
node = TreeNode(slow.val) # 根据slow指向的节点值,构建节点
if slow == fast: #???
return node
node.left = self.sortedListToBST(head) #递归构建左子树
node.right = self.sortedListToBST(slow.next) #递归构建右子树
return node
复杂度:
令 n 为链表长度。
//存在疑问:应该是不了解递归树
1.知道了通过快慢指针找到中点和结尾
2.我知道左子树小于节点,右子树大于节点,但代码中封装好了,NEXT:预习树
node.left = self.sortedListToBST(head)
node.right = self.sortedListToBST(slow.next)
\3. slow和fast没有变化,这句代码不可少,需要提问
if slow == fast:
return node
4.python return?//函数当然有,怎么if里也有?
5.?复杂度计算不太理解
「手画图解」三种解法逐个吃透 | 109. 有序链表转换二叉搜索树
class Solution:
def tolist(self, head):
val = []
while head:
val.append(head.val)
head = head.next
return val
def genTree(self, vals, start, end):
if start > end:
return None
mid = (start + end)//2
node = TreeNode(val=vals[mid])
if start == end:
return node
node.left = self.genTree(vals, start, mid-1)
node.right = self.genTree(vals, mid+1, end)
return node
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
vals = self.tolist(head)
return self.genTree(vals, 0, len(vals)-1)
先将链表转为list,再进行迭代。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
if not head:
return None
# 先计算出链表的长度
p1=head
n=0.0
data=[]
while p1:
data.append(p1.val) # 将数据存到list中
p1=p1.next
n+=1
def buildT(arr):
nn=float(len(arr))
mm=int(nn/2+0.5)
if nn<=0:
return None
mnode=TreeNode(val=arr[mm-1])
mnode.left=buildT(arr[0:mm-1])
mnode.right=buildT(arr[mm:int(nn)])
return mnode
return buildT(data)
时间复杂度:O(n)
空间复杂度:O(n)
class Solution {
public:
TreeNode* sortedListToBST(ListNode* head) {
if (head == nullptr) {
return nullptr;
}
if (head->next == nullptr)
{
return new TreeNode(head->val);
}
ListNode *p = head, *q = head, *pre = nullptr;
while (q != nullptr && q->next != nullptr)
{
pre = p;
p = p->next;
q = q->next->next;
}
pre->next = nullptr;
TreeNode *root = new TreeNode(p->val);
root->left = sortedListToBST(head);
root->right = sortedListToBST(p->next);
return root;
}
};
使用快慢指针,找到链表的中点,那么这就是树的根节点;
该节点左边就是左子树,对于左子树,再使用快慢指针,就能发现左子树根节点;
右子树同理;
Python3 Code:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
"""
将有序链表变换为二叉搜索树
Args:
head(ListNode):头节点
Returns:
new_head(ListNode):返回新的头节点
"""
"""
使用快慢指针,找到链表的中点,那么这就是树的根节点;
该节点左边就是左子树,对于左子树,再使用快慢指针,就能发现左子树根节点;
右子树同理;
"""
if not head:
return head
pre,slow,fast = None,head,head
while fast and fast.next:
fast = fast.next.next
pre = slow
slow = slow.next
if pre:
pre.next = None
node = TreeNode(slow.val)
if slow == fast:
return node
node.left = self.sortedListToBST(head)
node.right = self.sortedListToBST(slow.next)
return node
复杂度分析
令 n 为数组长度。
因为在链表中,找到中间节点的时间复杂度为O(n),如果换成数组,就可以在O(1)时间复杂度内找到中点;
这也是一种空间换时间的方法
Python3 Code:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
"""
将有序链表变换为二叉搜索树
Args:
head(ListNode):头节点
Returns:
new_head(ListNode):返回新的头节点
"""
def dfs(nodeList,l,r):
# 这里设计一个递归的边界问题,
# 例如:这里规定的区间是左闭右开的,那么l一定要小于r;
# 而且每次递归调用时,都是遵循左闭右开的原则
if l>=r:
return
mid = int((r+l)/2)
root = TreeNode(nodeList[mid])
root.left = dfs(nodeList,l,mid)
root.right =dfs(nodeList,mid+1,r)
return root
nodeList = []
while head:
nodeList.append(head.val)
head = head.next
return dfs(nodeList,0,len(nodeList))
复杂度分析
令 n 为数组长度。
找到中点后递归+中序遍历
class Solution {
public:
ListNode* h;
TreeNode* sortedListToBST(ListNode* head) {
//if(!head ) return head;
h = head;
int n = 0;
for(auto p = head; p; p = p->next) n ++;
return build(0, n - 1);
}
TreeNode* build(int l, int r) {
if(l > r) return nullptr;
TreeNode *root = new TreeNode();
int mid = (l + r +1) >> 1;
root->left = build(l, mid - 1);
root->val = h->val;
h = h->next;
root->right = build(mid + 1, r);
return root;
}
};
递归建立左右子树
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {ListNode} head
* @return {TreeNode}
*/
var sortedListToBST = function(head) {
if (head == null) return null;
let len = 0;
let h = head;
while (head) {
len++;
head = head.next;
}
const buildBST = (start, end) => {
if (start > end) return null;
const mid = (start + end) >>> 1;
const left = buildBST(start, mid - 1);
const root = new TreeNode(h.val);
h = h.next;
root.left = left;
root.right = buildBST(mid + 1, end);
return root;
};
return buildBST(0, len - 1);
};
4月9日
【day09】
难度 中等
给定一个单链表的头节点 head
,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过 1。
示例 1:
输入: head = [-10,-3,0,5,9]
输出: [0,-3,9,-10,null,5]
解释: 一个可能的答案是[0,-3,9,-10,null,5],它表示所示的高度平衡的二叉搜索树。
由于BST的性质可知,BST的中序遍历是单调递增的,题目中也说明了元素顺序递增,这样一来中序遍历构造二叉树即可,额外使用left,right,mid 三个元素规划左右子树空间,这样便免去寻找根节点的过程,借助一个辅助变量在链表中由前向后取值即可(链表顺序即为中序顺序)。
class Solution {
ListNode node;
public TreeNode sortedListToBST(ListNode head) {
node = head;
ListNode cur = head;
int len = 0;
while(cur != null){
len++;
cur = cur.next;
}
return traverse(0,len-1);
}
TreeNode traverse(int left,int right){
if(left > right){
return null;
}
int mid = (left+right)/2;
TreeNode root = new TreeNode();
root.left = traverse(left,mid-1);
root.val = node.val;
node = node.next;
root.right = traverse(mid+1,right);
return root;
}
}
https://leetcode-cn.com/problems/convert-sorted-list-to-binary-search-tree/
给定一个单链表的头节点 head ,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过 1。
示例 1:
输入: head = [-10,-3,0,5,9]
输出: [0,-3,9,-10,null,5]
解释: 一个可能的答案是[0,-3,9,-10,null,5],它表示所示的高度平衡的二叉搜索树。
示例 2:
输入: head = []
输出: []
提示:
head 中的节点数在[0, 2 * 104] 范围内
-105 <= Node.val <= 105
JavaScript Code:
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {ListNode} head
* @return {TreeNode}
*/
var sortedListToBST = function(head) {
if (!head) return null;
return dfs(head,null);
};
function dfs(head, tail) {
if (head == tail) {
return null;
}
let fast = head;
let slow = head;
while (fast != tail && fast.next != tail) {
fast = fast.next.next;
slow = slow.next;
}
let root = new TreeNode(slow.val);
root.left = dfs(head, slow);
root.right = dfs(slow.next, tail);
return root;
}
复杂度分析1(不太会。。。)
令 n 为链表长度。
class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
if head is None:
return head
d = []
node = head
while node is not None:
d.append(node.val)
node = node.next
return self.buildTree(d)
def buildTree(self, d):
if len(d) == 0:
return None
mid = len(d)//2
r = TreeNode(d[mid])
r.left = self.buildTree(d[:mid])
r.right = self.buildTree(d[mid+1:])
return r
time: O(n) space: O(n)
使用快慢指针找出中点所在的位置,将其作为节点建树
class Solution {
public:
ListNode* getMedian(ListNode* left, ListNode* right) {
ListNode* fast = left;
ListNode* slow = left;
while (fast != right && fast->next != right) {
fast = fast->next;
fast = fast->next;
slow = slow->next;
}
return slow;
}
TreeNode* buildTree(ListNode* left, ListNode* right) {
if (left == right) {
return nullptr;
}
ListNode* mid = getMedian(left, right);
TreeNode* root = new TreeNode(mid->val);
root->left = buildTree(left, mid);
root->right = buildTree(mid->next, right);
return root;
}
TreeNode* sortedListToBST(ListNode* head) {
return buildTree(head, nullptr);
}
};
思路: 说实话,我一开始根本没有思路,这类递归都不太会 我看了l神的答案,觉得题目难点就在于要想到递归 代码:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
l = 0
stack = []
cut, slow, fast = None, head, head
if not head:
return head
while fast and fast.next:
cut = slow
slow = slow.next
fast = fast.next.next
if cut:
cut.next = None
midTree = TreeNode(slow.val)
if slow==fast:
return midTree
midTree.left = self.sortedListToBST(head)
midTree.right = self.sortedListToBST(slow.next)
return midTree
具体:
<?php
/**
* Definition for a singly-linked list.
* class ListNode {
* public $val = 0;
* public $next = null;
* function __construct($val = 0, $next = null) {
* $this->val = $val;
* $this->next = $next;
* }
* }
*/
/**
* Definition for a binary tree node.
* class TreeNode {
* public $val = null;
* public $left = null;
* public $right = null;
* function __construct($val = 0, $left = null, $right = null) {
* $this->val = $val;
* $this->left = $left;
* $this->right = $right;
* }
* }
*/
class Solution
{
/**
* @param ListNode $head
* @return TreeNode
*/
function sortedListToBST($head)
{
if (!$head) {
return null;
}
return $this->dfs($head, null);
}
/**
* @param ListNode $head 头结点
* @param ListNode $tail 尾节点
* @return TreeNode|null
*/
private function dfs($head, $tail)
{
if ($head == $tail) { // 这个的作用是头尾节点相等的时候就不用遍寻了,说明就没有了
return null;
}
$fast = $head; // 快指针
$slow = $head; // 慢指针
while ($fast != $tail && $fast->next != $tail) { // 兼容奇数和偶数
$fast = $fast->next->next;
$slow = $slow->next;
}
$root = new TreeNode($slow->val);
$root->left = $this->dfs($head, $slow);
$root->right =$this->dfs($slow->next, $tail);
return $root;
}
}
/**
* Definition for a singly-linked list.
* class ListNode {
* public $val = 0;
* public $next = null;
* function __construct($val = 0, $next = null) {
* $this->val = $val;
* $this->next = $next;
* }
* }
*/
/**
* Definition for a binary tree node.
* class TreeNode {
* public $val = null;
* public $left = null;
* public $right = null;
* function __construct($val = 0, $left = null, $right = null) {
* $this->val = $val;
* $this->left = $left;
* $this->right = $right;
* }
* }
*/
class Solution
{
/**
* @param ListNode $head
* @return TreeNode
*/
function sortedListToBST($head)
{
$res = [];
while ($head) {
$res[] = $head->val;
$head = $head->next;
}
return $this->dfs($res, 0, count($res) - 1);
}
private function dfs($res, $l, $r)
{
if ($l > $r) {
return null;
}
$mid = ceil(($r - $l)/2) + $l;
$root = new ListNode($res[$mid]);
$root->left = $this->dfs($res, $l, $mid-1);
$root->right = $this->dfs($res, $mid+1, $r);
return $root;
}
}
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
"""
Keywords: LinkedList, BST, convert
Ideas:
recurssion
get mid value
fast & slow pointer -> build treeNode
TC: O(logn * n) = O(nlogn)
SC: O(logn * 1) = O(logn)
"""
def dfs(head, tail):
if head == tail: return None
slow, fast = head, head
while fast!= tail and fast.next != tail:
fast = fast.next.next
slow = slow.next
root = TreeNode(slow.val)
root.left = dfs(head, slow)
root.right = dfs(slow.next, tail)
return root
if not head: return head
return dfs(head, None)
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
"""
Use list to improve, no need find mid value in linkedlist
Improve: O(n)
TC: O(n)
SC: O(n)
"""
res = []
while head:
res.append(head.val)
head = head.next
def dfs(res, l, r):
if l > r: return None
m = (l + r) // 2
root = ListNode(res[m])
root.left = dfs(res, l, m - 1)
root.right = dfs(res, m + 1, r)
return root
return dfs(res, 0, len(res) - 1)
class Solution:
def __init__(self):
self.head = None
def sortedListToBST(self, head: ListNode) -> TreeNode:
n, self.head = 0, head
while head:
head = head.next
n += 1
return self.to_bst(0, n - 1)
def to_bst(self, left, right):
if left > right: return
m = (left + right) // 2
left_child = self.to_bst(left, m - 1)
father = TreeNode(self.head.val)
self.head = self.head.next
father.left = left_child
father.right = self.to_bst(m + 1, right)
return father
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {ListNode} head
* @return {TreeNode}
*/
var sortedListToBST = function(head) {
const linkedListArr = [];
while (head) {
linkedListArr.push(head.val);
head = head.next;
}
return formBST(0 , linkedListArr.length - 1, linkedListArr);
};
const formBST = (start, end, arr) => {
if (start > end) {
return null;
}
const mid = (start + end) >>> 1;
const root = new TreeNode(arr[mid]);
root.left = formBST(start, mid - 1, arr);
root.right = formBST(mid + 1, end, arr);
return root;
}
参考官方题解
if(head == null) return null;
return dfs(head,null);
}
private TreeNode dfs(ListNode head, ListNode tail){
if(head == tail) return null;
ListNode fast = head, slow = head;
while(fast != tail && fast.next != tail){
fast = fast.next.next;
slow = slow.next;
}
TreeNode root = new TreeNode(slow.val);
root.left = dfs(head, slow);
root.right = dfs(slow.next, tail);
return root;
给定一个单链表的头节点 head ,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树。 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过 1。
示例1
输入: head = [-10,-3,0,5,9] 输出: [0,-3,9,-10,null,5] 解释: 一个可能的答案是[0,-3,9,-10,null,5],它表示所示的高度平衡的二叉搜索树。
示例2
输入: head = [] 输出: [] 解释: 一个可能的答案是[0,-3,9,-10,null,5],它表示所示的高度平衡的二叉搜索树。
先把有序链表转成有序数组,由于题目中描述元素是按升序排序,那意味着中间值天然左边小,右边大,所以只要每次找中间点进行左右递归进行BST构建即可
const sortedListToBST = head => {
let arr = [];
while(head){
arr.push(head.val);
head = head.next;
}
// 通过索引start 和 end 构建子树
const buildBST = (start, end) => {
if(start > end)
return null;
const mid = (start + end) >>> 1;
const root = new TreeNode(arr[mid]);
root.left = buildBST(start, mid - 1);
root.right = buildBST(mid + 1, end);
return root;
};
return buildBST(0, arr.length - 1);
};
时间复杂度:O(n) 空间复杂度:O(n)
【Day 9】109. 有序链表转换二叉搜索树
快慢指针
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
if not head:
return head
pre, slow, fast = None, head, head
while fast and fast.next:
fast = fast.next.next
pre = slow
slow = slow.next
if pre:
pre.next = None
node = TreeNode(slow.val)
if slow == fast:
return node
node.left = self.sortedListToBST(head)
node.right = self.sortedListToBST(slow.next)
return node
时间复杂度:O(N)
空间复杂度:O(N)
class Solution:
def sortedListToBST(self, head: ListNode) -> TreeNode:
def getMedian(left, right):
fast = slow = left
while fast != right and fast.next != right:
fast = fast.next.next
slow = slow.next
return slow
def buildTree(left, right):
if left == right:
return
mid = getMedian(left, right)
root = TreeNode(mid.val)
root.left = buildTree(left, mid)
root.right = buildTree(mid.next, right)
return root
return buildTree(head, None)
将链表转为数组,然后递归构建平衡二叉树。在数组找到中点,即为根节点。左边为左子树,右边为右子树。
class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
if head == None:
return None
lists = []
cur = head
while cur:
lists.append(cur.val)
cur = cur.next
return self.createBST(lists, 0, len(lists)-1)
def createBST(self, lists, start, end):
if start > end:
return None
mid = (start + end) // 2
root = TreeNode(lists[mid])
root.left = self.createBST(lists, start, mid-1)
root.right = self.createBST(lists, mid+1, end)
return root
func sortedListToBST(head *ListNode) *TreeNode {
if head == nil {
return nil
}
arrValue := []int{}
cur := head
for cur != nil {
arrValue = append(arrValue, cur.Val)
cur = cur.Next
}
return createBST(arrValue, 0, len(arrValue)-1)
}
func createBST(arrValue []int, start int, end int) *TreeNode {
if start > end {
return nil
}
mid := (start + end) / 2
root := &TreeNode{Val:arrValue[mid]}
root.Left = createBST(arrValue, start, mid-1)
root.Right = createBST(arrValue, mid+1, end)
return root
}
空间复杂度:O(N)
时间复杂度:O(N)
分治
javaScript
var sortedListToBST = function(head) {
if(!head) return null;
let length = 0;
let current = head;
while(current){
current = current.next
length++
}
var buildBST = function(start, end){
if(start > end) return null;
const mid = start + ((end - start)>> 1)
const leftSide = buildBST(start, mid - 1);
const root = new TreeNode(head.val)
head = head.next;
root.left = leftSide
root.right = buildBST(mid+1, end)
return root;
}
return buildBST(0, length - 1)
};
1、使用快慢双指针找到中间元素 2、中间的就是二叉树的根,左右部分的就是左右子树,再按1去递归构造左右子树
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* sortedListToBST(ListNode* head) {
if (head == nullptr) {
return nullptr;
}
return sortedListToBST(head, nullptr);
}
TreeNode* sortedListToBST(ListNode* head, ListNode* tail) {
if (head == tail) {
return nullptr;
}
ListNode* slow = head;
ListNode* fast = head;
while (fast != tail && fast->next != tail) {
slow = slow->next;
fast = fast->next->next;
}
TreeNode* root = new TreeNode(slow->val);
root->left = sortedListToBST(head, slow);
root->right = sortedListToBST(slow->next, tail);
return root;
}
};
复杂度分析 递归树的深度为 logn 所以时间复杂度和空间复杂度都是logn * 递归函数内部所需要的时间和空间
109. 有序链表转换二叉搜索树
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/convert-sorted-list-to-binary-search-tree/
前置知识
题目描述
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:
给定的有序链表: [-10, -3, 0, 5, 9],
一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:
-3 9 / / -10 5