LeetCode第二题:两数相加(Java)

简介: LeetCode第二题:两数相加(Java)

前言


面对困难,许多人望而却步,而成功的人士往往非常清楚,只要敢于和困难拼搏一番,就会发现,困难不过如此!

一、题目内容


给你两个非空链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

image.png

示例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; }* }*/classSolution {
publicListNodeaddTwoNumbers(ListNodel1, ListNodel2) {
    }
}

二、解题过程


在看到这道题时,第一想法是逐个遍历链表的节点,将每个节点的数据取出并存储到String类型的数据中,再将这些String类型的字符数数据拼接起来反转后再成int类型的数据。之后夭折在了错误的思路上,后面看了相关的解答之后才明白,可以定义一条新的链表按节点来逐个存储两条链表相加的值,最后将这条新的链表返回。

1. 解题思路


image.png

创建一条新的链表,设置两个头指针current和result,在两条链表相加的过程中只移动current指针,result指针不移动,最后将result返回。两条链表节点的值在相加时会有进位的情况,因此要进位的数与不进位的数(即剩余的数)进行获取和存储,因此再定义用来存储需要进位的int类型的变量total和存储不需要进位的数值的int类型变量remainder,将两个变量的初值均定义为0。

对两条链表进行遍历,判断条件为当两条链表同时为空时结束循环,确保遍历到了每一条链表的每一个节点。获取需要进位与不需要进位的数值的方法为将两个链表对应节点相加后的值与10进行整除和取余操作,整除后的结果为需要进位的数,取余留下来的数据为不需要进位的数,因此在每一次求和时都会有三个数来相加(即两个链表对应的值和需要进位的数),需要进位的数初值为0,首次参与相加不会对结果产生影响。

将两个链表对应节点值分别存储到int类型数据中是因为如果在相加的过程中有一个链表为空的话就无法进行之后的相加,因此进行求和前先将两个链表的节点值存储到int类型数据中,在存储前进行当前节点是否为空的判断,如果当前节点不为空的话就将当前节点存储的值赋给int类型的数据,如果为空则将int类型的数据赋值为0。

在得到要进位的值total和不需要进位的值remainder后,首先进行新链表是否为空的判断(因为result不进行指针的移动,所以只对result进行非空判断即可),如果此时新链表为空的话,就将不需要进位的值remainder作为链表的含参构造对新链表进行初始化,此时新链表的头节点中存储的数据为不需要进位的值remainder,这样做的原因是为了防止最后返回的链表的头节点中存储着不需要的数据,在之后的判断中都不会再进入新链表为空的执行代码中,因此每一次只需要将不需要进位的值作为链表的含参构造的参数创建新的节点,确保当前节点中存储的值是不需要进位的值 remainder,所以需要进位的值total只参与求和的运算,而不需要进位的值remainder进行的是新链表节点的构造。最后将current指针向后移动,确保此时current指向的节点为null

在相加与存储到新链表的过程结束后,对链表L1和L2分别进行非空的判断,当L1和L2不为空时向后移动。如果不进行非空的判断,假设L1此时为null,再进行移动时会报空指针异常。

循环结束后,两个链表的节点都进行了相加,但是此时新链表的构造是用不需要进位的值remainder构造的,节点最后一次相加的结果如果需要进位的话这个时候最后一个值是没有存储到新链表当中的,因此需要在循环结束后再对需要进位的值total与0进行一次比较,如果大于0的话表示需要进位,则用total的值做为参数进行节点的含参构造,将最后一个值存储到新链表当中,如果total的值小于0则表明不存在还没有要添加到新链表当中的数据,此时将新链表result返回即可(current永远指向链表的下一个节点,永远为null,因此不将current返回)。

2. 解题代码


代码如下(示例):

/*** 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; }* }*/classSolution {
publicListNodeaddTwoNumbers(ListNodel1, ListNodel2) {
// 定义一个链表用来存储两条链表相加的结果,result和current为两个指针// current为头结点不进行移动,result为最后要输出的链表ListNoderesult=null, current=null;
// 定义total变量为l1和l2两条链表相加后需要进位的数据inttotal=0;
// 如果l1和l2两条链表相加后需要进位,remainder变量为个位数的值// 如果l1和l2两条链表相加后不需要进位,remainder为两数相加后的值intremainder=0;
// 只要有一条链表不为空就继续进行遍历while (l1!=null||l2!=null) {
intnum1=l1!=null?l1.val : 0;
intnum2=l2!=null?l2.val : 0;
// 定义sum为两数相加后再与进位数相加后的值intsum=num1+num2+total;
// 对两数相加的结果进行整除,取出进位的值total=sum/10;
// 对两数相加的结果对10进行取余,取出不需要进位的值remainder=sum%10;
if (result==null) {
result=current=newListNode(remainder);
            } else {
// 将当前不需要进位的值赋值给下一个节点要存储的值current.next=newListNode(remainder);
// 将current指针向后移动current=current.next;
            }
// 将l1和l2节点同时向后移动if (l1!=null) {
l1=l1.next;
            }
if (l2!=null) {
l2=l2.next;
            }
        }
if (total>0) {
current.next=newListNode(total);
        }
returnresult;
    }
}

三、提交结果


image.png

总结


以上便是LeetCode第二道题两数相加的解题思路和过程,在解题的过程中我认识到了要灵活的利用链表的特性而不是一味的使用最笨拙的办法去求解,可以转换思路,尝试构造一个新的相同的对象来进行求解。

真正成功的人生,不在于成就的大小,而在于你是否努力地去实现自我,喊出自己的声音,走出属于自己的道路!

image.png

image.png

相关文章
|
2月前
|
算法 Java
LeetCode(一)Java
LeetCode(一)Java
|
4月前
|
算法 Java
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
58 6
|
4月前
|
存储 算法 Java
LeetCode经典算法题:打家劫舍java详解
LeetCode经典算法题:打家劫舍java详解
79 2
|
4月前
|
人工智能 算法 Java
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
54 1
|
4月前
|
存储 算法 Java
LeetCode经典算法题:预测赢家+香槟塔java解法
LeetCode经典算法题:预测赢家+香槟塔java解法
69 1
|
4月前
|
存储 算法 Java
LeetCode经典算法题:二叉树遍历(递归遍历+迭代遍历+层序遍历)以及线索二叉树java详解
LeetCode经典算法题:二叉树遍历(递归遍历+迭代遍历+层序遍历)以及线索二叉树java详解
84 0
|
4月前
|
算法 Java
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
59 0
|
2天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
4天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
4天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。