這是一道比較綜合的題目。將鏈表中關於環和相交的問題聚集在一起了,關鍵是要思路清晰。
思路如下:
/*
* 判斷鏈表是否有環
* 1 如果一個有環一個無環,則肯定不相較
* 2 如果都無環,則遍歷到尾部,看看最後一個節點是否相等即可
* 如果要找到第一個相交的點,則讓長的鏈表先走len1-len2步,再同時走,找到相等的節點即可
* 3 如果都有環,則先找到各自的環入口點(快慢指針,第一次相遇後,快指針從頭節點開始,每次走一步,慢指針繼續向前走一步,直至再次相遇)
* 如果兩個入口點相等,則肯定相交
* 如果要找到第一個相交的點,則需要讓長的鏈表(從頭節點到相交的節點)先走len1-len2步,然後同時走,找到相等的點即可
* 如果兩個入口點不相等,則選其中一個相交點,繼續向後走,看看 是否會經歷另外一個相交點,如果經歷了,則相交,否則不相交
*/
具體代碼如下:
public boolean chkInter(ListNode head1, ListNode head2, int adjust0, int adjust1) {
if(head1==null || head2==null) return false;
ListNode node1 = chkLoop(head1);
ListNode node2 = chkLoop(head2);
//判斷是否有環
if(node1==null && node2==null) { //兩個都是無環鏈表
while(head1.next!=null) {
head1 = head1.next;
}
while(head2.next !=null) {
head2 = head2.next;
}
if(head1==head2) {
return true;
} else {
return false;
}
} else if(node1!=null && node2!=null) {//兩個都是有環鏈表
//node1和node2是環的入口點
if(node1==node2) {
return true;
} else {
ListNode cur = node1.next;
while(cur!=node1) {
if(cur == node2) { //相交
return true;
}
cur = cur.next;
}
//不相交
return false;
}
} else { //一個有環一個無環
return false;
}
}
private ListNode chkLoop(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while(fast!=null && fast.next!=null) {
slow = slow.next;
fast = fast.next.next;
if(slow==fast) {
break;
}
}
//沒有環則返回null
if(fast==null || fast.next==null) return null;
fast = head;
while(slow!=fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}