1. 题目描述
You are given two non-empty linked lists representing two non-negative integers. The most significant digit comes first 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.
2. Follow Up
What if you cannot modify the input lists? In other words, reversing the lists is not allowed.
3. 样例
Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 8 -> 0 -> 7
4. 分析
这道题表面上看起来很好理解:即给出了A、B两个链表,我们需要做的事情是将两个链表的对应节点元素相加,得到一个新的链表。但是笔者在做这道题整整花了3个小时!因为最开始努力全部用链表来解,失败了,最后不得不转向熟悉的vector。
分析一下:由于给出的两个链表相加,我们的计算方式都是从低位向高位相加计算的,那么找到两个链表的最低位就成了做这道题的关键步骤:给定的是单向链表,我们没办法很容易的从链表尾开始遍历提取节点存储的数,那么将链表逆置成为了解题思路。虽然题目中follow up提出不要逆置原链表,于是我们用vector将原链表的数值存储起来算作打擦边球吧。
我们用两个vector得到了原来的逆向存储的链表,接下来的事情就容易很多了,每一位对应相加,注意考虑进位的问题,因此要有模10得到这一位的最终数值以及相似的方法求取每一位的进位。需要格外注意的是边界问题的处理:
Example1:
Input: (5) + (5)
Output: (1 -> 0)而非(0)
Example2:
Input: (1) + (9 -> 9)
Output: (1 - > 0 -> 0)而非(10 -> 0)
5. 源码(vector版本通过)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
vector<int> getList(ListNode* h) {
vector<int> L;
int value;
while(h) {
value = h->val;
L.push_back(value);
h = h->next;
}
return L;
}
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode *l3 = NULL;
vector<int> v1 = getList(l1);
vector<int> v2 = getList(l2);
reverse(v1.begin(), v1.end());
reverse(v2.begin(), v2.end());
vector<int> v3;
int adds = 0;
int temp = 0;
if (v1.size() >= v2.size()) {
while(v2.size()) {
temp = (adds + v1.front() + v2.front()) % 10;
adds = (adds + v1.front() + v2.front()) / 10;
v3.push_back(temp);
v1.erase(v1.begin()+0);
v2.erase(v2.begin()+0);
}
while(v1.size()) {
temp = (adds + v1.front()) % 10;
adds = (adds + v1.front()) / 10;
v3.push_back(temp);
v1.erase(v1.begin()+0);
}
if (adds != 0) {
v3.push_back(adds);
}
}
else {
while(v1.size()) {
temp = (adds + v1.front() + v2.front()) % 10;
adds = (adds + v1.front() + v2.front()) / 10;
v3.push_back(temp);
v1.erase(v1.begin()+0);
v2.erase(v2.begin()+0);
}
while(v2.size()) {
temp = (adds + v2.front()) % 10;
adds = (adds + v2.front()) / 10;
v3.push_back(temp);
v2.erase(v2.begin()+0);
}
if (adds != 0) {
v3.push_back(adds);
}
}
ListNode *add = NULL;
ListNode *curr = (ListNode*)malloc(sizeof(ListNode));
curr->next = NULL;
while(v3.size()) {
add = (ListNode*)malloc(sizeof(ListNode));
add->val = v3.front();
v3.erase(v3.begin()+0);
add->next = curr->next;
curr->next = add;
}
l3 = curr->next;
return l3;
}
};
6. 链表版本(未通过)
这两种算法的基本思路是一样的,都是先求出原链表的逆向链表,然后建立新链表,对应项相加。只不过该版本可以直接利用头插法和尾插法去建立链表,但是好久没写代码了,发现自己链表的基本功都忘了差不多了,写的代码反复不过,这是GG。注意啊,以下是错的!!!!
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void Reverse(ListNode *&h, ListNode *a, int &length) {
ListNode* r;
ListNode* s;
ListNode* p;
p = a;
h = (ListNode*)malloc(sizeof(ListNode));
h->next = NULL;
r = h;
while(p) {
s = (ListNode*)malloc(sizeof(ListNode*));
s->val = p->val;
s->next = r->next;
r->next = s;
p = p->next;
length++;
}
}
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode *r1, *r2;
ListNode *result = NULL;
ListNode *curr = (ListNode*)malloc(sizeof(ListNode));
curr->next = NULL;
int length1 = 0, length2 = 0;
Reverse(r1, l1, length1);
Reverse(r2, l2, length2);
r1 = r1->next;
r2 = r2->next;
ListNode *add;
int adds = 0;
int temp = 0;
if (length1 >= length2) {
while(r2) {
temp = adds;
temp += (r1->val + r2->val)%10;
adds = (r1->val + r2->val) / 10;
add = (ListNode*)malloc(sizeof(ListNode));
add->val = temp;
add->next = curr->next;
curr->next = add;
r1 = r1->next;
r2 = r2->next;
}
while(r1) {
temp = adds;
temp += r1->val % 10;
adds = r1->val / 10;
add = (ListNode*)malloc(sizeof(ListNode));
add->val = temp;
add->next = curr->next;
curr->next = add;
r1 = r1->next;
}
result = curr->next;
}
else {
while(r1) {
temp = adds;
temp += (r1->val + r2->val)%10;
adds = (r1->val + r2->val) / 10;
add = (ListNode*)malloc(sizeof(ListNode));
add->val = temp;
add->next = curr->next;
curr->next = add;
r1 = r1->next;
r2 = r2->next;
}
while(r2) {
temp = adds;
temp += r2->val % 10;
adds = r2->val / 10;
add = (ListNode*)malloc(sizeof(ListNode));
add->val = temp;
add->next = curr->next;
curr->next = add;
r2 = r2->next;
}
result = curr->next;
}
return result;
}
};
7. 心得
审题仍然很重要,边界考虑也很重要,否则会卡在很多边界的测试样例上面。学会转化思想,链表写法实在搞不定还是老老实实换成自己熟悉的vector吧,但这方面的基本功要复习了。