「这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战」。
一、题目
二、我的解答
第一次解答:
报错日志,第1个测试用例:
第二次解答:
报错日志,第32个测试用例:
第三次解答:
报错日志,第1565个测试用例:
第四次解答:
三、系统解答
方法一:模拟
思路及算法
复杂度分析
一、题目
难度中等
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 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
• 题目数据保证列表表示的数字不含前导零
二、我的解答
第一次解答:
我一开始的写法,相当糟糕。题意没注意看。题目说了,这个数的位数在 [1, 100]之间,不一定几位,我写死了三位,辣鸡仔。运行代码,系统只跑了三位数的测试用例,所以我当然没问题。靠
/**
* 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; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if(l1==null||l2==null){
return null;
}
int num1=l1.next.next.val*100+l1.next.val*10+l1.val;
int num2=l2.next.next.val*100+l2.next.val*10+l2.val;
int num3=num1+num2;
int val3=num3/100;
ListNode l3_3=new ListNode(val3);
int val2=(num3-val3*100)/10;
ListNode l3_2=new ListNode(val2,l3_3);
int val1=num3-val3*100-val2*10;
ListNode l3=new ListNode(val1,l3_2);
return l3;
}
}
报错日志,第1个测试用例:
输入:l1 = [0], l2 = [0]预期输出:[0]
实际:异常终止
原因:16line,我这个小垃圾写死了三位,l1.next为null,我还去l1.next.next,当然会空指针异常了
第二次解答:
我的思路是先把两个链表转成整型加起来再转回去,操,结果被[1,9,9,9,9,9,9,9,9,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; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if (l1 == null || l2 == null) {
return null;
}
List num1List = new ArrayList<>();
ListNode temp1 = l1;
while (temp1 != null) {
num1List.add(temp1.val);
temp1 = temp1.next;
}
int num1 = 0;
for (int i = 0; i < num1List.size(); i++) {
num1 = (int) (num1List.get(i) * Math.pow(10, i) + num1);
}
List num2List = new ArrayList<>();
ListNode temp2 = l2;
while (temp2 != null) {
num2List.add(temp2.val);
temp2 = temp2.next;
}
int num2 = 0;
for (int i = 0; i < num2List.size(); i++) {
num2 = (int) (num2List.get(i) * Math.pow(10, i) + num2);
}
int num3 = num1 + num2;
ListNode l3 = null;
ListNode next = null;
String num3String = num3 + "";
for (int i = 0; i < num3String.length(); i++) {
int val = Integer.parseInt(num3String.charAt(i) + "");
ListNode node = new ListNode(val);
node.next = next;
next = node;
if (i == (num3String.length() - 1)) {
l3 = node;
}
}
return l3;
}
}
报错日志,第32个测试用例:
输入:l1 =[9], l2 = [1,9,9,9,9,9,9,9,9,9]****预期输出:[000000000001]
实际:异常终止
原因:我们算出来的num3String 是-2147483640,执行到Integer.parseInt("-");当然报错啦。
但是关键原因是我们为什么会算出一个负的数,害,还不是因为超出了数据类型的范围。
int的范围是 4*8 = 32 bit -2^32~2^31 (-2147483648 ~ 2147483647),你给他一个大于他的数强转,精度当然会出问题了。
第三次解答:
聪明的我又换成了long。
/**
* 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; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if (l1 == null || l2 == null) {
return null;
}
List num1List = new ArrayList<>();
ListNode temp1 = l1;
while (temp1 != null) {
num1List.add(temp1.val);
temp1 = temp1.next;
}
long num1 = 0;
for (int i = 0; i < num1List.size(); i++) {
num1 = (long) (num1List.get(i) * Math.pow(10, i) + num1);
}
List num2List = new ArrayList<>();
ListNode temp2 = l2;
while (temp2 != null) {
num2List.add(temp2.val);
temp2 = temp2.next;
}
long num2 = 0;
for (int i = 0; i < num2List.size(); i++) {
num2 = (long) ((num2List.get(i) * Math.pow(10, i)) + num2);
}
long num3 = num1 + num2;
ListNode l3 = null;
ListNode next = null;
String num3String = num3 + "";
for (int i = 0; i < num3String.length(); i++) {
int val = Integer.parseInt(num3String.charAt(i) + "");
ListNode node = new ListNode(val);
node.next = next;
next = node;
if (i == (num3String.length() - 1)) {
l3 = node;
}
}
return l3;
}
}
报错日志,第1565个测试用例:
输入:l1 =[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], l2 =[5,6,4]****预期输出:?
实际:异常终止
原因:操,又教做人了。题目不能认真点看吗?
• 每个链表中的节点数在范围 [1, 100] 内
看这意思岂不是我没办法用其他数据类型,哪有可以100位的数据类型,bigInt也不行啊。
看样子是方法没用对
第四次解答:
换个思路,不转类型了直接加。
最后我的解答,终于通过了。但是我看了官方解答后,才知道自己多么蠢。
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if (l1 == null || l2 == null) {
return null;
}
List num1List = new ArrayList<>();
ListNode temp1 = l1;
while (temp1 != null) {
num1List.add(temp1.val);
temp1 = temp1.next;
}
List num2List = new ArrayList<>();
ListNode temp2 = l2;
while (temp2 != null) {
num2List.add(temp2.val);
temp2 = temp2.next;
}
int length=num1List.size()>num2List.size()?num1List.size():num2List.size();
boolean add1=false;
ListNode next=null;
ListNode l3 = null;
ListNode node=null;
//可能会进位,所以多留一位=length
for (int i = 0; i <=length; i++) {
int temp=(num1List.size()<(i+1)?0:num1List.get(i))+(num2List.size()<(i+1)?0:num2List.get(i));
if (add1){
temp=temp+1;
}
if (temp>=10){
add1=true;
}else {
add1=false;
}
if (i==length&&temp==0){
return l3;
}
next = new ListNode(temp%10);
if (node==null){
l3=next;
}else {
node.next=next;
}
node=next;
}
return l3;
}}
三、系统解答
方法一:模拟
思路及算法
由于输入的两个链表都是逆序存储数字的位数的,因此两个链表中同一位置的数字可以直接相加。
我们同时遍历两个链表,逐位计算它们的和,并与当前位置的进位值相加。具体而言,如果当前两个链表处相应位置的数字为 n1,n2n1,n2,进位值为carry,则它们的和为 n1+n2+carry;其中,答案链表处相应位置的数字为 (n1+n2+carry)mod10,而新的进位值为:
如果两个链表的长度不同,则可以认为长度短的链表的后面有若干个 00 。
此外,如果链表遍历结束后,有carry>0,还需要在答案链表的后面附加一个节点,节点的值为 carry。
注释:思路和我一样,代码比我写的简单太多了吧
代码
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode head = null, tail = null;
int carry = 0;
while (l1 != null || l2 != null) {
int n1 = l1 != null ? l1.val : 0;
int n2 = l2 != null ? l2.val : 0;
int sum = n1 + n2 + carry;
if (head == null) {
head = tail = new ListNode(sum % 10);
} else {
tail.next = new ListNode(sum % 10);
tail = tail.next;
}
carry = sum / 10;
if (l1 != null) {
l1 = l1.next;
}
if (l2 != null) {
l2 = l2.next;
}
}
if (carry > 0) {
tail.next = new ListNode(carry);
}
return head;
}
}
复杂度分析
• 时间复杂度:O(max(m,n)),其中 m 和 n 分别为两个链表的长度。我们要遍历两个链表的全部位置,而处理每个位置只需要 O(1) 的时间。
• 空间复杂度:O(1)。注意返回值不计入空间复杂度。