剑指 Offer 22. 链表中倒数第k个节点
难度简单
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4`的节点。
示例:
给定一个链表: 1->2->3->4->5, 和 k = 2.
返回链表 4->5.
分析
由题可知, 要获取链表中倒数第k个节点, 就得先找到倒数第k个节点,
那么如何找到倒数第k个节点呢,
题解
方法一 直接获取:
最容易想到的就是直接获取
- 先遍历链表, 获取这个链表的长度n, 那么倒数第k个节点, 按正序的顺序就是第 n-k+1 的节点
- 再遍历一遍链表, 遍历至 第 n-k+1个节点, 返回即可 这个需要遍历两次链表, 2n, 时间复杂度就是 O(n), 空间复杂度O(1), 因为没有占用其他内存
具体代码:
public ListNode getKthFromEnd(ListNode head, int k) {
// 直接获取
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
// 获取链表的长度
int n = 0;
while (dummyNode.next != null) {
n++;
dummyNode = dummyNode.next;
}
dummyNode.next = head;
// 倒数第k个节点就是正序第 n - k个节点
int index = n - k + 1;
while (index != 0) {
index--;
dummyNode = dummyNode.next;
}
return dummyNode;
}
// Definition for singly-linked list.
public static class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
方法二 双指针:
也可以通过双指针来遍历链表
- 慢指针指向链表的开始位置, 快指针先跑k步,
- 然后快慢指针依次往后遍历
- 等到快指针遍历到链表的结尾, 因为快慢指针中间相差了k步, 那么慢指针就是链表中倒数第k个节点, 返回慢指针
具体代码:
public ListNode getKthFromEnd(ListNode head, int k) {
// 双指针
// 快慢指针, 快指针先跑k步
ListNode slowNode = new ListNode(0);
ListNode fastNode = new ListNode(0);
slowNode.next = head;
fastNode.next = head;
for (int i = 0; i < k; i++) {
fastNode = fastNode.next;
}
// 再往后遍历,快指针为空时,表示到达链表尾部,慢指针就是倒数第k个
while (fastNode != null) {
slowNode = slowNode.next;
fastNode = fastNode.next;
}
return slowNode;
}
// Definition for singly-linked list.
public static class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}