Leetcode-876.链表的中间结点-剑指22.到数第K个结点(快慢指针)

本文介绍了一种高效的链表处理方法——快慢指针技巧。通过对比指针速度,快速定位中间节点或倒数第K个节点,适用于解决各种链表相关问题。

中间结点

在这里插入图片描述
这种链表的题,找第几个结点,有个很骚的解法,就是用计数器找到那个结点,但是感觉完全避开了他想考察的算法。这种题应该要能熟练使用快慢指针这种算法。

这种算法就根据题目来一边分析一边介绍其用处
根据题目
要寻找中间的结点,如果是有两个中间结点,就返回第二个结点。
通常是设置一个快指针,一个慢指针。而快指针的速度是慢指针的两倍。也就是每次快指针一次走两个元素,而慢指针一次走一个元素。
它要找中间结点。

初始时
在这里插入图片描述
移动
在这里插入图片描述
再移动
在这里插入图片描述
这一步就已经达到目的了,慢指针移动到了中间结点,而此时,循环应该已经结束了,而快指针则是到了最后一个元素,这应该是一个循环结束的条件。

当有两个中间结点时。
在这里插入图片描述
移动

在这里插入图片描述
移动,慢指针已经到了第一个中间结点,再移动一次就可以到达第二个中间结点。
在这里插入图片描述
这种情况下, 快指针应该是走到了最后一个指针的next时,才结束循环移动。

一种是当快指针移动到最后一个结点时,循环结束,
一种是当快指针移动到最后一个结点的next时才结束循环。

总结一下条件是
fast==NULL结束条件对应有两个中间结点的情况,
fast->next == NULL,是对应只有一个中间结点的情况

无论哪种情况,都是快指针走两个结点,慢指针走一个结点。
当循环遇到两个条件中的y一个都要结束循环,返回慢指针

struct ListNode* middleNode(struct ListNode* head)
{
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    while (fast && fast->next)
    {
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow;
}

再来看看利用快慢指针的另一道题

倒数第K个结点

在这里插入图片描述
这就比较不太一样。这是规定好特定的结点。但我们结束快指针移动到最后一个结点或NULL时结束,也就是说,当快指针移动到末尾时,慢指针要正好移动到到数第K个结点。
意味着,快指针于慢指针相差K个结点。
可以让快指针先走K个结点,再快慢指针一起走,当结束时,正好在倒数第K个结点处。

先走K个结点
在这里插入图片描述
再两指针一起走
在这里插入图片描述

继续
在这里插入图片描述

继续
在这里插入图片描述
最后一步
在这里插入图片描述
因为是倒数第K个快指针如果再最后一个结点,那么慢指针与快指针相差两个结点,就是倒数第3个结点,所以快指针要在NULL时,才满足。

struct ListNode* getKthFromEnd(struct ListNode* head, int k)
{
    struct ListNode* fast=head;
    struct ListNode* slow=head;
    for(int i=0;i<k;i++)
    {
     	if(fast==NULL)
            return NULL;
        fast=fast->next;
    }
    while(fast)
    {
        fast=fast->next;
        slow=slow->next;
    }
    return slow;
}

上面都是常规情况,但是还有一些比较奇怪的测试用例。
比如k会超过链表的结点数,那就只能在快指针达到NULL是就提前结束。
或者本身就是一个空链表,那就也是直接结束。
快慢指针感觉挺巧妙的,可以好好理解使用。

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值