【面试题】链表中倒数第k个节点(两种解法)

题目描述

在这里插入图片描述
为了实现只遍历链表⼀次就能找到倒数第k个结点, 我们可以定义两个指针,初始化均指向头结点。
第⼀个指针 p1从链表的头指针开始遍历向前⾛ k-1 步, 第⼆个指针 p2保持不动;
从第k步开始, 第⼆个指针也开始从链表的头指针开始遍历,即双指针共同移动;
由于两个指针的距离保持在 k-1, 当第⼀个(⾛在前⾯的) 指针到达链表的尾结点时, 第⼆个指针(⾛在后⾯的) 指针与尾结点的距离为 k-1,正好是倒数第k个结点。
在这里插入图片描述
考虑到代码的鲁棒性,还需要对一些特殊情况进行处理:

  • 输入链表为空
  • 输入链表的结点个数少于 k个,由于在 for循环中第一个指针会在链表上向前⾛ k- 1步, 这时候可能会由于超出了链表的长度,导致空指针造成程序崩溃。
  • 输入参数 k为 0,由于 k是⼀个⽆符号整数, 那么在 for循环中 k- 1得到的将不是 -1,而是 4294967295(⽆符号的 0xFFFFFFFF) 。因此 for循环执⾏的次数远远超出我们的预计, 同样也会造成程序崩溃。

Java

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        if (head == null || k == 0) // 链表为空或者输入参数 k为0
            return null;
        ListNode p1 = head, p2 = head; // 定义快、慢指针
        // 快指针先走 k-1步
        for (int i=0; i<k-1; i++){ 
            if (p1 == null && i<k) // 链表结点个数少于 k个,快指针在向前走 k-1步的过程中就可能跳出了链表的范围,变成空指针
                return null;
            p1 = p1.next;
        }
        // 走完 k步后,此时两个指针距离为 k-1,
        // 接下来共同移动,直到快指针到达链表尾结点时,此时慢指针与尾结点距离为 k-1,正好为倒数第 k个结点
        while (p1.next != null){ 
            p1 = p1.next;
            p2 = p2.next;
        }
        return p2;
    }
}

简化代码,通过一个辅助变量 t 代替第一个 for 循环

class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        if (head == null || k == 0) return null;
        ListNode p1 = head, p2 = head;
        int t = 0;
        while (p1 != null){
            if (t>k-1) // p1先走 k-1步之后,p2才开始移动
                p2 = p2.next;
            p1 = p1.next;
            t++;
        }
        if (p1 == null && t<k) return null; // 链表长度小于 k
        return p2;
    }
}

时间复杂度:O(n),快指针遍历了整个链表,走了 n步,慢指针走了 n-k 步。
空间复杂度:O(1),双指针只需要常数大小的额外空间。

参考

https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/solution/mian-shi-ti-22-lian-biao-zhong-dao-shu-di-kge-j-11/

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值