题目
给你两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字0之外,这两个数都不会以 0 开头。
示例:
解释:342+465=807
解析
对于这个题目两个链表,各自的链表存储的是相应位上的数据,如示例中个位存储的2,十位存储4,以此类推。也就是说在进行两数相加时取各自对应位置上的元素值即为各位上的数,根据加法规则,取各自对应位置上元素相加即可,并且要注意是否有进位产生。
此题中需要考虑三点,1.相应位置上的数据相加可能会产生进位;2.加完之后的数可向最高位进1,如500+500=1000,两个三位数相加结果为4位数;3.两个相加的数可能不一样长。
考虑到上述三点情况,对应的解决办法为:1.设置一个进位标志carry,carry的值等于两个数对应位的数字相加后除以10,如果carry=1则表示产生了进位,否则carry=0,不产生进位;2.循环各位数字相加结束之后再判断一次carry是否产生高位进位;3.对于两个不一样长的数相加,采取低位对齐,高位补零的方法。
代码解析
代码使用C++语言编写
class Solution
{
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2)
{
//判断两个数如果有一个数为0则直接返回另一个数的链表即可
if (l1->val == 0 || l2->val == 0)
{
if (l1->val == 0)
{
return l2;
}
else
{
return l1;
}
}
int sum(0);
int n1(0), n2(0);
int carry(0);//进位标志
ListNode *head(nullptr), *tail(nullptr);
while (l1 || l2)
{
n1 = l1 ? l1->val : 0;//l1和l2较短的那个数高位补零
n2 = l2 ? l2->val : 0;
sum = n1 + n2 + carry;//每位上的数字等于相应位置对应的数字+低位的进位对10取余
if (!head)//第一次计算时应将链表的首、尾指针指向同一个位置
{
head = tail = new ListNode(sum % 10);
}
else//采用尾插法逐次将高位数字插入链表
{
tail->next = new ListNode(sum % 10);
tail = tail->next;
}
carry = sum / 10;//判断是否产生进位
if (l1)
{
l1 = l1->next;
}
if (l2)
{
l2 = l2->next;
}
}
if (carry > 0)//在循环结束后仍需判断一次是否向最高位产生进位
{
tail->next = new ListNode(carry);
}
return head;
}
};
其余细节
上述代码只是 简单封装了两数相加的方法,想要对代码结果进行测试需要自己手动编写链表的插入和显示方法。在我实现两个代码以后我发现了问题。一开始的插入方法具体实现代码为:
void push_list(ListNode *head, int n)
{
int elem = rand() % 10;;
ListNode *tail;
tail = head;
head->val = elem;
while (n > 1)
{
elem = rand() % 10;
tail->next = new ListNode(elem);
tail = tail->next;
n--;
}
}
但是当我定义两个空链表指针传入函数进行元素插入时发现问题,指针传入后在函数体内可以正常的进行赋值操作并且在函数体内正常的输出,但是在函数体外该链表指针仍旧是空指针。但是指针的方式以及引用的方式传入变量时是对变量地址进行访问,可以带到函数体外的。为什么空指针不行呢。查询汇编原理发现,当传入的指针p指向nullptr时,在函数体内会重新生成一个临时变量p但是函数体内的p和函数体外的p不是同一个变量。因此在函数体内对p指针的更改不会带到函数体外。
解决办法
1.函数传参时使用指向指针的指针
void push_list(ListNode **head, int n)//**head--指向指针的指针
{
int elem = rand() % 10;;
ListNode *tail;
tail = *head = new ListNode;
tail->val = elem;
while (n > 1)
{
elem = rand() % 10;
tail->next = new ListNode(elem);
tail = tail->next;
n--;
}
}
在调用函数时:
ListNode* l1(nullptr);
push_list(&l1, 5);
2.传入的指针进行初始化,分配内存空间
ListNode *l1(nullptr);
l1 = new ListNode;
push_list(l1, 5);
3.将临时变量返回
ListNode* push_list(ListNode *head, int n)
{
int elem = rand() % 10;;
ListNode *tail;
tail = head = ListNode(elem);
head->val = elem;
while (n > 1)
{
elem = rand() % 10;
tail->next = new ListNode(elem);
tail = tail->next;
n--;
}
return head;
}
ListNode *l1(nullptr);
//l1 = new ListNode;
l1 = push_list(l1, 5);