1. 题目
两数相加 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。 示例 1:
输入: l1 = [2,4,3], l2 = [5,6,4]
输出: [7,0,8]
解释: 342 + 465 = 807.
示例 2:
输入: l1 = [0], l2 = [0]
输出: [0]
2. 思路
这一题名为两数相加,其实是考察链表,两个链表之间的合并。 处理处理链表的要点: (1)注意指针 (2)巧用哨兵节点来简化逻辑
算法要从时间和空间复杂度来考虑, 这里的思路和通常的有所不同。 (1)空间上,合并完就得两个链表就不用了,不如我们不去创建新的链表,能省就省,旧瓶装新酒,直接用原来链表里的对象。 (2)时间上,假设短的链表长度为m,那么再合并完m对个节点后,又没有进位的话,后续的合并逻辑似乎也没必要执行了,直接指针指到剩下节点的开头。
3. 解题方法
结合代码的注释吧
4. 复杂度
这里的解法和其它不太一样,假设长的链表长度为n,短的链表长度为m。
其它一些算法空间复杂度是O(n),时间复杂度是O(n)。
而本算法复杂度分析如下:
时间复杂度:
最好时间复杂度为:
最差时间复杂度为:
较大概率一般情况的下时间复杂度为:
空间复杂度
5. Code
/**
* 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) {
// 如果有一个链表为空,则没有必要继续合并了,直接返回另外一个链表
if (l1 == null) {
return l2;
}
if (l2 == null) {
return l1;
}
// 哨兵节点,简化编程,head将作为该函数返回的链表的头节点
ListNode node = new ListNode(-1);
ListNode head = node;
int c = 0;
while(l1 != null && l2 != null) {
c = l1.val + l2.val + c;
// 复用l1链表里的对象
l1.val = c % 10;
c = c / 10;
node.next = l1;
node = l1;
l1 = l1.next;
l2 = l2.next;
}
// l1 长于l2,并且还有进位
while(l1 != null && c!=0) {
c = l1.val + c;
l1.val = c % 10;
c = c/10;
node.next = l1;
node = l1;
l1 = l1.next;
}
// l2长于l1,
if (l2 != null) {
node.next = l2;
}
while(l2 != null && c!=0) {
// l2 仍然有未遍历到的节点,并且有进位
c = l2.val + c;
// 复用l2链表里的对象
l2.val = c % 10;
c = c / 10;
node.next = l2;
node = l2;
l2 = l2.next;
}
// 处理最后的进位
if (c != 0) {
node.next = new ListNode(c);
}
return head.next;
}
}