Facebook Pixel

1634. Add Two Polynomials Represented as Linked Lists 🔒

Problem Description

This problem asks you to add two polynomials that are represented as linked lists and return the sum as a new polynomial linked list.

Each node in the polynomial linked list represents one term of the polynomial and contains:

  • coefficient: The numerical multiplier of the term (e.g., in 9x^4, the coefficient is 9)
  • power: The exponent of the variable (e.g., in 9x^4, the power is 4)
  • next: A pointer to the next term in the polynomial

The polynomial linked lists follow these rules:

  • Terms are arranged in strictly descending order by their power values
  • Terms with a coefficient of 0 are not included in the list

For example, the polynomial 5x^3 + 4x - 7 would be represented as a linked list with three nodes:

  • First node: coefficient=5, power=3 (representing 5x^3)
  • Second node: coefficient=4, power=1 (representing 4x)
  • Third node: coefficient=-7, power=0 (representing -7)

Your task is to:

  1. Take two polynomial linked lists (poly1 and poly2)
  2. Add them together by combining like terms (terms with the same power)
  3. Return the head of a new linked list representing the sum
  4. Ensure the result maintains descending power order and excludes any terms with coefficient 0

For instance, if you add (5x^3 + 4x - 7) and (3x^3 - 2x^2 + 6), the result would be (8x^3 - 2x^2 + 4x - 1).

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

When adding two polynomials manually, we combine terms with the same power. For example, 3x^2 + 5x^2 = 8x^2. Since both linked lists are already sorted in descending order by power, we can traverse them simultaneously using a two-pointer approach, similar to merging two sorted lists.

