剑指Offer #14 链表中倒数第k个结点(快慢指针) | 图文详解

题目来源:牛客网-剑指Offer专题
题目地址:链表中倒数第k个结点

题目描述

输入一个链表,输出该链表中倒数第k个结点。

节点结构如下:

public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}

题目解析

这是一道和链表相关的题,对于这种题目,在熟悉链表的基本操作解决基本问题之余,也一定要记得处理空指针之类的有可能造成程序异常终止的情况,不要贪图方便(尤其是那些前竞赛选手 )。

方法一:
这是一种最常规的方法,先遍历一次链表求出链表的的长度 l e n len ,然后将倒数第 k 个节点转换为顺数第len-k个节点,最后第二次遍历去求解即可。

public class Solution {
    public ListNode FindKthToTail(ListNode head, int k) {
        if (head == null || k < 1)
            return null;
        int len = 0, i = 0;
        //计算链表长度
        ListNode p = head;
        while (p != null) {
            p = p.next;
            len++;
        }
        //如果k比len还大,就直接返回null
        if (k > len) {
            return null;
        }
        //找倒数第k个节点(其实就是顺数第len-k个节点)
        p = head;
        while (i < len - k) {
            p = p.next;
            i++;
        }
        return p;
    }
}

方法二:
其实我们只需要进行一次遍历操作就可以求出需要的答案,网上很多人把这个称之为“快慢指针法”,即让慢指针在快指针移动 k k 个节点后再开始移动,当快指针移动到链表末尾(null)时,慢指针就到达了倒数 k k 个节点

听起来有点玄乎?请听我细细道来~

如下图所示,由于我们最后到达的是末端(null),那我们就从末端开始移动 k k 个节点,就到达了我们的倒数第 k k 个节点,也就是我们的目标 t a r g e t target 。最后再从 t a r g e t target 移动到慢指针 s l o w slow 的位置。
在这里插入图片描述
现在,我们把部分过程逆转过来,我们要从 s l o w slow 移动到慢指针 t a r g e t target 的位置。问题是我们又不知道要移动多少个节点,暂时设为 x x ,于是有
x + k = l e n x+k=len
我们让快指针先移动了 k k 个节点,再让慢指针和快指针一起移动,实际上就是用快指针去度量链表的长度 l e n len ,将慢指针移动的距离限定为 x = l e n k x=len-k 个节点。

public class Solution {
    public ListNode FindKthToTail(ListNode head, int k) {
        if (head == null || k < 1)
            return null;
        ListNode p, q;
        p = q = head;
        int i = 0;
        for (; p != null; i++) {
            if (i >= k) {
            	//快指针移动了k个节点后,慢指针开始移动
                q = q.next;
            }
            //快指针需要一直移动
            p = p.next;
        }
        return i < k ? null : q;
    }
}

本文为原创,作者博客地址为:Veggie的博客
如果本文对你有所帮助,要记得点赞哦~

发布了86 篇原创文章 · 获赞 192 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/weixin_42292229/article/details/104726496