面试题 02.05. 链表求和:以链表的形式完成两个数字的求和,并以链表的形式输出
给定两个用链表表示的整数,每个节点包含一个数位。
这些数位是反向存放的,也就是个位排在链表首部。
编写函数对这两个整数求和,并用链表形式返回结果。
示例:
输入:(7 -> 1 -> 6) + (5 -> 9 -> 2),即617 + 295 输出:2 -> 1 -> 9,即912
进阶:思考一下,假设这些数位是正向存放的,又该如何解决呢?
示例:
输入:(6 -> 1 -> 7) + (2 -> 9 -> 5),即617 + 295 输出:9 -> 1 -> 2,即912
结合两个链表的遍历以及两数按位求和并考虑进位两个操作。
反向存放的情况更为简单,因为从低位到高位进行计算,有进位便向上传递,若其中一个链表先结束,另外一个链表继续进行计算,最后等两个链表都结束且进位为0便停止;每次计算对应位以及进位之和后,添加一个新的链表结点用于存放结果链表的数字,最后反馈结果链表的头节点。
需要注意的是,反向存放情况下输出的链表同样采用反向存放的方式,从低位到高位,所以构建结果链表时采用尾插法即可。
(1)定义虚拟头结点,用于指向最终输出的结果链表;
(2)定义当前两个链表对应位数字之和sum以及进位carry;
(3)两个链表各对应位相加得到sum,sum再加上进位carry,以sum%10为val建立结果链表中的新的结点,更新进位carry,指针后移;
(4)两个链表均结束,且进位carry=0时,结束循环,反馈结果链表头节点。
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* dummyHead = new ListNode(0);
ListNode* cur = dummyHead;
int sum = 0, carry = 0;
while(l1 != NULL || l2 != NULL || carry != 0){
sum = 0;
if(l1 != NULL){
sum += l1->val;
l1 = l1->next;
}
if(l2 != NULL){
sum += l2->val;
l2 = l2->next;
}
sum += carry;
carry = sum / 10;
ListNode* temp = new ListNode(sum % 10);
cur->next = temp;
cur = cur->next;
}
return dummyHead->next;
}
};
正向存放的情况更加复杂,如果采用类似的直接遍历的方法,由于链表从高位开始,那么不能实现从低位到高位的进位,并且在两个链表长度不一定一致的情况下,直接遍历是无法对应各位的。因此,结合栈的性质,首先将两个链表各结点依次存放到两个栈中,再对两个栈中的元素依次出栈进行与反向存放情况下类似的操作即可。
同样需要注意的是,正向存放情况下输出的链表采用正向存放的方式,从高位到低位,那么构建结果链表时应采用头插法,这与反向存放的情况也不同。
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
stack<int> st1, st2;
while (l1 || l2) {
if (l1) {
st1.push(l1->val);
l1 = l1->next;
}
if (l2) {
st2.push(l2->val);
l2 = l2->next;
}
}
ListNode* dummyHead = new ListNode(-1);
int carry = 0, sum = 0;
while (!st1.empty() || !st2.empty() || carry != 0) {
sum = 0;
if (!st1.empty()) {
sum += st1.top();
st1.pop();
}
if (!st2.empty()) {
sum += st2.top();
st2.pop();
}
sum += carry;
carry = sum / 10;
ListNode* temp = new ListNode(sum % 10);
temp->next = dummyHead->next;
dummyHead->next = temp;
}
return dummyHead->next;
}
};