本文记录了作者在解决Leetcode上第二道算法题时尝试的方法。
使用的语言是C++。
1. 题目简介
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 :
输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8] 解释:342 + 465 = 807
提示:
- 每个链表中的节点数在范围
[1, 100]
内 0 <= Node.val <= 9
- 题目数据保证列表表示的数字不含前导零
2. 错误的解法
刚开始没有看到提示中的内容,想到了一个非常简单的想法:先将两个链表中的数据取出再相加 ,最后将结果赋给一个新的链表,返回这个链表就行。
于是我首先定义一个getnum()的函数,将链表转为整数。
int getnum(ListNode* l1) {
int num=0;
int i=0;
while (l1 != nullptr) {
num = num + (l1->val) * pow(10, i);
l1 = l1->next;
i++;
}
return num;
}
然后在题目给出的addTwoNumbers()函数中实现两数相加,并将结果赋给l3:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int num = getnum(l1) + getnum(l2);
// 两数之和为0,直接返回ListNode(0)
if(num == 0) {
return new ListNode(0);
}
ListNode *l3 = new ListNode(0);
ListNode *head= l3;
while(num != 0) {
int index = num % 10;
l3->next = new ListNode(index);
l3 = l3->next;
num = num / 10;
}
return head->next;
}
这里我先给l3第一个节点赋值为0,然后用head记录l3第一个节点的位置,最后返回值跳过这个0节点,实际上是返回l3整个链表。
这样思路是没错的。运行:
错辣!
意思是在第17行、第15字符处遇到了运行时错误:1e+10超出了int类型所能表示的数值范围。这意味着我正在尝试将一个非常大的数(在这个例子中是10的10次方,也就是10亿)存储到一个int类型的变量中,而int类型通常只能存储较小的数值范围(通常是-2,147,483,648到2,147,483,647对于32位系统)
很简单,我把 int 改为unsigned long long不就好了?说罢......(bushi)于是:
又错辣(不过[1,9,9,9,9,9,9,9,9,9]确实解决了哈哈哈哈哈)
此时我才想起来提示中的第一点, 每个链表中的节点数在范围 [1, 100] 内。看来得换种方法了。
3. 正确的解法
这种方法的思路是每次取出l1,和l2中的一个节点,相加后直接赋值给新的链表,并使用carry 来记录进位:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode *l3 = new ListNode();
ListNode *current = l3;
int carry = 0;
while (l1 != nullptr || l2 != nullptr || carry != 0) {
int x = (l1 != nullptr) ? l1->val : 0;
int y = (l2 != nullptr) ? l2->val : 0;
int sum = x + y + carry;
carry = sum / 10;
current->next = new ListNode(sum % 10);
current = current->next;
if (l1 != nullptr) l1 = l1->next;
if (l2 != nullptr) l2 = l2->next;
}
return l3->next;
}
这里我使用current 帮助动态构建链表,确保每次循环都能在链表的正确位置添加新节点。在循环结束后,current 将指向新链表的最后一个节点。不过,在函数的返回值中,返回的是 l3->next 而不是 l3 或 current,这是因为 l3 最初是一个空节点,用于辅助构建链表,实际的链表是从 l3->next 开始的。
运行,过辣!