leecode/problems/2.addTwoNumbers.md
2020-05-22 18:17:19 +08:00

177 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 题目地址
https://leetcode.com/problems/add-two-numbers/description/
## 题目描述
```
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.
Example
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.
```
## 思路
设立一个表示进位的变量carried建立一个新链表
把输入的两个链表从头往后同时处理每两个相加将结果加上carried后的值作为一个新节点到新链表后面。
![2.addTwoNumbers](../assets/2.addTwoNumbers.gif)
(图片来自: https://github.com/MisterBooo/LeetCodeAnimation)
## 关键点解析
1. 链表这种数据结构的特点和使用
2. 用一个carried变量来实现进位的功能每次相加之后计算carried并用于下一位的计算
## 代码
* 语言支持JSC++
JavaScript:
```js
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
var addTwoNumbers = function(l1, l2) {
if (l1 === null || l2 === null) return null
// 使用dummyHead可以简化对链表的处理dummyHead.next指向新链表
let dummyHead = new ListNode(0)
let cur1 = l1
let cur2 = l2
let cur = dummyHead // cur用于计算新链表
let carry = 0 // 进位标志
while (cur1 !== null || cur2 !== null) {
let val1 = cur1 !== null ? cur1.val : 0
let val2 = cur2 !== null ? cur2.val : 0
let sum = val1 + val2 + carry
let newNode = new ListNode(sum % 10) // sum%10取模结果范围为0~9即为当前节点的值
carry = sum >= 10 ? 1 : 0 // sum>=10carry=1表示有进位
cur.next = newNode
cur = cur.next
if (cur1 !== null) {
cur1 = cur1.next
}
if (cur2 !== null) {
cur2 = cur2.next
}
}
if (carry > 0) {
// 如果最后还有进位,新加一个节点
cur.next = new ListNode(carry)
}
return dummyHead.next
};
```
C++
> C++代码与上面的JavaScript代码略有不同将carry是否为0的判断放到了while循环中
```c++
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* ret = nullptr;
ListNode* cur = nullptr;
int carry = 0;
while (l1 != nullptr || l2 != nullptr || carry != 0) {
carry += (l1 == nullptr ? 0 : l1->val) + (l2 == nullptr ? 0 : l2->val);
auto temp = new ListNode(carry % 10);
carry /= 10;
if (ret == nullptr) {
ret = temp;
cur = ret;
}
else {
cur->next = temp;
cur = cur->next;
}
l1 = l1 == nullptr ? nullptr : l1->next;
l2 = l2 == nullptr ? nullptr : l2->next;
}
return ret;
}
};
```
## 拓展
通过单链表的定义可以得知单链表也是递归结构因此也可以使用递归的方式来进行reverse操作。
> 由于单链表是线性的,使用递归方式将导致栈的使用也是线性的,当链表长度达到一定程度时,递归会导致爆栈,因此,现实中并不推荐使用递归方式来操作链表。
### 描述
1. 将两个链表的第一个节点值相加结果转为0-10之间的个位数并设置进位信息
2. 将两个链表第一个节点以后的链表做带进位的递归相加
3. 将第一步得到的头节点的next指向第二步返回的链表
### C++实现
```C++
// 普通递归
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
return addTwoNumbers(l1, l2, 0);
}
private:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2, int carry) {
if (l1 == nullptr && l2 == nullptr && carry == 0) return nullptr;
carry += (l1 == nullptr ? 0 : l1->val) + (l2 == nullptr ? 0 : l2->val);
auto ret = new ListNode(carry % 10);
ret->next = addTwoNumbers(l1 == nullptr ? l1 : l1->next,
l2 == nullptr ? l2 : l2->next,
carry / 10);
return ret;
}
};
// (类似)尾递归
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* head = nullptr;
addTwoNumbers(head, nullptr, l1, l2, 0);
return head;
}
private:
void addTwoNumbers(ListNode*& head, ListNode* cur, ListNode* l1, ListNode* l2, int carry) {
if (l1 == nullptr && l2 == nullptr && carry == 0) return;
carry += (l1 == nullptr ? 0 : l1->val) + (l2 == nullptr ? 0 : l2->val);
auto temp = new ListNode(carry % 10);
if (cur == nullptr) {
head = temp;
cur = head;
} else {
cur->next = temp;
cur = cur->next;
}
addTwoNumbers(head, cur, l1 == nullptr ? l1 : l1->next, l2 == nullptr ? l2 : l2->next, carry / 10);
}
};
```