题目
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-two-numbers
记录目的
- 题目本身的实现并不难,主要是对链表运用。在实际操作中,我在一开始并不明确往新链表中插入数据的过程,导致多次组建链表失败,因此在此处记录并复习。
- 学习一个好的思想:三目运算符
代码区
题目中提供的节点定义
public class ListNode {
int val;
ListNode next;
//有参构造方法
ListNode(int x) { val = x; }
}
链表插入时我犯的错误
错误1
ListNode res = new ListNode(5);
res.next.val = 5;
res.next无地址(空指针),此时调用res.next的成员变量会报空指针异常。
正确方法
//创建一个节点,将next指针指向该节点的地址
res.next = new ListNode(5);
错误2
ListNode helper = res.next;
helper = new List Node(5);
helper = helper.next;
//val=5.next节点的地址被val=6节点的地址覆盖了,不能形成链表
helper = new List Node(6);
结果链表添加节点时要添加到helper.next节点上,否则无法形成链表
正确方法
ListNode helper = res;
helper = new List Node(5);
helper = helper.next;
我的算法实现
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode res = new ListNode(0);
ListNode current1 = l1;
ListNode current2 = l2;
ListNode helper = res;
//flag = 1说明要进位,flag = 0说明不用,相当于下文的变量carry
int flag = 0;
//先搜两个链表都有的长度的部分
while (current1 != null && current2 != null) {
if (flag == 0) {
//此次运算不用进位的时候
if ((current1.val + current2.val) >= 10) {
//下次运算要进位的时候
helper.next = new ListNode((current1.val + current2.val) % 10);
flag = 1;
} else {
//下次运算不用进位的时候
helper.next = new ListNode(current1.val + current2.val);
}
} else {
//此次运算要进位的时候
if ((current1.val + current2.val + 1) >= 10) {
//因为此时flag = 1,下次也要进位,就不用重置flag = 1
helper.next = new ListNode((current1.val + current2.val + 1) % 10);
} else {
helper.next = new ListNode(current1.val + current2.val + 1);
flag = 0;
}
}
//移动三个指针
helper = helper.next;
current1 = current1.next;
current2 = current2.next;
}
/*
如果链表1还没遍历完的话,把链表1里的数据全部放进新链表
需要注意判断是否有上面两个链表一起循环结束后的flag是否为1
并且剩余内容的数被进位后是否需要向下一位进位
*/
while (current1 != null) {
if (flag == 1){
if ((current1.val + 1) < 10){
helper.next = new ListNode(current1.val + 1);
flag = 0;
} else {
helper.next = new ListNode(0);
}
} else {
helper.next = new ListNode(current1.val);
}
helper = helper.next;
current1 = current1.next;
}
while (current2 != null) {
if (flag == 1){
if ((current2.val + 1) < 10){
helper.next = new ListNode(current2.val + 1);
flag = 0;
} else {
helper.next = new ListNode(0);
}
} else {
helper.next = new ListNode(current2.val);
}
helper = helper.next;
current2 = current2.next;
}
if (flag == 1) {
helper.next = new ListNode(1);
}
//注意不要将头节点返回,从有效数据节点开始返回
return res.next;
}
}
执行用时:3ms
消耗内存:40.1MB
缺点部分
在进位方面细节过多,导致判断语句过多,代码太长,且容易遗忘一些细节。
别人的算法实现
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode res = new ListNode(0);
ListNode p = l1;
ListNode q = l2;
ListNode helper = res;
int carry = 0;
//用于接收链表l1中的数据
int x = 0;
//用于接收链表l2中的数据
int y = 0;
while (p != null || q != null) {
//非常棒的思想:利用三目运算符获取链表val值
x = (p != null) ? p.val : 0;
y = (q != null) ? q.val : 0;
if (x + y + carry >= 10) {
helper.next = new ListNode((x + y + carry) % 10);
carry = 1;
} else {
helper.next = new ListNode(x + y + carry);
carry = 0;
}
helper = helper.next;
//这个判断一定要加,否则会在一个链表到末尾了但另一个链表还可以继续移动时产生空指针异常
if(p != null) {
p = p.next;
}
if(q != null) {
q = q.next;
}
}
//判断两个链表运算结束后的是否有最后剩下的进位
if (carry == 1) {
helper.next = new ListNode(1);
}
return res.next;
}
}
优秀的思想部分
利用三目运算符巧妙的解决了短链表结束时需要继续取0的问题。既不需要用0来扩充短链表长度至长链表长度,又不需要像我的方法那样有过多的判断,减少因遗漏判断而产生错误的可能。
本文介绍了解决LeetCode上的两数相加问题的链表实现方法,详细解析了在Java中如何避免链表插入时的常见错误,并分享了一种使用三目运算符简化代码的优秀思路。
616

被折叠的 条评论
为什么被折叠?



