package Chap5;

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

/**
 * 输入两个链表,找出它们的第一个公共结点。由于是单链表,第一个公共结点及其后的结点都相同
 */
public class FirstPublicNode {

    private class ListNode {
        int val;
        ListNode next = null;

        ListNode(int val) {
            this.val = val;
        }
    }

    /**
     * 方法1:两个辅助栈,从尾到头,找到最后一个相同的结点
     */
    public ListNode findFirstCommonNodeStack(ListNode pHead1, ListNode pHead2) {
        ListNode cur1 = pHead1;
        ListNode cur2 = pHead2;
        LinkedList<ListNode> stack1 = new LinkedList<>();
        LinkedList<ListNode> stack2 = new LinkedList<>();
        // 分别存入两个栈中
        while (cur1 != null) {
            stack1.push(cur1);
            cur1 = cur1.next;
        }
        while (cur2 != null) {
            stack2.push(cur2);
            cur2 = cur2.next;
        }
        // 用于记录逆序的上一个公共结点
        ListNode publicNode = null;
        while (!stack1.isEmpty() && !stack2.isEmpty()) {
            if (stack1.peek() == stack2.pop()) publicNode = stack1.pop();
                // 当前比较的不相同时,返回逆序的最后一个公共结点(也就是正序的第一个公共结点)
            else return publicNode;
        }
        return publicNode;
    }

    /**
     * 还可以用Set,先存入第一个链表的所有结点,然后存入第二个链表的结点,当第一次添加失败的时候说明发现了第一个重复结点
     */
    public ListNode findFirstCommonNodeSet(ListNode pHead1, ListNode pHead2) {
        Set<ListNode> set = new HashSet<>();
        ListNode cur1 = pHead1;
        ListNode cur2 = pHead2;
        while (cur1 != null) {
            set.add(cur1);
            cur1 = cur1.next;
        }

        while (cur2 != null) {
            if (!set.add(cur2)) return cur2;
            cur2 = cur2.next;
        }
        return null;
    }

    /**
     * 方法2:先得到两个链表的长度;
     * 让两个链表的尾部对齐,即先让长链表走若干部,然后两个链表同时走,保证它俩同时到链表末尾
     */
    public ListNode firstCommonNode(ListNode pHead1, ListNode pHead2) {
        ListNode cur1 = pHead1;
        ListNode cur2 = pHead2;
        int len1 = 0;
        int len2 = 0;
        // 计算链表1的长度
        while (cur1 != null) {
            len1++;
            cur1 = cur1.next;
        }
        // 计算链表2的长度
        while (cur2 != null) {
            len2++;
            cur2 = cur2.next;
        }
        // 长链表先走若干步,和短链表的尾部对齐
        if (len2 > len1) {
            for (int i = 0; i < len2 - len1; i++) pHead2 = pHead2.next;
        }

        if (len1 > len2) {
            for (int i = 0; i < len1 - len2; i++) pHead1 = pHead1.next;
        }
        // 同时前进,第一个相等的结点即是
        while (pHead1 != null && pHead2 != null) {
            if (pHead1 == pHead2) return pHead1;
            pHead1 = pHead1.next;
            pHead2 = pHead2.next;
        }
        return null;
    }

    /**
     * 很短的代码
     */
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        ListNode p1 = pHead1;
        ListNode p2 = pHead2;
        while (p1 != p2) {
            p1 = (p1 == null ? pHead2 : p1.next);
            p2 = (p2 == null ? pHead1 : p2.next);
        }
        return p1;
    }
}