Think of it like merging two sorted arrays, but with a twist. As we traverse both lists:

  • If one polynomial has a term with a higher power than the other, that term appears in the result unchanged (since there's no matching term to add to it)
  • If both polynomials have terms with the same power, we add their coefficients together
  • If the sum of coefficients equals zero, we skip that term entirely (as per the problem's requirement)

The key insight is that we don't need to collect all terms first and then sort them. Since both input lists are already sorted, we can build the result in sorted order directly by comparing powers at each step.

We use a dummy head node to simplify the list construction - this eliminates the need for special handling of the first node. We maintain a curr pointer to track where we're building the result list.

After processing all matching terms, one list might still have remaining terms (with lower powers than anything in the other list). These remaining terms can be directly appended to our result since there are no corresponding terms to add them with.

This approach processes each term exactly once, making it efficient with O(m + n) time complexity where m and n are the lengths of the two input polynomial lists.

Learn more about Linked List, Math and Two Pointers patterns.

Solution Approach

The implementation uses a two-pointer technique to traverse both polynomial linked lists simultaneously while building the result list.

Step-by-step implementation:

  1. Initialize pointers and dummy node:

    • Create a dummy head node to simplify list construction: dummy = curr = PolyNode()
    • curr will be used to build the result list
  2. Main traversal loop - process both lists while both have nodes:

    while poly1 and poly2:

    At each iteration, we compare the powers of the current nodes:

    • Case 1: poly1.power > poly2.power

      • The term from poly1 has no matching term in poly2
      • Add this node directly to the result: curr.next = poly1
      • Advance poly1 and curr pointers
    • Case 2: poly1.power < poly2.power

      • The term from poly2 has no matching term in poly1
      • Add this node directly to the result: curr.next = poly2
      • Advance poly2 and curr pointers
    • Case 3: poly1.power == poly2.power

      • Both polynomials have terms with the same power - we need to add coefficients
      • Calculate sum: c = poly1.coefficient + poly2.coefficient
      • Using the walrus operator :=, we check if the sum is non-zero:
        if c := poly1.coefficient + poly2.coefficient:
            curr.next = PolyNode(c, poly1.power)
            curr = curr.next
      • If the sum is 0, we skip creating a node (terms cancel out)
      • Advance both poly1 and poly2 pointers regardless of whether we created a node
  3. Handle remaining nodes:

    curr.next = poly1 or poly2

    After the main loop, one list might have remaining nodes (the one with smaller powers). We append all remaining nodes directly since there are no corresponding terms to add.

  4. Return the result:

    return dummy.next

    Skip the dummy head and return the actual head of the result list.

Key optimizations:

  • We reuse existing nodes when possible (Cases 1 and 2) instead of creating new ones
  • The walrus operator := allows us to compute and check the coefficient sum in one expression
  • The expression poly1 or poly2 elegantly handles appending remaining nodes from whichever list is non-empty

This approach maintains the required descending power order naturally and automatically excludes zero-coefficient terms.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through adding two polynomials step by step:

  • poly1: 3x^2 + 2x (represented as [3,2] -> [2,1])
  • poly2: x^2 - 2x + 1 (represented as [1,2] -> [-2,1] -> [1,0])

Initial Setup:

  • Create dummy node and curr pointer
  • poly1 points to [3,2]
  • poly2 points to [1,2]

Iteration 1:

  • Compare powers: poly1.power = 2, poly2.power = 2 (equal)
  • Add coefficients: 3 + 1 = 4
  • Since 4 ≠ 0, create new node [4,2]
  • Advance both pointers: poly1[2,1], poly2[-2,1]
  • Result so far: dummy -> [4,2]

Iteration 2:

  • Compare powers: poly1.power = 1, poly2.power = 1 (equal)
  • Add coefficients: 2 + (-2) = 0
  • Since sum is 0, skip creating a node (terms cancel out)
  • Advance both pointers: poly1null, poly2[1,0]
  • Result remains: dummy -> [4,2]

After main loop:

  • poly1 is null, poly2 still has [1,0]
  • Append remaining: curr.next = poly2
  • Final result: dummy -> [4,2] -> [1,0]

Return: 4x^2 + 1 (skipping the dummy head)

This demonstrates how the algorithm:

  1. Merges terms with matching powers by adding coefficients
  2. Automatically excludes zero-coefficient terms
  3. Maintains descending power order
  4. Efficiently handles remaining terms

Solution Implementation

1# Definition for polynomial singly-linked list.
2# class PolyNode:
3#     def __init__(self, x=0, y=0, next=None):
4#         self.coefficient = x
5#         self.power = y
6#         self.next = next
7
8
9class Solution:
10    def addPoly(self, poly1: "PolyNode", poly2: "PolyNode") -> "PolyNode":
11        """
12        Add two polynomials represented as linked lists.
13        Each node contains a coefficient and power, sorted by power in descending order.
14      
15        Args:
16            poly1: First polynomial as linked list
17            poly2: Second polynomial as linked list
18          
19        Returns:
20            Resulting polynomial after addition as linked list
21        """
22        # Create dummy head node to simplify list construction
23        dummy_head = PolyNode()
24        current = dummy_head
25      
26        # Process both polynomials while both have remaining terms
27        while poly1 and poly2:
28            # Case 1: poly1 has higher power term - add it to result
29            if poly1.power > poly2.power:
30                current.next = poly1
31                poly1 = poly1.next
32                current = current.next
33            # Case 2: poly2 has higher power term - add it to result
34            elif poly1.power < poly2.power:
35                current.next = poly2
36                poly2 = poly2.next
37                current = current.next
38            # Case 3: Both terms have same power - add coefficients
39            else:
40                coefficient_sum = poly1.coefficient + poly2.coefficient
41                # Only create new node if sum is non-zero (cancel out terms)
42                if coefficient_sum != 0:
43                    current.next = PolyNode(coefficient_sum, poly1.power)
44                    current = current.next
45                # Move both pointers forward
46                poly1 = poly1.next
47                poly2 = poly2.next
48      
49        # Append remaining terms from either polynomial
50        if poly1:
51            current.next = poly1
52        else:
53            current.next = poly2
54          
55        # Return the head of resulting polynomial (skip dummy node)
56        return dummy_head.next
57
1/**
2 * Definition for polynomial singly-linked list.
3 * class PolyNode {
4 *     int coefficient, power;
5 *     PolyNode next = null;
6 *
7 *     PolyNode() {}
8 *     PolyNode(int x, int y) { this.coefficient = x; this.power = y; }
9 *     PolyNode(int x, int y, PolyNode next) { this.coefficient = x; this.power = y; this.next = next; }
10 * }
11 */
12
13class Solution {
14    /**
15     * Adds two polynomial linked lists and returns the sum as a new polynomial linked list.
16     * The polynomials are represented in descending order of powers.
17     * 
18     * @param poly1 First polynomial linked list
19     * @param poly2 Second polynomial linked list
20     * @return Sum of the two polynomials as a linked list
21     */
22    public PolyNode addPoly(PolyNode poly1, PolyNode poly2) {
23        // Create a dummy head node to simplify list construction
24        PolyNode dummyHead = new PolyNode();
25        PolyNode current = dummyHead;
26      
27        // Traverse both lists simultaneously while both have remaining terms
28        while (poly1 != null && poly2 != null) {
29            if (poly1.power > poly2.power) {
30                // poly1 has higher power, add it to result
31                current.next = poly1;
32                poly1 = poly1.next;
33                current = current.next;
34            } else if (poly1.power < poly2.power) {
35                // poly2 has higher power, add it to result
36                current.next = poly2;
37                poly2 = poly2.next;
38                current = current.next;
39            } else {
40                // Both terms have same power, add their coefficients
41                int sumCoefficient = poly1.coefficient + poly2.coefficient;
42              
43                // Only add the term if the sum is non-zero
44                if (sumCoefficient != 0) {
45                    current.next = new PolyNode(sumCoefficient, poly1.power);
46                    current = current.next;
47                }
48              
49                // Move both pointers forward
50                poly1 = poly1.next;
51                poly2 = poly2.next;
52            }
53        }
54      
55        // Append remaining terms from poly1 if any
56        if (poly1 != null) {
57            current.next = poly1;
58        }
59      
60        // Append remaining terms from poly2 if any
61        if (poly2 != null) {
62            current.next = poly2;
63        }
64      
65        // Return the head of the result list (skip dummy node)
66        return dummyHead.next;
67    }
68}
69
1/**
2 * Definition for polynomial singly-linked list.
3 * struct PolyNode {
4 *     int coefficient, power;
5 *     PolyNode *next;
6 *     PolyNode(): coefficient(0), power(0), next(nullptr) {};
7 *     PolyNode(int x, int y): coefficient(x), power(y), next(nullptr) {};
8 *     PolyNode(int x, int y, PolyNode* next): coefficient(x), power(y), next(next) {};
9 * };
10 */
11
12class Solution {
13public:
14    /**
15     * Adds two polynomial linked lists and returns the sum as a new polynomial linked list.
16     * The polynomials are represented in descending order of powers.
17     * 
18     * @param poly1 - First polynomial linked list
19     * @param poly2 - Second polynomial linked list
20     * @return PolyNode* - Head of the resulting polynomial after addition
21     */
22    PolyNode* addPoly(PolyNode* poly1, PolyNode* poly2) {
23        // Create a dummy head node to simplify list construction
24        PolyNode* dummyHead = new PolyNode();
25        PolyNode* current = dummyHead;
26      
27        // Process both lists while they have remaining terms
28        while (poly1 != nullptr && poly2 != nullptr) {
29            // If poly1's power is greater, add poly1's term to result
30            if (poly1->power > poly2->power) {
31                current->next = poly1;
32                poly1 = poly1->next;
33                current = current->next;
34            }
35            // If poly2's power is greater, add poly2's term to result
36            else if (poly1->power < poly2->power) {
37                current->next = poly2;
38                poly2 = poly2->next;
39                current = current->next;
40            }
41            // If powers are equal, add coefficients
42            else {
43                int sumCoefficient = poly1->coefficient + poly2->coefficient;
44              
45                // Only add the term if the sum is non-zero (terms cancel out if sum is 0)
46                if (sumCoefficient != 0) {
47                    current->next = new PolyNode(sumCoefficient, poly1->power);
48                    current = current->next;
49                }
50              
51                // Move both pointers forward
52                poly1 = poly1->next;
53                poly2 = poly2->next;
54            }
55        }
56      
57        // Append remaining terms from poly1 (if any)
58        if (poly1 == nullptr) {
59            current->next = poly2;
60        }
61      
62        // Append remaining terms from poly2 (if any)
63        if (poly2 == nullptr) {
64            current->next = poly1;
65        }
66      
67        // Return the head of the result list (skip dummy node)
68        return dummyHead->next;
69    }
70};
71
1/**
2 * Definition for polynomial singly-linked list node.
3 * Each node represents a term in the polynomial with coefficient and power.
4 */
5class PolyNode {
6    coefficient: number;
7    power: number;
8    next: PolyNode | null;
9  
10    constructor(x: number = 0, y: number = 0, next: PolyNode | null = null) {
11        this.coefficient = x;
12        this.power = y;
13        this.next = next;
14    }
15}
16
17/**
18 * Adds two polynomials represented as linked lists.
19 * The polynomials are sorted in descending order by power.
20 * 
21 * @param poly1 - First polynomial linked list
22 * @param poly2 - Second polynomial linked list
23 * @returns The sum of the two polynomials as a linked list
24 */
25function addPoly(poly1: PolyNode | null, poly2: PolyNode | null): PolyNode | null {
26    // Create a dummy head node to simplify list construction
27    const dummyHead: PolyNode = new PolyNode();
28    let currentNode: PolyNode = dummyHead;
29  
30    // Traverse both polynomials simultaneously
31    while (poly1 && poly2) {
32        if (poly1.power > poly2.power) {
33            // Poly1 has higher power, add it to result
34            currentNode.next = poly1;
35            poly1 = poly1.next;
36            currentNode = currentNode.next;
37        } else if (poly1.power < poly2.power) {
38            // Poly2 has higher power, add it to result
39            currentNode.next = poly2;
40            poly2 = poly2.next;
41            currentNode = currentNode.next;
42        } else {
43            // Same power, add coefficients
44            const sumOfCoefficients: number = poly1.coefficient + poly2.coefficient;
45          
46            // Only add the term if the sum is non-zero
47            if (sumOfCoefficients !== 0) {
48                currentNode.next = new PolyNode(sumOfCoefficients, poly1.power);
49                currentNode = currentNode.next;
50            }
51          
52            // Move both pointers forward
53            poly1 = poly1.next;
54            poly2 = poly2.next;
55        }
56    }
57  
58    // Append any remaining terms from either polynomial
59    currentNode.next = poly1 || poly2;
60  
61    // Return the actual head (skip dummy node)
62    return dummyHead.next;
63}
64

Time and Space Complexity

Time Complexity: O(m + n) where m is the number of nodes in poly1 and n is the number of nodes in poly2.

The algorithm traverses both linked lists exactly once. In each iteration of the while loop, we advance at least one pointer (either poly1, poly2, or both). The loop continues until both lists are fully traversed. Each node from both polynomials is visited exactly once, resulting in linear time complexity relative to the total number of nodes.

Space Complexity: O(1) for auxiliary space, or O(min(m, n)) if we consider the output space.

The algorithm uses only a constant amount of extra space for the dummy and curr pointers. However, when two nodes have the same power and their coefficients sum to a non-zero value, a new node is created. In the worst case, all nodes from the shorter polynomial could have matching powers with the longer one, creating up to min(m, n) new nodes. For nodes where powers don't match or when one list is exhausted, the algorithm reuses existing nodes by adjusting pointers rather than creating new ones.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Modifying Input Lists Instead of Creating New Nodes

The Pitfall: In the current implementation, when powers don't match (Cases 1 and 2), we directly link to existing nodes from the input lists:

if poly1.power > poly2.power:
    current.next = poly1  # Reusing original node!
    poly1 = poly1.next
    current = current.next

This means the result list shares nodes with the input lists. If the caller later modifies either input list, it will inadvertently modify the result list too. This violates the principle of immutability and can lead to unexpected bugs.

Example Scenario:

# Original lists
poly1: 5x^3 -> 4x -> -7
poly2: 3x^2 -> 6

# After addition, result shares nodes
result: 5x^3 -> 3x^2 -> 4x -> -1

# If someone modifies poly1's first node later:
poly1.coefficient = 10  # Changes 5x^3 to 10x^3

# The result is now corrupted:
result: 10x^3 -> 3x^2 -> 4x -> -1  # Unexpected change!

The Solution: Always create new nodes for the result to ensure complete independence:

class Solution:
    def addPoly(self, poly1: "PolyNode", poly2: "PolyNode") -> "PolyNode":
        dummy_head = PolyNode()
        current = dummy_head
      
        while poly1 and poly2:
            if poly1.power > poly2.power:
                # Create a new node instead of reusing
                current.next = PolyNode(poly1.coefficient, poly1.power)
                poly1 = poly1.next
                current = current.next
            elif poly1.power < poly2.power:
                # Create a new node instead of reusing
                current.next = PolyNode(poly2.coefficient, poly2.power)
                poly2 = poly2.next
                current = current.next
            else:
                coefficient_sum = poly1.coefficient + poly2.coefficient
                if coefficient_sum != 0:
                    current.next = PolyNode(coefficient_sum, poly1.power)
                    current = current.next
                poly1 = poly1.next
                poly2 = poly2.next
      
        # Handle remaining terms - create new nodes
        while poly1:
            current.next = PolyNode(poly1.coefficient, poly1.power)
            current = current.next
            poly1 = poly1.next
          
        while poly2:
            current.next = PolyNode(poly2.coefficient, poly2.power)
            current = current.next
            poly2 = poly2.next
          
        return dummy_head.next

2. Forgetting to Handle Zero Coefficients After Addition

The Pitfall: When adding terms with the same power, beginners often forget to check if the sum equals zero:

# WRONG - creates unnecessary zero-coefficient nodes
if poly1.power == poly2.power:
    current.next = PolyNode(poly1.coefficient + poly2.coefficient, poly1.power)
    current = current.next
    poly1 = poly1.next
    poly2 = poly2.next

This violates the problem requirement that terms with coefficient 0 should not be included in the result.

Example: Adding 3x^2 and -3x^2 would incorrectly produce a node with 0x^2 instead of omitting it entirely.

The Solution: Always check if the coefficient sum is non-zero before creating a node, as shown in the correct implementation above.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which algorithm should you use to find a node that is close to the root of the tree?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More