[链表]–两数相加和两数相加Ⅱ
题目链接
相似题型 相同题型
题目
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
解析
- 两个数字相加可能存在进位,所以需要一个 carry 来保存进位。除此之外,相加后需要一个新链表来保存,当然 temp 作为工具针必不可少;
- 新链表每一个节点的值是 两个链表对应节点的值以及 carry 的值之和去掉进位。当然,节点为 null 那值就是 0 没跑了;
- 将新节点连接在 temp 后面,然后继续遍历就需要判断两个链表是否相加完:使用三目运算符就 OK,节点是 null 那就继续是 null 吧,不为 null 就需要遍历下一个节点,同时 carry 怎么算?我也不知道;
- 什么时候结束?不仅是两个链表都遍历完,carry 同时也不能为空。不怕万一就怕一万,相加以后多出来一位数。
- 返回的一定是 dummyHead.next,不然体现不到傀儡和工具针的作用。
public class Solution2 {
/**
* Definition for singly-linked list
*/
class ListNode {
int val;
ListNode next;
public ListNode(int val) {
this.val = val;
}
}
/**
* 每一次创建新节点的值 时 l1.val/0 + l2.val/0 + carry;
* 1.定义一个傀儡头结点用作连接新链表
* 2.只有 l1、l2 为 null 并且进位 carry = 0 时才说明计算结束
* 3.计算三者之和创建新节点连接在新链表后面
* 4.每次的进位等于这次三者之和 sum/10
*/
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int carry = 0;// 进位
ListNode dummyHead = new ListNode(0);
ListNode temp = dummyHead;
while (l1 != null || l2 != null || carry > 0) {
int sum = carry;
sum += l1 == null ? 0 : l1.val;
sum += l2 == null ? 0 : l2.val;
ListNode node = new ListNode(sum % 10);
temp.next = node;
temp = temp.next;
l1 = l1 == null ? null : l1.next;
l2 = l2 == null ? null : l2.next;
carry = sum / 10;
}
return dummyHead.next;
}
}
题目链接
题目
给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
示例
输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 8 -> 0 -> 7
解析
还行不难,它既然不反转了,那我反转:编写一个辅助方法 reverse() 用于反转链表,学以致用!
- 定义新链表 dummyHead 以及配套工具针 temp;
- 反转两个链表;
- leetcode 2.两数相加
- 反转新链表返回就好了;
- 运行 beat 90% 也可。突然下面有行字看不清,CV 过来看清楚点。
进阶:如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。
这个… 行吧,不翻转还想相加还存在进位…
对了,有个结构叫做 栈----Stack :先进的后出
- 链表压栈,当然了,是两个栈;
- 然后把链表操作换成栈的操作就行了呗:next = pop();
public class Solution445 {
/**
* Definition for singly-linked list
*/
class ListNode {
int val;
ListNode next;
public ListNode(int val) {
this.val = val;
}
}
/**
* 需要一个反转链表函数进行辅助
* 1.反转两个链表
* 2.定义一个进位 carry, 只有 l1 l2 为空且 carry = 0 时, 才能说明运算结束, 否则还要继续运算
* 3.l1、l2 的 val 在它们不为空时 就是本身 val, 为空时等于 0
* 4.新结点的 val = (carry + l1.val + l2.val) % 10, %10 是因为 val 大于时应该有进位, 只需要取个位即可
* 5.使用 val 创建结点, 连接在新链表后面, 然后判断了 l1、l2 为空时等于 null 就行, 不为空继续遍历, carry 需要使用 val/10 取十位上的数
* 6.直到第二步说的条件结束才结束, 反转新链表就结束了
*/
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode dummyHead = new ListNode(-1);
ListNode temp = dummyHead;
l1 = reverse(l1);
l2 = reverse(l2);
int carry = 0;
while (l1 != null || l2 != null || carry > 0) {
int sum = carry;
sum += ((l1 == null) ? 0 : l1.val) + ((l2 == null) ? 0 : l2.val);
ListNode node = new ListNode(sum % 10);
temp.next = node;
temp = temp.next;
l1 = (l1 == null) ? null : l1.next;
l2 = (l2 == null) ? null : l2.next;
carry = sum / 10;
}
return reverse(dummyHead.next);
}
/**
* 反转链表
*/
public static ListNode reverse(ListNode head) {
if (head == null) return null;
ListNode prev = null;
while (head != null) {
ListNode headNext = head.next;
head.next = prev;
prev = head;
head = headNext;
}
return prev;
}
}
进阶
public class Solution445 {
/**
* Definition for singly-linked list
*/
class ListNode {
int val;
ListNode next;
public ListNode(int val) {
this.val = val;
}
}
/**
* 1.将两个链表的结点全都压栈, 这样弹出顺序就是计算顺序
* 2.定义一个进位 carry ,两个栈都为空并且进位为 0 时结束计算
* 3.当栈为空但是运算没结束时, 就让它等于0, 求三者之和创建新结点
* 4.注意: 定义的 head 是头结点, 所以让它时刻等于新创建的结点, 这样最后就不用反转链表
*/
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
Stack<ListNode> stack1 = new Stack<>();
Stack<ListNode> stack2 = new Stack<>();
// 将结点压栈, 弹出顺序就是计算顺序
while (l1 != null) {
stack1.push(l1);
l1 = l1.next;
}
while (l2 != null) {
stack2.push(l2);
l2 = l2.next;
}
ListNode head = null;// 新链表的头结点
int carry = 0;// 进位
while (!stack1.isEmpty() || !stack2.isEmpty() || carry > 0) {
int sum = carry;
sum += (stack1.isEmpty() ? 0 : stack1.pop().val) + (stack2.isEmpty() ? 0 : stack2.pop().val);
ListNode node = new ListNode(sum % 10);
// 头结点是紧跟着新创建结点的, 这样可以保证最后结束时, head 就是新链表的头结点, 不用进行反转
node.next = head;
head = node;
carry = sum / 10;
}
return head;
}
}
-----------------------------------------------------------------------------有始有终分割线----------------------------------------------------------------------------------