力扣2. 两数相加

题目描述

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

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

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
在这里插入图片描述
图片和题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-two-numbers

解题思路

两个数字,通过链表存储每个数字,以倒序的方式存储,这样做的好处是,倒序直接相加即可,只需要考虑进位就行。如果说链表存储的是两个正序的数字,而且是单链表,反而会更难处理。首先可以想到的思路是,每个数字相加,求和之后,需要考虑前面是否有进位。而且,还要考虑当前相加是否会给后面带来进位。代码写的不是很好,因为链表的知识都快忘得差不多了。有些地方可能会有冗余操作,浪费时间。虽然结果正确,但是,通过leetcode调试之后,才改成这版代码。正确步骤应该是你的思路就是正确,然后在写代码,不能有逻辑问题。while循环结束的条件,是l1和l2不为空,而不是l1->next和l2->next不为空,不能漏掉尾节点的数值。当l1和l2有一个为空,就应该停止,继续对剩下一个不为空的继续求和。
我一般在做链表题的时候都会画出链表的图,这样方便理解和写代码。但是有人可能不需要。

代码实现

1.这是第一版代码,写的不是很好,内存占用率很好,而且速度也不是很快。优化的地方肯定有很多,冗余也有很多。“小白的痛苦”

ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    //头结点需要单独处理,因为头结点和其他节点的操作不同,逆置链表原来的头结点相当于尾节点,next为null
    //头结点是链表指向的真实节点,但数据值是空的,这样做的好处是while循环中没有额外的操作。
    //l3首先指向头结点,记录当前的尾节点。尾插法
    ListNode* l3 = new ListNode(-1, NULL);
    ListNode *tail = l3;
    //数字相加,需要考虑进位
    int carry = 0;

    while(l1 != NULL && l2 != NULL) {
        //printf("1");
        int itemp = l1->val + l2->val + carry;

        //printf("%d ", itemp);
        if(itemp >= 10) {
            carry = 1;
            itemp -= 10;
        } else {
            carry = 0;
        }

        ListNode *temp = new ListNode(itemp, NULL);
        tail->next = temp;
        tail = tail->next;
        l1 = l1->next;
        l2 = l2->next;
    }

    // carry是来自之前的进位
    while(l1 != NULL) {
        int itemp = l1->val + carry;

        if(itemp >= 10) {
            carry = 1;
            itemp -= 10;
        } else {
            carry = 0;
        }

        ListNode *temp = new ListNode(itemp, NULL);
        tail->next = temp;
        tail = tail->next;
        l1 = l1->next;
    }

    while(l2 != NULL) {
        int itemp = l2->val + carry;

        if(itemp >= 10) {
            carry = 1;
            itemp -= 10;
        } else {
            carry = 0;
        }

        ListNode *temp = new ListNode(itemp, NULL);
        tail->next = temp;
        tail = tail->next;
        l2 = l2->next;
    }

    // l1和l2都已经为null,但是最后一个尾节点还有进位,则需要在新建一个节点。
    if(carry == 1) {
        ListNode *temp = new ListNode(1, NULL);
        tail->next = temp;
    }

    //当前l3指向头结点,找到第一个节点,抛弃头结点。
    return l3->next;
}

2.第一版本的优化,其实都是leetcode官方题解,我只是复制过来了可参考上面的来源链接找到详细内容。
步骤1.判断l1和l2是否null,不为空取出数值相加,否则数值为0
步骤2.相加的时候考虑上一个是否有进位,是否对下次产生进位。
步骤3.建立节点,尾节点向后移动一个
步骤4.判断l1和l2是否为空,不为空向后移动一个。
步骤5.是否有进位,有进位需要建立值为1的元素。

ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    ListNode* l3 = new ListNode(-1, NULL);
    ListNode *tail = l3;
    int carry = 0;

    while(l1 || l2) {
        int n1 = l1 ? l1->val : 0;
        int n2 = l2 ? l2->val : 0;
        int n3 = n1 + n2 + carry;
        carry = n3 / 10;    //先求出下一次是否进位,进位是为下次准备的
        n3 = n3 % 10;      //模余
        tail->next = new ListNode(n3);
        tail = tail -> next;

        if(l1) {
            l1 = l1->next;
        }

        if(l2) {
            l2 = l2->next;
        }
    }

    if(carry == 1) {
        tail->next = new ListNode(1);
    }

    return l3->next;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值