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)的分析~

原文地址:https://www.cnblogs.com/magicy/p/5313778.html