天天看點

兩個單向連結清單的第一個公共結點

leetcode160:相交連結清單

題目:

編寫一個程式,找到兩個單連結清單相交的起始節點

執行個體:

A:          a1 → a2
                   ↘
                     c1 → c2 → c3
                   ↗            
B:     b1 → b2 → b3
           
思路:

因為連結清單是單向連結清單,是以相交連結清單的形狀就像倒置的 Y,這就有個==特點==:相交點之後的結點都相同。是以找到第一個相同的結點就是連結清單的第一個公共結點。

如果正向周遊連結清單,因為連結清單的長度不相同,是以無法通過的時間使他們的步伐統一。解決辦法是首先比較連結清單兩個的長度,然後讓較長的連結清單的先走他們長度的內插補點,然後同一步伐一起走,知道走到的結點相同時,就找的了第一個公共結點。

時間複雜度分析:空間複雜度O(1),時間複雜度O(n)

運作時間:2ms

//計算連結清單的長度
private int calculateNodes(ListNode head){
    int val=;
    for(;head!=null;head=head.next)
        val++;
    return val;
}
//循環周遊,需要借助于棧
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    if(headA==null || headB==null)
        return null;
    //用來儲存連結清單之間的內插補點
    int temp=;
    ListNode res=null;

    //計算兩個連結清單的長度,較長的連結清單先走幾步
    int lenA=calculateNodes(headA);
    int lenB=calculateNodes(headB);
    if(lenA>lenB){
        temp=lenA-lenB;
        for(int i=;i<temp;i++)
          headA=headA.next;
    }
    else{
        temp=lenB-lenA;
        for(int i=;i<temp;i++)
            headB=headB.next;
    }

    //兩個連結清單同步走,當腳下節點相同時,就找到了
    for(;headA!=null && headB!=null;headA=headA.next,headB=headB.next){
        if(headA==headB){
            res=headA;
            break;
        }

    }
    return res;
}
           

如果從後面周遊連結清單,因為結點都相同,是以第一個不相同的結點就是他們第一個公共結點。但是連結清單隻能從頭開始周遊,但卻要從後面開始比較,可以利用棧結構。使用兩個棧,分别從頭開始周遊兩個連結清單,然後出棧,如果棧頂元素不相同,那麼剛出棧的元素就是第一個公共結點。

時間複雜度分析:空間複雜度O(M+n),時間複雜度O(m+n)

運作時間:17ms

//使用兩個棧存儲空間
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
         if(headA==null ||  headB==null)
            return null;

        Stack<ListNode> list1 = new Stack<>();
        Stack<ListNode> list2 = new Stack<>();
        //儲存出棧結點
        ListNode temp=null;

        //向兩個棧中添加結點
        while(headA!=null){
            list1.add(headA);
            headA=headA.next;
        }
        while(headB!=null){
            list2.add(headB);
            headB=headB.next;
        }

        //比較,出棧
        while(!list1.isEmpty() && !list2.isEmpty() ){
            if(list1.peek() == list2.peek()){
                temp=list1.pop();
                list2.pop();
            }else
                break;
        }
        return temp;
}