Double a Number Represented as a Linked List solution and explanation
9 more videos on this problem
Double a Number Represented as a Linked List | 4 Approaches | Story|Leetcode 2816 | codestorywithMIKcodestorywithMIK · 43:12 · 5K views
2816. Double a Number Represented as a Linked List | 5 Approaches | Two Pointers | One PointerAryan Mittal · 21:17 · 2K views
Leetcode 2816 Double a Number Represented as a Linked List | Beats 100% | JavaTech Diet · 4:36 · 1K views
Double a Number Represented as a Linked List | Leetcode 2816 | Linked List | C++Tech Courses · 9:16 · 1K views
Daily Leetcode #1498: May 07, 2024 - 2816. Double a Number Represented as a Linked ListProgramming Live with Larry · 13:52 · 539 views
2816. Double a Number Represented as a Linked List (Leetcode Medium)Programming Live with Larry · 8:40 · 466 views
2816 Double a Number Represented as Linked List | Leet Code problems| Coding in Telugu | LVS LogicsLVS Logics · 6:07 · 406 views
Recursion on Linked Lists in Python | LeetCode 2816 Double a Number Represented as a Linked ListvanAmsen · 7:44 · 331 views
LeetCode 2816 - Double a Number Represented as a Linked List - JavaAlpha-Code · 12:41 · 89 views
Leetcode 2816 | Double a Number Represented as a Linked ListLCReviewer · 16:17 · 85 views
The problem
You are given the head of a non-empty linked list representing a non-negative integer without leading zeroes.
Return the head of the linked list after doubling it.
Example 1:
Input: head = [1,8,9] Output: [3,7,8] Explanation: The figure above corresponds to the given linked list which represents the number 189. Hence, the returned linked list represents the number 189 * 2 = 378.
Example 2:
Input: head = [9,9,9] Output: [1,9,9,8] Explanation: The figure above corresponds to the given linked list which represents the number 999. Hence, the returned linked list reprersents the number 999 * 2 = 1998.
Constraints:
- The number of nodes in the list is in the range
[1, 104] 0 <= Node.val <= 9- The input is generated such that the list represents a number that does not have leading zeros, except the number
0itself.
Approach overview
Problem Overview: You are given a linked list where each node stores a single digit of a non‑negative integer. The most significant digit appears first. The task is to double the number and return the resulting linked list while preserving the same digit-by-digit structure.
The main difficulty is handling carry when doubling digits. Since the list stores the most significant digit first, carries propagate toward the left side of the list, which makes a simple forward traversal tricky.
Approach 1: Stack-Based Simulation (O(n) time, O(n) space)
This approach treats the linked list like a number where digits must be processed from right to left. Traverse the list once and push each node onto a stack. Then pop nodes one by one and double the digit using basic math. Maintain a carry variable while computing newDigit = (digit * 2 + carry) % 10 and update carry = (digit * 2 + carry) / 10. Because the stack reverses processing order, carry propagation becomes straightforward. If a carry remains after processing all nodes, insert a new head node. This method is intuitive and mirrors how manual multiplication works, though it uses extra memory for the stack.
Approach 2: Two-Pointer Technique (O(n) time, O(1) space)
The optimized approach avoids extra space by managing carry during a forward traversal. Start with a dummy node before the head in case the most significant digit generates a carry. Traverse the list with a pointer while keeping track of the last node whose value is not 9. When doubling a digit produces a carry, increment that stored node and set all nodes between it and the current node to zero. This works because any digit 9 doubled becomes 18, forcing carry propagation. By remembering the last "safe" node (not equal to 9), you can adjust earlier digits without reversing the list. The algorithm completes in a single pass and only uses a few pointers.
Recommended for interviews: The two-pointer technique is usually the expected solution because it achieves O(n) time with O(1) extra space. The stack method demonstrates clear understanding of digit-by-digit arithmetic and carry handling, but interviewers typically prefer the in-place pointer solution for linked list problems.
Approach 1: Binary Search Approach
This approach utilizes binary search to efficiently find the target element in a sorted array. Since the array is sorted, binary search can be applied, reducing the time complexity significantly compared to a linear search.
The core idea is to repeatedly divide the search interval in half. If the search key is less than the item in the middle of the interval, narrow the interval to the lower half. Otherwise, narrow it to the upper half until the target is found or the interval is empty.
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = left + (right - left) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
arr = [1, 2, 3, 4, 5]
target = 3
result = binary_search(arr, target)
print(f"Element found at index: {result}")public class BinarySearch {
public static int binarySearch(int[] arr, int target) {
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
int target = 3;
int result = binarySearch(arr, target);
System.out.println("Element found at index: " + result);
}
}#include <iostream>
#include <vector>
int binarySearch(const std::vector<int>& arr, int target) {
int left = 0, right = arr.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
int main() {
std::vector<int> arr = {1, 2, 3, 4, 5};
int target = 3;
int result = binarySearch(arr, target);
std::cout << "Element found at index: " << result << std::endl;
return 0;
}function binarySearch(arr, target) {
let left = 0, right = arr.length - 1;
while (left <= right) {
const mid = Math.floor(left + (right - left) / 2);
if (arr[mid] === target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
const arr = [1, 2, 3, 4, 5];
const target = 3;
const result = binarySearch(arr, target);
console.log(`Element found at index: ${result}`);#include <stdio.h>
int binarySearch(int arr[], int size, int target) {
int left = 0, right = size - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
int target = 3;
int result = binarySearch(arr, 5, target);
printf("Element found at index: %d\n", result);
return 0;
}using System;
class Program {
public static int BinarySearch(int[] arr, int target) {
int left = 0, right = arr.Length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
static void Main() {
int[] arr = {1, 2, 3, 4, 5};
int target = 3;
int result = BinarySearch(arr, target);
Console.WriteLine("Element found at index: " + result);
}
}This Python implementation reads a sorted array and performs binary search to find the target value. It continuously halves the search space and checks positions using mid indices, resulting in an efficient search.
Time Complexity: O(log n), where n is the number of elements in the array.
Space Complexity: O(1), implying constant use of space.
Approach 2: Two-Pointer Technique
The two-pointer approach helps to solve the problem with pointers or two index variables. This technique is beneficial when you need to minimize the number of iterations or traverse the array with controlled steps. Often used in problems involving arrays, especially when the sum or difference needs to be calculated between distinct elements.
def two_pointer_search(arr, target):
left, right = 0, len(arr) - 1
while left < right:
sum_ = arr[left] + arr[right]
if sum_ == target:
return True
elif sum_ < target:
left += 1
else:
right -= 1
return False
arr = [1, 2, 3, 4, 5]
target = 8
result = two_pointer_search(arr, target)
print(f"Pair found: {'Yes' if result else 'No'}")public class TwoPointer {
public static boolean twoPointerSearch(int[] arr, int target) {
int left = 0, right = arr.length - 1;
while (left < right) {
int sum = arr[left] + arr[right];
if (sum == target) return true;
else if (sum < target) left++;
else right--;
}
return false;
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
int target = 8;
boolean result = twoPointerSearch(arr, target);
System.out.println("Pair found: " + (result ? "Yes" : "No"));
}
}#include <iostream>
#include <vector>
bool twoPointerSearch(const std::vector<int>& arr, int target) {
int left = 0, right = arr.size() - 1;
while (left < right) {
int sum = arr[left] + arr[right];
if (sum == target) return true;
else if (sum < target) left++;
else right--;
}
return false;
}
int main() {
std::vector<int> arr = {1, 2, 3, 4, 5};
int target = 8;
bool result = twoPointerSearch(arr, target);
std::cout << "Pair found: " << (result ? "Yes" : "No") << std::endl;
return 0;
}function twoPointerSearch(arr, target) {
let left = 0, right = arr.length - 1;
while (left < right) {
const sum = arr[left] + arr[right];
if (sum === target) return true;
else if (sum < target) left++;
else right--;
}
return false;
}
const arr = [1, 2, 3, 4, 5];
const target = 8;
const result = twoPointerSearch(arr, target);
console.log(`Pair found: ${result ? 'Yes' : 'No'}`);#include <stdio.h>
int twoPointerSearch(int arr[], int size, int target) {
int left = 0, right = size - 1;
while (left < right) {
int sum = arr[left] + arr[right];
if (sum == target) return 1;
else if (sum < target) left++;
else right--;
}
return 0;
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
int target = 8;
int result = twoPointerSearch(arr, 5, target);
printf("Pair found: %s\n", result ? "Yes" : "No");
return 0;
}using System;
class Program {
public static bool TwoPointerSearch(int[] arr, int target) {
int left = 0, right = arr.Length - 1;
while (left < right) {
int sum = arr[left] + arr[right];
if (sum == target) return true;
else if (sum < target) left++;
else right--;
}
return false;
}
static void Main() {
int[] arr = {1, 2, 3, 4, 5};
int target = 8;
bool result = TwoPointerSearch(arr, target);
Console.WriteLine("Pair found: " + (result ? "Yes" : "No"));
}
}This Python function operates with two pointers set initially at opposite ends of the array, inspecting possibilities for a sum match to the target. It strategically adjusts the pointers based on their current sum until results are achieved.
Time Complexity: O(n), where n is the number of elements in the array.
Space Complexity: O(1), as no extra space is involved in the process.
Approach 3: Reverse Linked List + Simulation
First, we reverse the linked list, then simulate the multiplication operation, and finally reverse the linked list back.
Time complexity is O(n), where n is the length of the linked list. Ignoring the space taken by the answer linked list, the space complexity is O(1).
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function doubleIt(head: ListNode | null): ListNode | null {
head = reverse(head);
const dummy = new ListNode();
let cur = dummy;
let mul = 2;
let carry = 0;
while (head) {
const x = head.val * mul + carry;
carry = Math.floor(x / 10);
cur.next = new ListNode(x % 10);
cur = cur.next;
head = head.next;
}
if (carry) {
cur.next = new ListNode(carry);
}
return reverse(dummy.next);
}
function reverse(head: ListNode | null): ListNode | null {
const dummy = new ListNode();
let cur = head;
while (cur) {
const next = cur.next;
cur.next = dummy.next;
dummy.next = cur;
cur = next;
}
return dummy.next;
}/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func doubleIt(head *ListNode) *ListNode {
head = reverse(head)
dummy := &ListNode{}
cur := dummy
mul, carry := 2, 0
for head != nil {
x := head.Val*mul + carry
carry = x / 10
cur.Next = &ListNode{Val: x % 10}
cur = cur.Next
head = head.Next
}
if carry > 0 {
cur.Next = &ListNode{Val: carry}
}
return reverse(dummy.Next)
}
func reverse(head *ListNode) *ListNode {
dummy := &ListNode{}
cur := head
for cur != nil {
next := cur.Next
cur.Next = dummy.Next
dummy.Next = cur
cur = next
}
return dummy.Next
}Complexity comparison
| Approach | Complexity |
|---|---|
| Binary Search Approach | Time Complexity: O(log n), where n is the number of elements in the array. |
| Two-Pointer Technique | Time Complexity: O(n), where n is the number of elements in the array. |
| Reverse Linked List + Simulation | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Stack-Based Simulation | O(n) | O(n) | Simple implementation when reverse processing of digits is easier to reason about |
| Two-Pointer Technique | O(n) | O(1) | Preferred interview solution when minimizing extra memory is required |
Frequently asked questions
Is Double a Number Represented as a Linked List easy or hard?
The problem is rated Medium because handling carry in a forward-order linked list requires careful pointer management. The arithmetic itself is simple, but implementing correct carry propagation without reversing the list can be tricky.
Double a Number Represented as a Linked List Python/Java solution
Most solutions follow the same logic across languages. Traverse the linked list, double each digit, and manage carry propagation. Python, Java, C++, and JavaScript implementations typically use either a stack-based simulation or an in-place two-pointer technique with O(n) time complexity.
How to solve Double a Number Represented as a Linked List in O(n)?
Traverse the linked list while doubling each digit and tracking carry. Use a dummy head and remember the last node whose value is not 9. When a carry occurs, increment that node and reset intermediate digits to zero. This allows correct carry propagation in a single pass with O(n) time and O(1) space.
What is the best approach for Double a Number Represented as a Linked List?
The two-pointer carry propagation technique is generally considered the best approach. It scans the linked list once, tracks the last non‑9 digit, and handles carry without reversing the list or using extra memory. This achieves O(n) time and O(1) space complexity, which is optimal for this problem.
Is Double a Number Represented as a Linked List asked at Google/Amazon/Meta?
Linked list arithmetic problems similar to this appear in interviews at large tech companies including Amazon, Google, and Meta. Variants such as adding numbers represented by linked lists or handling digit carry are common interview patterns.
What data structure is used in Double a Number Represented as a Linked List?
The primary data structure is a singly linked list where each node stores one digit of the number. Some implementations also use a stack to process digits from right to left, while the optimal approach uses pointer tracking within the linked list.
What is the time complexity of Double a Number Represented as a Linked List?
The optimal solution runs in O(n) time where n is the number of nodes in the linked list. Each node is processed at most once during traversal. Stack-based implementations also run in O(n) time but require additional O(n) space.
