@@ -164,7 +164,9 @@ public class Solution {
164
164
165
165
### 问题分析
166
166
167
- 首先两个节点/指针,一个节点 node1 先开始跑,指针 node1 跑到 k-1 个节点后,另一个节点 node2 开始跑,当 node1 跑到最后时,node2 所指的节点就是倒数第k个节点。
167
+ > ** 链表中倒数第k个节点也就是正数第(L-K+1)个节点,知道了只一点,这一题基本就没问题!**
168
+
169
+ 首先两个节点/指针,一个节点 node1 先开始跑,指针 node1 跑到 k-1 个节点后,另一个节点 node2 开始跑,当 node1 跑到最后时,node2 所指的节点就是倒数第k个节点也就是正数第(L-K+1)个节点。
168
170
169
171
170
172
### Solution
@@ -180,42 +182,43 @@ public class ListNode {
180
182
}
181
183
}*/
182
184
183
- // 时间复杂度O(n),一次遍历即可
184
- // https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId=13&tqId=11167&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
185
+ // 时间复杂度O(n),一次遍历即可
186
+ // https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId=13&tqId=11167&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
185
187
public class Solution {
186
- public ListNode FindKthToTail (ListNode head ,int k ) {
187
- // 如果链表为空或者k小于等于0
188
- if (head== null || k <= 0 ) {
189
- return null ;
190
- }
188
+ public ListNode FindKthToTail (ListNode head , int k ) {
189
+ // 如果链表为空或者k小于等于0
190
+ if (head == null || k <= 0 ) {
191
+ return null ;
192
+ }
191
193
// 声明两个指向头结点的节点
192
194
ListNode node1 = head, node2 = head;
193
- // 记录节点的个数
194
- int count= 0 ;
195
- // 记录k值,后面要使用
196
- int index= k;
197
- // p指针先跑,并且记录节点数,当node1节点跑了k-1个节点后,node2节点开始跑,
198
- // 当node1节点跑到最后时,node2节点所指的节点就是倒数第k个节点
199
- while (node1!= null ){
200
- node1= node1. next;
201
- count++ ;
202
- if (k< 1 ){
203
- node2= node2. next;
204
- }
205
- k-- ;
206
- }
207
- // 如果节点个数小于所求的倒数第k个节点,则返回空
208
- if (count< index) return null ;
209
- return node2;
210
-
211
- }
212
- }
195
+ // 记录节点的个数
196
+ int count = 0 ;
197
+ // 记录k值,后面要使用
198
+ int index = k;
199
+ // p指针先跑,并且记录节点数,当node1节点跑了k-1个节点后,node2节点开始跑,
200
+ // 当node1节点跑到最后时,node2节点所指的节点就是倒数第k个节点
201
+ while (node1 != null ) {
202
+ node1 = node1. next;
203
+ count++ ;
204
+ if (k < 1 && node1 != null ) {
205
+ node2 = node2. next;
206
+ }
207
+ k-- ;
208
+ }
209
+ // 如果节点个数小于所求的倒数第k个节点,则返回空
210
+ if (count < index)
211
+ return null ;
212
+ return node2;
213
213
214
+ }
215
+ }
214
216
```
215
217
216
218
217
219
# 4. 删除链表的倒数第N个节点
218
220
221
+
219
222
> Leetcode:给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
220
223
221
224
** 示例:**
@@ -239,15 +242,16 @@ public class Solution {
239
242
240
243
### 问题分析
241
244
242
- 我们注意到这个问题可以容易地简化成另一个问题:删除从列表开头数起的第 (L - n + 1)个结点,其中 LL 是列表的长度。只要我们找到列表的长度 L,这个问题就很容易解决。
245
+
246
+ 我们注意到这个问题可以容易地简化成另一个问题:删除从列表开头数起的第 (L - n + 1)个结点,其中 L是列表的长度。只要我们找到列表的长度 L,这个问题就很容易解决。
243
247
244
248
![ 图 1. 删除列表中的第 L - n + 1 个元素] ( http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-20/94354387.jpg )
245
249
246
250
### Solution
247
251
248
252
** 两次遍历法**
249
253
250
- 首先我们将添加一个 ** 哑结点** 作为辅助,该结点位于列表头部。哑结点用来简化某些极端情况,例如列表中只含有一个结点,或需要删除列表的头部。在第一次遍历中,我们找出列表的长度 L。然后设置一个指向哑结点的指针,并移动它遍历列表,直至它到达第 (L - n) 个结点那里。我们把第 (L - n)个结点的 next 指针重新链接至第 (L - n + 2)个结点,完成这个算法。
254
+ 首先我们将添加一个 ** 哑结点** 作为辅助,该结点位于列表头部。哑结点用来简化某些极端情况,例如列表中只含有一个结点,或需要删除列表的头部。在第一次遍历中,我们找出列表的长度 L。然后设置一个指向哑结点的指针,并移动它遍历列表,直至它到达第 (L - n) 个结点那里。** 我们把第 (L - n)个结点的 next 指针重新链接至第 (L - n + 2)个结点,完成这个算法。**
251
255
252
256
``` java
253
257
/**
@@ -286,16 +290,18 @@ public class Solution {
286
290
}
287
291
```
288
292
289
- 复杂度分析:
293
+ ** 复杂度分析:**
290
294
291
- - 时间复杂度 O(L) :该算法对列表进行了两次遍历,首先计算了列表的长度 LL 其次找到第 (L - n)(L−n) 个结点。 操作执行了 2L-n2L−n 步,时间复杂度为 O(L)O(L)。
292
-
293
- - 空间复杂度 O(1) :我们只用了常量级的额外空间。
295
+ - ** 时间复杂度 O(L)** :该算法对列表进行了两次遍历,首先计算了列表的长度 LL 其次找到第 (L - n)(L−n) 个结点。 操作执行了 2L-n2L−n 步,时间复杂度为 O(L)O(L)。
296
+ - ** 空间复杂度 O(1)** :我们只用了常量级的额外空间。
294
297
295
298
296
299
297
300
** 进阶——一次遍历法:**
298
301
302
+
303
+ > ** 链表中倒数第N个节点也就是正数第(L-N+1)个节点。
304
+
299
305
其实这种方法就和我们上面第四题找“链表中倒数第k个节点”所用的思想是一样的。** 基本思路就是:** 定义两个节点 node1、node2;node1 节点先跑,node1节点 跑到第 n+1 个节点的时候,node2 节点开始跑.当node1 节点跑到最后一个节点时,node2 节点所在的位置就是第 (L-n ) 个节点(L代表总链表长度,也就是倒数第 n+1 个节点)
300
306
301
307
``` java
@@ -315,17 +321,17 @@ public class Solution {
315
321
// 声明两个指向头结点的节点
316
322
ListNode node1 = dummy, node2 = dummy;
317
323
318
- // node1 节点先跑,node1节点 跑到第 n+1 个节点的时候,node2 节点开始跑
319
- // 当node1 节点跑到最后一个节点时,node2 节点所在的位置就是第 (L-n ) 个节点(L代表总链表长度 ,也就是倒数第 n+1 个节点 )
324
+ // node1 节点先跑,node1节点 跑到第 n 个节点的时候,node2 节点开始跑
325
+ // 当node1 节点跑到最后一个节点时,node2 节点所在的位置就是第 (L-n ) 个节点,也就是倒数第 n+1(L代表总链表长度 )
320
326
while (node1 != null ) {
321
327
node1 = node1. next;
322
- if (n < 0 ) {
328
+ if (n < 1 && node1 != null ) {
323
329
node2 = node2. next;
324
330
}
325
331
n-- ;
326
332
}
327
333
328
- node2. next = node2. next. next;
334
+ node2. next = node2. next. next;
329
335
330
336
return dummy. next;
331
337
@@ -389,4 +395,3 @@ public ListNode Merge(ListNode list1,ListNode list2) {
389
395
}
390
396
```
391
397
392
-
0 commit comments