基础知识要求:
Java:方法、构造器、while循环、if语句、三元运算符、逻辑运算符、关系运算符、算术运算符
Python: 方法、构造器、while循环、if语句、三元运算符、逻辑运算符、算术运算符
数据结构:链表
题目:
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:
输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8] 解释:342 + 465 = 807.
示例 2:
输入:l1 = [0], l2 = [0] 输出:[0]
示例 3:
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] 输出:[8,9,9,9,0,0,0,1]
提示:
- 每个链表中的节点数在范围
[1, 100]
内 0 <= Node.val <= 9
- 题目数据保证列表表示的数字不含前导零
思路解析:
想象一下,你有两个逆序的纸条,每个纸条上都写着一串数字,这些数字代表一个非负的整数,但是是从低位到高位排列的(也就是个位数在最前面,十位数在后面,依此类推)。你的任务是将这两个数字加起来,并将结果写成一个新的逆序纸条。
步骤:
- 准备阶段:
- 拿出一个新的空纸条(这就是我们的哑节点),用来记录加法的结果。
- 准备一个额外的纸条(这就是我们的当前节点),指向新纸条的开头,这样我们就可以在需要的时候添加新的数字。
- 准备一个小纸片,用来记录进位(比如加法中的“满十进一”)。
- 加法过程:
- 对照两个原始纸条上的数字,从个位开始(也就是纸条的开头),将两个数字相加,并加上小纸片上的进位。
- 将加法的结果(0-9)写在新的纸条上,对应的位置是当前节点指向的位置。
- 更新进位:如果加法结果大于或等于10,那么进位就是1,否则是0。
- 移动到下一个位置(也就是纸条的下一个数字):将当前节点向前移动一位,指向新的位置;同时,如果原始纸条上还有数字,也向前移动一位。
- 重复上述步骤,直到两个原始纸条都遍历完。
- 处理剩余的进位:
- 如果在所有数字都加完之后,进位纸片上还有一个1(意味着最高位还有进位),那么就在新纸条的开头添加一个数字1。
- 完成:
- 现在,你手中的新纸条就是从低位到高位排列的加法结果了。
代码中的对应:
- 哑节点(dummy node)对应准备阶段的新纸条。
- 当前节点(current node)对应准备阶段的额外纸条。
- 进位(carry)对应准备阶段的小纸片。
- 遍历两个链表(l1 和 l2)对应对照两个原始纸条上的数字。
- 创建新节点对应在新纸条上写数字。
Java代码示例:
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
public class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0); // 哑节点
ListNode curr = dummy; // 当前节点
int carry = 0; // 进位
while (l1 != null || l2 != null) {
int x = (l1 != null) ? l1.val : 0;
int y = (l2 != null) ? l2.val : 0;
int sum = carry + x + y;
carry = sum / 10; // 更新进位
curr.next = new ListNode(sum % 10); // 创建新节点保存当前位的值
curr = curr.next; // 移动到下一个节点
if (l1 != null) l1 = l1.next; // 如果l1不为空,移动到下一个节点
if (l2 != null) l2 = l2.next; // 如果l2不为空,移动到下一个节点
}
// 如果最高位还有进位,则添加一个新节点
if (carry > 0) {
curr.next = new ListNode(carry);
}
// 返回哑节点的下一个节点作为结果链表的头节点
return dummy.next;
}
// 以下为测试代码
public static void printList(ListNode head) {
ListNode curr = head;
while (curr != null) {
System.out.print(curr.val + " -> ");
curr = curr.next;
}
System.out.println("NULL");
}
public static void main(String[] args) {
// 创建示例链表 l1: 2 -> 4 -> 3
ListNode l1 = new ListNode(2);
l1.next = new ListNode(4);
l1.next.next = new ListNode(3);
// 创建示例链表 l2: 5 -> 6 -> 4
ListNode l2 = new ListNode(5);
l2.next = new ListNode(6);
l2.next.next = new ListNode(4);
Solution solution = new Solution();
ListNode result = solution.addTwoNumbers(l1, l2);
// 打印结果链表
printList(result);
}
}
在上面的代码中,我们首先定义了链表节点类 ListNode
。然后,在 Solution
类中实现了 addTwoNumbers
方法来执行两个链表的相加操作。在 main
方法中,我们创建了示例链表 l1
和 l2
,并调用了 addTwoNumbers
方法来得到相加后的结果链表,最后打印了结果链表的内容。
Python代码示例:
# 首先,定义链表节点的数据结构
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
# 实现链表相加的功能
def addTwoNumbers(l1, l2):
dummy = ListNode(0) # 创建一个哑节点作为结果链表的头节点
curr = dummy # 当前节点,初始化为哑节点
carry = 0 # 进位
# 当两个链表都不为空,或者进位不为0时,继续循环
while l1 or l2 or carry:
# 获取当前位的值(如果链表为空,则视为0)
x = l1.val if l1 else 0
y = l2.val if l2 else 0
# 计算当前位的和(包括进位)
total = x + y + carry
# 更新进位
carry = total // 10
# 创建新节点存储当前位的值(0-9)
curr.next = ListNode(total % 10)
# 移动到下一个节点
curr = curr.next
# 如果链表l1或l2不为空,则移动到下一个节点
if l1:
l1 = l1.next
if l2:
l2 = l2.next
# 返回结果链表的头节点(哑节点的下一个节点)
return dummy.next
# 示例
# 创建链表 l1: 2 -> 4 -> 3
l1 = ListNode(2)
l1.next = ListNode(4)
l1.next.next = ListNode(3)
# 创建链表 l2: 5 -> 6 -> 4
l2 = ListNode(5)
l2.next = ListNode(6)
l2.next.next = ListNode(4)
# 相加并打印结果
result = addTwoNumbers(l1, l2)
while result:
print(result.val, end=" -> ")
result = result.next
# 输出应为:7 -> 0 -> 8 ->
在上面的代码中,我们使用了一个哑节点(dummy)来简化链表的创建过程,因为我们不需要在循环开始前就知道链表的长度。哑节点是一个特殊的节点,它不包含任何数据(或包含默认值,如0),但它的下一个节点是结果链表的第一个实际节点。在循环结束后,我们返回哑节点的下一个节点作为结果链表的头节点。