两数相加
- https://leetcode.cn/problems/add-two-numbers/
描述
-
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
-
请你将两个数相加,并以相同形式返回一个表示和的链表。
-
你可以假设除了数字 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
- 题目数据保证列表表示的数字不含前导零
Typescript 版算法实现
1 )方案 1
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function addTwoNumbers(l1: ListNode | null, l2: ListNode | null): ListNode | null {
const l3 = new ListNode(0); // 初始化l3链表,空链表
// 通过指针遍历链表,声明各个指针
let p1 = l1; // p1指向第一个链表的头部
let p2 = l2; // 同上
let p3 = l3; // 同上
let carry = 0; // 十位数上的数
// 两个链表中都没有遍历完成都可以继续执行
while(p1 || p2) {
const v1 = p1 ? p1.val : 0; // 拿到p1指针的值
const v2 = p2 ? p2.val : 0; // 拿到p2指针的值
// 对两个链表的值进行计算
const val = v1 + v2 + carry; // 比如 2+5, 4+6
// 下面两行是核心
carry = Math.floor(val / 10); // 拿到进位,以便下位进行相加(下一轮)
p3.next = new ListNode(val % 10); // 处理新链表的next
// 把所有指针往后移动一位
p1 && (p1 = p1.next);
p2 && (p2 = p2.next);
p3 = p3.next; // p3永远有值
}
// 循环结束后,判断是否有进位,有则处理进位
carry && (p3.next = new ListNode(carry));
return l3.next; // 因为l3初始的时候是一个临时的初始值,所以返回它的next
};
-
解题思路
- 小学数学题,模拟相加操作
- 从个位开始相加
- 执行相加逻辑,需要遍历链表
-
解题步骤
- 新建一个空链表
- 遍历被相加的两个链表,模拟相加操作,将个位数追加到新链表上,将十位数留到下一位去相加
- 因为都是一位数字,每个节点存储的数字都是个位数,十位数是是两个链表对应节点数字相加产生的进位
- 链表遍历完,新链表也构建完成
2 )方案2
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function addTwoNumbers(l1: ListNode | null, l2: ListNode | null): ListNode | null {
// 链表边界条件判断,特殊情况可提前结束程序
if (l1 === null && l2 === null) {
return null;
} else if (l1 === null) {
return l2;
} else if (l2 === null) {
return l1;
}
let head = null, tail = null
let carry = 0;
while (l1 || l2) {
const val1 = l1 ? l1.val : 0;
const val2 = l2 ? l2.val : 0;
const sum = val1 + val2 + carry;
if (!head) {
head = tail = new ListNode(sum % 10)
} else {
tail.next = new ListNode(sum % 10)
tail = tail.next
}
carry = Math.floor(sum / 10);
l1 = l1 && l1.next;
l2 = l2 && l2.next;
}
if (carry) {
tail.next = new ListNode(carry)
}
return head;
};
- 上述是官方示例程序,类似的思想
Python3 版算法实现
1 )方案1
# 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]:
l3 = ListNode(0) # 初始化l3链表,空链表
# 声明各个指针
p1 = l1 # p1指向第一个链表的头部
p2 = l2 # p2指向第二个链表的头部
p3 = l3 # p3指向结果链表的当前节点
carry = 0 # 十位数上的数
# 当两个链表中有任意一个未遍历完时,继续循环
while p1 or p2:
v1 = p1.val if p1 else 0 # 拿到p1指针的值
v2 = p2.val if p2 else 0 # 拿到p2指针的值
# 对两个链表的值进行计算
val = v1 + v2 + carry # 计算当前位的和
# 更新进位和当前位的值
carry = val // 10 # 获取进位
p3.next = ListNode(val % 10) # 创建新节点保存当前位的值
# 将指针向后移动一位
p1 = p1.next if p1 else None
p2 = p2.next if p2 else None
p3 = p3.next # 移动结果链表的指针
# 如果循环结束后还有进位,需要添加新节点保存进位
if carry:
p3.next = ListNode(carry)
# 返回结果链表的下一个节点(跳过初始化时的临时节点)
return l3.next
# 注意:在Python中,链表节点通常是通过实例化ListNode类来创建的
# 并且链表的尾部通常是通过将新节点的next指向None来结束
# 当传递链表给函数时,确保链表的尾部节点的next属性为None
2 )方案2
# 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]:
# 链表边界条件判断,特殊情况可提前结束程序
if not l1:
return l2
elif not l2:
return l1
# 初始化头尾节点和进位
head = tail = ListNode(0)
carry = 0
# 遍历链表
while l1 or l2:
val1 = l1.val if l1 else 0
val2 = l2.val if l2 else 0
total = val1 + val2 + carry
# 创建新节点并更新头尾指针
if not head:
head = tail = ListNode(total % 10)
else:
tail.next = ListNode(total % 10)
tail = tail.next
# 更新进位
carry = total // 10
# 移动链表指针
l1 = l1.next if l1 else None
l2 = l2.next if l2 else None
# 检查是否还有进位需要处理
if carry:
tail.next = ListNode(carry)
# 返回头节点
return head.next # 跳过初始化的哑节点
# 注意:在Python中,链表节点通常是通过实例化ListNode类来创建的,
# 并且链表的尾部通常是通过将新节点的next指向None来结束。
# 当传递链表给函数时,确保链表的尾部节点的next属性为None。
Golang 版算法实现
1 )方案1
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
// 实现链表相加函数
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
// 初始化l3链表,哑节点
dummy := &ListNode{}
current := dummy
carry := 0 // 进位
// 通过指针遍历链表
for l1 != nil || l2 != nil {
var x, y int
if l1 != nil {
x = l1.Val
l1 = l1.Next
} else {
x = 0
}
if l2 != nil {
y = l2.Val
l2 = l2.Next
} else {
y = 0
}
// 计算当前位的和以及进位
sum := x + y + carry
carry = sum / 10
digit := sum % 10
// 创建新节点并添加到l3链表中
current.Next = &ListNode{Val: digit}
current = current.Next
}
// 如果最后还有进位,添加到l3链表尾部
if carry > 0 {
current.Next = &ListNode{Val: carry}
}
// 返回l3链表的下一个节点(跳过哑节点)
return dummy.Next
}
2 ) 方案2
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
// 实现链表相加函数
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
// 链表边界条件判断,特殊情况可提前结束程序
if l1 == nil && l2 == nil {
return nil
} else if l1 == nil {
return l2
} else if l2 == nil {
return l1
}
var head, tail *ListNode
carry := 0
for l1 != nil || l2 != nil {
var val1, val2 int
if l1 != nil {
val1 = l1.Val
l1 = l1.Next
} else {
val1 = 0
}
if l2 != nil {
val2 = l2.Val
l2 = l2.Next
} else {
val2 = 0
}
sum := val1 + val2 + carry
if head == nil {
head = &ListNode{Val: sum % 10}
tail = head
} else {
tail.Next = &ListNode{Val: sum % 10}
tail = tail.Next
}
carry = sum / 10
}
if carry > 0 {
tail.Next = &ListNode{Val: carry}
}
return head
}
678



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



