單鏈表面試題——進階篇

1.判斷單鏈表是否帶環?若帶環,求環的長度?求環的入口點?並計算每個算法的時間複雜度&空間複雜度。
判斷是否帶環:利用快慢指針,快指針每次走兩步,慢指針每次走一步,如果快慢指針相遇,則該鏈表帶環。

ListNode* IsHaveLoop(ListNode* plist)
{
    if (plist == NULL)
    {
        return NULL;
    }
    ListNode* fast = plist;
    ListNode* slow = plist;
    while (fast->next&&fast)
    {
        fast = fast->next->next;
        slow = slow->next;
        if (fast == slow)
        {
            return slow;
        }
    }
    return NULL;
}

求環的長度:相遇之後,每次追一步,再次相遇剛好追一圈——環的長度。

int SizeofLoop(ListNode* plist)//求環長
{
    ListNode* meet = IsHaveLoop(plist);
    if (meet)
    {
        int count = 1;
        ListNode* tmp = meet->next;
        while (tmp != meet)
        {
            tmp = tmp->next;
            count++;
        }
        return count;
    }
    return 0;
}

求環入口點: T——尾長(非環長度),S——慢指針入環到被追上, C——快指針追慢指針多跑的圈。那麼,慢指針走的路程爲 T+S,快指針走的路程爲 T+S+C,可得 2(T+S)=T+S+C,T=C-S,此時,一個指針從起點出發走T步,一個指針從快慢指針相遇點出發走 C-S 步,此時兩指針剛好都在入口點。

ListNode* EnterNode(ListNode* plist) 
{
    ListNode* meet = IsHaveLoop(plist);
    if(meet)
    {
        while (meet != plist)
        {
            meet = meet->next;
            plist = plist->next;
        }
        return plist;
    }
    return NULL;
}

2.判斷兩個鏈表是否相交,若相交,求交點。(假設鏈表不帶環)

ListNode* Intersect(ListNode* pList1, ListNode* pList2)
{
    int count1 = 0, count2 = 0;
    ListNode* p1 = pList1, *p2 = pList2;
    while (p1->next)
    {
        count1++;
        p1 = p1->next;
    }
    while (p2->next)
    {
        count2++;
        p2 = p2->next;
    }
    if (p1 != p2)
    return NULL;
    if (count1 >= count2)
    {
        count1 -= count2;
        while (count1--)
            pList1 = pList1->next;
        while (pList1 != pList2)
        {
            pList1 = pList1->next;
            pList2 = pList2->next;
        }
        return pList1;
    }
    else
    {
        count2 -= count1;
        while (count2--)
            pList2 = pList2->next;
        while (pList1 != pList2)
        {
            pList1 = pList1->next;
            pList2 = pList2->next;
        }
        return pList1;
    }
}

3.判斷兩個鏈表是否相交,若相交,求交點。(假設鏈表可能帶環)【升級版】
這裏寫圖片描述

ListNode* Intersect(ListNode* plist1, ListNode* plist2)//判斷鏈表是否相交升級版
{
    //先判斷是否爲空
    if ((plist1 == NULL) || (plist2 == NULL))
    {
        return NULL;
    }
    ListNode* enter1 = EnterNode(plist1);
    ListNode* enter2 = EnterNode(plist2);
    //1和2:若兩個鏈表都無環,則直接用題目二的函數解決
    if ((enter1 == NULL) && (enter2 == NULL))
    {
        return IsListIntersect(plist1, plist2);
    }
        //4:若一個有環,一個無環,則不想交,返回NULL
       else if ((enter1 == NULL) && (enter2 != NULL) || (enter1 != NULL) && (enter2 == NULL))
    {
        return NULL;
    }
    //3: 若入口點相同都在尾巴,去掉環,轉化成無環相交問題
    else if (enter1 == enter2)
    {
        enter1->next = NULL;
        enter2->next = NULL;
        return IsListIntersect(plist1, plist2);
    }
    //6 :同環,兩個入口點  一個入口點開始遍歷一圈,看環上是否有另一個入口點  
        // 找到則返回plist1的入口點  
    else
    {
        ListNode* tmp = enter1->next;
        while (tmp != enter1)
        {
            if (tmp == enter2)
            {
                return enter1;
            }
            tmp = tmp->next;
        }
        return NULL;
    }
}

4.複雜鏈表的複製。一個鏈表的每個節點,有一個指向next指針指向下一個節點,還有一個random指針指向這個鏈表中的一個隨機節點或者NULL,現在要求實現複製這個鏈表,返回複製後的新鏈表。

這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述

ComplexNode* CopyList(ComplexNode* plist)
{
    if (plist == NULL)
    {
        return NULL;
    }
    ComplexNode* newnode = NULL;
    ComplexNode* tmp = plist;
    //1.1 插入節點
    while (tmp != NULL)
    {
        newnode = (ComplexNode*)malloc(sizeof(ComplexNode));
        newnode->_data = tmp->_data;
        newnode->_next = tmp->_next;
        newnode->_random = NULL;
        tmp->_next = newnode;
        tmp = tmp->_next->_next;
    }
    //1.2開始連接random
    tmp = plist;
    newnode = plist->_next;
    while (tmp != NULL)
    {
        if (tmp->_random != NULL)
        {
            newnode->_random = tmp->_random->_next;
        }
        tmp = tmp->_next->_next;
        if (tmp)
        {
            newnode = tmp->_next;
        }
    }
    //2.分離兩個鏈表
    ComplexNode* res = plist->_next;
    tmp = plist;
    tmp->_next = tmp->_next->_next;
    tmp = tmp->_next;
    newnode = plist->_next;
    while ((tmp->_next != NULL)&&(tmp != NULL))
    {
        newnode->_next = newnode->_next->_next;
        tmp->_next = tmp->_next->_next;
        tmp = tmp->_next;
        newnode = newnode->_next;
    }
    return res;
}

發佈了49 篇原創文章 · 獲贊 28 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章