leetcode第二题C++(自己的思考过程)

题目:

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

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

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

示例 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
  • 题目数据保证列表表示的数字不含前导零

我的思路:

1.可以观察到两个链表的插入方式为头插法,因此在计算的时候先遍历的就是低位,因此可以通过使用一个累加器sum和进位信息来记录。

2.要先将两个链表进行处理,因为两个链表的长度不同,遍历的时候会出现空节点想现象,出现空节点val值就要用0来代替。

3.将最后得到的sum转换成字符串,按照数组存储的位置使用头插法插入最后的链表即可。

以下是我的代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
       int l1Sum = 0,l2Sum = 0,Sum = 0;
        ListNode *p1 = l1;
        ListNode *p2 = l2;
        ListNode *head=new ListNode();
        int x =1;//用来进行对十进制数据进行前移一位操作
        while(p1!=NULL||p2!=NULL){
            if(p1==NULL)l1Sum = 0;//用来解决链表长度不一的问题
            else  l1Sum = p1->val;

            if(p2==NULL)l2Sum = 0;
            else  l2Sum = p2->val;

            Sum+=(l1Sum+l2Sum)*x;
            x *=10;//每计算一位要乘以10

            if(p1!=NULL) p1=p1->next;
            if(p2!=NULL) p2=p2->next;
        }

        string ss = to_string(Sum);//将Sum转换成字符串方便进行操作
        int len = ss.length();
        for(int i = 0;i<len;i++){
           ListNode *p3=new ListNode(ss[i]-'0');
           p3->next = head -> next;//进行头插法
           head->next = p3;
        }
        return head->next;
    }
};

很明显里面有一个致命的错误,int所能表示的数据太有限了,数据样本中存在大量的大数。

解决办法:

        我的第一想法是使用long long 来更换数据格式,但是这所能表示的数据范围依然有限。故想到了根据IEEE745,浮点数所表示的范围是非常大的大致范围为-2^1024 ~ +2^1024(-1.79E+308 ~ +1.79E+308),由于这里只涉及整数的计算,不会涉及到精度问题,所以感觉应该是一个不错的解决方法,开始进行实践。

一次修改的代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        double l1Sum = 0,l2Sum = 0,Sum = 0;
        ListNode *p1 = l1;
        ListNode *p2 = l2;
        ListNode *head=new ListNode();
        double x =1;//用来进行对十进制数据进行前移一位操作
        while(p1!=NULL||p2!=NULL){
            if(p1==NULL)l1Sum = 0;//用来解决链表长度不一的问题
            else  l1Sum = p1->val;

            if(p2==NULL)l2Sum = 0;
            else  l2Sum = p2->val;

            Sum+=(l1Sum+l2Sum)*x;
            x *=10;//每计算一位要乘以10
            if(p1!=NULL)p1=p1->next;
            if(p2!=NULL)p2=p2->next;
        }

        string ss = to_string(Sum);//将Sum转换成字符串方便进行操作
        int len = ss.length();
        for(int i = 0;ss[i]-'0'!=-2;i++){//ss[i]-'0'!=-2是为了解决转换成字符串小数点问题,.所对应的ASCII在0上面前两个位置
           ListNode *p3=new ListNode(ss[i]-'0');
           p3->next = head -> next;//进行头插法
           head->next = p3;
        }
        return head->next;
    }
};

可是还是存在问题:

已经通过了绝大部分的用例了,还是有三个精度不够。只能考虑将每一个数字分开计算了。

再次修改

        看来这种累加的方法是行不通了,要换个思路考虑数字加法的本质了。加法的本质无非也就是大于等于10的时候进位为1,小于等于10的时候进位为0,只有这两种情况,因此只需要将两个节点数值相加保留尾数,使用尾插法插入到新链表中,进位信息保留到下一次加法中即可。这么一想,这道题就变的十分简单了。

最终代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        int l1Sum = 0,l2Sum = 0,Sum = 0 ,carry = 0;;
        ListNode *p1 = l1;
        ListNode *p2 = l2;
        ListNode *head=new ListNode();
        ListNode *p3 = new ListNode();
        p3 = head;
        while(p1!=NULL||p2!=NULL){
            if(p1==NULL)l1Sum = 0;
            else  l1Sum = p1->val;

            if(p2==NULL)l2Sum = 0;
            else  l2Sum = p2->val;

            Sum=l1Sum+l2Sum+carry;

            if(Sum >=10){
                carry = Sum / 10;//保留相加后的进位信息
                Sum = Sum % 10;//保留相加后的尾数
            }
            else carry = 0;  

            ListNode *p4=new ListNode(Sum);//使用尾插法进行插入
            p3->next= p4;
            p3 = p3->next;
            if(p1!=NULL)p1=p1->next;
            if(p2!=NULL)p2=p2->next;
        }
        if(carry==1){//由于最后相加的长度可能超过最长的链表,因此需要通过进位信息来检查是否需要向高位进1
            ListNode *p4=new ListNode(1);
            p3->next= p4;
            p3 = p3->next;
        }
        return head->next;
    }
};

总结:

        这道题主要考察的是对加法本质的理解以及对链表的一些基础操作,收获到经验教训为在做题的时候不要只想着表象,要从更深刻的角度去理解,不要机械的把一些工作粗暴的交给计算机去做,就比如之前我进行的多次累加,这源于对加法操作的理解不深刻,追求本质会让问题变的更加简单。

        我是小田,加油每一天!!!!大家也要加油呦!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值