【剑指offer】链表中倒数第 k 个结点

题目描述

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

解题思路

思路一:

这个思路比较简单粗暴,因为要找倒数第 k 个结点,可以利用栈“先进后出”的特性,首先,遍历链表所有的结点,存储到栈内;然后将栈内前 k-1 个结点推出来,那么剩下的栈顶结点就是倒数第 k 个结点。这个方法的空间复杂度是 O(n),时间复杂度 O(n)。

实现代码:

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(!pListHead||k<=0)  return NULL;
        int len = 0;
        stack<ListNode*> Lstack;
        while(pListHead){
            Lstack.push(pListHead);
            pListHead = pListHead->next;
            len++;
        }
        if(k>len)  return NULL;
        while(k>1){
            Lstack.pop();
            k--;
        }
        return Lstack.top();
    }
};
思路二:快慢指针

快慢指针在解决单链表是否存在环的时候使用过,可以回顾博客《【剑指offer】链表中环的入口结点》

下面我们再次用快慢指针解决链表问题。想一想,我们在判断倒数第 k 个结点是怎么做的。我们会首先找到结尾结点,然后从后往前找 k 个,那么怎么判断尾结点呢?如果这个结点的下一个结点为空,我们就认为这个是尾结点。

设置快慢指针,我们先让快指针从头结点开始走 k-1 步,然后慢指针再从头结点开始走。快慢指针每次只走一步。这样快指针就可以看作是“探针”,如果快指针指向尾结点,说明慢指针再走 k-1 步就结束了,慢指针指向的结点就是倒数第 k 个结点。

实现代码:

class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(!pListHead||k<=0)  return NULL;
        // 设置快慢指针
        ListNode* fast = pListHead;
        ListNode* slow = pListHead;
        int len = k;
        // 快指针先走 k-1 步。
        while(k>1){
            // 如果 k 大于链表长度,fast指针会走到 NULL
            if(!fast->next) return NULL;
            fast = fast->next;
            k--;
        }
        // 确定k<链表长度,快慢指针一起走,直到快指针走到尾结点。
        while(fast->next){
            fast = fast->next;
            slow = slow->next;
        }
        return slow;
    }
};
思路三:

举个例子,看下图。

<图>

假设链表有 8 个结点,我们要找倒数第 3 个结点。我们给每个结点加上索引 index,分别是 0-7。那么倒数第 3 个结点的索引是 5,这等于链表长度 - k,k是倒数第几个,也等于最后索引值 - k + 1。基于这个想法,如果我们设置一个结点从头到尾遍历,就可以得到链表长度 len,此时倒数第 k 个结点则在遍历过程中等于比遍历少走了 k-1 步。这样,我们可以设置两个指针,一个是遍历指针,另一个是目标指针。遍历指针从头走到尾,直至指向NULL;目标指针则在遍历了 k-1 步后才开始从头移动,即 i>= k 时,才移动,这样当遍历指针指向NULL时,目标指针就会指向倒数第 k 个结点。

实现代码:

class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(!pListHead||k<=0)  return NULL;
        // 设置两个指针
        ListNode* p = pListHead;
        ListNode* q = pListHead;
        for(int i=0;p!=NULL;i++){
            if(i>=k){
                q = q->next;
            }
            p = p->next;
        }
        return i<k? NULL:q;
    }
};

参考链接:
1.https://www.nowcoder.com/questionTerminal/529d3ae5a407492994ad2a246518148a?f=discussion

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值