Skip to content

Commit 0fccc5e

Browse files
committed
117
1 parent 863d586 commit 0fccc5e

File tree

3 files changed

+210
-3
lines changed

3 files changed

+210
-3
lines changed

SUMMARY.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
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 题到 116](leetcode-101-200.md)
105+
* [101 题到 117](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)
@@ -118,4 +118,5 @@
118118
* [113. Path Sum II](leetcode-113-Path-SumII.md)
119119
* [114. Flatten Binary Tree to Linked List](leetcode-114-Flatten-Binary-Tree-to-Linked-List.md)
120120
* [115*. Distinct Subsequences](leetcode-115-Distinct-Subsequences.md)
121-
* [116. Populating Next Right Pointers in Each Node](leetcode-116-Populating-Next-Right-Pointers-in-Each-Node.md)
121+
* [116. Populating Next Right Pointers in Each Node](leetcode-116-Populating-Next-Right-Pointers-in-Each-Node.md)
122+
* [117. Populating Next Right Pointers in Each Node II](leetcode-117-Populating-Next-Right-Pointers-in-Each-NodeII.md)

leetcode-101-200.md

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

2929
<a href="leetcode-115-Distinct-Subsequences.html">115. Distinct Subsequences</a>
3030

31-
<a href="leetcode-116-Populating-Next-Right-Pointers-in-Each-Node.html">116. Populating Next Right Pointers in Each Node</a>
31+
<a href="leetcode-116-Populating-Next-Right-Pointers-in-Each-Node.html">116. Populating Next Right Pointers in Each Node</a>
32+
33+
<a href="leetcode-117-Populating-Next-Right-Pointers-in-Each-NodeII.html">117. Populating Next Right Pointers in Each Node II</a>
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
# 题目描述(中等难度)
2+
3+
![](https://windliang.oss-cn-beijing.aliyuncs.com/117.jpg)
4+
5+
![](https://windliang.oss-cn-beijing.aliyuncs.com/117_2.jpg)
6+
7+
给定一个二叉树,然后每个节点有一个 `next` 指针,将它指向它右边的节点。和 [116 题](<https://leetcode.wang/leetcode-116-Populating-Next-Right-Pointers-in-Each-Node.html>) 基本一样,区别在于之前是满二叉树。
8+
9+
# 解法一 BFS
10+
11+
直接把 [116 题](<https://leetcode.wang/leetcode-116-Populating-Next-Right-Pointers-in-Each-Node.html>) 题的代码复制过来就好,一句也不用改。
12+
13+
利用一个栈将下一层的节点保存。通过`pre`指针把栈里的元素一个一个接起来。
14+
15+
```java
16+
public Node connect(Node root) {
17+
if (root == null) {
18+
return root;
19+
}
20+
Queue<Node> queue = new LinkedList<Node>();
21+
queue.offer(root);
22+
while (!queue.isEmpty()) {
23+
int size = queue.size();
24+
Node pre = null;
25+
for (int i = 0; i < size; i++) {
26+
Node cur = queue.poll();
27+
if (i > 0) {
28+
pre.next = cur;
29+
}
30+
pre = cur;
31+
if (cur.left != null) {
32+
queue.offer(cur.left);
33+
}
34+
if (cur.right != null) {
35+
queue.offer(cur.right);
36+
}
37+
38+
}
39+
}
40+
return root;
41+
}
42+
```
43+
44+
# 解法二
45+
46+
当然题目要求了空间复杂度,可以先到 [116 题](<https://leetcode.wang/leetcode-116-Populating-Next-Right-Pointers-in-Each-Node.html>) 看一下思路,这里在上边的基础上改一下。
47+
48+
我们用第二种简洁的代码,相对会好改一些。
49+
50+
```java
51+
Node connect(Node root) {
52+
if (root == null)
53+
return root;
54+
Node pre = root;
55+
Node cur = null;
56+
while (pre.left != null) {
57+
cur = pre;
58+
while (cur != null) {
59+
cur.left.next = cur.right;
60+
if (cur.next != null) {
61+
cur.right.next = cur.next.left;
62+
}
63+
cur = cur.next;
64+
}
65+
pre = pre.left;
66+
}
67+
68+
return root;
69+
}
70+
```
71+
72+
需要解决的问题还是挺多的。
73+
74+
```java
75+
cur.left.next = cur.right;
76+
cur.right.next = cur.next.left;
77+
```
78+
79+
之前的关键代码就是上边两句,但是在这道题中我们无法保证`cur.left` 或者 `cur.right` 或者 `cur.next.left`或者`cur.next.right` 是否为`null`。所以我们需要用一个`while`循环来保证当前节点至少有一个孩子。
80+
81+
```java
82+
while (cur.left == null && cur.right == null) {
83+
cur = cur.next;
84+
}
85+
```
86+
87+
这样的话保证了当前节点至少有一个孩子,然后如果一个孩子为 `null`,那么就可以保证另一个一定不为 `null` 了。
88+
89+
整体的话,就用了上边介绍的技巧,代码比较长,可以结合的看一下。
90+
91+
```java
92+
Node connect(Node root) {
93+
if (root == null)
94+
return root;
95+
Node pre = root;
96+
Node cur = null;
97+
while (true) {
98+
cur = pre;
99+
while (cur != null) {
100+
//找到至少有一个孩子的节点
101+
if (cur.left == null && cur.right == null) {
102+
cur = cur.next;
103+
continue;
104+
}
105+
//找到当前节点的下一个至少有一个孩子的节点
106+
Node next = cur.next;
107+
while (next != null && next.left == null && next.right == null) {
108+
next = next.next;
109+
if (next == null) {
110+
break;
111+
}
112+
}
113+
//当前节点的左右孩子都不为空,就将 left.next 指向 right
114+
if (cur.left != null && cur.right != null) {
115+
cur.left.next = cur.right;
116+
}
117+
//要接上 next 的节点的孩子,所以用 temp 处理当前节点 right 为 null 的情况
118+
Node temp = cur.right == null ? cur.left : cur.right;
119+
120+
if (next != null) {
121+
//next 左孩子不为 null,就接上左孩子。
122+
if (next.left != null) {
123+
temp.next = next.left;
124+
//next 左孩子为 null,就接上右孩子。
125+
} else {
126+
temp.next = next.right;
127+
}
128+
}
129+
130+
cur = cur.next;
131+
}
132+
//找到拥有孩子的节点
133+
while (pre.left == null && pre.right == null) {
134+
pre = pre.next;
135+
//都没有孩子说明已经是最后一层了
136+
if (pre == null) {
137+
return root;
138+
}
139+
}
140+
//进入下一层
141+
pre = pre.left != null ? pre.left : pre.right;
142+
}
143+
}
144+
```
145+
146+
# 解法三
147+
148+
参考 [这里](<https://leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/discuss/37979/O(1).-Concise.-Fast.-What's-so-hard>)
149+
150+
利用解法一的思想,我们利用 `pre` 指针,然后一个一个取节点,把它连起来。解法一为什么没有像解法二那样考虑当前节点为 `null` 呢?因为我们没有添加为 `null` 的节点,就是下边的代码的作用。
151+
152+
```java
153+
if (cur.left != null) {
154+
queue.offer(cur.left);
155+
}
156+
if (cur.right != null) {
157+
queue.offer(cur.right);
158+
}
159+
```
160+
161+
所以这里是一样的,如果当前节点为`null`不处理就可以了。
162+
163+
第二个问题,怎么得到每次的开头的节点呢?我们用一个`dummy`指针,当连接第一个节点的时候,就将`dummy`指针指向他。此外,之前用的`pre`指针,把它当成`tail`指针可能会更好理解。如下图所示:
164+
165+
![](https://windliang.oss-cn-beijing.aliyuncs.com/117_3.jpg)
166+
167+
`cur` 指针利用 `next` 不停的遍历当前层。
168+
169+
如果 `cur` 的孩子不为 `null` 就将它接到 `tail` 后边,然后更新`tail`
170+
171+
`cur``null` 的时候,再利用 `dummy` 指针得到新的一层的开始节点。
172+
173+
`dummy` 指针在链表中经常用到,他只是为了处理头结点的情况,它并不属于当前链表。
174+
175+
代码就异常的简单了。
176+
177+
```java
178+
Node connect(Node root) {
179+
Node cur = root;
180+
while (cur != null) {
181+
Node dummy = new Node();
182+
Node tail = dummy;
183+
//遍历 cur 的当前层
184+
while (cur != null) {
185+
if (cur.left != null) {
186+
tail.next = cur.left;
187+
tail = tail.next;
188+
}
189+
if (cur.right != null) {
190+
tail.next = cur.right;
191+
tail = tail.next;
192+
}
193+
cur = cur.next;
194+
}
195+
//更新 cur 到下一层
196+
cur = dummy.next;
197+
}
198+
return root;
199+
}
200+
```
201+
202+
#
203+
204+
本来为了图方便,在 [116 题](<https://leetcode.wang/leetcode-116-Populating-Next-Right-Pointers-in-Each-Node.html>) 的基础上把解法二改了出来,还搞了蛮久,因为为 `null` 的情况太多了,不停的报空指针异常,最后终于理清了思路。但和解法三比起来实在是相形见绌了,解法三太优雅了,但其实这才是正常的思路,从解法一的做法产生灵感,利用 `tail` 指针将它们连起来。

0 commit comments

Comments
 (0)