题意分析
给出两个链表,这两个链表代表两个数字(注意,这个数字可能很大,大数),从表头到表尾表示的是这个链表的高位到低位。需要我们将这两个链表的数字进行相加,然后构造一个新的链表表示出这个和。
样例解释请看下面的图
思路分析
- 首先,我们可以看到这个题目的本质就是一个大数加法运算,两个链表存储的数字的长度很长,需要先将这两个链表代表的数字相加,然后构造出一个新的链表存储这个和。首先,我们看大数加法运算,这个可以用字符串表示这两个数字,然后模拟大数加法的操作。最后构造出一个新的链表即可。
- 这里大数高精度运算是核心,但是思路比较简单,就是按照我们小学的时候进行加法运算的操作进行处理就行了。从低位开始进行运算,记录下进位和当前位置的数字,最后就可以得到大数相加的和了。另外一点要注意的就是如果两个数字的位数不一样,最好还是先通过前面补0使两个数字的位数相同。这样便于我们进行操作。
解法一 字符串版
- 这种写法是利用字符串存储两个数字进行处理,比较常规的做法。
- 代码如下
- 需要遍历两个链表,时间复杂度为O(lena+lenb)
- 需要存储两个链表,空间复杂度为O(lena+lenb)
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: /** * * @param head1 ListNode类 * @param head2 ListNode类 * @return ListNode类 */ ListNode* addInList(ListNode* head1, ListNode* head2) { // write code here string a,b; // 先将两个链表里面的数据分别存入两个字符串 while(head1){ a+=(head1->val+'0'); head1=head1->next; } while(head2){ b+=(head2->val+'0'); head2=head2->next; } int lena=a.size(); int lenb=b.size(); // 如果两个字符串的长度不相同,在短的那一个字符串的前面补0 while(lena<lenb){ lena++; a="0"+a; } while(lenb<lena){ lenb++; b="0"+b; } int cnt=0; vector<int> ans; int x=lenb-1; // 模拟进行大数加法运算 while(x>=0){ int tmp=a[x]-'0'+b[x]-'0'+cnt; cnt=tmp/10; tmp%=10; ans.push_back(tmp); x--; } // 注意最后的进位 if(cnt){ ans.push_back(cnt); } // for(auto y:ans){ // std::cout<<y<<endl; // } x=lenb-1; ListNode* now=new ListNode(ans[x--]); ListNode* head=now; // 构建一个新的链表 while(x>=0){ ListNode* now1 = new ListNode(ans[x--]); now->next=now1; now=now1; } return head; } };
解法二 用栈模拟
- 这个写法是利用栈的先进后出的性质,如下
我们遍历链表的时候,发现低位反倒是最后遍历的,如果使用栈的话,我们发现我们取的时候正好是低位,那么可以直接取栈顶进行操作。然后最后的结果我们发现高位也是最后得到的,而我们构造链表的时候恰好就是先用高位构造,这不也是我们想要的吗?所以这个题目用栈是最方便的,不要在进行顺序的变换。
代码如下
- 需要遍历两个链表,时间复杂度为O(lena+lenb)
- 需要存储两个链表,空间复杂度为O(lena+lenb)
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: /** * * @param head1 ListNode类 * @param head2 ListNode类 * @return ListNode类 */ ListNode* addInList(ListNode* head1, ListNode* head2) { // write code here stack<int> a,b; // 利用两个栈来存储这两个链表的值 while(head1){ a.push(head1->val); head1=head1->next; } while(head2){ b.push(head2->val); head2=head2->next; } int cnt=0; stack<int> ans; // 不断遍历两个链表,模拟大数加法运算 while(!a.empty()||!b.empty()){ int tmp=0; // 注意如果栈为空的时候不能遍历再执行出栈操作 if(!a.empty()){ tmp+=a.top(); a.pop(); } if(!b.empty()){ tmp+=b.top(); b.pop(); } tmp+=cnt; cnt=tmp/10; tmp%=10; ans.push(tmp); } // 最后存在进位操作 if(cnt){ ans.push(cnt); } ListNode* now=new ListNode(ans.top()); ListNode* head=now; ans.pop(); // 重建这个链表 while(!ans.empty()){ ListNode* now1=new ListNode(ans.top()); ans.pop(); now->next=now1; now=now1; } return head; } };