给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
解题思路
由于输入的两个链表都是逆序存储数字的位数的,因此两个链表中同一位置的数字可以直接相加。
我们同时遍历两个链表,逐位计算它们的和,并与当前位置的进位值相加。具体而言,如果当前两个链表处相应位置的数字为 n1,n2,进位值为 carry,则它们的和为 n1+n2+carry;其中,答案链表处相应位置的数字为 (n1+n2+carry)mod10,而新的进位值为 (n1+n2+carry) / 10 。
如果两个链表的长度不同,则可以认为长度短的链表的后面有若干个 0 ;或者 短的链表 结束后,只留长的链表 与 进位 参与运算。两种不同的写法。
此外,如果链表遍历结束后,有 carry>0,还需要在答案链表的后面附加一个节点,节点的值为 carry。

C
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
struct ListNode *head = NULL, *tail = NULL;
int carry = 0;
while (l1 || l2){
int n1 = l1 ? l1->val : 0;
int n2 = l2 ? l2->val : 0;
int sum = carry + n1 + n2;
if (!head){
head = tail = malloc(sizeof(struct ListNode));
tail->val = sum % 10;
tail->next = NULL;
}else{
tail->next = malloc(sizeof(struct ListNode));
tail->next->val = sum % 10;
tail = tail->next;
tail->next = NULL;
}
carry = sum / 10;
if (l1){
l1 = l1->next;
}
if (l2){
l2 = l2->next;
}
}
if (carry>0){
tail->next = malloc(sizeof(struct ListNode));
tail->next->val = carry;
tail = tail->next;
tail->next = NULL;
}
return head;
}
三元运算符
n1 = l1 ? l1->val : 0
条件 ? 表达式1 : 表达式2
如果链表节点 l1 不为空,则 n1 的值为 l1->val;如果 l1 为空,则 n1 的值为 0。
Python3
由C翻译得到
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
head = tail = None
carry = 0
while l1 or l2:
n1 = l1.val if l1 else 0
n2 = l2.val if l2 else 0
total = carry + n1 + n2
if not head:
head = ListNode(total%10)
tail = head
else:
tail.next = ListNode(total%10)
tail = tail.next
carry = total // 10
if l1:
l1 = l1.next
if l2:
l2 = l2.next
if carry > 0:
tail.next = ListNode(carry)
tail = tail.next
return head
在Python中,sum是一个内置函数,用于计算可迭代对象(如列表、元组等)中所有元素的总和。然而,Python允许开发者将内置函数的名称用作变量名,但这样做会覆盖内置函数的功能,可能导致代码的可读性和功能性问题。
-
变量名:将
sum改为total避免与内置函数冲突
Python的三元运算符的语法结构是这样的:
a if condition else b
这里,condition 是一个布尔表达式,a 和 b 是在条件为真或假时返回的值。如果 condition 为真(True),则表达式的结果是 a;如果为假(False),则结果是 b。
在Python中,/ 和 // 是两种不同的除法运算符,主要区别如下:
1. / - 普通除法(真除法)
-
结果类型:总是返回浮点数(float)
-
功能:执行精确的数学除法
2. // - 整数除法(地板除)
-
结果类型:返回整数(向下取整)
-
功能:取商的整数部分
Python中的引用行为
# Python中的引用行为
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
# 创建链表: 1 -> 2 -> 3
node1 = ListNode(1)
node2 = ListNode(2)
node3 = ListNode(3)
node1.next = node2
node2.next = node3
# l1 引用 node1
l1 = node1
print(l1.val) # 输出: 1
# "移动指针" - 实际上是改变引用指向下一个节点
l1 = l1.next
print(l1.val) # 输出: 2
区别
| 特性 | C指针 | Python引用 |
|---|---|---|
| 语法 | *l1, l1->val | l1.val |
| 移动 | l1 = l1->next | l1 = l1.next |
| 空值 | NULL | None |
| 内存操作 | 直接操作内存地址 | 自动内存管理 |
另解
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
total = l1.val + l2.val
carry = 1 if total >= 10 else 0
head = ListNode(total%10)
tail = head
while l1.next and l2.next:
l1 = l1.next
l2 = l2.next
total = l1.val + l2.val + carry
carry = 1 if total >= 10 else 0
tail.next = ListNode(total%10)
tail = tail.next
while l1.next:
l1 = l1.next
total = l1.val + carry
carry = 1 if total >= 10 else 0
tail.next = ListNode(total%10)
tail = tail.next
while l2.next:
l2 = l2.next
total = l2.val + carry
carry = 1 if total >= 10 else 0
tail.next = ListNode(total%10)
tail = tail.next
if carry == 1:
tail.next = ListNode(1)
tail = tail.next
return head
C++
单链表节点的结构体定义
struct ListNode {
int val; // 节点存储的数据(整数值)
ListNode *next; // 指向下一个节点的指针
// 构造函数重载
};
三个构造函数
1. 默认构造函数
ListNode() : val(0), next(nullptr) {}
-
创建节点时:
new ListNode() -
值
val默认为 0 -
指针
next默认为nullptr(空指针)
2. 带值的构造函数
ListNode(int x) : val(x), next(nullptr) {}
-
创建节点时:
new ListNode(5) -
值
val设置为传入的参数x -
指针
next默认为nullptr
3. 完整构造函数
ListNode(int x, ListNode *next) : val(x), next(next) {}
-
创建节点时:
new ListNode(5, nextNode) -
值
val设置为x -
指针
next指向传入的下一个节点
构造函数和析构函数
类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。
构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。默认的构造函数没有任何参数,但如果需要,构造函数也可以带有参数。
类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。
析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
使用初始化列表来初始化字段
| 特性 | 初始化列表 | 普通赋值 |
|---|---|---|
| 执行时机 | 在构造函数体执行之前 | 在构造函数体内部 |
| 效率 | 更高(直接初始化) | 较低(先默认构造再赋值) |
| 必须使用的情况 | const 成员、引用成员、没有默认构造的类成员 | 无限制 |
区别原因:
C语言:struct 关键字是必须的,因为 struct 名称和普通标识符在不同的命名空间中。
C++:struct 名称进入普通的标识符命名空间,所以可以直接使用类名。
现代C++推荐写法:
// 方式1:每个变量单独声明(更清晰)
ListNode* head = nullptr;
ListNode* tail = nullptr;
// 方式2:使用一行声明
ListNode *head = nullptr, *tail = nullptr;
解法
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode *head = nullptr, *tail = nullptr;
int carry = 0;
while(l1 || l2){
int n1 = l1 ? l1->val : 0;
int n2 = l2 ? l2->val : 0;
int sum = n1 + n2 + carry;
if (!head){
head = tail = new ListNode(sum%10);
}else{
tail->next = new ListNode(sum%10);
tail = tail->next;
}
carry = sum / 10;
if(l1){
l1 = l1->next;
}
if(l2){
l2 = l2->next;
}
}
if(carry>0){
tail->next = new ListNode(carry);
tail = tail->next;
}
return head;
}
};
Java
/**
* 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 head = null, tail = null;
int carry = 0;
while (l1 != null || l2 != null){
int n1 = (l1 != null) ? l1.val : 0;
int n2 = (l2 != null) ? l2.val : 0;
int sum = n1 + n2 + carry;
if (head == null){
head = tail = new ListNode(sum % 10);
}else{
tail.next = new ListNode(sum % 10);
tail = tail.next;
}
carry = sum / 10;
if (l1 != null){
l1 = l1.next;
}
if (l2 != null){
l2 = l2.next;
}
}
if (carry>0){
tail.next = new ListNode(carry);
tail = tail.next;
}
return head;
}
}
必须显式与 null 比较
| 语言 | 语法 | 原理 |
|---|---|---|
| C/C++ | while (l1) | 指针到bool的隐式转换 |
| Java | while (l1 != null) | 严格的类型系统,无隐式转换 |
| Python | while l1 | 所有对象都有布尔值 |
Java 中引用类型不能直接作为布尔条件,必须显式与 null 比较。

1457

被折叠的 条评论
为什么被折叠?



