3 minute read

Problem Statement

2816

Intuition

The problem seems to involve traversing a singly-linked list and doubling each digit, considering any carryover. A recursive approach might be suitable for this task.

Approach

Define a helper function to recursively traverse the linked list, starting from the last node. Within this function, update each node’s value by doubling it and considering any carryover from the previous node. If there’s a carryover after the traversal, prepend a new node with the carryover value to the linked list.

Complexity

  • Time complexity: O(n) where n is the number of nodes in the linked list

  • Space complexity: O(n)

Code

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def doubleIt(self, head: Optional[ListNode]) -> Optional[ListNode]:
        def helper(node):
            if not node:
                return 0
            carry = helper(node.next)
            carry += node.val * 2
            node.val = carry % 10
            return carry // 10

        carry = helper(head)
        if carry == 1:
            return ListNode(carry, head)
        return head

Editorial Solution

Approach 1: Reversing the List

class Solution:
    def doubleIt(self, head: ListNode) -> ListNode:
        # Reverse the linked list
        reversed_list = self.reverse_list(head)
        # Initialize variables to track carry and previous node
        carry = 0
        current, previous = reversed_list, None

        # Traverse the reversed linked list
        while current:
            # Calculate the new value for the current node
            new_value = current.val * 2 + carry
            # Update the current node's value
            current.val = new_value % 10
            # Update carry for the next iteration
            carry = 1 if new_value > 9 else 0
            # Move to the next node
            previous, current = current, current.next

        # If there's a carry after the loop, add an extra node
        if carry:
            previous.next = ListNode(carry)

        # Reverse the list again to get the original order
        result = self.reverse_list(reversed_list)

        return result

    # Method to reverse the linked list
    def reverse_list(self, node: ListNode) -> ListNode:
        previous, current = None, node

        # Traverse the original linked list
        while current:
            # Store the next node
            next_node = current.next
            # Reverse the link
            current.next = previous
            # Move to the next nodes
            previous, current = current, next_node

        # Previous becomes the new head of the reversed list
        return previous
  • Time: O(n)
  • Space: O(1)

Approach 2: Using Stack

class Solution:
    # To compute twice the value of each node's value and propagate carry
    def twice_of_val(self, head: Optional[ListNode]) -> int:
        # Base case: if head is None, return 0
        if not head:
            return 0

        # Double the value of current node and add the result of next nodes
        doubled_value = head.val * 2 + self.twice_of_val(head.next)

        # Update current node's value with the units digit of the result
        head.val = doubled_value % 10

        # Return the carry (tens digit of the result)
        return doubled_value // 10

    def doubleIt(self, head: Optional[ListNode]) -> Optional[ListNode]:
        carry = self.twice_of_val(head)

        # If there's a carry, insert a new node at the beginning with the carry value
        if carry:
            head = ListNode(carry, head)

        # Return the head of the updated linked list
        return head

### class Solution:
    # To compute twice the value of each node's value and propagate carry
    def twice_of_val(self, head: Optional[ListNode]) -> int:
        # Base case: if head is None, return 0
        if not head:
            return 0

        # Double the value of current node and add the result of next nodes
        doubled_value = head.val * 2 + self.twice_of_val(head.next)

        # Update current node's value with the units digit of the result
        head.val = doubled_value % 10

        # Return the carry (tens digit of the result)
        return doubled_value // 10

    def doubleIt(self, head: Optional[ListNode]) -> Optional[ListNode]:
        carry = self.twice_of_val(head)

        # If there's a carry, insert a new node at the beginning with the carry value
        if carry:
            head = ListNode(carry, head)

        # Return the head of the updated linked list
        return head

Approach 4: Two Pointers

class Solution:
    def doubleIt(self, head: ListNode) -> ListNode:
        curr = head
        prev = None

        # Traverse the linked list
        while curr:
            twice_of_val = curr.val * 2

            # If the doubled value is less than 10
            if twice_of_val < 10:
                curr.val = twice_of_val
            # If doubled value is 10 or greater
            elif prev:  # other than first node
                # Update current node's value with units digit of the doubled value
                curr.val = twice_of_val % 10
                # Add the carry to the previous node's value
                prev.val += 1
            else:  # first node
                # Create a new node with carry as value and link it to the current node
                head = ListNode(1, curr)
                # Update current node's value with units digit of the doubled value
                curr.val = twice_of_val % 10

            # Update prev and curr pointers
            prev = curr
            curr = curr.next

        return head