トピックの説明
説明
単方向にリンクされた 2 つのリストが交差する開始ノードを見つけるプログラムを作成します。
ノード c1 で交差を開始します (単結合リストには交差がありませんが、交差はあります)
交差する場合は、ノードが配置されている場所の値を返し、ばらばらの場合は null を返します。結果が返された後も、2 つの連結リストは元の構造を維持している必要があり、
連結リスト構造全体に循環はないと見なすことができます。プログラムは O(n) 時間の複雑さを満たそうとし、O(1) メモリのみを使用します。
問題解決分析:
アイデア 1:
A リンク リストの各ノードのアドレスを使用して、B リンク リストのすべてのノードのアドレスと比較します。同じアドレスがあれば、それらは交差します。そして、最初に交差したノードを返します。
時間計算量は O(M*N) です
アイデア 2: テール ノードが同じ場合は交差し、そうでない場合は交差せず、交差するノードを見つけます。
交差判定: 2 つのリンクされたリストを別々にトラバースし、最後のノードのアドレスが同じかどうかを判定します。
交差ノードを見つける: 2 つの連結リストの長さが異なる場合は、最初に長い連結リストに長さの差 L1-L2 ステップを移動させ、次に 2 つの連結リストを同時に移動させます。2 つのノードが同じ場合は、交差したノードを終了して返します。
コードの実装 2:
struct ListNode
{
int val;
struct ListNode* next;
};
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB)
{
if (headA == NULL || headB == NULL)
{
return NULL;
}
//1、判断是否相交
//定义两个变量存放头结点来操作,防止迭代时头结点的值改变
struct ListNode* tailA = headA;
struct ListNode* tailB = headB;
//2、计算两个链表的长度
int lenA = 1;//这是从1开始
int lenB = 1;
while (tailA->next != NULL)
{
lenA++;
tailA = tailA->next;
}
while (tailB->next != NULL)
{
lenB++;
tailB = tailB->next;
}
if(tailA != tailB)
{
return NULL;
}
//3、计算两链表长度的差值
int subValue = abs(lenA - lenB);//三目运算符也可以
//4、判断两个链表的长度关系:分三种情况,lenA>lenB,lenA<lenB,lenA=lenB
//假设默认lenA>lenB
struct ListNode* longList = headA;//这里还要用到头指针,所以前面不用头指针迭代。
struct ListNode* shortList = headB;
//矫正
if (lenB > lenA)
{
longList = headB;
shortList = headA;
}
//5、长的链表的指针先走subValue步
while (subValue)//subValue--,走subValue步
{
longList = longList->next;
subValue--;
}
//注意:遍历下标,一般用for循环。
//6、两个指针同时走
while (longList != shortList)
{
longList = longList->next;
shortList = shortList->next;
}
return longList;//返回任意一个指针即可
}
アイデア 3: 交点を見つける: 長い連結リストが最初 (長さの差) のステップに進み、同時に、同じアドレスを持つ最初のアドレスが交点になります。
2 つのリンクされたリスト A と B の長さを計算します。それらが lA と lB (A は B よりも短い) であると仮定すると、差は k であり、2 つのポインター headA と headB はそれぞれ 2 つのリンクされたリストの先頭を指します
。同時に行く、headA (ショート) は毎回 1 歩、headB (ロング) は毎回 k 歩、または headB (ロング) は最初に k 歩を踏んでから同時に歩きます (方法 2)。
アドレスが同じ場合は交差点のノードのアドレスです。
注意: 前面是先判断尾节点是否相同,判断是否相交。再求相交节点。 下面是假设相交,求相交节点的,如果存在相交节点,则判断相交。
コードの実装 3:
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB)
{
//1、计算两个链表的长度
//定义两个变量存放头结点,防止迭代时头结点的值改变
struct ListNode* curA = headA;
int lA = 0;
while (curA != NULL)
{
lA++;
curA = curA->next;
}
struct ListNode* curB = headB;
int lB = 0;
while (curB != NULL)
{
lB++;
curB = curB->next;
}
//2、判断两个链表的长度关系:分三种情况,lA>lB,lA<lB,lA=lB
//假设默认lA>lB
struct ListNode* longList = headA;
struct ListNode* shortList = headB;
if (lB > lA)
{
longList = headB;
shortList = headA;
}
//3、计算两链表长度的差值
int subValue = abs(lA - lB);
//4、长的链表的指针先走subValue步
while (subValue)
{
longList = longList->next;
subValue--;
}
//5、两个指针同时走
while (longList)//有一个链表走到尾
{
if (longList == shortList)
{
return longList;
}
longList = longList->next;
shortList = shortList->next;
}
//来到这里,说明走到尾了也没有找到相交
return NULL;
}