Leetcode 第2题:两数相加

题目描述

给你两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字0之外,这两个数都不会以0开头。

难度:中等

题目链接2. 两数相加 - 力扣(LeetCode)

示例1:

输入:L1=[2,4,3],L2=[5,6,4]
输出:[7,0,8]
解释:342+465=807

示例2:

输入:L1=[0],L2=[0]
输出:[0]

示例3:

输入:L1=[9,9,9,9,9,9,9],L2=[9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

提示:

  • 每个链表中的节点数在范围[1,100]内。
  • 0<=Node.val<=9。
  • 题目数据保证列表表示的数字不含前导零。

解题思路:

方法一:迭代

首先请看如何遍历一个链表,代码框架如下:

while(L1){//从链表头节点开始向后遍历,直到遇到空节点
    printf("%d\n",L1->val);//输出当前节点
    L1=L1->next;//准备遍历下一个节点

}

迭代的思路:初始化答案为一个[NULL链表],每次循环向该链表末尾添加一个节点(保存一个数位)。

循环即遍历链表L1和L2,每次把两个节点值L1.val和L2.val与进位值carry相加,除以10的余数即为当前节点需要保存的数位,除以10的商即为新的进位值。

注意:在首次循环时,无法在一个空节点的末尾添加节点,故创建一个哨兵节点(dummy node),当成初始的[NULL链表]。循环结束后,哨兵节点的下一个节点就是最终要返回的链表头节点。

struct ListNode* createListNode(int val)
{
    struct ListNode* node=(struct ListNode*)malloc(sizeof(struct ListNode));
    node->val = val;
    node->next = NULL;
    return node;
}
struct ListNode* addTwoNumbers(struct ListNode* L1,struct ListNode* L2)
{
    //构造哨兵节点dummy,最后返回dummy.next,以方便处理新链表的头节点
    struct ListNode* dummy = createListNode(0);
    struct ListNode* node = dummy; //node一直会变化(前进)
    int carry = 0;//进位
    
    //只要没走到头的链表或进位不为0就一直前进
    while(L1!=NULL || L2!=NULL || carry!=0)
    {
        //求和,考虑可能有链表走到头
        int sum=(L1!=NULL ? L1->val:0)+(L2!=NULL ? L2->val:0)+carry;
        //在尾部添加节点
        node->next=createListNode(sum%10);
        node = node->next;

        //更新进位,并向两个链表尾部前进
        carry = sum/10;
        if(L1!=NULL) L1=L1->next;
        if(L2!=NULL) L2=L2->next;

    }
    
    struct ListNode* result dummy->next;//保存结果链表的头节点
    free(dummy);//释放哨兵节点的内存
    return result;


}

复杂度分析:

  • 时间复杂度:O(n),其中n为L1长度和L2长度的最大值。
  • 空间复杂度:O(1),返回值不计入。

方法二:模拟

由于输入的两个链表都是逆序存储数字的位数,因此两个链表中同一位置的数字可以直接相加。如果两个链表的长度不同,则可以认为长度短的链表的后面有若干个0。

struct ListNode* addTwoNumbers(struct ListNode* L1,struct ListNode* L2)
{
    struct ListNode* head = NULL,*tail = NULL; //定义头、尾指针都为NULL
    int carry=0;  //初始化进位
    while(L1||L2)
    {
        //定义n1、n2和求和位
        int n1=L1?L1->val:0;
        int n2=L2?L2->val:0;
        int sum=n1+n2+carry;
        //从尾到头,一直遍历到头部截至
        if(!head)
        {
            head = tail = malloc(sizeof(struct ListNode));
            tail->val = sum%10;
            tail->next = NULL;

        }else{
             tail->next = malloc(sizeof(struct ListNode));
             tail->next->val = sum%10;
             tail = tail->next;
             tail->next = NULL;

            }
        carry =sum/10;
        if(L1)  L1=L1->next;
        if(L2)  L2=L2->next;

    }

    //两个数字相加,最后结果有可能会比原来数字的位数多1
    if(carry>0)
    {
        tail->next = malloc(sizeof(struct ListNode));
        tail->next->val=carry;
        tail->next->next=NULL;
    }

}

复杂度分析:

  • 时间复杂度:O(max(m,n)),其中m和n分别为两个了链表的长度。
  • 空间复杂度:O(1)。

方法三:网上简易做法2. 两数相加 - 力扣(LeetCode)

struct ListNode* addTwoNumbers(struct ListNode* L1,struct ListNode* L2)
{
    //创造一个头结点,让头指针dummy指向它
    struct ListNode* dummy = malloc(sizeof(struct ListNode));
    //创造一个指针,让cur指向最后
    struct ListNode* cur = dummy;
    //创造一个进位判断值
    int t=0;
    //循环(L1指向非空或L2指向非空或进位值非空)就执行
    while(L1 || L2 || t)
    {
        //如果L1指向非空,则将L1的值加到t上,L1指向L1的下一个结点。
        if(L1) t=t+L1->val,L1=L1->next;
        if(L2) t=t+L2->val,L2=L2->next;
        //创造一个结点并赋值。本来没想给新结点的next赋值,可是报错啊,
        //如果不赋值就是野指针
         cur->next = malloc(sizeof(struct ListNode)); 
         cur->next->val = t%10;
         cur->next->next = NULL;
        //cur指向下一个,也就是cur指向了新结点
         cur = cur->next;
         t=t/10; 
    }
       
    return dummy->next;
    
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值