Add Two Numbers in C++ (Time Complexity: O(max(n, m)))


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 contains a single digit. Add the two numbers and return the sum as a linked list.

You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Example 1:

Input: list1 = [2, 4, 3], list2 = [5, 6, 4]
Output: [7, 0, 8]
Explanation: 342 + 465 = 807




Example 2:

Input: list1 = [9,9,9,9,9,9,9], list2 = [9,9,9,9]
Output: [8,9,9,9,0,0,0,1]
Explanation: 9999999 + 9999 = 10009998

Understanding the Problem

The core challenge of this problem is to handle the addition of two numbers represented as linked lists, where each node contains a single digit. The digits are stored in reverse order, which means the least significant digit comes first. This is similar to how we perform addition manually, starting from the rightmost digit and moving to the left.

Common applications of this problem include scenarios where large numbers need to be processed that cannot fit into standard data types, such as in financial calculations or scientific computations.

Potential pitfalls include handling the carry-over correctly and ensuring that the resulting linked list is properly constructed without any leading zeros (except for the number 0 itself).

Approach

To solve this problem, we can use a straightforward approach that mimics the manual addition process:

  1. Initialize a dummy node to act as the head of the result linked list.
  2. Use two pointers to traverse the input linked lists.
  3. Initialize a carry variable to handle the carry-over during addition.
  4. Iterate through the linked lists, adding corresponding digits along with the carry.
  5. Create new nodes for the result linked list and update the carry accordingly.
  6. Handle any remaining carry after the main loop.

This approach ensures that we correctly handle the addition of digits and the carry-over, resulting in the correct sum represented as a linked list.

Algorithm

Here is a step-by-step breakdown of the algorithm:

  1. Initialize a dummy node and a current pointer to build the result linked list.
  2. Initialize a carry variable to 0.
  3. While either of the input linked lists has nodes left or there is a carry:
  4. Return the next node of the dummy node as the head of the result linked list.

Code Implementation


#include <iostream>
using namespace std;

// Definition for singly-linked list.
struct ListNode {
    int val;
    ListNode *next;
    ListNode() : val(0), next(nullptr) {}
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode(int x, ListNode *next) : val(x), next(next) {}
};

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        // Initialize a dummy node to act as the head of the result linked list
        ListNode* dummy = new ListNode();
        ListNode* current = dummy;
        int carry = 0;

        // Traverse both linked lists
        while (l1 != nullptr || l2 != nullptr || carry != 0) {
            // Get the values of the current nodes (or 0 if the list is exhausted)
            int val1 = (l1 != nullptr) ? l1->val : 0;
            int val2 = (l2 != nullptr) ? l2->val : 0;

            // Calculate the sum and update the carry
            int sum = val1 + val2 + carry;
            carry = sum / 10;

            // Create a new node with the value of sum % 10
            current->next = new ListNode(sum % 10);
            current = current->next;

            // Move to the next nodes
            if (l1 != nullptr) l1 = l1->next;
            if (l2 != nullptr) l2 = l2->next;
        }

        // Return the next node of the dummy node as the head of the result linked list
        return dummy->next;
    }
};

// Helper function to print the linked list
void printList(ListNode* node) {
    while (node != nullptr) {
        cout << node->val << " ";
        node = node->next;
    }
    cout << endl;
}

// Main function to test the solution
int main() {
    // Create the first linked list: 2 -> 4 -> 3
    ListNode* l1 = new ListNode(2);
    l1->next = new ListNode(4);
    l1->next->next = new ListNode(3);

    // Create the second linked list: 5 -> 6 -> 4
    ListNode* l2 = new ListNode(5);
    l2->next = new ListNode(6);
    l2->next->next = new ListNode(4);

    // Create a solution object
    Solution solution;

    // Add the two numbers
    ListNode* result = solution.addTwoNumbers(l1, l2);

    // Print the result linked list
    printList(result);

    return 0;
}

Complexity Analysis

The time complexity of this approach is O(max(n, m)), where n and m are the lengths of the input linked lists. This is because we traverse both linked lists once. The space complexity is O(max(n, m)) as well, due to the space required for the result linked list.

Edge Cases

Potential edge cases include:

Our algorithm handles these edge cases by checking for null pointers and ensuring the carry is correctly managed.

Testing

To test the solution comprehensively, we can use a variety of test cases:

We can use the provided helper function to print the linked list and verify the results manually.

Thinking and Problem-Solving Tips

When approaching such problems, it is essential to:

Practicing similar problems and studying algorithms can help improve problem-solving skills.

Conclusion

In this blog post, we discussed how to solve the problem of adding two numbers represented as linked lists. We covered the problem definition, approach, algorithm, code implementation, complexity analysis, edge cases, and testing. Understanding and solving such problems is crucial for developing strong problem-solving skills and improving coding proficiency.

We encourage readers to practice and explore further to enhance their understanding and skills.

Additional Resources

For further reading and practice, consider the following resources: