• leetcode速度才是王道 2. Add Two Numbers


    2. Add Two Numbers

    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

      题目的意思是将两个非负数放到两个链表list1和list2,链表的存储方式是高位在右低位在左(类似小端模式存储,这样的效果是往右边进位),而且每个节点都只能饿保存一位数。然后需要设计一个算法将两个非负数相加,将结果以之前规则的链表形式返回。题目很直接,没有啥让人疑惑的地方,下面开始第一次尝试:

      为了减少内存的分配次数,最开始的想法是先求出两个链表的长度,使用长的来保存计算出来的结果,如果最后有进位的话只需要重新分配一个节点的内存。代码如下:

     1 struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
     2     struct ListNode *head, *p, *res = l1;
     3     struct ListNode *q, *tmp = l2;
     4     
     5     int l1Length = 0;
     6     int l2Length = 0;
     7     p = l1;
     8     q = l2;
     9     while(1)
    10     {
    11         if(l1)
    12         {
    13             l1 = l1->next;
    14             l1Length++;
    15         }
    16         if(l2)
    17         {
    18             l2 = l2->next;
    19             l2Length++;
    20         }
    21         if(!(l1 || l2))
    22             break;
    23         if( !(l1Length == l2Length))
    24             break;
    25     }
    26     if(l2Length > l1Length)
    27     {
    28         res = q;
    29         tmp = p;
    30     }
    31     
    32     head = res;
    33     
    34     int carry = 0;
    35     p = res;
    36     while(1)
    37     {
    38         if(tmp)
    39         {
    40             res->val += tmp->val + carry;
    41             carry = res->val / 10;
    42             res->val = res->val % 10;
    43             
    44             p = res;
    45             res = res->next;
    46             tmp = tmp->next;
    47         }
    48         else
    49         {
    50             if(res)
    51             {
    52                 res->val += carry;
    53                 carry = res->val / 10;
    54                 res->val = res->val % 10;
    55                 p = res;
    56                 res = res->next;
    57             }
    58             else if(carry)
    59             {
    60                 struct ListNode *cur = (struct ListNode*)malloc(sizeof(struct ListNode));
    61                 cur->val = carry;
    62                 cur->next = NULL;
    63                 p->next = cur;
    64                 return head;
    65             }
    66             else
    67                 return head;
    68         }
    69     }
    70     return NULL;
    71 }

    代码中用res指针来指向长的那个链表,作为保存结果的链表,用carry来记录是否进位,运行的结果是:

    Runtime: 20 ms  这个与最快的16ms还有差距的,于是开始了第二次尝试

      第二次尝试的方向删除比较两个链表长度的部分,因为两个链表节点都是相同类型,所以我们可以任意拼接。 代码如下:

     1 struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
     2     struct ListNode head, *p;  
     3     p = &head;
     4     
     5     int carry = 0;
     6 
     7     while(1)
     8     {
     9         if(l1 && l2)
    10         {
    11             l1->val += (l2->val + carry);
    12             carry = l1->val / 10;
    13             l1->val = l1->val % 10;
    14 
    15             p->next = l1;
    16             p = l1;
    17         
    18             l1 = l1->next;
    19             l2 = l2->next;
    20         }
    21         else if(l1)
    22         {
    23             l1->val += carry;
    24             carry = l1->val / 10;
    25             l1->val = l1->val % 10;
    26             
    27             p->next = l1;
    28             p = l1;
    29             
    30             l1 = l1->next;
    31         }
    32         else if(l2)
    33         {
    34             l2->val += carry;
    35             carry = l2->val / 10;
    36             l2->val = l2->val % 10;
    37             
    38             p->next = l2;
    39             p = l2;
    40             
    41             l2 = l2->next;
    42         }
    43         else if(carry)
    44         {
    45             struct ListNode *cur = (struct ListNode*)malloc(sizeof(struct ListNode));
    46             cur->val = 1;
    47             cur->next = NULL;
    48             p->next = cur;
    49             return head.next;
    50         }
    51         else
    52             return head.next;
    53     }
    54     return NULL;
    55 }

      需要注意的是因为我们并不知道哪一个该作为保存结果的list,为了保证wihle循环里的一致性,这个地方的我们先定义一个ListNode的实例head,然后定义一个指向head的指针p,这样while循环里每次得到一个节点都放到p节点后面,然后将该节点的地址赋值给p就行了,使用p来记录result链表的走向,最后返回的head.next就能返回正确结果,运行的结果是:

    Runtime: 20 ms 速度竟然没有任何改变!!! 看来比较两个链表长度的操作并没有怎麽耗时,好吧,只能再从别的角度突破了

      第三次的尝试方向是再次是否还能继续较少内存,因为list2链表里的内存是等着释放的,所以完全可以使用来存储进位,也就是最后将list1和list2合并成了一个链表,用list2的头结点来保存进位,这样完全可以不用分配内存。代码如下

     1 struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
     2     struct ListNode head, *p, *end;  
     3     p = &head;
     4     end = NULL;
     5     
     6     int carry = 0;
     7 
     8     while(1)
     9     {
    10         if(l1 && l2)
    11         {
    12             l1->val += (l2->val + carry);
    13             carry = l1->val / 10;
    14             l1->val = l1->val % 10;
    15 
    16             p->next = l1;
    17             p = p->next;
    18             l1 = l1->next;
    19             !end && (end = l2);
    20             l2 = l2->next;
    21         }
    22         else if(l1)
    23         {
    24             l1->val += carry;
    25             carry = l1->val / 10;
    26             l1->val = l1->val % 10;
    27             
    28             p->next = l1;
    29             p = p->next;
    30             l1 = l1->next;
    31         }
    32         else if(l2)
    33         {
    34             l2->val += carry;
    35             carry = l2->val / 10;
    36             l2->val = l2->val % 10;
    37             
    38             p->next = l2;
    39             p = l2;
    40             
    41             l2 = l2->next;
    42         }
    43         else if(carry)
    44         {
    45             if( !end )
    46             {
    47                 end = (struct ListNode*)malloc(sizeof(struct ListNode));
    48             }
    49             end->val = 1;
    50             end->next = NULL;
    51             p->next = end;
    52             return head.next;
    53         }
    54         else
    55             return head.next;
    56     }
    57     return NULL;
    58 }

      代码中定义了一个指向end的指针,在代码19行将链表2的头结点地址赋值给了end,48~51行表示如果有进位,那麽使用end所指向的list2头结点来保存进位,并加在result结点后面,这样不用分配内存了,运行结果是:

     Runtime: 16 ms     终于达到了最快的速度 !!!有图有真相,You are here !

  • 相关阅读:
    Http协议(一)基础知识
    Redis问题汇总
    Sql Server存储过程传递XML参数
    C# Redis
    Task的异常捕获和处理方法
    Entity Framework教程
    WebBrowser 弹窗体关闭原理
    C# 虹软SDK视频人脸识别和注册
    C#性能优化:延迟初始化Lazy
    DZ 特殊主题简单开发教程
  • 原文地址:https://www.cnblogs.com/JeroZeng/p/4668784.html
Copyright © 2020-2023  润新知