9. <tag-链表和两数之和问题>lt-2. 两数相加 + lt-445. 两数相加 II
lt.240-搜索二维矩阵 ||
[案例需求]
[思路分析]
- 本道题给定的两条链表比较容易理解, 跟合并两条链表的遍历过程基本是一致的,
- 我们只需要同时遍历两条链表, 把对应的两个结点的值加在一起,
进位存储起来用于下次求和时加上
, 得到的加数的个位数作为新链表结点的val
即可;- 细节很多, 仔细把握即可;
- 两条链表不等长, 同时遍历相加结束的条件是 ? --> 所有的链表均为空;
- 对于carry不为空的情况( 即99 + 999的情况), 我们需要在遍历链表结束后, 加上判断, 并把不为0的carry作为新的结点接到新的结果链表中去;
[代码实现]
/**
* 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 temp1 = l1;
ListNode temp2 = l2;
int carry = 0;
int sum = 0;
int nodeVal = 0;
ListNode dummyNode = new ListNode(-1);
ListNode temp = dummyNode;
while(l1 !=null || l2 != null){
int val1 = l1 == null ? 0 : l1.val;
int val2 = l2 == null ? 0 : l2.val;
sum = (carry + val1 + val2);
nodeVal = sum % 10;
carry = sum / 10;
temp.next = new ListNode(nodeVal);
temp = temp.next;
if(l1 != null)l1 = l1.next;
if(l2 != null)l2 = l2.next;
}
//链表都遍历完了, carry(进位)依然不为0;
if(carry != 0){
temp.next = new ListNode(carry);
}
return dummyNode.next;
}
}
[简洁一点的]
/**
* 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) {
//同时遍历两条链表, 获得加数, 被加数, 如果其中一个链表为空了, 就把那个链表对应位置的数值置为0, 同时我们用carry存储进位, 每次加完之后, carry = sum/10 (进位), sum = sum % 10(加数的个位数), 用加数的个位数成立新的加数结点, 往后遍历结点
//在两条链表全部遍历完之后, 判断进位还存在吗, 存在则再创建一个新的加数结点, 值为carry
ListNode head = new ListNode(0);
ListNode temp = head;
int carry = 0;
while(l1 != null || l2 != null){
int x = l1 == null ? 0 : l1.val;
int y = l2 == null ? 0 : l2.val;
int sum = x + y + carry;
//取出sum的个位数新建结果链表的结点
//对carry 取 十位数
/千万要注意这倆数的次序问题!!!!!!!!!!!!!!
carry = sum / 10;
sum = sum % 10;
//新建结点
temp.next = new ListNode(sum);
//移动链表指针, 注意判空, 避免空指针异常
if(l1 != null)l1 = l1.next;
if(l2 != null)l2 = l2.next;
temp = temp.next;
}
if(carry != 0){
temp.next = new ListNode(carry);
}
return head.next;
}
}
lt-445. 两数相加 II
[案例需求]
[思路分析]
- 这题比较有意思, 因为看起来是倒序相加的, 链表也是倒序的, 还是那句话, 如果你觉着链表遍历解题比较困难的话, 请考虑一下用集合工具解题, 这道题其实用栈Stack即可, 但是我为了体验一下双端队列, 所以两钟解法都列在了下面;
- 在使用栈时, 我们需要新建两个栈来存储这两条链表, 然后再出栈相加每个数, 正好就是倒序相加, 而且很方便, 我们把
数加完之后直接新建结点, 并通过temp指针连接起来
;
[代码示例]
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
Deque<Integer> stack1 = new LinkedList<Integer>();
Deque<Integer> stack2 = new LinkedList<Integer>();
while (l1 != null) {
stack1.push(l1.val);
l1 = l1.next;
}
while (l2 != null) {
stack2.push(l2.val);
l2 = l2.next;
}
int carry = 0;
ListNode ans = null;
while (!stack1.isEmpty() || !stack2.isEmpty() || carry != 0) {
int a = stack1.isEmpty() ? 0 : stack1.pop();
int b = stack2.isEmpty() ? 0 : stack2.pop();
int cur = a + b + carry;
carry = cur / 10;
cur %= 10;
ListNode curnode = new ListNode(cur);
curnode.next = ans;
ans = curnode;
}
return ans;
}
}
[思路分析二, 双端队列]
- 相比于栈, 这种写法在逻辑上稍微复杂了一些. 把题目中给定的每一条链表都分别进行遍历利用头插法(xx.addFirst())放入到两个双端队列中, 然后取出进行计算.
/**
* 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) {
//链表的两数之和
//尝试一下双端队列
//addFirst(); removeFirst();
//addLast(); pollFirst();
Deque<ListNode> queue1 = new ArrayDeque<>();
Deque<ListNode> queue2 = new ArrayDeque<>();
Deque<ListNode> resQueue = new ArrayDeque<>();
//把题目中的两条链表分别进行遍历, 使用头插法插入到双端堆中
while(l1 != null){
queue1.addFirst(l1); //头插法. 每次都放到头部 7,2,4,3 就会变味3,4,2,7
l1 = l1.next;
}
while(l2 != null){
queue2.addFirst(l2);// 5,6,4 变为 4,5,6
l2 = l2.next;
}
ListNode dummyNode = new ListNode(-1);
ListNode temp = dummyNode;
int sum = 0, carry = 0, nodeVal = 0;
while(!queue1.isEmpty() || !queue2.isEmpty()){
//从末尾取出元素, 做和
int val1 = queue1.isEmpty() ? 0 : queue1.pollFirst().val; //从头部取出进行计算
int val2 = queue2.isEmpty() ? 0 : queue2.pollFirst().val;
sum = carry + val1 + val2;
carry = sum / 10;
nodeVal = sum % 10;
resQueue.offerFirst(new ListNode(nodeVal));
}
if(carry != 0){
resQueue.offerFirst(new ListNode(carry));
}
//取出resQueue
while(! resQueue.isEmpty()){
temp.next = resQueue.pollFirst();
temp = temp.next;
}
return dummyNode.next;
}
}
简单的优化一下:
把resQueue舍弃, 直接构建链表, 因为是逆序的, 所以采用头插法构建
/**
* 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) {
//链表的两数之和
//尝试一下双端队列
//addFirst(); removeFirst();
//addLast(); pollFirst();
Deque<ListNode> queue1 = new ArrayDeque<>();
Deque<ListNode> queue2 = new ArrayDeque<>();
Deque<ListNode> resQueue = new ArrayDeque<>();
//把题目中的两条链表分别进行遍历, 使用头插法插入到双端堆中
while(l1 != null){
queue1.addFirst(l1); //头插法. 每次都放到头部 7,2,4,3 就会变味3,4,2,7
l1 = l1.next;
}
while(l2 != null){
queue2.addFirst(l2);// 5,6,4 变为 4,5,6
l2 = l2.next;
}
ListNode dummyNode = new ListNode(-1);
ListNode temp = dummyNode;
int sum = 0, carry = 0, nodeVal = 0;
while(!queue1.isEmpty() || !queue2.isEmpty()){
//从末尾取出元素, 做和
int val1 = queue1.isEmpty() ? 0 : queue1.pollFirst().val; //从头部取出进行计算
int val2 = queue2.isEmpty() ? 0 : queue2.pollFirst().val;
sum = carry + val1 + val2;
carry = sum / 10;
nodeVal = sum % 10;
//resQueue.offerFirst(new ListNode(nodeVal));
//头插法, 创建结果链表
temp = new ListNode(nodeVal);
temp.next = dummyNode.next;
dummyNode.next = temp;
}
if(carry != 0){
// resQueue.offerFirst(new ListNode(carry));
temp = new ListNode(carry);
temp.next = dummyNode.next;
dummyNode.next = temp;
}
// //取出resQueue
// while(! resQueue.isEmpty()){
// temp.next = resQueue.pollFirst();
// temp = temp.next;
// }
return dummyNode.next;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具