【剑指offer】22. 链表中倒数第k个节点

192 阅读2分钟

题目描述

在这里插入图片描述 在这里插入图片描述

// 力扣
// 输入一个链表,输出该链表中倒数第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;
    }
}