Site Search:

FirstOverlapDetectionGeneral.java


import java.util.HashSet;
import java.util.Set;

public class FirstOverlapDetectionGeneral {
    static LNode loopHead;
    public static void main(String...args) {
        LNode head1 = createLinkedList1();
        LNode head2 = createLinkedList2();
        printResult(head1, loopHead);
        System.out.println();
        printResult(head2, loopHead);
        System.out.println();
        System.out.println("firstOverlapBrutalForce: " + firstOverlapBrutalForce(head1, head2).value);
        head1 = createLinkedList1();
        head2 = createLinkedList2();
        System.out.println("firstOverlapSlowFastPointer: " + firstOverlapSlowFastPointerGeneral(head1, head2).value);
    }
    
    public static LNode firstOverlapBrutalForce(LNode head1, LNode head2) {
        if(head1 == null || head1.next == null ||
                head2 == null || head2.next == null) return null;
        Set<LNode> visited1 = new HashSet<>();
        Set<LNode> visited2 = new HashSet<>();
        LNode current = head1.next;
        while(current != null) {
            if(visited1.contains(current)) break;
            visited1.add(current);
            current = current.next;
        }
        current = head2.next;
        while(current != null) {
            if(visited2.contains(current)) break;
            visited2.add(current);
            current = current.next;
        }
        visited1.retainAll(visited2);
        if(!visited1.isEmpty()) {
            current = head1.next;
            while(!visited1.contains(current))
                current = current.next;
            return current;
        }
            
        return null;
    }
    
    public static LNode firstOverlapSlowFastPointer(LNode head1, LNode head2) {
        if(head1 == null || head1.next == null ||
                head2 == null || head2.next == null) return null;
        LNode current = head1.next;
        while(current.next != null) {
            current = current.next;
        }
        //link the first linked list's tail to the head of the second linked list.
        current.next = head2;
        
        LNode slowPointer = head1.next;
        LNode fastPointer = head1.next;
        while(fastPointer != null && fastPointer.next != null) {
            slowPointer = slowPointer.next;
            fastPointer = fastPointer.next.next;
            if(slowPointer == fastPointer) break;
        }
        if(fastPointer == null || fastPointer.next == null) 
            return null;
        slowPointer = head1.next;
        while(slowPointer != fastPointer) {
            slowPointer = slowPointer.next;
            fastPointer = fastPointer.next;
        }
        
        return fastPointer;
    }
    
    public static LNode firstOverlapSlowFastPointerGeneral(LNode head1, LNode head2) {
        LNode start1 = firstOverlapNode(head1);
        LNode start2 = firstOverlapNode(head2);
        if((start1 == null && start2 != null) || (start1 != null && start2 == null))
            return null;
        if(start1 == null && start2 == null) 
            return firstOverlapSlowFastPointer(head1, head2); //link tail to head and detect loop solution.
        else if(start1 == start2){
            //convert to 2 loop-free linked lists' overlap
            start1.next = null;
            return firstOverlapSlowFastPointer(head1, head2);
        } else {
            if(!contains(head1, start1, start2)) { //no common node
                return null;
            }
            //has 2 first common node, we return either of them
            return start1; 
        }
    }
    
    public static boolean contains(LNode head, LNode start1, LNode start2) {
        if(head == null || head.next == null) return false;
        LNode current = head.next;
        int count = 0;
        while(current.next != null && count <= 1) {
            if(current == start1) count ++;
            if(current == start2) return true;
            current = current.next;
        }
        return false;
    }

    
    public static LNode firstOverlapNode(LNode head1) {
        if(head1 == null || head1.next == null) return null;
        LNode slowPointer = head1.next;
        LNode fastPointer = head1.next;
        while(fastPointer != null && fastPointer.next != null) {
            slowPointer = slowPointer.next;
            fastPointer = fastPointer.next.next;
            if(slowPointer == fastPointer) break;
        }
        if(fastPointer == null || fastPointer.next == null) 
            return null;
        slowPointer = head1.next;
        while(slowPointer != fastPointer) {
            slowPointer = slowPointer.next;
            fastPointer = fastPointer.next;
        }
        return fastPointer;
    }
    
    
    public static LNode createLinkedList1() {
        LNode head = new LNode(0, null);
        LNode current = new LNode(1, null);
        head.next = current;
        current.next = new LNode(2, null);
        current = current.next;
        current.next = new LNode(3, null);
        current = current.next;
        current.next = new LNode(4, null);
        current = current.next;
        loopHead = current;
        current.next = new LNode(5, null);
        current = current.next;
        current.next = new LNode(6, null);
        current = current.next;
        current.next = new LNode(7, null);
        current = current.next;
        current.next = loopHead;
        return head;
    }
    
    public static LNode createLinkedList2() {
        LNode head = new LNode(0, null);
        LNode current = new LNode(11, null);
        head.next = current;
        current.next = new LNode(22, null);
        current = current.next;
        current.next = new LNode(33, null);
        current = current.next;
        current.next = loopHead;
        return head;
    }
    
    public static void printResult(LNode head, LNode loopHead) {
        System.out.println();
        if(head == null || head.next == null) return;
        LNode current = head.next;
        int count = 0;
        while(current.next != null && count <= 1) {
            if(current == loopHead) count ++;
            System.out.print(current.value + " ");
            current = current.next;
        }
        if(loopHead == null)
            System.out.print(current.value + " ");
    }

}