【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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章