链表中倒数的第K个节点

本文介绍了一种寻找链表中倒数第K个节点的方法,通过使用双指针技术,其中一个指针先向前移动K个位置,然后两个指针同步移动直至首个指针到达链表尾部,此时第二个指针即指向倒数第K个节点。此外还讨论了如何处理特殊情况以及提升代码鲁棒性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

剑指Offer_15 链表中倒数的第K个节点


2018/5/21 星期一

代码的鲁棒性

鲁棒性对于软件开发的重要性不言而喻,提高代码的鲁棒性的有效途径就是进行防御性编程。这是一种习惯,提高在何处遇见有什么地方可能会出现问题,并为这些问题制定处理方式。比如:当出现找不到文件名时,提醒用户检查输入路径和文件名,当服务器连接不上时,我们可以试图连接备用服务器等。

题目:输入一个链表,输出该链表的倒数第k个结点。为了符合大多数人的阅读习惯,本题从1开始计数,及链表的尾结点为链表的倒数第1个结点。链表结点的定义如下:

class ListNode {
    int data;
    ListNode nextNode;
}

分析:很自然的一个想法就是先走到链表的尾部,然后往前回溯k个结点,就可以得到第k个元素。但是题目中给出的是单链表结点结构,很明显的是希望我们在单链表中实现这个操作。在单链表中,可以通过一次遍历循环得到链表的长度n,然后再遍历一次,到n-k就可以找到倒数的第k个结点信息。

面试官期待的解法

除了前面的思路,我们可以定义两个指针,前一个指针比后一个指针快k个结点,当后一个指针到达链表末尾的时候,第一个指针就刚好指向了倒数的第k个结点。基于这样的思路可以写出如下的Java代码:

public ListNode FindKthToTail(ListNode pListHead, int k) {
    ListNode pAhead = pListHead;
    ListNode pBehind = null;
    // pAhead先走k步
    for (int i = 0; i < k; i++) {
        pAhead = pAhead.nextNode;
    }
    // 一起顺序顺序查找
    pBehind = pListHead;
    while (pAhead.nextNode != null) {
        pAhead = pAhead.nextNode;
        pBehind = pBehind.nextNode;
    }
    return pBehind;
}

当我们洋洋洒洒的写下上面代码的时候,很难让人满意。有如下的情况让代码崩溃:

  1. 输入的pListHead为空
  2. 输入的pListHead为头结点的链表节点总数小于k

修复后代码如下:

public ListNode FindKthToTail(ListNode pListHead, int k) {
    if (pListHead == null || k == 0) {
        return null;
    }
    ListNode pAhead = pListHead;
    ListNode pBehind = null;
    // pAhead先走k步
    for (int i = 0; i < k; i++) {
        if (pAhead.nextNode != null) {
            pAhead = pAhead.nextNode;
        } else {
            return null;
        }
    }
    // 一起顺序顺序查找
    pBehind = pListHead;
    while (pAhead.nextNode != null) {
        pAhead = pAhead.nextNode;
        pBehind = pBehind.nextNode;
    }
    return pBehind;
}

测试用例:

  1. 功能测试:第k个结点是链表的中间结点,是头结点;是尾结点
  2. 特殊输入测试:链表头结点为null,链表的结点小于k,k等于0。

相关题目

  1. 求一个链表的中间结点?如果链表的结点总数为奇数,则返回中间结点,如果链表的结点为偶数,则放回中间结点的任意一个结点。

    解决思路:我们可以定义两个指针,一个指针一次走一步,一个每次走两步。当走的快的指针走到末尾的时候,走的慢的指针刚好在链表的中间。

  2. 判断一个单项链表是否形成了环形结构?和前面一样,如果走的快的指针追上了走的慢的指针,那么链表就是环形链表;如果走的快的指针走到了链表的末尾都没有追上第一个指针,那么链表就不是环形链表。

举一反三

当用一个指针来遍历链表不能解决问题的时候,可以尝试用两个指针来遍历链表。可以让其中的一个链表遍历的快些(比如一次走两步)或者先走若干步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值