單鏈表系列問題

2021-10-08 23:14:22 字數 4051 閱讀 5421

這道題目主要討論單鏈表相交的一系列問題。在本題中,單鏈表可能有環,也可能無環。給定兩個單鏈表的頭節點 head1 和 heda2 ,這兩個鍊錶可能相交,也可能不相交。請實現乙個函式,如果兩個鍊錶相交,請返回相交的第乙個節點;如果不相交返回 null 即可。

要求:如果鍊錶 1 的長度為n,鍊錶 2 的長度為 m,時間複雜度請達到 o(n+m),空間複雜帶請達到 o(1)。

這道題需要分析的情況非常多,同時因為有額外空間複雜度為 o(1) 的限制,非常具有挑戰。

這道題可以使用數學中的分類討論思想,分成三個子問題:

問題一:如何判斷乙個鍊錶是否相交,相交則返回第乙個相交節點,不相交則返回 null。

問題二:如何判斷兩個無環鏈表是否相交,相交則返回第乙個相交節點,不相交則返回null。

問題三:如何判斷兩個有環鏈表是否相交,相交則返回第乙個相交節點,不相交則返回null。

這道題目主要就兩個任務:一是如何判斷有環,二是如何判斷相交。在判斷相交分兩種情況,兩個無環鏈表是否相交,兩個有環鏈表是否相交。

注意:如果乙個鍊錶有環,另外乙個鍊錶無環,它們是不可能相交的,直接返回null。

下面逐個分析每個問題。

問題一:如何判斷乙個鍊錶是否相交,相交則返回第乙個相交節點,不相交則返回 null。

如果乙個鍊錶沒有環,那麼遍歷鍊錶一定可以遇到鍊錶的終點;如果乙個鍊錶有環,那麼遍歷鍊錶就永遠在環裡轉下去了。下面給出找到第乙個入環節點的思路:

使用乙個快指標 fast,和乙個慢指標 slow,快指標的移動速度是慢指標的2倍;

如果鍊錶沒有環,fast 先到鍊錶尾,且next為null;

如果鍊錶有環,最後快指標和慢指標會在某個位置相遇,即 slow==fast;

此時讓其中乙個指標指向head,例如 slow = head,然後slow,fast速度同步繼續往前,當 slow == fast,此時的節點便是第乙個入環的節點。

**實現如下:

1//問題一:如何判斷乙個鍊錶是否有環,如果有,則返回進入環的第乙個節點,否則返回null

2    public  node getloopnode(node head) 

6        node slow = head.next;

7        node fast = head.next.next;

8        while (slow != fast) 

13            fast = fast.next.next;

14            slow = slow.next;

15        }

16        fast = head;

17        while (slow != head) 

21        return slow;

22    }

問題二:如何判斷兩個無環鏈表相交,相交則返回第乙個相交節點,否則返回null

如果兩個無環鏈表相交,那麼從相交節點開始,直到煉表表尾,這段節點是兩個鍊錶共享的。思路如下:

遍歷兩個無環鏈表,並統計鍊錶的長度,len1、len2;

判斷兩個鍊錶的 end 節點是否相等,如果 end1 != end2,兩個鍊錶無相交,直接返回null;end1 == end2,兩個鍊錶相交,進入3,尋找相交的第乙個節點;

如果len1-len>0,則鍊錶1 先走 len1-len2 的長度,如果len2-len1>0,則鍊錶2先走len2-len1的長度,然後兩個鍊錶一起向前走,當鍊表第一次走到一起的那個節點時,這個節點就是相交的第乙個節點。

**實現如下:

1//問題二:如何判斷兩個無環鏈表相交,相交則返回第乙個相交節點,否則返回null

2     public  node noloop(node head1,node head2) 

6        node cur1 = head1;

7        node cur2 = head2;

8        int n = 0;

9        while (cur1.next != null) 

13        while (cur2.next != null) 

17        cur1 = n > 0 ? head1 : head2;//cur1 始終指向較長鍊錶的head

18        cur2 = cur1 == head1 ? head2 : head1;

19        n = math.abs(n);

20        while (n != 0) 

24        while (cur1 != cur2) 

28        return cur1;

29     }

問題三:如何判斷兩個有環鏈表是否相交,相交則返回第乙個相交節點,否則返回null

在解決問題三的時候,已經可以通過前面的方法可以獲得入環的第乙個節點了,假設鍊錶 1 的第一入環節點為 loop1,鍊錶二的第乙個入環節點為 loop2。具體思路如下:

如果鍊錶的loop1、loop2 相等,則鍊錶1和鍊錶2相交的第乙個節點在 loop1 之前,只需使用問題二的方式找出即可,唯一的區別,問題二鍊錶的終點是null ,而這裡終點是loop1 或 loop2;

如果 loop1 != loop2 ,讓 節點從loop1 開始,因為鍊錶有環,所以肯定會回到 loop1,如果在這個過程中,遇到了loop2 ,則說明兩個鍊錶相交,返回loop1 或者loop2 ,如果沒有遇到 loop2 ,則說明兩個鍊錶不相交,返回null 即可。

**實現如下:

1//問題三:如何判斷兩個有環鏈表是否相交,相交則返回第乙個相交節點,否則返回null

2     public  node bothloop (node head1,node loop1,node head2,node loop2) 

14                while (cur2.next != loop2) 

18                cur1 = n>0 ? head1 : head2;

19                cur2 = cur1==head1 ? head2 : head1;

20                n = math.abs(n);

21                while (n != 0) 

25                while (cur1 != cur2) 

29                return cur1;

3031            } else 

38                    cur1 = cur1.next;

39                }

40                return null;

41            }

42     }

回到最開始的那個問題,全部的實現過程看如下**,這也是整個問題的主方法。

1class node 

7public  node getintersectnode(node head1,node head2) 

11            //獲取兩個鍊錶的第乙個入環節點(如果有)

12            node loop1 = getloopnode(head1);

13            node loop2 = getloopnode(head2);

14            //如果第乙個入環節點為空,說明是問題二的情況

15            if (loop1 == null & loop2 == null) 

18            //如果第乙個入環節點不為空,說明是問題三的情況

19            if (loop1 != null & loop2 != null) 

22            return null;

23     }

單鏈表操作系列

include includetypedef int elemtype 定義結點型別 typedef struct node lnode,linklist 單鏈表的建立1,頭插法建立單鏈表,逆序生成 linklist linklistcreateh return l 單鏈表的建立2,尾插法建立單鏈表...

單鏈表操作 單鏈表反轉問題?

單鏈表 typedef struct nodelnode 關於但鍊錶的操作很多 增刪改查,逆序,子交並補等,以及一些經典的變式 考研題目中,有很多好的演算法值得學習。下面是c語言實現的,採用乙個method,乙個test method,方便逐個學習,這個需要不斷的積累,最好用敲幾遍,再在紙上多寫寫,...

演算法系列 單鏈表

public class linkedlist else size 插入方法 public void add int index,e e this.top.addnewnode index,newnode size 修改方法 public void set int index,e e 刪除方法 pu...