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., in9x^4
, the coefficient is9
)power
: The exponent of the variable (e.g., in9x^4
, the power is4
)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
(representing5x^3
) - Second node:
coefficient=4, power=1
(representing4x
) - Third node:
coefficient=-7, power=0
(representing-7
)
Your task is to:
- Take two polynomial linked lists (
poly1
andpoly2
) - Add them together by combining like terms (terms with the same power)
- Return the head of a new linked list representing the sum
- 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)
.
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:
-
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
- Create a dummy head node to simplify list construction:
-
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 inpoly2
- Add this node directly to the result:
curr.next = poly1
- Advance
poly1
andcurr
pointers
- The term from
-
Case 2:
poly1.power < poly2.power
- The term from
poly2
has no matching term inpoly1
- Add this node directly to the result:
curr.next = poly2
- Advance
poly2
andcurr
pointers
- The term from
-
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
andpoly2
pointers regardless of whether we created a node
-
-
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.
-
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 EvaluatorExample 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:
poly1
→null
,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:
- Merges terms with matching powers by adding coefficients
- Automatically excludes zero-coefficient terms
- Maintains descending power order
- 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.
Which algorithm should you use to find a node that is close to the root of the tree?
Recommended Readings
Linked List Cycle Given a linked list with potentially a loop determine whether the linked list from the first node contains a cycle in it For bonus points do this with constant space Parameters nodes The first node of a linked list with potentially a loop Result Whether there is a loop contained
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
Want a Structured Path to Master System Design Too? Don’t Miss This!