题目描述
// 力扣
// 输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,
// 本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有
// 6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的
// 倒数第3个节点是值为4的节点。
// 牛客
// 输入一个链表,输出该链表中倒数第k个结点。
题解
//////////////////////////// 双指针滑窗 //////////////////////////
// 由于需要返回以倒数第k个结点为头结点。第k结点往后的链表。
// 假如1->2->3->4->5,k = 2。我们需要返回的就是4->5。
// 那么我们就从链表头构建两个指针pre和end,end先右移扩大窗口,
// 直到pre到end的窗口的长度就等于第k结点往后的链表长度为止。
// 再以这个窗口滑动遍历链表,窗口右顶点到达链表尾即可返回。
// 力扣
// 力扣的版本比较简单,给定的k不会为0,也不会超过链表的长度,比较容易理解
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
if (head == null) // 特殊情况判定
return head;
ListNode pre = head; // 滑窗前指针
ListNode end = head; // 滑窗后指针
int i = 1; //
// 将end右移,直到pre到end的窗口长度等于k到链表尾的长度
while (i < k) {
end = end.next;
i += 1;
}
while (end.next != null) { // 窗口右移,直到右顶点到达链表尾
end = end.next;
pre = pre.next;
}
return pre; // 此时的窗口左顶点位置即为倒数第k结点位置,直接返回
}
}
// 牛客
// 运行时间:14ms
// 占用内存:9976k
public class Solution {
public ListNode FindKthToTail(ListNode head, int k) {
if (head == null)
return head;
if (k == 0) // 如果k是0,返回null
return null;
ListNode pre = head;
ListNode end = head;
int i = 1;
// 保证不要超过链表长度范围,把end指针向后,移动次数记为i
while (i != k && end.next != null) {
end = end.next;
i += 1; // end右移一次,i计数一次
}
// 如果k大于整个链表长度,i的大小是达不到k的,所以直接返回null
if (i < k)
return null;
// 如果k没有大于整个链表长度,滑窗
while (end.next != null) {
end = end.next;
pre = pre.next;
}
return pre;
}
}