第二道题,就是理解一下链表就解决了,题目如下:
You are given two non-empty linked lists representing two non-negative integers. 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.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
For example:
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
大致意思是,输入给出两个链表来代表两个非负的整数,不过这个整数是按照倒序来表示的,简单的说就是2->4->3实际上代表的是整数342,就是这样的两个整数,最后要得到这两个链表所代表整数的和,结果也按照链表的形式返回。
首先要考虑的几种情况:
1)两个链表可能不一定一样长
2)最后可能存在一个进位
3)两个链表刚好一样长
一开始的时候我本来想把这两个数拿出来,反一下,按照整数的加减法来做的,结果测试集中肯定会存在超过int范围的数存在,果然不行,所以只能一位一位的循环来加。
在使用C++来写的时候:
已经给出定义节点的结构体如下
1 /** 2 * Definition for singly-linked list. 3 * struct ListNode { 4 * int val; 5 * ListNode *next; 6 * ListNode(int x) : val(x), next(NULL) {} 7 * }; 8 */
也就是只需要挨个访问链表的元素,对应位上的数进行求和,计算进位,结合上面的三种情扩,最后就能得到结果,C++的代码如下
1 class Solution { 2 public: 3 ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { 4 int carry=0; 5 ListNode *result=new ListNode(0); 6 ListNode *pointer=result; 7 while(l1!=NULL||l2!=NULL||carry){ 8 int sum=0; 9 if(l1!=NULL){ 10 sum=sum+l1->val; 11 l1=l1->next; 12 } 13 if(l2!=NULL){ 14 sum=sum+l2->val; 15 l2=l2->next; 16 } 17 if(carry==1){ 18 sum=sum+1; 19 } 20 pointer->next=new ListNode(sum%10); 21 carry=sum/10; 22 pointer=pointer->next; 23 } 24 ListNode* res=result->next; 25 delete result; 26 return res; 27 } 28 };
由于效率不是最好的,我想了想有没有别的提高效率的方法,参考discussion,也可以这样解决,使用下面的方法,可以不用从头开始一个一个的插入元素节点,直接让l1,l2的其中一个变成最后的结果链表:
1 class Solution { 2 public: 3 ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { 4 int carry=0; 5 ListNode *result=l1; 6 while(l1!=NULL){ 7 int sum=l1->val+carry; 8 if(l2!=NULL){ 9 sum=sum+l2->val; 10 l2=l2->next; 11 } 12 if(l1->next==NULL&&l2!=NULL){ 13 l1->next=l2; 14 l2=NULL; 15 } 16 l1->val=sum%10; 17 carry=sum/10; 18 19 if(l1->next==NULL&&carry){ 20 ListNode *tmp=new ListNode(1); 21 l1->next=tmp; 22 carry=0; 23 } 24 25 l1=l1->next; 26 } 27 return result; 28 } 29 };
这个主要有一个点就是在链表l1比链表l2短的时候,需要把原来指向l1链表的指针指向l2链表使得while循环继续下去。
不过效率也没有改善多少。
同理,使用javascript中也事先定义了节点
1 /** 2 * Definition for singly-linked list. 3 * function ListNode(val) { 4 * this.val = val; 5 * this.next = null; 6 * } 7 */ 8 /**
在这里ListNode是作为一个函数存在的,一样的方法,使用javascript的写法如下:
1 var addTwoNumbers = function(l1, l2) { 2 var result=new ListNode(0); 3 var pointer=result; 4 var carry=0; 5 while(l1!==null||l2!==null||carry){ 6 var sum=0; 7 if(l1!==null){ 8 sum=sum+l1.val; 9 l1=l1.next; 10 } 11 if(l2!==null){ 12 sum=sum+l2.val; 13 l2=l2.next; 14 } 15 if(carry){ 16 sum=sum+1; 17 } 18 var tmp=new ListNode(sum%10); 19 carry=parseInt(sum/10); 20 pointer.next=tmp; 21 pointer=pointer.next; 22 } 23 return result.next; 24 };
总结使用到的C++知识点:
主要就是对链表进行操作,最最主要的是在链表中插入元素,
初始化一个ListNode类型的指针,ListNode *result=new ListNode(0);
pointer表示和result指向同一个地址空间的指针(都在链表头),每次新增元素赋给pointer->next,同时让pointer指向链表的下一个元素,这样直到最后返回链表头的下一个指针result->next(去掉初始化的那个),就是最终的结果。
最后其实有一个操作,就是把result->next赋给一个新的ListNode类型的指针,直接返回新赋值的指针就行了,这样要记得刚开始分配的result指针的内存空间应该使用delete进行释放(这样做实际上是会提高效率的)
在最后存在一个进位的情况,就需要new一个新的节点,并把这个新的节点加到返回链表的最后,假设当前pointer指向的链表的末尾,tmp节点是新的要加入的节点,这时候只需要tmp->next=result->next;result-next=tmp;即可,一般在链表的中间插入节点也可以用上面的方法。
总结使用到的javascript知识点:
由于javascript没有支持指针,节点listNode被定义为一个function,function作为object的一种,当然可以使用new来进行初始化,这样调用了function的内部属性this,表示当前执行函数的环境对象来初始化节点进行赋值操作。