目录
题目
解题思路
首先我们可以发现本题给的是链表,且只有两个链表,然后我们又可以发现他是个单向链表,然后我们一看解释和输出就发现,就是遍历了一下两个链表并且使用了加法,然后进一位到后面,这个时候我们就发现了,就是单纯的加减法。
所以我们只需要同时遍历第一位相加,如果大于等于10了那就让他对10取余,因为十进制只有0~9,但是我们可以做一个判断,因为要进一位的,所以我们可以再声明一个临时变量来保存进的那一位。这是大体的思路,然后我们落实到具体实现。
错误想法(使用列表)
注:该标题下的是思路正确,但是实行错误的
基于取每一位进行相加,那我们可以稍微变一下完全根据他解释来,让他变成正向取出来,然后合并成数字是不是就可以了。但是使用这种方法的时候你肯定没仔细看提示,他的节点的范围在[1,100],什么数字的十进制长度能有100位,long也只有19位,也就只有python可以实现了,如果是java的话那就得使用bigdecimal使用大数来实现,相对比较麻烦。话已至此,我们来看看虽然会报错,但是应该怎么写
/**
* 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) {
ListNode head = new ListNode();
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
List<Integer> result = new ArrayList<>();
while (l1 != null) {
list1.add(l1.val);
l1 = l1.next;
}
while (l2 != null) {
list2.add(l2.val);
l2 = l2.next;
}
int l1Val = 0, l2Val = 0, sum = 0;
for (int i = 0, index = 1; i < list1.size(); i++, index *= 10) {
Integer x = list1.get(i);
l1Val += index * x;
}
for (int i = 0, index = 1; i < list2.size(); i++, index *= 10) {
Integer x = list2.get(i);
l2Val += index * x;
}
sum = l1Val + l2Val;
while (sum > 0) {
int i = sum % 10;
sum /= 10;
result.add(i);
}
if (result.isEmpty())
return head;
head.val = result.get(0);
ListNode temp = head;
for (int i = 1; i < result.size(); i++) {
temp.next = new ListNode(result.get(i));
temp = temp.next;
}
return head;
}
}
再次强调,这个代码是对的,但是呢会超范围,然后如果你看到他是int所以就感觉可以试试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) {
ListNode head = new ListNode();
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
List<Integer> result = new ArrayList<>();
while (l1 != null) {
list1.add(l1.val);
l1 = l1.next;
}
while (l2 != null) {
list2.add(l2.val);
l2 = l2.next;
}
long l1Val = 0, l2Val = 0, sum = 0;
for (long i = 0, index = 1; i < list1.size(); i++, index *= 10) {
Integer x = list1.get((int) i);
l1Val += index * x;
}
for (long i = 0, index = 1; i < list2.size(); i++, index *= 10) {
Integer x = list2.get((int) i);
l2Val += index * x;
}
sum = l1Val + l2Val;
while (sum > 0) {
int i = (int) (sum % 10);
sum /= 10;
result.add(i);
}
if (result.isEmpty())
return head;
head.val = result.get(0);
ListNode temp = head;
for (int i = 1; i < result.size(); i++) {
temp.next = new ListNode(result.get(i));
temp = temp.next;
}
return head;
}
}
将int全部变为了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) {
ListNode head = null, tempList = null;
int temp = 0, sum = 0;
while (l1 != null || l2 != null) {
int l1Val = 0, l2Val = 0;
if (l1 != null) {
l1Val = l1.val;
l1 = l1.next;
}
if (l2 != null) {
l2Val = l2.val;
l2 = l2.next;
}
sum = l1Val + l2Val + temp;
if (sum > 9) {
temp = 1;
sum %= 10;
} else {
temp = 0;
}
if (head == null) {
head = tempList = new ListNode(sum);
} else {
tempList.next = new ListNode(sum);
tempList = tempList.next;
}
}
if (temp == 1) {
tempList.next = new ListNode(temp);
}
return head;
}
}
用到的思路就和刚刚说明的是一样的,用到同时提取同一位的两个链表的值,然后我们得防止取到为空的情况,然后还有取完值得进入到下一个节点。然后我们再判断进位的情况,当他大于等于10也就是大于9的情况下,我们就保存一个进位,然后把和超了10的部分进行取余,获得需要保存的值。
然后我们应该考虑如何保存链表,这个其实不算难题,因为在我们学习链表这个数据结构的时候我们就知道我们需要保留一个头节点,然后再做一个临时节点拿来保存的新的值然后到下一个节点再保存。
最后我们再检查进位有没有值,如果有的话,我们再存一位,如果没有,那我们就不管。
官方解法
然后我们再看向官方解法。
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;
}
}
官方的解法就是我们的正确思路,只不过写法略有不同,他使用的是三元运算符替代了我们的if else但是也没完全替代因为他下面在进位的时候还判断了一遍。
他的这个carry是有点不太合适的操作了,我们在写算法的时候尽量不要写乘除,能用位移最好,除非只有乘除可用,不然还是尽量考虑一下其他办法,而且他的这个carry没考虑个位数的加法及时带上进位也只有19,所以根本无需使用除法直接判断即可。
如果对你有帮助的话不要忘记点赞收藏