Skip to content

Commit 7d97c16

Browse files
committed
109
1 parent f206b20 commit 7d97c16

File tree

4 files changed

+156
-3
lines changed

4 files changed

+156
-3
lines changed

SUMMARY.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,13 @@
102102
* [99. Recover Binary Search Tree](leetcode-99-Recover-Binary-Search-Tree.md)
103103
* [100. Same Tree](leetcode-100-Same-Tree.md)
104104
* [leetcode 100 斩!回顾](leetcode100斩回顾.md)
105-
* [101 题到 108](leetcode-101-200.md)
105+
* [101 题到 109](leetcode-101-200.md)
106106
* [101. Symmetric Tree](leetcode-101-Symmetric-Tree.md)
107107
* [102. Binary Tree Level Order Traversal](leetcode-102-Binary-Tree-Level-Order-Traversal.md)
108108
* [103. Binary Tree Zigzag Level Order Traversal](leetcode-103-Binary-Tree-Zigzag-Level-Order-Traversal.md)
109109
* [104. Maximum Depth of Binary Tree](leetcode-104-Maximum-Depth-of-Binary-Tree.md)
110110
* [105. Construct Binary Tree from Preorder and Inorder Traversal](leetcode-105-Construct-Binary-Tree-from-Preorder-and-Inorder-Traversal.md)
111111
* [106. Construct Binary Tree from Inorder and Postorder Traversal](leetcode-106-Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal.md)
112112
* [107. Binary Tree Level Order Traversal II](leetcode-107-Binary-Tree-Level-Order-TraversalII.md)
113-
* [108. Convert Sorted Array to Binary Search Tree](leetcode-108-Convert-Sorted-Array-to-Binary-Search-Tree.md)
113+
* [108. Convert Sorted Array to Binary Search Tree](leetcode-108-Convert-Sorted-Array-to-Binary-Search-Tree.md)
114+
* [109. Convert Sorted List to Binary Search Tree](leetcode-109-Convert-Sorted-List-to-Binary-Search-Tree.md)

leetcode-101-200.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@
1212

1313
<a href="leetcode-107-Binary-Tree-Level-Order-TraversalII.html">107. Binary Tree Level Order Traversal II</a>
1414

15-
<a href="leetcode-108-Convert-Sorted-Array-to-Binary-Search-Tree.html">108. Convert Sorted Array to Binary Search Tree</a>
15+
<a href="leetcode-108-Convert-Sorted-Array-to-Binary-Search-Tree.html">108. Convert Sorted Array to Binary Search Tree</a>
16+
17+
<a href="leetcode-109-Convert-Sorted-List-to-Binary-Search-Tree.html">109. Convert Sorted List to Binary Search Tree</a>

leetcode-108-Convert-Sorted-Array-to-Binary-Search-Tree.md renamed to leetcode-108-Convert-Sorted-Array-to-Binary-Search-Tree - 副本.md

