import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 *   public ListNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param head1 ListNode类
     * @param head2 ListNode类
     * @return ListNode类
     */
    public ListNode addInList (ListNode head1, ListNode head2) {
        // write code here

        // 算法的时间复杂度O(N),额外空间复杂度O(N)

        // 1.先把两个链表都遍历到底,统计各自结点个数,并得到个位指针
        // 此外,分别创建一个HashMap记录某个结点的上一个结点
        if (head1 == null || head1.val == 0) {
            return head2;
        }
        if (head2 == null || head2.val == 0) {
            return head1;
        }
        int length1 = 1;
        int length2 = 1;
        ListNode cur1 = head1;
        ListNode cur2 = head2;
        HashMap<ListNode, ListNode> preNodeMap1 = new HashMap<>();
        HashMap<ListNode, ListNode> preNodeMap2 = new HashMap<>();
        // 预先把头结点及其前驱结点null存入HashMap
        preNodeMap1.put(head1, null);
        preNodeMap2.put(head2, null);
        while (cur1.next != null) {
            // cur1还不是最后一个结点
            length1++;
            // 存入结点cur1.next,及其前驱结点cur1
            preNodeMap1.put(cur1.next, cur1);
            cur1 = cur1.next;
        }
        while (cur2.next != null) {
            // cur2还不是最后一个结点
            length2++;
            // 存入结点cur2.next,及其前驱结点cur2
            preNodeMap2.put(cur2.next, cur2);
            cur2 = cur2.next;
        }
        // 此时,cur1和cur1指向了各自链表的最后一个非null结点

        // 2.两个链表同步往前遍历,直到各自的head
        ListNode result = null;
        int jinwei = 0;
        while (cur1 != null && cur2 != null) {
            // 3.创建result链表节点,对应结点相加,注意考虑进位,头插法
            int num1 = cur1.val;
            int num2 = cur2.val;
            int numResult = num1 + num2 + jinwei;
            int valResult = numResult % 10;
            jinwei = numResult / 10;
            // 头插法插入结果节点
            ListNode curResultNode = new ListNode(valResult);
            curResultNode.next = result;
            result = curResultNode;
            // cur1和cur2共同往前走一个结点
            cur1 = preNodeMap1.get(cur1);
            cur2 = preNodeMap2.get(cur2);
        }

        // 4.出了循环后,查看是否有一个链表没有走到头,让其无限加0即可
        // 以下两个while最多只会执行一个
        while (cur1 != null) {
            // 说明链表1没走到头,而链表2已经走到头了
            // 直接令num2 = 0
            int num1 = cur1.val;
            int num2 = 0;
            int numResult = num1 + num2 + jinwei;
            int valResult = numResult % 10;
            jinwei = numResult / 10;
            // 头插法插入结果节点
            ListNode curResultNode = new ListNode(valResult);
            curResultNode.next = result;
            result = curResultNode;
            // cur1往前走一个结点
            cur1 = preNodeMap1.get(cur1);
        }
        while (cur2 != null) {
            // 说明链表1已经走到头了,而链表2没走到头
            // 直接令num1 = 0
            int num1 = 0;
            int num2 = cur2.val;
            int numResult = num1 + num2 + jinwei;
            int valResult = numResult % 10;
            jinwei = numResult / 10;
            // 头插法插入结果节点
            ListNode curResultNode = new ListNode(valResult);
            curResultNode.next = result;
            result = curResultNode;
            // cur2往前走一个结点
            cur2 = preNodeMap2.get(cur2);
        }
        // 注意!此时jinwei中可能还有值!如果有的话,还需要再头插一个结点
        if (jinwei > 0) {
            // 头插法插入结果节点
            ListNode curResultNode = new ListNode(jinwei);
            curResultNode.next = result;
            result = curResultNode;
        }
        return result;
    }
}