LeetCode 445. Add Two Numbers II

问题描述

  • You are given two non-empty linked lists representing two non-negative integers. The most significant digit comes first and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
    You may assume the two numbers do not contain any leading zero, except the number 0 itself.
    Follow up:
    What if you cannot modify the input lists? In other words, reversing the lists is not allowed.
  • Example:

Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 8 -> 0 -> 7

问题分析

  • 该题是 LeetCode 2. Add Two Numbers 的进阶题,原题是最低位在链表头部,该题是最高位在链表头部。如果反转链表后计算的话,十分容易,但题目要求不能反转链表,再加上这是链表,不是数组,所以相对麻烦一些
  • 解法1 : 用实现“反转链表”的功能
  • 解法2 : 用递归(实际还是栈)
  • 解法3: 利用找新链表中的最右边的第一个非 9 的节点,来处理进位信息
    其实方法还是来源于 LeetCode 的另一道题目,[LeetCode] Plus One Linked List 链表加一运算 , 以及 LeetCode 66. Plus One
    思路是遍历链表,找到右起第一个不为9的数字,如果找不到这样的数字,说明所有数字均为9,那么在表头新建一个值为0的新节点,进行加1处理,然后把右边所有的数字都置为0即可。举例来说:
    比如1->2->3,那么第一个不为9的数字为3,对3进行加1,变成4,右边没有节点了,所以不做处理,返回1->2->4。
    再比如说8->9->9,找第一个不为9的数字为8,进行加1处理变成了9,然后把后面的数字都置0,得到结果9->0->0。
    再来看9->9->9的情况,找不到不为9的数字,那么再前面新建一个值为0的节点,进行加1处理变成了1,把后面的数字都置0,得到1->0->0->0。
    至于该题的情况,有进位就需要将新链表(尚未加入当前产生进位信息的节点)加1 ,所以只要实时维护新链表中右起第一个不为9的数字的位置即可。有进位时,该位置加1,该位置后面所有值都为0。更加复杂。
    并且,还要注意虚拟节点的使用

经验教训

  • 递归处理链表问题,还是十分好用的
  • 解法3这种奇淫技巧!!!

代码实现

  • 解法1
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        if (l1 == null || l2 == null) {
            return null;
        }
        ListNode cur1 = l1;
        ListNode cur2 = l2;
        Stack<Integer> s1 = new Stack<>();
        Stack<Integer> s2 = new Stack<>();
        ListNode addedList = null;
        while (cur1 != null) {
            s1.push(cur1.val);
            cur1 =cur1.next;
        }
        while (cur2 != null) {
            s2.push(cur2.val);
            cur2 = cur2.next;
        }
        int carry = 0;
        while (!s1.isEmpty() || !s2.isEmpty()) {
            int val = 0;
            if (!s1.isEmpty()) {
                val += s1.pop();
            }
            if (!s2.isEmpty()) {
                val += s2.pop();
            }
            val += carry;
            ListNode newHead = new ListNode(val % 10);
            newHead.next = addedList;
            addedList = newHead;
            carry = val / 10;
        }
        if (carry != 0) { //处理进位信息
            ListNode newHead = new ListNode(1);
            newHead.next = addedList;
            return newHead;
        }
        return addedList;
    }
  • 解法2
     public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        if (l1 == null || l2 == null) {
            return null;
        }
        int length1 = getLength(l1);
        int length2 = getLength(l2);
         //确保长链以及短链
        ListNode res = length1 > length2 ? addTwoNumbers(l1, l2, length1 - length2) : addTwoNumbers(l2, l1, length2 - length1);
         //处理最高位信息
        if (res.val > 9) {
            res.val = res.val % 10;
            ListNode newHead = new ListNode(1);
            newHead.next = res;
            return newHead;
        }
         return res;
     }
    //统计长度
    public int getLength(ListNode head) {
        ListNode curNode = head;
        int length = 0;
        while (curNode != null) {
            ++length;
            curNode = curNode.next;
        }
        return length;
    }
    //已知 l1长度大于l2长度offset,对两链表进行"相加", 9 -> 6 -> 3 与 5 - > 8 相加结果为 10 -> 2 -> 1
    //也就是对最高位的进位不处理
    public ListNode addTwoNumbers(ListNode l1, ListNode l2, int offset) {
        //base case
        if (l1 == null) {
            return null;
        }
        //当前位的相加结果
        ListNode curRes = offset == 0 ? new ListNode(l1.val + l2.val) : new ListNode(l1.val);
        //递归得出 下一位的相加结果
        ListNode nextRes = offset == 0 ? addTwoNumbers(l1.next, l2.next, offset) : addTwoNumbers(l1.next, l2, offset - 1);
        //根据下一位的结果,修正当前结果以及下一位结果
        if (nextRes != null && nextRes.val > 9) {
            curRes.val += 1;
            nextRes.val = nextRes.val % 10;
        }
        //连接
        curRes.next = nextRes;
        //返回整体相加后结果
        return curRes;
    }
  • 解法3
     public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        if (l1 == null || l2 == null) {
            return null;
        }
         int diff = getLength(l1) - getLength(l2);
         //让 l1指向长链表,l2指向短链表
        if (diff < 0) {
            ListNode temp = l1;
            l1 = l2;
            l2 = temp;
        }
        diff = Math.abs(diff);
        //虚拟节点
        ListNode dummy = new ListNode(0);
         //新形成链表的尾部
         ListNode tail = dummy;
         //指向新链表中 :从右起第一个不为9的节点(它的后面全是 9)
         ListNode lastNot9 = dummy;
         ListNode cur1 = l1;
         //将长链表多于的一部分(不参与加法)直接加入新链表,并更新lastNot9
         while (diff > 0) {
             tail.next = new ListNode(cur1.val);
             tail = tail.next;
             if (tail.val != 9) {
                 lastNot9 = tail;
             }
              cur1 = cur1.next;
             --diff;
         }
         //两链表相加
         ListNode cur2 = l2;
         while (cur1 != null) {
             int val = cur1.val + cur2.val;
             //如果当前值大于10
             if (val >= 10) {
                 val -= 10;
                 //新链表中,从右起第一个不为9的节点加1,进位的原因
                 ++lastNot9.val;
                 //该节点后面节点全部置为0,因为原先都为9,一发生进位变为0
                 ListNode is9 = lastNot9.next;
                 while (is9 != null) {
                     is9.val = 0;
                     is9 = is9.next;
                 }
             }
             tail.next = new ListNode(val);
             //更新lastNot9
            lastNot9 = val != 9 ? tail.next : lastNot9;
             tail = tail.next;
             cur1 = cur1.next;
             cur2 = cur2.next;
         }
         //dummy.val == 1 说明 原链表中第一位相加后结果为9,但因进位,又多了一位。
         return dummy.val == 1 ? dummy : dummy.next;
     }

    //统计长度
    public int getLength(ListNode head) {
        ListNode curNode = head;
        int length = 0;
        while (curNode != null) {
            ++length;
            curNode = curNode.next;
        }
        return length;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值