Medium
题目描述
给你一个非空链表的头节点 head,表示一个不含前导零的非负整数。
返回将其表示的数字翻倍后的链表头节点。
示例 1:
输入:head = [1,8,9]
输出:[3,7,8]
解释:上图对应于给定的链表,表示数字 189。因此,返回的链表表示数字 189 * 2 = 378。
示例 2:
输入:head = [9,9,9]
输出:[1,9,9,8]
解释:上图对应于给定的链表,表示数字 999。因此,返回的链表表示数字 999 * 2 = 1998。
约束条件:
- 链表中节点的数量在范围 [1, 10^4] 内
- 0 <= Node.val <= 9
- 输入保证链表表示的数字不含前导零,除了数字 0 本身
提示:
- 从最低有效位到最高有效位遍历链表,将每个节点的值乘以 2
- 处理翻倍过程中可能产生的进位
- 如果最高位有进位,创建一个新节点并将其指向给定链表的开头
解题思路
这道题要求我们将链表表示的数字翻倍。有几种解法思路:
方法1:栈 + 进位处理 由于链表是从高位到低位存储,而加法需要从低位开始计算,我们可以使用栈来逆序处理。先将所有节点压栈,然后从栈顶开始弹出(相当于从个位开始),对每位乘以2并处理进位。
方法2:递归 使用递归可以天然地实现从低位到高位的处理。递归到链表末尾,然后在回溯过程中处理每一位的翻倍和进位。
方法3:反转链表 先反转链表,然后从头开始处理翻倍和进位,最后再反转回来。
推荐使用递归方法,代码简洁且易理解。递归函数返回进位值,在处理当前节点时将当前值乘以2加上来自低位的进位,然后更新当前节点值并返回新的进位。如果最终还有进位,就在链表头部添加新节点。
代码实现
class Solution {
public:
ListNode* doubleIt(ListNode* head) {
int carry = helper(head);
if (carry) {
return new ListNode(carry, head);
}
return head;
}
private:
int helper(ListNode* node) {
if (!node) return 0;
int carry = helper(node->next);
int sum = node->val * 2 + carry;
node->val = sum % 10;
return sum / 10;
}
};
class Solution:
def doubleIt(self, head: Optional[ListNode]) -> Optional[ListNode]:
def helper(node):
if not node:
return 0
carry = helper(node.next)
total = node.val * 2 + carry
node.val = total % 10
return total // 10
carry = helper(head)
if carry:
return ListNode(carry, head)
return head
public class Solution {
public ListNode DoubleIt(ListNode head) {
int carry = Helper(head);
if (carry > 0) {
return new ListNode(carry, head);
}
return head;
}
private int Helper(ListNode node) {
if (node == null) return 0;
int carry = Helper(node.next);
int sum = node.val * 2 + carry;
node.val = sum % 10;
return sum / 10;
}
}
var doubleIt = function(head) {
function helper(node) {
if (!node) return 0;
const carry = helper(node.next);
const sum = node.val * 2 + carry;
node.val = sum % 10;
return Math.floor(sum / 10);
}
const carry = helper(head);
if (carry) {
return new ListNode(carry, head);
}
return head;
};
复杂度分析
| 复杂度 | 递归方法 |
|---|---|
| 时间复杂度 | O(n) |
| 空间复杂度 | O(n) |
其中 n 是链表的长度。时间复杂度为 O(n) 是因为需要遍历每个节点一次。空间复杂度为 O(n) 是由于递归调用栈的深度与链表长度成正比。
相关题目
. Add Two Numbers (Medium)
. Plus One Linked List (Medium)