zoukankan      html  css  js  c++  java
  • 2. Add Two Numbers

    昨天小试牛刀,做了一下第二题,感觉还不错,但是做完之后再看到别人的代码之后,就只剩下震惊于心塞了

    文章目录如下

    (1)自己的思路

    (2)自己的代码

    (3)别人的思路

    (4)别人的代码

    (5)对比自己的不足之处

    题目如下

    You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

    Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
    Output: 7 -> 0 -> 8

    Subscribe to see which companies asked this question

    (1)自己的思路

    a.拿到这道题,首先我想到的是进位的问题,例如上面所给的例子(2 -> 4 -> 3) + (5 -> 6 -> 4)中间的4+6=10,这样的话就得往前进一位,同时该位的数字还要减去10。如何让程序知道什么时候进位呢?可以通过各bool变量flag来表示,当某一位大于10时,那么设置flag为true,否则为false。

    b.第二个想到的是,如果是两个数的位数不一样该怎么办呢?例如(2 -> 4 ) + (5 -> 6 -> 4),这样的话得判断那个加数的位数要小一些,然后相加完之后,只需要把位数多的加数的剩余位直接赋值给目标就可以了,由于加数都存放在链表中,所以可以通过判断链表的长度(即尾指针是否为null来解决),下面代码片段展示了当l1的位数比l2小时候的情况,其中l3为目标链表(保存结果的链表),其中下面的代码也考虑到了位数增加的这种情况,例如(2) + (8 ->9)=(0->0->1),结果比两个加数的位数还要多一位。我的解决思路是,将多出的那一位添加到位数长的那个加数上去,然后在下一轮循环的时候,赋值给目标链表

    //l1为空
                    if (l1 == NULL)
                        //判断前一位是否大于10
                        if (flag)
                        {
                            l3->val = l2->val + 1;    
                            if (l3->val >= 10)
                            {
                                l3->val = l3->val - 10;
                                
                                //如果满10进一之后,l2没有更高的位了,那么要重新申请一个位
                                if (l2 == NULL)
                                    l2 = new ListNode(1);
                                //要在continue之前就执行l2 = l2->next;因为如果在60行再执行该操作的话,那么永远都不会执行这句话,以为continue会直接返回循环
                                l2 = l2->next;
                                flag = true;
                                continue;
                            }
                            else
                            {
                                flag = false;
                                l2 = l2->next;
                                continue;
                            }
                            
                        }
                        //前一位小于10,那么直接将L2上的值复制给l3即可
                        else
                        {
                            l3->val = l2->val;
                            flag = false;
                            l2 = l2->next;
                            continue;
                        }

    c.第三点是关于合适终止的问题,我觉得终止应该由两个加数的长度来决定,更精确的来讲因该是有长度长的那个加数的长度来决定,由于原始加数l1与l2的长度已经固定,无法考虑到b中所说的位数增加的那种情况(2) + (8 ->9)=(0->0->1),所以在判断条件中,还应该添加flag变量,因为当flag==true的时候,意味着有进位要处理

    所以代码结构如下

    class Solution {
    public:
        ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) 
        {
            //判断是否大于10
            bool flag = false;
            ListNode *l3 = new ListNode(0);
            ListNode *head = l3;
            while (l1!=NULL | l2!=NULL | flag)
            {
                if (l3->next == NULL)
                {
                    l3->next = new ListNode(0);
                    l3 = l3->next;
                }
    
                //首先判断l1、l2之一是否为空
               ...//接下来处理l1,l2都不为空的情况
           ...

          } return head->next; } };

    d.正常的情况(l1,l2都不为空的情况)就是那种最普通的相加,即l1,l2位数一致,在相加的过程中没有进位运算,这样的话只需要将对应位的值相加并将结果赋值给l3对应的元素即可。

    所以完整代码如下:

    (2)自己的代码

    class Solution {
    public:
        ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) 
        {
            //判断是否大于10
            bool flag = false;
            ListNode *l3 = new ListNode(0);
            ListNode *head = l3;
            while (l1!=NULL | l2!=NULL | flag)
            {
                if (l3->next == NULL)
                {
                    l3->next = new ListNode(0);
                    l3 = l3->next;
                }
    
                //首先判断l1、l2之一是否为空
                if (l1 == NULL | l2 == NULL)
                {    
    
                    if(l1==NULL&&l2==NULL)
                    {
                        l3->val = 1;
                        flag = false;
                        break;
                    }
    
                    //l1为空
                    if (l1 == NULL)
                        //判断前一位是否大于10
                        if (flag)
                        {
                            l3->val = l2->val + 1;    
                            if (l3->val >= 10)
                            {
                                l3->val = l3->val - 10;
                                
                                //如果满10进一之后,l2没有更高的位了,那么要重新申请一个位
                                if (l2 == NULL)
                                    l2 = new ListNode(1);
                                //要在continue之前就执行l2 = l2->next;因为如果在60行再执行该操作的话,那么永远都不会执行这句话,以为continue会直接返回循环
                                l2 = l2->next;
                                flag = true;
                                continue;
                            }
                            else
                            {
                                flag = false;
                                l2 = l2->next;
                                continue;
                            }
                            
                        }
                        //前一位小于10,那么直接将L2上的值复制给l3即可
                        else
                        {
                            l3->val = l2->val;
                            flag = false;
                            l2 = l2->next;
                            continue;
                        }
                    //l2为空,与l1为空处理类似
                    else
                        //判断前一位是否大于10
                        if (flag)
                        {
                            l3->val = l1->val + 1;
                            if (l3->val >= 10)
                            {
                                l3->val = l3->val - 10;
                                
                                //如果满10进一之后,l2没有更高的位了,那么要重新申请一个位
                                if (l1 == NULL)
                                    l1 = new ListNode(1);
                                flag = true;
                                l1 = l1->next;
                                continue;
                            }
                            else
                            {
                                flag = false;
                                l1 = l1->next;
                                continue;
                            }
                            
                        }
                    //前一位小于10,那么直接将L2上的值复制给l3即可
                        else
                        {
                            l3->val = l1->val;
                            l1 = l1->next;
                            flag = false;
                            continue;
                        };
                }
    
    
    
                //接下来处理l1,l2都不为空的情况
    
                int tmp1 = l1->val;
                int tmp2 = l2->val;
                int tmp3 = 0;
        
                if (flag)
                {
                    tmp3 = tmp1 + tmp2 + 1;
                }
                else
                {
                    tmp3 = tmp1 + tmp2;
                }
    
                //判断tmp3是否大于10
                if (tmp3 >= 10)
                {
                    tmp3 = tmp3 - 10;
                    flag = true;
                }
                else
                    flag = false;
    
                l3->val = tmp3;
                l2 = l2->next;
                l1 = l1->next;
            }
    
            return head->next;
        }
    };

    写了100多行,调试成功之后,还没来得及高兴,就被更好地代码打懵逼了……

    给出更好地代码思路

    (3)别人的思路

    a.因为这是两个数的相加,所以即使是进位,最多也只能往高位进1,那么可以用单独的一个变量carry来保存这个进位,不管有没有进位,在运算的过程中一直保持着l3->val = l1->val + l2->val + carry;如果有进位,那么让carry=1,如果没有,让carry=0.这样的好处是不管有没有进位,都可以进行统一的操作,而不用像我那样分类来讨论。这样的话便可以极大地减少了代码量

    (4)别人的代码

    class Solution {
    public:
        ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
            ListNode dummy(-1); // 头节点
            int carry = 0;
            ListNode *prev = &dummy;
            for (ListNode *pa = l1, *pb = l2;
            pa != nullptr || pb != nullptr;
                pa = pa == nullptr ? nullptr : pa->next,
                pb = pb == nullptr ? nullptr : pb->next,
                prev = prev->next) 
            {
                const int ai = pa == nullptr ? 0 : pa->val;
                const int bi = pb == nullptr ? 0 : pb->val;
                const int value = (ai + bi + carry) % 10;
                carry = (ai + bi + carry) / 10;
                prev->next = new ListNode(value); // 尾插法
            }
            if (carry > 0)
                prev->next = new ListNode(carry);
            return dummy.next;
        }
    };

    (5)对比自己的不足之处

    见(3)的分析~

  • 相关阅读:
    【下一代核心技术DevOps】:(三)私有代码库阿里云Git使用
    【下一代核心技术DevOps】:(二)Rancher的应用及优点简介
    【下一代核心技术DevOps】:(一)容器服务的Rancher选型
    微服务时代之2017年五军之战:Net PHP谁先死
    Jackrabbit 文件上传下载
    eclipse闪退
    SDE For SQLServer配置说明
    RegexBuddy图文使用教程
    Eclipse闪退/打不开/无法启动/一闪而过打解决方法
    如何在window上把你的项目提交到github
  • 原文地址:https://www.cnblogs.com/magicy/p/5313778.html
Copyright © 2011-2022 走看看