LeetCode 精选百题斩-2-两数相加

170 阅读3分钟

题目信息

题号:2 题目描述:

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

题目难度:中等

测试参数:

参数一  输入:l1 = [2,4,3], l2 = [5,6,4]                  输出:[7,0,8]
参数二  输入:l1 = [0], l2 = [0]                          输出:[0]
参数三  输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]        输出:[8,9,9,9,0,0,0,1]

提示信息:
每个链表中的节点数在范围 [1, 100] 内
0 <= Node.val <= 9
题目数据保证列表表示的数字不含前导零

解法一:递归

题解思路:

题目给的示例看出,其实就可以看成是两个数字的加法运算,我们按照相同位数字相加,大于10则进行进位,
下一位运算带上进位做相同运算操作。这种重复相同的操作让我们想起是否可以利用递归去完成,每次都是同一位
的数字相加再加上一位运算的进位。

请添加图片描述

java代码示例

public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
  List result = new ArrayList<>();
     sumNum(l1,l2,false,result);
     ListNode nextNode = null;
     for(int i=result.size()-1;i>=0;i--){
         ListNode newNode = new ListNode((int) result.get(i));
         newNode.next = nextNode;
         nextNode = newNode;
     }
     return nextNode;
 }
 private static void sumNum(ListNode node1,ListNode node2,boolean isAdd,List result){
    if(node1 == null && node2 == null){
        if(isAdd){
            result.add(1);
        }
        return;
    }
    if(node1 == null){
        int num = (node2.val +(isAdd?1:0)) % 10;
        result.add(num);
        isAdd = (((node2.val +(isAdd?1:0)) / 10) == 1);
        sumNum(null,node2.next,isAdd,result);
    }
    if(node2 == null){
        int num = (node1.val +(isAdd?1:0)) % 10;
        result.add(num);
        isAdd = (((node1.val +(isAdd?1:0)) / 10) == 1);
        sumNum(node1.next,null,isAdd,result);
    }
    if(node1!=null && node2 !=null){
        int num = (node1.val + node2.val +(isAdd?1:0)) % 10;
        result.add(num);
        isAdd = (((node1.val + node2.val +(isAdd?1:0)) / 10) == 1);
        sumNum(node1.next,node2.next,isAdd,result);
    }
}

在这里插入图片描述

上述代码我们再进行一次优化 如下:

public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    List<Integer> result = new ArrayList<>();
    sumNum(l1,l2,false,result);
    ListNode nextNode = null;
    for(int i=result.size()-1;i>=0;i--){
        ListNode newNode = new ListNode((int) result.get(i));
        newNode.next = nextNode;
        nextNode = newNode;
    }
    return nextNode;
}
private static void sumNum(ListNode node1,ListNode node2,boolean isAdd,List<Integer> result){
    if(node1 == null && node2 == null && !isAdd){
        return;
    }
    int sum = (node1 == null?0:node1.val) + (node2 == null?0:node2.val) +(isAdd?1:0);
    int num = sum % 10;
    isAdd = sum > 9;
    result.add(num);
    sumNum(node1 == null?null:node1.next,node2 == null?null:node2.next,isAdd,result);
}

在这里插入图片描述

效果不是很明显,只是在代码的简洁度上有所提高,也有所收获嘛!

复杂度分析:

时间复杂度:O(max(m,n))
空间复杂度:O(max(m,n)) 开辟了一块List的空间

解法二:指针循环(官方叫模拟)

题解思路:

其实跟上一解法类似,除了用递归去处理同一位的数字计算,我们还可以考虑是不是可以直接循环遍历处理。
其实最大遍历也是链表长度最长的次数,但是我们要考虑可能存在两个链表不一致长度,同一位用0代替处理,
以及最后一次计算完如果有进位,也需要加到新的结果链表中去。图解跟上一解法一样,只不过循环结束的条件即是
递归结束的条件。

java代码示例

public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    ListNode result = new ListNode();
    ListNode currentNode = result;
    ListNode n1 = l1;
    ListNode n2 = l2;
    int add = 0;
    while(n1 != null || n2 != null || add > 0){
        int sum = (n1 == null? 0:n1.val) + (n2 == null?0:n2.val) + add;
        add = sum / 10;
        int nextVal = sum % 10;
        currentNode.next = new ListNode(nextVal);
        n1 = n1 == null?null:n1.next;
        n2 = n2 == null?null:n2.next;
        currentNode = currentNode.next;
    }
    return result.next;
}

在这里插入图片描述

复杂度分析:

时间复杂度:O(max(m,n))
空间复杂度:O(1) 返回值不计入空间复杂度

总结

这种算法题,我们主要就是找规律,然后看是否有算法模型可以对得上,在进行尝试的基础上做优化。抓住终止条件的处理,也是对边界问题的把握!再多说写就扯了,还是多刷找感觉吧!