Leetcode算法热题 --- 链表篇链表中倒数第k个节点

Posted 大家好我叫张同学

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode算法热题 --- 链表篇链表中倒数第k个节点相关的知识,希望对你有一定的参考价值。


题目内容:

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。

leetcode题目链接(点击即可跳转):链表中倒数第k个节点


题目理解:这个题目要求我们找到倒数第k个节点,顺数的最后一个元素是倒数第1个节点(有的地方会把这里叫做倒数第0个,但是这个题目已经说的很清楚了,是倒数第一个)

假设我们的链表是这样的,如果要求倒数第2个节点,那么我们应该是找到值为5的这个节点。(下面的讲解默认以该图为例)
题目中给的是单链表,也就是我们无法从“6”直接找到“5”,而且单链表的头指针head也有可能指向NULL(也就是链表一个元素都没有)

思路一:链表长度法

核心思路:既然我们没法从后往前走,只能从链表的头走到尾,那么我们可以先遍历链表求出长度length,然后将倒数第k个节点转换成求顺数第n个节点,n = length - k + 1,(比如说倒数第1个节点实际上就是顺数的第6个节点,倒数第2个节点就是顺数第5个节点),然后再从头遍历链表,找到顺数第n个节点返回即可。

注意:
1)链表为空时需要单独处理!(直接返回head或者NULL均可,推荐NULL,方便阅读)
2)题目中k的取值范围并没有说明,所以我们应该考虑为k任意取值,当k取负数,或者k的大小大于length的时候,此时应该超出链表范围了,应该单独处理!(直接返回NULL)

代码实现:

//方法一:链表长度法
struct ListNode* getKthFromEnd(struct ListNode* head, int k){
     //判断是否为空链表
     if(head == NULL)
        return NULL;
    //遍历求出链表长度
    int length = 0;
    struct ListNode* cur = head;
    while(cur)
    {
        cur = cur->next;
        length++;
    }
    //对k的取值范围做一个限定
    if(k < 0 || k > length)
        return NULL;
    int n = length - k + 1;//k的大小未定,取值范围未定,有坑!
    cur = head;
    while(n-- != 1)
    {
        cur = cur->next;
    }
    return cur;
}


上面这种方法虽然实现了求第k个节点,但是因为遍历了两遍链表,实际上效率有所损失,有没有更好的方法呢?先看一下下面的图找一找规律吧!

不难看出应该存在关系 顺数第n个和倒数第k个加起来的和是一个定值,为链表的长度+1
也就是n + k = length + 1;理解这个后,我们接下来介绍第二种方法

思路二:双指针先行法

核心思想:我们创建两个指针都指向头节点,让一个先走k步,然后两个指针一起走,当先走的指针到达尾节点指向的NULL时,就停止!


注意:
1)链表为空时需要单独处理!(直接返回head或者NULL均可,推荐NULL,方便阅读)
2)题目中k的取值范围并没有说明,所以我们应该考虑为k任意取值,当k取负数,或者k的大小大于length的时候,此时应该超出链表范围了,应该单独处理!(这个时候先走的指针会提前指向NULL,这个时候就需要停止并返回NULL)

代码实现:

struct ListNode* getKthFromEnd(struct ListNode* head, int k){
    if(head == NULL)
       return NULL;
    struct ListNode* fast = head;//快指针先走
    struct ListNode* slow = head;//慢指针后走
    while(k--)//k不为0,fast就继续往后走
    {
        if(fast == NULL)//需要判断fast是否已经走到NULL了
           return NULL;
        fast = fast->next;
    }
    //快慢指针手拉手,一起走
    while(fast)
    {
        fast = fast->next;
        slow = slow->next;
    }
    return slow;
}

以上是关于Leetcode算法热题 --- 链表篇链表中倒数第k个节点的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode初级算法(链表篇)

LeetCode与《代码随想录》链表篇:做题笔记与总结-JavaScript版

算法leetcode剑指 Offer 22. 链表中倒数第k个节点(多语言实现)

算法leetcode剑指 Offer 22. 链表中倒数第k个节点(多语言实现)

算法_链表篇

算法_链表篇