Leetcode-142: Linked List Cycle II

这题非常经典,其实没见过的话短时间内想出空间复杂度O(1)的解法我觉得不容易。
解法1:用set或map。但要是要求空间复杂度O(1)就不行了。

ListNode *detectCycle(ListNode *head) {

    if (!head) return NULL;
    set<ListNode *> s;

    ListNode* p = head;
    while(p) {
        if (s.count(p)) {
            return p;
        }
        else {
            s.insert(p);
            p=p->next;
        }
    }

    return NULL;
}

解法2:还是快慢指针法,我是参考网上的解法。
这里写图片描述

如图所示,p1和p2都从head出发,p1每次走1步,p2每次走2步,那么当p1和p2在环中某处相遇时,p2已经走s+m+kr, p1走了s+m+lr,也就是说相遇的时候p2和p1所花次数一样,但p2比p1多走了k-l圈。此处l>=0,k>=1, r为一圈周长。
另外我们知道p2走的路应该是p1的两倍,那么有s+m+kr=2(s+m+lr),可推出s+m=(k-2l)r。设n=k-2l,这个n圈实际上就是s+m的距离。

那么我们有s=nr-m。这个说明什么呢?说明如果让p1从head开始,p2从meet place开始,两个每次都只走一步,则p1走了s步,p2走了nr-m步,两者刚好相遇在环的起始点。

代码如下:

#include <iostream>
#include <set>

using namespace std;

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

ListNode *detectCycle(ListNode *head) {

    if (!head) return NULL;
    ListNode *p1=head, *p2=head;
    while(p2) {
        p1=p1->next;
        p2=p2->next;
        if (!p2 || !p2->next) return NULL;
        p2=p2->next;

        if (p2==p1)
            break;
    }
    p1=head;
    while(p1 && p2 && p1!=p2) {
        p1=p1->next;
        p2=p2->next;
    }

    return p1;
}

int main()
{
    ListNode a=ListNode(1);
    ListNode b=ListNode(2);
    ListNode c=ListNode(3);
    ListNode d=ListNode(4);
    ListNode e=ListNode(5);
    a.next=&b;
    b.next=&c;
    c.next=&d;
    d.next=&e;
    //e.next=&c;

    ListNode* p = detectCycle(&a);
    if (p)
        cout<<p->val<<endl;

    return 0;
}

我的另一个类似解法如下:

/**
 * Definition of singly-linked-list:
 * class ListNode {
 * public:
 *     int val;
 *     ListNode *next;
 *     ListNode(int val) {
 *        this->val = val;
 *        this->next = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param headA: the first list
     * @param headB: the second list
     * @return: a ListNode
     */
    ListNode * getIntersectionNode(ListNode * headA, ListNode * headB) {

        if (!headA || !headB) return NULL;
        
        ListNode * nodeA = headA;
        ListNode * endA = NULL;
        
        while(nodeA && nodeA->next) {
            nodeA = nodeA->next;
        }
        endA = nodeA;
        endA->next = headA;  // construct a circle
        
        ListNode * node1 = headB;
        ListNode * node2 = node1->next;
        ListNode * meetNode = NULL;
        
        while(node1 && node2 && node1->next && node2->next) {
            if (node1 == node2) {
                meetNode = node1;
                break;
            }
            node1 = node1->next;
            node2 = node2->next->next;
        }

        if (!meetNode) {
            endA->next = NULL;
            return NULL;
        }
        
        node1 = meetNode->next;
        node2 = headB;
        while(node1 != node2) {
            node1 = node1->next;
            node2 = node2->next;
        }
        
        endA->next = NULL;
        return node1;
    }
};

解法3:参考九章。
思路很清晰。先两个链表各自遍历,如果最后没走到一起就返回NULL。
然后算好两个链表的长度差,短的从头开始走,长的从长度差那个地方开始 走,走到一起的地方就是交汇点。

代码如下:

class Solution {
public:
    /**
     * @param headA: the first list
     * @param headB: the second list
     * @return: a ListNode
     */
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        // write your code here
        if(headA == NULL || headB == NULL)
            return NULL;
        ListNode* iter1 = headA;
        ListNode* iter2 = headB;
        int len1 = 1;
        while(iter1->next != NULL)
        {
            iter1 = iter1->next;
            len1 ++;
        }
        int len2 = 1;
        while(iter2->next != NULL)
        {
            iter2 = iter2->next;
            len2 ++;
        }
        if(iter1 != iter2)
            return NULL;
        if(len1 > len2)
        {
            for(int i = 0; i < len1-len2; i ++)
                headA = headA->next;
        }
        else if(len2 > len1)
        {
            for(int i = 0; i < len2-len1; i ++)
                headB = headB->next;
        }
        while(headA != headB)
        {
            headA = headA->next;
            headB = headB->next;
        }
        return headA;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的纺织品企业财务管理系统,源码+数据库+毕业论文+视频演示 在如今社会上,关于信息上面的处理,没有任何一个企业或者个人会忽视,如何让信息急速传递,并且归档储存查询,采用之前的纸张记录模式已经不符合当前使用要求了。所以,对纺织品企业财务信息管理的提升,也为了对纺织品企业财务信息进行更好的维护,纺织品企业财务管理系统的出现就变得水到渠成不可缺少。通过对纺织品企业财务管理系统的开发,不仅仅可以学以致用,让学到的知识变成成果出现,也强化了知识记忆,扩大了知识储备,是提升自我的一种很好的方法。通过具体的开发,对整个软件开发的过程熟练掌握,不论是前期的设计,还是后续的编码测试,都有了很深刻的认知。 纺织品企业财务管理系统通过MySQL数据库与Spring Boot框架进行开发,纺织品企业财务管理系统能够实现对财务人员,员工,收费信息,支出信息,薪资信息,留言信息,报销信息等信息的管理。 通过纺织品企业财务管理系统对相关信息的处理,让信息处理变的更加的系统,更加的规范,这是一个必然的结果。已经处理好的信息,不管是用来查找,还是分析,在效率上都会成倍的提高,让计算机变得更加符合生产需要,变成人们不可缺少的一种信息处理工具,实现了绿色办公,节省社会资源,为环境保护也做了力所能及的贡献。 关键字:纺织品企业财务管理系统,薪资信息,报销信息;SpringBoot
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值