LeetCode 2. 两数相加

算法就是解题方案的准确而完整的描述,是一系列解决问题的清晰指令。一些大厂经常会考察面试者算法能力,观察面试者编码的熟练程度、思考的速度和深度,以此衡量面试者的能力和潜力,所以算法重要性不言而喻。想进大厂,就必须拿下算法,而算法学习,就是要不断地练习。为了帮助大家提升算法能力,我将带大家每天做一道算法题!

今天的题目是两数相加(Add Two Numbers),涉及到链表。链表是一种线性数据结构,其中的每个元素实际上是一个单独的对象,而所有对象都通过每个元素中的引用字段链接在一起。

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* 2. 两数相加
* 2. Add Two Numbers
* 标签:链表
* 难度:中等
*
* 给你两个非空的链表,表示两个非负的整数。
* 它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。
* 请你将两个数相加,并以相同形式返回一个表示和的链表。
* 你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
*
* 示例 1:
* 输入:l1 = [2,4,3], l2 = [5,6,4]
* 输出:[7,0,8]
* 解释:342 + 465 = 807.
*
* 示例 2:
* 输入:l1 = [0], l2 = [0]
* 输出:[0]
*
* 示例 3:
* 输入: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
* 题目数据保证列表表示的数字不含前导零
*
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
* @author yonghongwang#163.com
* @link <a href="https://leetcode-cn.com/problems/add-two-numbers"></a>
* @link <a href="https://leetcode.com/problems/add-two-numbers"></a>
* @since 2021/02/26
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {

}
}

题解

方法一:模拟

思路及算法

由于输入的两个链表都是逆序存储数字的位数的,因此两个链表中同一位置的数字可以直接相加。

我们同时遍历两个链表,逐位计算它们的和,并与当前位置的进位值相加。具体而言,如果当前两个链表处相应位置的数字为 n1,n2,进位值为 carry,则它们的和为 n1+n2+carry;其中,答案链表处相应位置的数字为 (n1+n2+carry) mod 10,而新的进位值为 (n1+n2+carry)/10。

如果两个链表的长度不同,则可以认为长度短的链表的后面有若干个 0 。

此外,如果链表遍历结束后,有 carry>0,还需要在答案链表的后面附加一个节点,节点的值为 carry。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode head = new ListNode();
ListNode curr = head;
int carry = 0, sum = 0;
while (l1 != null || l2 != null) {
if (l1 != null && l2 != null) {
sum = l1.val + l2.val + carry;
l1 = l1.next;
l2 = l2.next;
} else if (l1 != null) {
sum = l1.val + carry;
l1 = l1.next;
} else if (l2 != null) {
sum = l2.val + carry;
l2 = l2.next;
}
curr.next = new ListNode(sum % 10);
curr = curr.next;
carry = sum / 10;
}
if (carry == 1) {
curr.next = new ListNode(1);
}
return head.next;
}

复杂度分析

时间复杂度:O(max(m,n)),其中 m 和 n 分别为两个链表的长度。我们要遍历两个链表的全部位置,而处理每个位置只需要 O(1) 的时间。

空间复杂度:O(1)。注意返回值不计入空间复杂度。

方法二:递归

直接上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if (l1 == null) {
return l2;
}
if (l2 == null) {
return l1;
}
int val = l1.val + l2.val;
ListNode next = addTwoNumbers(l1.next, l2.next);
if (val >= 10) {
val -= 10;
next = addTwoNumbers(next, new ListNode(1));
}
return new ListNode(val, next);
}

好了,今天的文章就到这里,如果觉得有所收获,请顺手点个在看或者转发吧,你们的支持是我最大的动力。