LeetCode 第二道题目是 “两数相加”(Add Two Numbers)。以下是详细的解题思路及 C、Java 和 Python 的实现。
题目描述
给定两个非空链表表示两个非负整数。它们的数字是按照逆序存储的,也就是个位在链表的头部。请你将两个数相加,并以相同的逆序链表形式返回它们的和。
解题思路
-
链表遍历与加法操作:
- 从两个链表的头部开始遍历,同时考虑进位的情况。
- 对于每一对节点,将其值相加,再加上之前的进位(如果有的话),计算出新的节点值和进位。
- 创建一个新节点,将计算出的值赋给它,并将新节点连接到结果链表上。
- 移动到下一个节点,继续直到两个链表和进位都处理完毕。
-
处理不同长度的链表:
- 如果两个链表长度不同,需要处理短链表的情况。
- 处理链表遍历的同时,要考虑进位的可能性,如果遍历结束后还有进位,需要创建一个新的节点来表示。
C 语言实现
#include <stdio.h>
#include <stdlib.h>
// 定义链表节点
struct ListNode {
int val;
struct ListNode *next;
};
// 创建一个新的节点
struct ListNode* createNode(int val) {
struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode));
node->val = val;
node->next = NULL;
return node;
}
// 两数相加
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
struct ListNode dummy;
struct ListNode* p = &dummy;
int carry = 0;
while (l1 != NULL || l2 != NULL || carry) {
int sum = carry;
if (l1 != NULL) {
sum += l1->val;
l1 = l1->next;
}
if (l2 != NULL) {
sum += l2->val;
l2 = l2->next;
}
carry = sum / 10;
p->next = createNode(sum % 10);
p = p->next;
}
return dummy.next;
}
// 打印链表
void printList(struct ListNode* node) {
while (node != NULL) {
printf("%d -> ", node->val);
node = node->next;
}
printf("NULL\n");
}
int main() {
// 示例用法
struct ListNode* l1 = createNode(2);
l1->next = createNode(4);
l1->next->next = createNode(3);
struct ListNode* l2 = createNode(5);
l2->next = createNode(6);
l2->next->next = createNode(4);
struct ListNode* result = addTwoNumbers(l1, l2);
printList(result);
return 0;
}
Java 实现
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
ListNode p = dummy;
int carry = 0;
while (l1 != null || l2 != null || carry != 0) {
int sum = carry;
if (l1 != null) {
sum += l1.val;
l1 = l1.next;
}
if (l2 != null) {
sum += l2.val;
l2 = l2.next;
}
carry = sum / 10;
p.next = new ListNode(sum % 10);
p = p.next;
}
return dummy.next;
}
public static void printList(ListNode node) {
while (node != null) {
System.out.print(node.val + " -> ");
node = node.next;
}
System.out.println("NULL");
}
public static void main(String[] args) {
ListNode l1 = new ListNode(2);
l1.next = new ListNode(4);
l1.next.next = new ListNode(3);
ListNode l2 = new ListNode(5);
l2.next = new ListNode(6);
l2.next.next = new ListNode(4);
ListNode result = addTwoNumbers(l1, l2);
printList(result);
}
}
Python 实现
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def add_two_numbers(l1: ListNode, l2: ListNode) -> ListNode:
dummy = ListNode()
p = dummy
carry = 0
while l1 or l2 or carry:
sum_val = carry
if l1:
sum_val += l1.val
l1 = l1.next
if l2:
sum_val += l2.val
l2 = l2.next
carry = sum_val // 10
p.next = ListNode(sum_val % 10)
p = p.next
return dummy.next
def print_list(node: ListNode):
while node:
print(node.val, end=' -> ')
node = node.next
print('NULL')
# 示例使用
l1 = ListNode(2, ListNode(4, ListNode(3)))
l2 = ListNode(5, ListNode(6, ListNode(4)))
result = add_two_numbers(l1, l2)
print_list(result)
时间复杂度
-
时间复杂度:O(max(m, n)),其中 m 和 n 分别是两个链表的长度。我们需要遍历两个链表的所有节点一次,因此时间复杂度是链表长度的最大值。
-
空间复杂度:O(max(m, n))。我们需要创建新的链表来存储结果,其长度最多为两个输入链表的长度之和,因此空间复杂度是链表长度的最大值。