这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战
题目
给你两个 非空
的链表,表示两个非负的整数。它们每位数字都是按照 逆序
的方式存储的,并且每个节点只能存储 一位
数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
提示:
- 每个链表中的节点数在范围
[1, 100]
内 0 <= Node.val <= 9
- 题目数据保证列表表示的数字不含前导零
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/ad…
示例:
示例 1:
输入: l1 = [2,4,3], l2 = [5,6,4]
输出: [7,0,8]
解释: 342 + 465 = 807.
示例 2:
输入: l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出: [8,9,9,9,0,0,0,1]
理解题意:
题目主要内容:
- 给定两个非空的链表
- 逆序存储的链表
- 即 2—>4->3 正序数字为
342
- 即 2—>4->3 正序数字为
- 两个数相加后,返回一个新的链表
- 即 也是一个逆序的链表
细节点:
- 两个链表都是非空的
- 两个非负整数
- 两个数字都不会以0开头
- 数字逆序排列,第一个节点表示整数的最低位
- 题目没有明确整数的范围,这是个容易忽略的点
实现方案
- 暴利破解1 - 链表转数字,相加,再转字符数组,输出新链表
- 暴利破解2 - 链表转数字,相加,转换链表
- 优化解法 - 链表直接遍历,对应位置数字相加,直接返回新链表
注
方法1 和 方法2 纯属使用笨方法实现功能,完成
示例
中的案例,但 在 leetCode 提交的时候没有跑过测试 > 主要是存在一个问题:若超过语⾔⽀持的数据类型范围,则报错 ,因为:[题目:没有明确整数的范围] 解决办法:BigInteger
实现方案1 :暴利破解1 - 链表转数字,相加,再转字符数组,输出新链表
实现逻辑:
-
l1、l2 执行相同的步骤:
- 循环遍历链表,将逆序排列的元素,转换成整数
-
两个整数相加
-
转换成 String数组
-
循环遍历 String数组 逆序 输出新的链表
public ListNode addTwoNumbersOne(ListNode l1, ListNode l2) {
// 把链表转成数字
long num1 = 0;
// 位数:0代表个位,1代表十位,以此递增
int square1 = 0;
while (l1 != null) {
num1 += (long) l1.val * Math.pow(10, square1);
l1 = l1.next;
square1++;
}
long num2 = 0;
int square2 = 0;
while (l2 != null) {
num2 += (long) l2.val * Math.pow(10, square2);
l2 = l2.next;
square2++;
}
long sumNum = num1 + num2;
// 如果 和 为 0 ,则直接返回新的链表
if (sumNum == 0) {
return new ListNode(0);
}
// 转换成 字符串 数组
String[] strArr = String.valueOf(sumNum).split("");
ListNode newNode = null;
// 循环遍历,组成新的逆序链表
for (String aStr : strArr) {
if (newNode == null) {
newNode = new ListNode(Integer.parseInt(aStr));
} else {
newNode = new ListNode(Integer.parseInt(aStr), newNode);
}
}
return newNode;
}
实现方案2 : 暴利破解2 - 链表转数字,相加,转换链表
实现逻辑: 对暴利解法进行优化,去除 整数 转 字符串 数组,减少空间复杂度
- 循环遍历链表,将逆序排列的元素,转换成整数
- 两个整数相加
- 使用 数学思维,对数取余,可获取每位的值,创建成新的链表
public ListNode addTwoNumbersTwo(ListNode l1, ListNode l2) {
long num1 = 0;
int square1 = 0;
while (l1 != null) {
num1 += (long) l1.val * Math.pow(10, square1);
l1 = l1.next;
square1++;
}
long num2 = 0;
int square2 = 0;
while (l2 != null) {
num2 += (long) l2.val * Math.pow(10, square2);
l2 = l2.next;
square2++;
}
long sumNum = num1 + num2;
ListNode head = new ListNode(); // 创建一个新链表,头部为空节点
ListNode cur = head;
if (sumNum == 0) {
return new ListNode(0);
}
// 循环遍历,两数之和
while (sumNum > 0) {
// 每次 对整数 取余 获取最低位值
int val = (int) sumNum % 10;
// 添加到链表中
cur.next = new ListNode(val);
cur = cur.next;
// 移除 整数的 最低位值
sumNum = sumNum / 10;
}
return head.next;
}
实现方案3 : 链表直接遍历,对应位置数字相加,直接返回新链表
实现逻辑:
- 同时 循环遍历2个链表,对 两个链表同位置的数,进行累加,追加到新链表中
- 设置 进位数
- 每位数 相加时,都要加一下进位数,以防有进位
- 链表 全部遍历完成后,判断是否还有进位,有进在尾部,追加进位数
核心计算公式:sum = x的最后位数 + y的最后位数 + carry进位数
public ListNode addTwoNumbersThree(ListNode l1, ListNode l2) {
ListNode head = null, tail = null;
int carry = 0;
while (l1 != null || l2 != null) {
// 判断链表 该位是否有值,无值,则返回零
int x = l1 != null ? l1.val : 0;
int y = l2 != null ? l2.val : 0;
// 两链表位数相加 and 加 进位值
int temp = x + y + carry;
// 将 累加值 放入新的链表中
if (head == null) {
head = tail = new ListNode(temp % 10);
} else {
tail.next = new ListNode(temp % 10);
tail = tail.next;
}
// 获取进位值
carry = temp / 10;
l1 = l1 == null ? l1 : l1.next;
l2 = l2 == null ? l2 : l2.next;
}
if (carry > 0) {
tail.next = new ListNode(carry);
}
return head;
}