File renamed without changes.
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# 题目描述(中等难度)
2+
3+
![](https://windliang.oss-cn-beijing.aliyuncs.com/109.jpg)
4+
5+
[108 题](<https://leetcode.wang/leetcode-108-Convert-Sorted-Array-to-Binary-Search-Tree.html>) 是一样的,都是给定一个升序序列,然后生成二分平衡查找树。区别在于 108 题给定的是数组,这里给的是链表。
6+
7+
# 解法一
8+
9+
大家先看一下 [108 题](<https://leetcode.wang/leetcode-108-Convert-Sorted-Array-to-Binary-Search-Tree.html>) 吧,算法的关键是取到中间的数据做为根节点。而这里链表的话,由于不支持随机访问,所以会麻烦些。最简单的思路就是我们把链表先用线性表存起来,然后题目就转换成 108 题了。
10+
11+
为了方便,把上一道题的数组参数改为`List`
12+
13+
```java
14+
public TreeNode sortedListToBST(ListNode head) {
15+
ArrayList<Integer> nums = new ArrayList<>();
16+
while (head != null) {
17+
nums.add(head.val);
18+
head = head.next;
19+
}
20+
return sortedArrayToBST(nums);
21+
}
22+
23+
public TreeNode sortedArrayToBST(ArrayList<Integer> nums) {
24+
return sortedArrayToBST(nums, 0, nums.size());
25+
}
26+
27+
private TreeNode sortedArrayToBST(ArrayList<Integer> nums, int start, int end) {
28+
if (start == end) {
29+
return null;
30+
}
31+
int mid = (start + end) >>> 1;
32+
TreeNode root = new TreeNode(nums.get(mid));
33+
root.left = sortedArrayToBST(nums, start, mid);
34+
root.right = sortedArrayToBST(nums, mid + 1, end);
35+
return root;
36+
}
37+
```
38+
39+
时间复杂度:`O(log(n))`
40+
41+
空间复杂度:数组进行辅助,`O(n)`
42+
43+
# 解法二
44+
45+
参考 [这里](<https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/discuss/35476/Share-my-JAVA-solution-1ms-very-short-and-concise.>)
46+
47+
有没有一种方案,不用数组的辅助呢?那么我们需要解决怎么得到 mid 的值的问题。
48+
49+
最直接的思路就是根据 start 和 end,求出 mid,然后从 head 遍历 mid - start 次,就到达了 mid 值。但最开始的 end,我们还得遍历一遍链表才能得到,总体来说就是太复杂了。
50+
51+
这里有一个求中点节点值的技巧,利用快慢指针。
52+
53+
快指针和慢指针同时从头部开始遍历,快指针每次走两步,慢指针每次走一步,当快指针走到链表尾部,此时慢指针就指向了中间位置。
54+
55+
除了求中点节点的值不一样,基本架构和 [108 题](<https://leetcode.wang/leetcode-108-Convert-Sorted-Array-to-Binary-Search-Tree.html>) 是一样的。
56+
57+
```java
58+
public TreeNode sortedListToBST(ListNode head) {
59+
return sortedArrayToBST(head, null);
60+
}
61+
62+
private TreeNode sortedArrayToBST(ListNode head, ListNode tail) {
63+
if (head == tail) {
64+
return null;
65+
}
66+
ListNode fast = head;
67+
ListNode slow = head;
68+
while (fast != tail && fast.next != tail) {
69+
slow = slow.next;
70+
fast = fast.next.next;
71+
}
72+
73+
TreeNode root = new TreeNode(slow.val);
74+
root.left = sortedArrayToBST(head, slow);
75+
root.right = sortedArrayToBST(slow.next, tail);
76+
return root;
77+
}
78+
```
79+
80+
时间复杂度:根据递归式可知,`T(n) = 2 * T(n / 2 ) + n``O(nlog(n))`
81+
82+
空间复杂度:`O(log(n))`
83+
84+
# 解法三
85+
86+
解法二虽然没有借助数组,优化了空间复杂度,但是时间复杂度增加了,那么有没有一种两全其美的方法,时间复杂度是解法一,空间复杂度是解法二。还真有,参考 [这里](<https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/discuss/35472/Share-my-O(1)-space-and-O(n)-time-Java-code>)
87+
88+
主要思想是,因为我们知道题目给定的升序数组,其实就是二叉搜索树的中序遍历。那么我们完全可以按照这个顺序去为每个节点赋值。
89+
90+
实现的话,我们套用中序遍历的递归过程,并且将 `start``end` 作为递归参数,当 `start == end` 的时候,就返回 `null`
91+
92+
先回想一下中序遍历的算法。
93+
94+
```java
95+
public List<Integer> inorderTraversal(TreeNode root) {
96+
List<Integer> ans = new ArrayList<>();
97+
getAns(root, ans);
98+
return ans;
99+
}
100+
101+
private void getAns(TreeNode node, List<Integer> ans) {
102+
if (node == null) {
103+
return;
104+
}
105+
getAns(node.left, ans);
106+
ans.add(node.val);
107+
getAns(node.right, ans);
108+
}
109+
```
110+
111+
之前是将 `node.val` 进行保存,这里的话我们是给当前节点进行赋值,为了依次赋值,我们需要一个`cur`指针指向给定的数列,每赋一个值就进行后移。
112+
113+
```java
114+
ListNode cur = null;
115+
116+
public TreeNode sortedListToBST(ListNode head) {
117+
cur = head;
118+
int end = 0;
119+
while (head != null) {
120+
end++;
121+
head = head.next;
122+
}
123+
return sortedArrayToBSTHelper(0, end);
124+
}
125+
126+
private TreeNode sortedArrayToBSTHelper(int start, int end) {
127+
if (start == end) {
128+
return null;
129+
}
130+
int mid = (start + end) >>> 1;
131+
//遍历左子树并且将根节点返回
132+
TreeNode left = sortedArrayToBSTHelper(start, mid);
133+
//遍历当前根节点并进行赋值
134+
TreeNode root = new TreeNode(cur.val);
135+
root.left = left;
136+
cur = cur.next; //指针后移,进行下一次的赋值
137+
//遍历右子树并且将根节点返回
138+
TreeNode right = sortedArrayToBSTHelper(mid + 1, end);
139+
root.right = right;
140+
return root;
141+
}
142+
```
143+
144+
时间复杂度:`O(n)`,主要是得到开始的 end,需要遍历一遍链表。
145+
146+
空间复杂度:`O(log(n))`,递归压栈的消耗。
147+
148+
#
149+
150+
快慢指针求链表的中间值,这个技巧不错。此外,解法三的模仿中序遍历的过程,然后把给定的数组依次赋值过去,太强了。

0 commit comments

Comments
 (0)