码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-07-22 22:40:11      阅读:119      评论:0      收藏:0      [点我收藏+]

标签:

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 !技术分享

 

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

标签:

原文地址:http://www.cnblogs.com/JeroZeng/p/4668784.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!