題目描述:編寫一個程序,找到兩個單鏈表相交的起始節點。
如下面的兩個鏈表:
在節點 c1 開始相交。
示例 1:
輸入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
輸出:Reference of the node with value = 8
輸入解釋:相交節點的值爲 8 (注意,如果兩個列表相交則不能爲 0)。從各自的表頭開始算起,鏈表 A 爲 [4,1,8,4,5],鏈表 B 爲 [5,0,1,8,4,5]。在 A 中,相交節點前有 2 個節點;在 B 中,相交節點前有 3 個節點。
示例 2:
輸入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
輸出:Reference of the node with value = 2
輸入解釋:相交節點的值爲 2 (注意,如果兩個列表相交則不能爲 0)。從各自的表頭開始算起,鏈表 A 爲 [0,9,1,2,4],鏈表 B 爲 [3,2,4]。在 A 中,相交節點前有 3 個節點;在 B 中,相交節點前有 1 個節點。
示例 3:
輸入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
輸出:null
輸入解釋:從各自的表頭開始算起,鏈表 A 爲 [2,6,4],鏈表 B 爲 [1,5]。由於這兩個鏈表不相交,所以 intersectVal 必須爲 0,而 skipA 和 skipB 可以是任意值。
解釋:這兩個鏈表不相交,因此返回 null。
注意:
如果兩個鏈表沒有交點,返回 null.
在返回結果後,兩個鏈表仍須保持原有的結構。
可假定整個鏈表結構中沒有循環。
程序儘量滿足 O(n) 時間複雜度,且僅用 O(1) 內存。
來源:力扣(LeetCode)
解題思路:
我們不確定兩個鏈表的交點,只有先遍歷出兩個鏈表的長度, 當兩個鏈表的長度已知時,我們可以採用右對齊,就是將遍歷鏈表的兩個指針從距末尾相同位置開始向前遍歷,然後每次判斷兩指針的指向是否相等,相等就說明相交,並相等處爲交點;否則,向前遍歷,直到兩指針均走到鏈表末尾還沒有相遇,說明鏈表不相交!
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
if(headA==NULL||headB==NULL)
{
return NULL;
}
int sizeA=0;
int sizeB=0;
struct ListNode*curA=headA;
struct ListNode*curB=headB;
while(curA!=NULL||curB!=NULL)
{
if(curA!=NULL)
{
sizeA++;
curA=curA->next;
}
if(curB!=NULL)
{
sizeB++;
curB=curB->next;
}
}
curA=headA;
curB=headB;
if(sizeA>sizeB)//當A鏈表長度大於B鏈表長度
{
while(sizeA>sizeB)
{
curA=curA->next;
sizeA--;
}
}
else
{
while(sizeA<sizeB)
{
curB=curB->next;
sizeB--;
}
}
//此時curA和curB距鏈表尾部的距離相同
while(curA!=NULL&&curB!=NULL)
{
if(curA==curB)
{
return curA;
}
curA=curA->next;
curB=curB->next;
}
return NULL;
}
題目描述:給定一個鏈表,判斷鏈表中是否有環。
爲了表示給定鏈表中的環,我們使用整數 pos 來表示鏈表尾連接到鏈表中的位置(索引從 0 開始)。 如果 pos 是 -1,則在該鏈表中沒有環。
示例 1:
輸入:head = [3,2,0,-4], pos = 1
輸出:true
解釋:鏈表中有一個環,其尾部連接到第二個節點。
示例 2:
輸入:head = [1,2], pos = 0
輸出:true
解釋:鏈表中有一個環,其尾部連接到第一個節點。
示例 3:
輸入:head = [1], pos = -1
輸出:false
解釋:鏈表中沒有環。
來源:力扣(LeetCode)
解題思路:
我在常見鏈表常見算法題三中使用了快慢指針法,這道題同樣採用快慢指針法,鏈表成環,快慢指針會相遇,(可以想象成跑道,一人二倍速,一人原速,很像高中物理的追擊相遇問題,兩人勢必會在跑道上相遇,不過二倍速的人比原速的多跑一圈的距離。)
快指針二倍速遍歷,慢指針一步步向前遍歷,
當快指針和慢指針指向同一節點時,說明快指針已經經過一圈追到慢指針;
當快指針遇到NULL(鏈表尾部)時,說明不成環,直接返回
代碼實現:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
if(head==NULL)
{
return false;
}
struct ListNode*fast=head;
struct ListNode*low=head;
while(fast->next!=NULL&&fast->next->next!=NULL)
{
low=low->next;
fast=fast->next->next;
if(low==fast)//滿足條件說明快慢指針相遇,有環
{
return true;
}
}
return false;//退出while循環時說明鏈表遍歷完,fast遇到NULL,則不成環
}
題目描述:給定一個鏈表,返回鏈表開始入環的第一個節點。 如果鏈表無環,則返回 null
爲了表示給定鏈表中的環,我們使用整數 pos 來表示鏈表尾連接到鏈表中的位置(索引從 0 開始)。 如果 pos 是 -1,則在該鏈表中沒有環。
說明:不允許修改給定的鏈表。
示例 1:
輸入:head = [3,2,0,-4], pos = 1
輸出:tail connects to node index 1
解釋:鏈表中有一個環,其尾部連接到第二個節點。
示例 2:
輸入:head = [1,2], pos = 0
輸出:tail connects to node index 0
解釋:鏈表中有一個環,其尾部連接到第一個節點。
示例 3:
輸入:head = [1], pos = -1
輸出:no cycle
解釋:鏈表中沒有環。
進階:
你是否可以不用額外空間解決此題?
來源:力扣(LeetCode)
代碼實現:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *detectCycle(struct ListNode *head) {
if(head==NULL)
{
return NULL;
}
struct ListNode *fast=head;
struct ListNode *low=head;
while(fast!=NULL&&fast->next!=NULL)
{
low=low->next;
fast=fast->next->next;
if(low==fast)
{
break;
}
}
if(fast==NULL||fast->next==NULL)
{
return NULL;//不是環形,返回
}
low=head;//low從頭開始,fast此時和low均和入環節點距離相同
while(low!=fast)
{
low=low->next;
fast=fast->next;
}
return low;
}