Leetcode 445-Add Two Numbers II
题干:
以非空链表的形式顺序给出两个数(最高位在最前面),链表每个结点对应一位数字。返回两数和的链表。
Input: l1 = [7,2,4,3], l2 = [5,6,4]
Output: [7,8,0,7]
Explanation: 7243 + 564 = 7807.
即两个链表从末尾开始,向前做有进位加法。
解:
反转/栈/递归/顺序迭代。不能转换成数字(因为有100位)。
方法1:反转链表
//方法1:reverse。将顺序数字链表反转,得到两个逆序数字链表,做法同上题,但注意求和链表要求是顺序,所以是从链表头部添加新数字(反着建链表)。不如用stack。
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* rl1 = reverseList(l1);
ListNode* rl2 = reverseList(l2);
ListNode* cur = NULL;
int sum = 0;
while(rl1||rl2||sum){
if(rl1){
sum += rl1->val;
rl1 = rl1->next;
}
if(rl2){
sum += rl2->val;
rl2 = rl2->next;
}
ListNode* tmp = new ListNode(sum%10);
sum/=10;
tmp->next = cur;
cur = tmp;
}
return cur;
}
private:
ListNode* reverseList(ListNode* head){
ListNode* prev = NULL;
while(head){
ListNode* tmp = head->next;
head->next = prev;
prev = head;
head = tmp;
}
return prev;
}
};
方法2:借助栈
// 方法2:stack。将两个顺序数字链表分别放到栈中,再从栈中弹出加和,方法类似上题,注意求和链表要求是顺序,所以是从链表头部添加新数字(反着建链表)。
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
stack<int> st1, st2;
while(l1){
st1.push(l1->val);
l1 = l1->next;
}
while(l2){
st2.push(l2->val);
l2 = l2->next;
}
ListNode* cur = NULL;
int sum = 0;
while((!st1.empty()) || (!st2.empty()) || sum){
if(!st1.empty()){
sum += st1.top();
st1.pop();
}
if(!st2.empty()){
sum += st2.top();
st2.pop();
}
ListNode* tmp = new ListNode(sum%10);
sum /= 10;
tmp->next = cur;
cur = tmp;
}
return cur;
}
};
方法3:递归
// 方法3:recursive。递归时使用diff记录两个顺序数字链表的长度差,若diff!=0,则长链表置为next,diff-1继续递归;若diff=0,则两个链表都置为next继续递归,直到递归至两链表为空。并用diff判断此次加和计算是否包括短链表的结点值。注意进位。
// 注意:先向下递归再求此次链表结点值的加和。递归完成后,注意最后的进位情况。
class Solution {
public:
int carry=0;
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int len1 = getLength(l1), len2 = getLength(l2);
ListNode* head;
if(len1>=len2){
head = addTwoNumbers(l1, l2, len1-len2);
}
else head = addTwoNumbers(l2, l1, len2-len1);
if(carry){ //最后仍有进位
ListNode* dummy = new ListNode(carry, head);
return dummy;
}
return head;
}
private:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2, int diff){
if((!l1) && (!l2)) return NULL;
ListNode* cur = new ListNode;
ListNode* next;
//注意顺序,先递归再加和
next = diff ? addTwoNumbers(l1->next, l2, diff - 1) : addTwoNumbers(l1->next, l2->next, 0);
cur->next = next;
carry += l1->val;
carry += diff? 0: l2->val;
cur->val = carry % 10;
carry /= 10;
return cur;
}
int getLength(ListNode* head){
int len = 0;
while(head){
len++;
head = head->next;
}
return len;
}
};
方法4:迭代
// 方法4:iterative。先迭代,建立两个顺序链表加和且不处理进位的逆序链表(从链表头部添加结点,即反着建链表),变成逆序的目的是方便处理进位。再处理进位+建立顺序求和链表(反着建链表)。
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int len1 = getLength(l1), len2 = getLength(l2);
if(len1 < len2){
swap(len1, len2);
swap(l1, l2);
}
ListNode* cur = NULL;
while(l1){
int sum = l1->val;
l1 = l1->next;
if(len1 > len2) len1--;
else{
sum += l2->val;
l2 = l2->next;
len1--;
len2--;
}
ListNode* tmp = new ListNode(sum);
tmp->next = cur;
cur = tmp;
}
ListNode* head = NULL;
int carry = 0;
while(cur){
carry += cur->val;
ListNode* tmp = new ListNode(carry%10);
tmp->next = head;
head = tmp;
carry /= 10;
ListNode* p = cur;
cur = cur->next;
delete(p);
}
if(carry){
ListNode* dummy = new ListNode(carry, head);
return dummy;
}
return head;
}
private:
int getLength(ListNode* head){
int len = 0;
while(head){
len++;
head = head->next;
}
return len;
}
};