每日一题:LeetCode 算法题

456 阅读3分钟

两数相加

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

例如:

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

题目来源:力扣(LeetCode)
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

初始思路
拿到题目的第一个思路是:通过将链表解析成数字,相加后再转换成链表 于是有了以下代码。。。(错误代码)

class ListNode {
    int val;
    ListNode next;
    ListNode() {}
    ListNode(int val) { this.val = val; }
    ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        Long listNodeBack = getListNodeBack(l1);
        System.out.println(listNodeBack);
        Long listNodeBack1 = getListNodeBack(l2);
        System.out.println(listNodeBack1);

        Long rtnNum = listNodeBack + listNodeBack1;
        System.out.println(rtnNum);
        return getListNode(rtnNum);
    }
    public Long getListNodeBack(ListNode LN){
        Long x = Long.valueOf(LN.val);
        Long rtn = 10L;
        ListNode next = LN;
        while ((next = next.next)!=null){
            x = x+next.val*rtn;
            rtn*=10;
        }
        return x;
    }
    public ListNode getListNode(Long num){
        ListNode listNodeNext = null;
        ListNode rtn = new ListNode(0);
        while (num>0){
            int i = new Long(num % 10).intValue();
            num = (num - i)/10;
            ListNode listNode ;
            if(listNodeNext == null){
                listNode = new ListNode(i);
                rtn= listNode;
            }else {
                listNodeNext.val = i;
                listNode = null;
                listNode = listNodeNext;
            }
            if(num>0){
                listNode.next = new ListNode();
                listNodeNext = null;
                listNodeNext = listNode.next;
            }
        }
        return rtn;
    }
}
以上代码存在一个致命问题:链表长度无限加长时,long类型也无法支撑
转换思路:将每个节点各自相加
如:9-8-71-3-1-4-6-3
   9+18+37+1463
   10-11-8-4-6-310 进位 ----》 0-2-9-4-6-3
于是又有了下面的代码

BUG修复后(初版 =_= 仍然不完美):

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
            // 遍历两个链表对应位相加
            // 9-8-7 和 1-3-1-4-6-3
            // 9+1 、8+3 、7+1 、4、6、3
            // 遍历 两个链表其中一个存在下一节点则继续
            ListNode l1Parent = l1;
            ListNode l2Parent = l2;
            // 相加大于 10表示需要进位 1 否则 0
            int carry = 0;
            ListNode listNodeNext = null;
            ListNode rtn = new ListNode();
            while (l1Parent!=null||l2Parent!=null||carry==1){
                int l1Val = 0;
                int l2Val = 0;
                if(l1Parent!=null&&l1Parent.val!=0){
                    l1Val = l1Parent.val;
                }
                if(l2Parent!=null&&l2Parent.val!=0){
                    l2Val = l2Parent.val;
                }
                int rtnNum = l1Val + l2Val + carry;
                if(rtnNum>=10){
                    rtnNum = rtnNum %10;
                    carry = 1;
                }else {
                    carry = 0;
                }
                ListNode listNode ;
                if(listNodeNext == null){
                    listNode = new ListNode(rtnNum);
                    rtn= listNode;
                }else {
                    listNodeNext.val = rtnNum;
                    listNode = listNodeNext;
                }
                

                // 下一节点还有子节点时 新增链表也要加一个子节点
                if((l1Parent!=null&&l1Parent.next!=null)
                        ||(l2Parent!=null&&l2Parent.next!=null)||carry==1){
                    listNode.next = new ListNode();
                    listNodeNext = listNode.next;
                }
                // 转至下一节点
                if(l1Parent!=null){
                    l1Parent = l1Parent.next;
                }
                if(l2Parent!=null){
                    l2Parent = l2Parent.next;
                }
            }
            return rtn;
        }
此时程序已经可以正常执行,但是耗时较久,在代码层面上再次优化

优化后:

public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
            // 遍历两个链表对应位相加
            // 9-8-7 和 1-3-1-4-6-3
            // 9+1 、8+3 、7+1 、4、6、3
            // 遍历 两个链表其中一个存在下一节点则继续
            // 相加大于 10表示需要进位 1 否则 0
            int carry = 0;
            ListNode listNodeNext = null;
            ListNode rtn = new ListNode();
            while (l1!=null||l2!=null){
                int l1Val = l1!=null?l1.val:0;
                int l2Val = l2!=null?l2.val:0;
                int rtnNum = l1Val + l2Val + carry;
                carry = rtnNum/10;
                if(listNodeNext == null){
                    rtn = listNodeNext = new ListNode(rtnNum %10);
                }else {
                    listNodeNext.next = new ListNode(rtnNum %10);
                    listNodeNext = listNodeNext.next;
                }
                // 转至下一节点
                if(l1!=null){
                    l1 = l1.next;
                }
                if(l2!=null){
                    l2 = l2.next;
                }
            }
            if(carry==1){
                listNodeNext.next = new ListNode(carry);
            }
            return rtn;
        }
此时程序就比较完美了