IntersectionOfTwoLinkedLists2 [source code]

public class IntersectionOfTwoLinkedLists2 {
static
/******************************************************************************/
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) return null;
        int lenA = length(headA), lenB = length(headB);
        while (lenA > lenB) {
            lenA--;
            headA = headA.next;
        }
        while (lenB > lenA) {
            lenB--;
            headB = headB.next;
        }
        while (headA != headB) {
            headA = headA.next;
            headB = headB.next;
        }
        return headA;
    }

    public int length(ListNode head) {
        int res = 0;
        while (head != null) {
            res++;
            head = head.next;
        }
        return res;
    }
}
/******************************************************************************/

    public static void main(String[] args) {
        IntersectionOfTwoLinkedLists2.Solution tester = new IntersectionOfTwoLinkedLists2.Solution();
        int[][] inputs = {
            {1,2,3,4}, {9,8}, {5, 6, 7},
            {1}, {}, {},
            {1,3,5,7,9,11,13,15,17,19,21}, {2}, {},
            {}, {}, {1,2,3,4,5,6,7,8,9,10,11,12,13},
        };
        for (int i = 0; i < inputs.length / 3; i++) {
            System.out.println(Printer.seperator());
            ListNode h1 = ListNode.buildListNode(inputs[3 * i]);
            ListNode h2 = ListNode.buildListNode(inputs[1 + 3 * i]);
            ListNode h3 = ListNode.buildListNode(inputs[2 + 3 * i]);
            ListNode headA = ListNode.append(h1, h3);
            ListNode headB = ListNode.append(h1, h3);
            Printer.openColor("red");
            System.out.print(ListNode.serialize (headA) + " AND " + ListNode.serialize (headB));
            Printer.closeColor();
            System.out.println(" -> " + ListNode.serialize (tester.getIntersectionNode(headA, headB)));
            Printer.openColor("green");
            System.out.println(ListNode.serialize (headA) + " AND " + ListNode.serialize (headB));
            Printer.closeColor();
        }
    }
}

这个思路是在 discussion 里面看到的一个思路, 整体的想法很简单. 如果直接从两个 head 开始扫, 找不到 intersection 的原因是因为两个 list 可能长度不一样; 所以我们人为的进行一下补偿就行了;

还是注意 loop header 的写法: header condition is yes-condition, and what you WANT is the terminating condition;

最后的速度是2(37);


这个是 discussion 最优解:

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {  
    //boundary check  
    if(headA == null || headB == null) return null;  

    ListNode a = headA;  
    ListNode b = headB;  

    //if a & b have different len, then we will stop the loop after second iteration  
    while( a != b){  
        //for the end of first iteration, we just reset the pointer to the head of another linkedlist  
        a = a == null? headB : a.next;  
        b = b == null? headA : b.next;      
    }  

    return a;  
}

这个比普通的补偿做法的有点在于, 不需要explicitly 的去计算这个差值: 他这里第一个 iteration 跑完之后, 两个指针的位置就自动对齐了;
另外这个算法看起来有点像是主动构造 cycle 的做法(因为 LinkedList 里面 cycle 也跟 reverse 一样是一个常用的也好处理的技巧), 不过好像并不能完全这样说, 因为他这里最后只可能跑两圈.
他这里的这个思路可以是这样: 还是两个指针赛跑思路, 但是我们想要他们共同起跑. 两个 list 长度不一样的情形, 可以理解为一个指针需要跑的距离比另一个指针需要跑的距离要长: 那么我们就让跑的快(短)的那个, 跑完了直接再去跑长的; 跑的长的, 跑完了直接去快车道, 这样长度差值就补偿掉了;

真正想到这个算法还是挺难的, 我个人看法这个就是一个值得称赞的小 trick, 不过真正面试的时候不用执迷于这种技巧; 这个算法其实并没有提高速度;


这个是 discussion 上面一个稍微有点奇葩的解法:

ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {  
    ListNode *tmp = headB;  
    int amoutB = 0,lengthB=0;  

    //calculate the amount of values in listB and get the length of listB  
    while (tmp!=NULL)  
    {  
        amoutB += tmp->val;  
        lengthB ++;  
        tmp = tmp->next;  
    }  

    //add 1 value to all nodes in listA  
    tmp = headA;  
    while (tmp!=NULL)  
    {  
        tmp->val++;  
        tmp = tmp->next;  
    }  

    //re-calculate the amount of values in listB again  
    tmp = headB;  
    int newamoutB = 0;  
    while (tmp!=NULL)  
    {  
        newamoutB += tmp->val;  
        tmp = tmp->next;  
    }  
    tmp = headA;  

    //subtract 1 from all the nodes in listA  
    while (tmp!=NULL)  
    {  
        tmp->val--;  
        tmp = tmp->next;  
    }  

    //if two amounts are the same, there is no node intersecting  
    if(newamoutB==amoutB)  
       return NULL;  
    //the difference of two amounts means the number of intersecting nodes,   
    //we can get the first one by comparing it with number of nodes in listB  
    else  
    {  
        tmp = headB;  
        for(int i=0; i<lengthB-(newamoutB-amoutB);i++)  
            tmp = tmp->next;  
        return tmp;  
    }  
}

整体思路就是如果两个 list 有共享的 node, 那么我们修改其中一个 list 里面所有的 val, 另外一个 list 所有的 val 也会改变. 用 sum 来记录这个改变(来达到O(1)空间), 然后最后这个差值就是number of nodes shared.
不过底下还是有人认为这个算法有问题, 因为这个算是改变了;
另外这个算法有一个问题, 如果这里的 intersection 不是一直持续到两个 list 的底部, 也就是说 intersection 一段之后有分叉, 那么这个算法就不对了; 我自己的 reverse 的算法好像也 handle 不了这种情况; //分个屁的叉! 根本不可能分叉! 一个 node 只可能有一个 child, 一旦汇合就不可能分叉. 不过这个问题想到一次也好, 不然面试的时候碰到了也是自己蠢自己;


Problem Description

Write a program to find the node at which the intersection of two singly linked lists begins.

For example, the following two linked lists:

A: a1 → a2

c1 → c2 → c3

B: b1 → b2 → b3
begin to intersect at node c1.

Notes:

  • If the two linked lists have no intersection at all, return null.
  • The linked lists must retain their original structure after the function returns.
  • You may assume there are no cycles anywhere in the entire linked structure.
  • Your code should preferably run in O(n) time and use only O(1) memory.
    Credits:
    Special thanks to @stellari for adding this problem and creating all test cases.

Difficulty:Easy
Total Accepted:134.4K
Total Submissions:440.5K
Contributor: LeetCode
Companies
amazon microsoft bloomberg airbnb
Related Topics
linked list
Similar Questions
Minimum Index Sum of Two Lists

results matching ""

    No results matching ""