给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
进阶:
如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。
示例:
输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 8 -> 0 -> 7
解答:
思路1:
刚拿到这个题目的时候,第一反应就是和我们平时做加法一样,将每一位对其,然后对应位上的数字进行相加,生成一个新的链表。这应该也是这个题目想要考察的。但是现在面临一个问题就是两数相加应该是从各位开始加,但是对于单链表的访问只能从最高位进行访问,所以应该先将链表进行反转的操作。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
// 反转链表函数
void reverse(ListNode* &list){
vector<int> vec;
ListNode* p = list;
while(p != NULL){
vec.push_back(p->val);
p = p->next;
}
p = list;
for(int i=vec.size()-1; i>=0; i--){
p->val = vec[i];
p = p->next;
}
}
// 尾插函数(返回新插入的节点)
ListNode* backInsert(ListNode* node, int num){
ListNode* s = new ListNode(num);
node->next = s;
s->next = NULL;
return s;
}
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
// 首先反转初始的两个链表
reverse(l1);
reverse(l2);
ListNode* new_List = new ListNode(-1);
ListNode* head = new_List;
// 进行相加操作
bool b = false; // 标记是否大于等于10
while(l1 != NULL && l2 != NULL){
int num = 0;
if(b == true){
num = l1->val + l2->val + 1;
b = false;
}else
num = l1->val + l2->val;
if(num >=10){
b = true;
num = num - 10;
}
new_List = backInsert(new_List, num);
l1 = l1->next;
l2 = l2->next;
}
// 考虑到链表长度相等的情况(是否需要进位)
if(l1 == NULL && l2 == NULL){
if(b == true)
new_List = backInsert(new_List, 1);
reverse(head->next);
return head->next;
}
// 对较长的链表进行添加(l1和l2只会执行一个)
// 和前面的相同,只不过只有一个链表
while(l1 != NULL){
int num = 0;
if(b == true){
num = l1->val + 1;
b = false;
}else
num = l1->val;
if(num >=10){
b = true;
num = num - 10;
}
new_List = backInsert(new_List, num);
l1 = l1->next;
}
while(l2 != NULL){
int num = 0;
if(b == true){
num = l2->val + 1;
b = false;
}else
num = l2->val;
if(num >=10){
b = true;
num = num - 10;
}
new_List = backInsert(new_List, num);
l2 = l2->next;
}
// 判断最后是否需要进位(需要进位)
if(b == true){
new_List = backInsert(new_List, 1);
}
// 反转相加后的链表
reverse(head->next);
// 返回结果
return head->next;
}
};
思路2:
除了这种方法,我还想到了另一种方法。就是先将两个链表中的数字转换为真实的数字,然后将真实的数字相加得到最终相加的数字,最后将这个结果存储到一个新的链表中去。但是这种方法的局限性就是:我们无法表示无穷大的数,根据数据类型只能存储有限大的数,不过我觉得也是一种思路,具体的实现代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
// 前插函数(返回新插入的节点)
ListNode* frontInsert(ListNode* node, int num){
ListNode* s = new ListNode(num);
s->next = node;
return s;
}
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int len1 = 0; // 计算第一个链表的长度
ListNode* p1 = l1;
while(p1 != NULL){
p1 = p1->next;
len1++;
}
long real_num1 = 0;
p1 = l1;
for(int i=len1-1; i>=0; i--){
long num = p1->val; // 取出相应节点中的数
for(int j = 0; j < i; j++){ // 对每一位上的数字扩大相应的倍数
num = num * 10;
}
real_num1 = real_num1 + num; // 每一位数字相加
p1 = p1->next; // 节点移动
}
int len2 = 0; // 计算第二个链表的长度
ListNode* p2 = l2;
while(p2 != NULL){
p2 = p2->next;
len2++;
}
long real_num2 = 0;
p2 = l2;
for(int i=len2-1; i>=0; i--){
long num = p2->val; // 取出相应节点中的数
for(int j = 0; j < i; j++){ // 对每一位上的数字扩大相应的倍数
num = num * 10;
}
real_num2 = real_num2 + num; // 每一位数字相加
p2 = p2->next; // 节点移动
}
// 计算得到相加之后的真实数字
long real_num = real_num1 + real_num2;
// 将相加之后的真实数字转换为链表(注意需要向前插入)
ListNode* new_node = NULL;
// 判断相加后结果是否为0
if(real_num == 0)
new_node = new ListNode(0);
else{
while(real_num > 0){
// 取出个位数字
int num = 0;
num = real_num % 10;
real_num = real_num/10;
// 调用前插函数
new_node = frontInsert(new_node, num);
}
}
return new_node;
}
};