【LeetCode #2 题解】两数相加
一、题目
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
二、笨方法题解(因为存在数据大小局限性,所以提交时报错误)
刚拿到这个问题,第一想法就是这个笨方法,实测结果小没问题,但一旦数据很大时,会出现超出内存,
所以提交 leetcode 时,自然报错。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
int get_list_value(struct ListNode * l)
{
unsigned long long sum = 0, temp=1;
struct ListNode *p = l;
while(p != NULL){
sum = sum + p->val * temp;
p = p->next;
if(p!=NULL)
temp *= 10;
}
return sum;
}
struct ListNode* int_to_list(unsigned long long value)
{
struct ListNode *result=NULL, *end_l=NULL, *temp=NULL;
unsigned long long value_t = value;
while(value_t / 10 > 0){
temp = (struct ListNode *)malloc(sizeof(struct ListNode));
temp->val = value_t % 10;
temp->next= NULL;
value_t = value_t / 10;
if(result == NULL){
result = temp;
}else{
end_l->next = temp;
}
end_l =temp;
}
temp = (struct ListNode *)malloc(sizeof(struct ListNode));
temp->val = value_t % 10;
temp->next= NULL;
if(result == NULL){
result = temp;
}else{
end_l->next = temp;
}
end_l = temp;
return result;
}
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
unsigned long long sum = 0;
struct ListNode *result;
sum = get_list_value(l1) + get_list_value(l2);
return int_to_list(sum);
}
2.1 测试结果(小数据时计算正常)
2.2 测试结果(大数据时计算错误)
继续增大数据,将前面的数据从1 改 为 9,
此时,实际结果就出问题了,并不是正确的answer。
三、正解(无局限性)
详细的解题思路,我都写在注释里了,可以根据代码注释理解下。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* new_ListNode(int val)
{
struct ListNode *new_l = (struct ListNode *)malloc(sizeof(struct ListNode));
new_l->val = val;
new_l->next = NULL;
return new_l;
}
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
struct ListNode *p_l1=l1, *p_l2=l2;
struct ListNode *result=NULL, *temp_l=NULL, *end_l=NULL, *temp_p=NULL;
int val_t=0, advance_flag=0;
// 开始根据链表元素按位相加
// 此时分两种情况:
// 1. L1 和 L2 链表当前节点均不为空,将两数据相加保存到result链表中,同时判断是否要进位
while( (NULL != p_l1) && (NULL != p_l2) ){
// 计算时加上进位标志位
val_t = p_l1->val + p_l2->val + advance_flag;
// 清除进位标志位
advance_flag = 0;
// 如果计算值大于10 ,说明需要进位,设置进位标志位
if(val_t >= 10){
advance_flag = 1;
}
// 将当前值保存到新 list 中
val_t = val_t % 10;
temp_l = new_ListNode(val_t); // 新建一个list 节点
if(NULL == result){ // 头结点
result = temp_l;
}else{
end_l->next = temp_l;
}
end_l = temp_l;
// 开始下一节点判断
p_l1 = p_l1->next;
p_l2 = p_l2->next;
}
// 2. L1 和 L2 中有一项为NULL时,直接保存到result
if( ( (NULL == p_l1) && (NULL != p_l2) ) || ( (NULL != p_l1) && (NULL == p_l2) ) ){
// 得到非空的 listnode
temp_p = (p_l1 != NULL) ? p_l1 : p_l2;
while(temp_p != NULL){
val_t = temp_p->val + advance_flag;
// 清除进位标志位
advance_flag = 0;
// 如果计算值大于10 ,说明需要进位,设置进位标志位
if(val_t >= 10){
advance_flag = 1;
}
// 将当前值保存到新 list 中
val_t = val_t % 10;
temp_l = new_ListNode(val_t); // 新建一个list 节点
if(NULL == result){ // 头结点
result = temp_l;
}else{
end_l->next = temp_l;
}
end_l = temp_l;
// 开始下一节点判断
temp_p = temp_p->next;
}
}
// 3. 跑到这里说明是已经判断到最后一个节点了,此时只需要考虑进位的问题了
if(advance_flag == 1){
temp_l = new_ListNode(advance_flag); // 新建一个list 节点
if(NULL == result){ // 头结点
result = temp_l;
}else{
end_l->next = temp_l;
}
end_l = temp_l;
}
return result;
}
四、提交结果
通过结果看还不错,内存最优,但运行时间并非最优,
五、别人的更优答案
从 leetcode 上看到了有更快的 8 ms,思路一样,但他的代码写的更加简洁
地址:《faster than 98.46% of C》
此处附上,可以学习下
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
struct ListNode *head = NULL;
struct ListNode *curNode = NULL;
//记录上一个节点的和是否有进位
int addNum = 0;
//每个节点当前位的和
int sum = 0;
while (l1!=NULL || l2!=NULL || addNum==1) {
struct ListNode *node = (struct ListNode *)malloc(sizeof(struct ListNode));
node->val = 0;
node->next = NULL;
if (l1!=NULL&&l2!=NULL) {
//两个链表长度都覆盖到的节点
sum = l1->val + l2->val;
sum += addNum;
int val = sum%10;
node->val = val;
l1 = l1->next;
l2 = l2->next;
}else if (l1!=NULL) {
sum = l1->val;
sum += addNum;
int val = sum%10;
node->val = val;
l1 = l1->next;
}else if (l2!=NULL) {
sum = l2->val;
sum += addNum;
int val = sum%10;
node->val = val;
l2 = l2->next;
}else {//两个链表都遍历结束但尾节点相加还有进位
node->val = 1;
addNum = 0;
sum = 0;
}
addNum = sum>=10 ? 1 : 0;
if(head==NULL){
head = node;
}else{
curNode->next = node;
}
curNode = node;
}
return head;
}