初次看到这个题,我的想法是先将输入中两个逆序的链表还原出来,由于不知道输入链表的长度,所以先统计l1,l2的位数,即链表的长度:
int bit1 = 0;
int bit2 = 0; // 统计位数bit
ListNode* temp1 = l1;
ListNode* temp2 = l2; // 防止移动头指针
while (temp1 != NULL)
{
bit1++;
temp1 = temp1->next;
}
while (temp2 != NULL)
{
bit2++;
temp2 = temp2->next;
}
//算出了两个数的位数bit1,bit2
知道了位数后,开始还原l1,l2中正序代表的数字,由于逆序存储分别代表实际数字的个、十、百...位,所以可以用pow函数:
int num1 = 0;
int num2 = 0; // 待逆序存储的数字
ListNode* temp11 = l1;
ListNode* temp22 = l2; // 防止移动头指针
for (int i = 0; i < bit1; i++)
{
num1 += temp11->val * pow(10, i);
temp11 = temp11->next;
}
for (int i = 0; i < bit2; i++)
{
num2 += temp22->val * pow(10, i);
temp22 = temp22->next;
}
int sum = num1 + num2; // 计算出最终存储的逆序前的数
至此,算出了要存储到链表中返回的数,现在将其逆序存储到返回链表中,需要知道sum的位数count,即代表了链表的节点数:
int temp = sum; // 防止直接对sum操作导致sum值改变
int count = 1; // sum的位数
while (temp / 10 != 0) // 统计sum的位数
{
temp /= 10;
count++;
}
//count是最后和的位数,sum是最后和的值
有了位数之后,由于将整数的每位单独存储非常麻烦,想到了用to_string函数将sum转化成字符串,最后利用字符数组把每位还原成int型进行存储:
ListNode* head = new ListNode;
head->val = NULL;
head->next = NULL;
ListNode* current = head; // 防止移动头指针
string sum_str = to_string(sum); // 将最后和结果转换为字符串,方便逆序存储
// 没有头节点,先对第一位进行操作,类似于初始化头节点
int digit_value = sum_str[count - 1] - '0'; // char型转化为int型需要减去'0'的ASCII码
current->val = digit_value;
// 再对头节点后的数进行操作
for (int i = count - 1; i > 0; i--)
{
ListNode* temp = new ListNode;
int digit_value = sum_str[i - 1] - '0';
temp->val = digit_value;
current->next = temp;
current = current->next;
}
// 最后节点的指针指向空
current->next = NULL;
return head;
注意:这里采用的是没有头节点的链表。
这种方法可以通过力扣运行时的3个简单测试用例
但是,当提交时发现问题:
如果测试用例中的链表过长,即数字过大,会导致超出int所能表示的范围,所以这种方法不可行。
在看了b站上关于第二题的讲解后,我更新了我的算法:
首先,观察题目中的链表,发现如果按位逆序相加(带进位),然后直接按位存储,也可以实现最终的结果。这是因为数学计算中,也是按照个、十、百...的顺序进行进位的。所以,并不需要将l1、l2中的数字还原出来,直接单独计算每位的总和(sum),然后用总和算出个位(即要存在返回链表节点的数)、进位即可,总和=l1对应节点的值+l2对应节点的值+进位(初始化为0,默认第一次计算前没有进位),然后遍历l1,l2两个链表。
int sum = 0; // 两位总和
int data = 0;// 个位
int bit = 0; // 进位
ListNode* res; // 指针不会调用构造和析构函数,只是定义了一个指针,没有申请内存
res = new ListNode; // 使用new创建对象时,申请分配内存,调用构造函数
ListNode* current = res;
while (l1 != NULL && l2 != NULL)
{
ListNode* temp;
temp = new ListNode;
sum = l1->val + l2->val + bit; // 在这里加上进位
bit = sum / 10;
data = sum % 10;
temp->val = data;
current->next = temp;
l1 = l1->next;
l2 = l2->next;
current = current->next;
}
l1,l2不一定等长,当任何一个遍历完时,还需要检查一下对方遍历完没:
while (l1 != NULL)
{
ListNode* temp;
temp = new ListNode;
sum = l1->val + bit;
bit = sum / 10;
data = sum % 10;
temp->val = data;
current->next = temp;
l1 = l1->next;
current = current->next;
}
while (l2 != NULL)
{
ListNode* temp;
temp = new ListNode;
sum = l2->val + bit;
bit = sum / 10;
data = sum % 10;
temp->val = data;
current->next = temp;
l2 = l2->next;
current = current->next;
}
l1,l2都遍历完后,再检查进位是否为0,若不为0,还需要创建一个新的节点存放进位:
if (bit != 0)
{
ListNode* temp;
temp = new ListNode;
temp->val = bit;
current->next = temp;
current = current->next;
}
由于采用的是带头结点(方便插值)的链表,所以最终返回res->next:
return res->next;
至此,本题得解。
第一次做题的源代码:
#include<iostream>
#include<string>
using namespace std;
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)
{
int bit1 = 0;
int bit2 = 0; // 统计位数bit
ListNode* temp1 = l1;
ListNode* temp2 = l2; // 防止移动头指针
while (temp1 != NULL)
{
bit1++;
temp1 = temp1->next;
}
while (temp2 != NULL)
{
bit2++;
temp2 = temp2->next;
}
//算出了两个数的位数bit1,bit2
int num1 = 0;
int num2 = 0; // 待逆序存储的数字
ListNode* temp11 = l1;
ListNode* temp22 = l2; // 防止移动头指针
for (int i = 0; i < bit1; i++)
{
num1 += temp11->val * pow(10, i);
temp11 = temp11->next;
}
for (int i = 0; i < bit2; i++)
{
num2 += temp22->val * pow(10, i);
temp22 = temp22->next;
}
int sum = num1 + num2; // 计算出最终存储的逆序前的数
int temp = sum;
int count = 1;
while (temp / 10 != 0) // 统计sum的位数
{
temp /= 10;
count++;
}
//count是最后和的位数,sum是最后和的值
ListNode* head = new ListNode;
head->val = NULL;
head->next = NULL;
ListNode* current = head; // 防止移动头指针
string sum_str = to_string(sum); // 将最后和结果转换为字符串,方便逆序存储
// 没有头节点,先对第一位进行操作,类似于初始化头节点
int digit_value = sum_str[count - 1] - '0'; // char型转化为int型需要减去'0'的ASCII码
current->val = digit_value;
// 再对头节点后的数进行操作
for (int i = count - 1; i > 0; i--)
{
ListNode* temp = new ListNode;
int digit_value = sum_str[i - 1] - '0';
temp->val = digit_value;
current->next = temp;
current = current->next;
}
// 最后节点的指针指向空
current->next = NULL;
return head;
}
};
void test()
{
ListNode* l1 = new ListNode;
l1->val = 5;
ListNode* node12 = new ListNode;
node12->val = 6;
l1->next = node12;
ListNode* node13 = new ListNode;
node13->val = 4;
node12->next = node13;
ListNode* l2 = new ListNode;
l2->val = 2;
ListNode* node22 = new ListNode;
node22->val = 4;
l2->next = node22;
ListNode* node23 = new ListNode;
node23->val = 3;
node22->next = node23;
Solution s;
ListNode* res = s.addTwoNumbers(l1, l2);
cout << res->val << " " << res->next->val << " " << res->next->next->val << endl;
// 结果:可以满足题目要求,但是无法满足l1,l2中存放过大数据的情况,因为int类型能存储的位数有限,见39、44行
// 结论:我写的这种方法不适用
}
int main()
{
test();
system("pause");
}
第二次做题的源代码:
#include<iostream>
#include<string>
using namespace std;
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)
{
int sum = 0; // 两位总和
int data = 0;// 个位
int bit = 0; // 进位
ListNode* res; // 指针不会调用构造和析构函数,只是定义了一个指针,没有申请内存
res = new ListNode; // 使用new创建对象时,申请分配内存,调用构造函数
// 此时的res!=NULL,因为res内有val=0
// res->next为NULL
ListNode* current = res;
while (l1 != NULL && l2 != NULL)
{
ListNode* temp;
temp = new ListNode;
sum = l1->val + l2->val + bit; // 在这里加上进位
bit = sum / 10;
data = sum % 10;
temp->val = data;
current->next = temp;
l1 = l1->next;
l2 = l2->next;
current = current->next;
}
while (l1 != NULL)
{
ListNode* temp;
temp = new ListNode;
sum = l1->val + bit;
bit = sum / 10;
data = sum % 10;
temp->val = data;
current->next = temp;
l1 = l1->next;
current = current->next;
}
while (l2 != NULL)
{
ListNode* temp;
temp = new ListNode;
sum = l2->val + bit;
bit = sum / 10;
data = sum % 10;
temp->val = data;
current->next = temp;
l2 = l2->next;
current = current->next;
}
if (bit != 0)
{
ListNode* temp;
temp = new ListNode;
temp->val = bit;
current->next = temp;
current = current->next;
}
return res->next;
}
};
void test()
{
ListNode* l1 = new ListNode;
l1->val = 5;
ListNode* node12 = new ListNode;
node12->val = 6;
l1->next = node12;
ListNode* node13 = new ListNode;
node13->val = 4;
node12->next = node13;
ListNode* l2 = new ListNode;
l2->val = 2;
ListNode* node22 = new ListNode;
node22->val = 4;
l2->next = node22;
ListNode* node23 = new ListNode;
node23->val = 3;
node22->next = node23;
Solution s;
ListNode* res = s.addTwoNumbers(l1, l2);
cout << res->val << " " << res->next->val << " " << res->next->next->val << endl;
}
int main()
{
test();
system("pause");
}