题目描述
解题思路
思路一: 倒数变正数
我们可以将倒数第k个节点变成正数第 n - k
个节点。
单链表算倒数第 k
个节点的难处在于无法从尾向头遍历,只能从头向尾遍历,但是如果我们知道链表的长度 n
,知道要返回倒数第 k
个节点,那么转换成计算:链表的正数第 h
个节点,这样不就好做了嘛。
那我们怎么将倒数第k个节点变成正数第 h 个节点呢?直接将链表的长度 - k即可,即 h = n - k
。
接下来我们只需要再遍历一次链表,然后让链表在数到 h
的时候返回即可。
再梳理一遍:
- 计算出链表长度 n
- 计算出正数位置 h:
h = n - k
- 遍历单链表,并在 h 处时返回节点。
代码
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} k
* @return {ListNode}
*/
var getKthFromEnd = function(head, k) {
if(!head) return head;
// 计算单链表长度 n
let n = 0;
for(let cur = head; cur != null; cur = cur.next){
n++;
}
// 计算正数为第 h 个节点
let h = n - k;
// 遍历将正数第 h 个元素返回
let cur= head;
while(cur || h){
if(h === 0){
return cur;
}
cur = cur.next;
h--;
}
};
时间复杂度: O(n) 空间复杂度: O(1)
思路二: 快慢指针
也是遍历,让快指针先走 k
步,慢指针再走,等快指针走完整个链表,慢指针所在位置即为倒数 第 k
个节点的位置。
实际上是思路一的变形。
代码
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} k
* @return {ListNode}
*/
var getKthFromEnd = function(head, k) {
if(!head) return head;
let slow = head, fast = head;
for(let i = 0; i < k; i++){
fast = fast.next;
}
while(fast){
fast = fast.next;
slow = slow.next;
}
return slow;
};
时间复杂度和空间复杂度同上。
总结
只要想清楚正数是第 n - k
步即可。 不管是先算出链表的整个长度,再计算正数是第 n - k
节点,还是用快慢指针,让快指针先走 k
步,然后快慢指针一起走,最后慢指针就是倒数第 k
个节点, 目的都是一样的。