【LeetCode】linked-list-cycle-ii

題幹

Given a linked list, return the node where the cycle begins. If there is no cycle, returnnull.
Follow up:
Can you solve it without using extra space?

鏈表是否有環?如果有找到環的入口結點。
是否可以不開闢額外空間。

數據結構

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

解題思路

1.有額外空間的話是可以用vector等數據結構,遍歷結點,遍歷結點的時候存儲訪問過的結點,用O(1)的時間可以檢索是否已經存儲過相同結點。如果有相同結點,便得到了入口結點;如果沒找到,便添加當前結點到vector中。

2.沒有空間開銷的方法分幾步:
a.判斷鏈表是否有環:用兩個指針,一慢p1一快p2,遍歷鏈表,如果兩個指針相遇,則說明有環。
b.得到環中結點的數量:a步當中相遇的快慢指針位置,一個指針固定p2,另一個p1以步長爲1繼續遍歷,並計數,再次相遇得到環中結點的數量cyc_num。
c.得到環入口結點:置p1,p2兩指針爲頭結點head,先讓p2結點向後走cyc_num步,然後p1,p2一起以步長爲1遍歷鏈表。相遇得到的結點即爲入口結點。

參考代碼

方法一:

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if (head==NULL) return NULL;
        ListNode *cur=head;
        vector<ListNode *>data;//建立vector以存儲經過的結點
        while(cur->next!=NULL){
            vector<ListNode *>::iterator s=find(data.begin(),data.end(),cur);//O(1)時間查找,是否存儲過當前結點
            if (s!=data.end())//存儲過當前結點
                return cur;
            data.push_back(cur);//添加結點到vector中
            cur=cur->next;
        }
        return NULL;

    }
};

方法二:

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if (head==NULL) return NULL;
        ListNode *p1=head,*p2=head;
        int cyc_num=1;
        //第一步:判斷是否存在環
        while(p2->next!=NULL&&p2->next->next!=NULL){
            p1=p1->next;//步長爲1
            p2=p2->next->next;//步長爲2
            if (p1==p2){//如果存在環
                //第二步:確定環中結點數量
                while(p1->next!=p2){
                    p1=p1->next;
                    cyc_num++;
                }
                //第三步:找到入口結點
                p1=head;p2=head;
                for(int i=0;i<cyc_num;i++)
                    p2=p2->next;
                while(p1!=p2){
                    p1=p1->next;
                    p2=p2->next;
                }
                return p1;
            }
        }
        return NULL;

    }
};

方法討論

方法1代碼簡單但需要額外開銷。
方法2代碼相對複雜但是沒有額外的空間開銷。
綜上兩個方法應用場景不同,所以各有用處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章