zoukankan      html  css  js  c++  java
  • 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 !

  • 相关阅读:
    hiveserver2 with kerberos authentication
    python Basic usage
    python Quicksort demo
    Python HeapSort
    mrunit for wordcount demo
    CCDH证书
    Hadoop question list
    Hadoop Yarn core concepts
    Hadoop Resource
    Hadoop could not find or load main class
  • 原文地址:https://www.cnblogs.com/JeroZeng/p/4668784.html
Copyright © 2011-2022 走看看