LeetCode 单链表判断回文开始结点 O(1)空间复杂度

上次讲了如何实现判断单链表中是否存在回文
这次我们将算法提升一下,判断在哪里将会产生回文。如果没有链表中无回路则直接返回NULL

既然是算法提升,说明之前的算法仍有它的可取之处,分析一下,我们可以将此任务分为两步来解决:
①判断链表是否有回文,如果没有则直接返回NULL;
②如果有回文,如何利用数学分析来找到回文开始结点并返回该结点。

该题选自LeetCode 142,有兴趣的朋友可以直接去看看。

思路分析

首先我们仍然采用追击算法的思想,即当两个指针在回文里循环时,如果发生追击现象,则说明链表内有回文,否则没有。

那么,当我们得知有回文后,肯定还需要一些信息才能对回文开始的地方进行判断,那么这些信息在哪里获取呢?想一想,是否他们相遇的位置中存在其他隐含信息?

其实,他们相遇的位置确实隐藏着重要的信息,我们现在假设该链表分为两部分,前一部分是无回文的直链,后一部分是回文,两者相交的位置即我们最后要计算的位置,取名为P点
假设前一部分的长度为a,后一部分长为b

  1. 当fast_p(快指针)跑了一个a的距离时,slow_p(慢指针)跑了a/2。此时fast_p恰好在P点
  2. 当slow_p跑了一个a的时候,fast_p已经跑了2a的距离,假设回文单圈长度大于a,那么我们此时将回文总长划分为a+c(a+c=b),此时slow_p恰好在P点,而fast_p已经跑了一个a,他还剩一个c就跑完了一圈
  3. 当slow再跑了一个c之后,fast跑了2c,他(fast_p)此时恰好跑满了一圈、又多了一个c的长度,还差一个a的距离就又到P点;而slow此时刚刚第一次进去圈中,跑了一个c的长度,也差一个a的长度就到P点。(等等!他们此时距离P点的距离是一样的,那不就是说,他们此时已经相遇了吗? fast_p刚好在P点后距离P点c的地方追上了slow_p,仔细想想看是不是这样。)
  4. 我们再观察,此时fast_p和slow_p都离P点差一个a的距离,那么a又是多远的?诶!a不就是从head(头结点)开始到P点的距离吗?也就是说,如果现在再有一个slow_p2,让他从头开始跑,并且速度和slow_p是一样的,那么他们将恰好可以在P点相遇! 这不就刚好凑出了我们要的控制条件吗?

OK,综上所述,我们终于分析清楚了整个流程,编码就很简单了:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if(head == NULL)
            return NULL;
        ListNode * fast_p = head;
        ListNode * slow_p = head;
        ListNode * p2 = NULL;
        while(fast_p !=NULL && fast_p->next != NULL){
            fast_p = fast_p->next->next;
            slow_p = slow_p->next;
            if(fast_p == slow_p){
                p2 = fast_p;
                while(head != p2){
                    head = head->next;
                    p2 = p2->next;
                }   
                return head;
            }
        }
        return NULL;
           
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值