2130. Maximum Twin Sum of a Linked List
Problem Description
You are given a linked list with an even number of nodes. In this linked list, certain nodes form "twin" pairs based on their positions.
For a linked list of size n
(where n
is even), the twin relationship is defined as:
- Node at position
i
is the twin of node at position(n-1-i)
- This relationship exists for all nodes where
0 <= i <= (n/2) - 1
For example, in a linked list with 4 nodes:
- Node 0 (first node) is the twin of node 3 (last node)
- Node 1 (second node) is the twin of node 2 (third node)
The twin sum is calculated by adding the values of a node and its twin together.
Your task is to find the maximum twin sum among all possible twin pairs in the linked list.
Example walkthrough:
If the linked list is 1 -> 2 -> 3 -> 4
:
- Twin pair (node 0, node 3): sum = 1 + 4 = 5
- Twin pair (node 1, node 2): sum = 2 + 3 = 5
- Maximum twin sum = 5
The solution approach converts the linked list to an array for easier access to elements. It then iterates through the first half of the array, calculating the sum of each element with its twin (accessed using negative indexing s[-(i + 1)]
which corresponds to the twin position). The maximum of all these twin sums is returned as the answer.
Intuition
The key insight is recognizing that finding twins in a linked list requires accessing nodes from both ends simultaneously - we need to pair the first node with the last, the second with the second-to-last, and so on.
In a linked list, we can only traverse forward, making it difficult to access nodes from the end efficiently. To find the twin of node i
, we'd need to traverse to position (n-1-i)
, which would be inefficient if done repeatedly.
This naturally leads us to think about converting the linked list to a data structure that allows random access - an array. Once we have all values in an array s
, finding twins becomes straightforward:
- For any index
i
in the first half, its twin is at indexn-1-i
- Using Python's negative indexing,
s[-(i+1)]
gives us the twin element directly
The transformation simplifies our problem from "traverse a linked list in a complex pattern" to "iterate through half an array and access corresponding elements from the end". We only need to check the first n/2
elements since each twin pair is counted exactly once.
The expression range(n >> 1)
efficiently gives us indices for the first half (using bit shift for division by 2), and for each index i
, we calculate s[i] + s[-(i + 1)]
to get the twin sum. The maximum of all these sums is our answer.
This approach trades a small amount of extra space O(n)
for much simpler and cleaner logic compared to more complex solutions that might try to manipulate the linked list directly.
Learn more about Stack, Linked List and Two Pointers patterns.
Solution Approach
The implementation follows a straightforward two-phase approach:
Phase 1: Convert Linked List to Array
s = []
while head:
s.append(head.val)
head = head.next
We traverse the entire linked list once, extracting each node's value and storing it in an array s
. This gives us O(1)
access to any element by index, which is crucial for efficiently finding twin pairs.
Phase 2: Find Maximum Twin Sum
n = len(s)
return max(s[i] + s[-(i + 1)] for i in range(n >> 1))
After getting the array length n
, we use a generator expression to calculate all twin sums:
range(n >> 1)
iterates through indices0
to(n/2 - 1)
, covering exactly the first half of the array- The bit shift operation
n >> 1
is equivalent ton // 2
, efficiently dividing by 2 - For each index
i
, we calculate the twin sum usings[i] + s[-(i + 1)]
The negative indexing pattern s[-(i + 1)]
deserves special attention:
- When
i = 0
:s[-1]
gives the last element (twin of first) - When
i = 1
:s[-2]
gives the second-to-last element (twin of second) - This pattern continues for all elements in the first half
The max()
function efficiently finds the largest twin sum among all pairs in a single pass.
Time Complexity: O(n)
- we traverse the linked list once and then iterate through half the array
Space Complexity: O(n)
- we store all node values in the array s
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 the solution with a linked list: 5 -> 4 -> 2 -> 1
Step 1: Convert Linked List to Array
Starting with the linked list, we traverse it and build an array:
- Visit node with value 5, add to array:
s = [5]
- Visit node with value 4, add to array:
s = [5, 4]
- Visit node with value 2, add to array:
s = [5, 4, 2]
- Visit node with value 1, add to array:
s = [5, 4, 2, 1]
Step 2: Calculate Twin Sums
Now we have n = 4
elements. We iterate through the first half (n >> 1 = 2
iterations):
Iteration 1 (i = 0):
- First element:
s[0] = 5
- Its twin using negative indexing:
s[-(0 + 1)] = s[-1] = 1
- Twin sum:
5 + 1 = 6
Iteration 2 (i = 1):
- Second element:
s[1] = 4
- Its twin using negative indexing:
s[-(1 + 1)] = s[-2] = 2
- Twin sum:
4 + 2 = 6
Step 3: Find Maximum
Among all twin sums calculated: [6, 6]
The maximum twin sum is 6
This demonstrates how the negative indexing pattern s[-(i + 1)]
naturally pairs each element in the first half with its corresponding twin from the end, allowing us to find the maximum twin sum efficiently.
Solution Implementation
1# Definition for singly-linked list.
2# class ListNode:
3# def __init__(self, val=0, next=None):
4# self.val = val
5# self.next = next
6
7class Solution:
8 def pairSum(self, head: Optional[ListNode]) -> int:
9 # Store all node values in a list
10 values = []
11
12 # Traverse the linked list and collect all values
13 current = head
14 while current:
15 values.append(current.val)
16 current = current.next
17
18 # Get the total number of nodes
19 n = len(values)
20
21 # Find the maximum twin sum
22 # Twin pairs are: (0, n-1), (1, n-2), ..., (n/2-1, n/2)
23 # We iterate through the first half and pair with corresponding element from the end
24 max_twin_sum = max(values[i] + values[n - 1 - i] for i in range(n // 2))
25
26 return max_twin_sum
27
1/**
2 * Definition for singly-linked list.
3 * public class ListNode {
4 * int val;
5 * ListNode next;
6 * ListNode() {}
7 * ListNode(int val) { this.val = val; }
8 * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
9 * }
10 */
11class Solution {
12 /**
13 * Finds the maximum twin sum in a linked list.
14 * Twin sum is defined as the sum of a node at position i and the node at position (n-1-i).
15 *
16 * @param head The head of the linked list
17 * @return The maximum twin sum
18 */
19 public int pairSum(ListNode head) {
20 // Store all node values in a list for easy access by index
21 List<Integer> nodeValues = new ArrayList<>();
22
23 // Traverse the linked list and collect all values
24 ListNode current = head;
25 while (current != null) {
26 nodeValues.add(current.val);
27 current = current.next;
28 }
29
30 // Initialize variables for maximum sum and list size
31 int maxSum = 0;
32 int listSize = nodeValues.size();
33
34 // Calculate twin sums for the first half of the list
35 // Each element at index i is paired with element at index (listSize - 1 - i)
36 for (int i = 0; i < listSize / 2; i++) {
37 int twinSum = nodeValues.get(i) + nodeValues.get(listSize - 1 - i);
38 maxSum = Math.max(maxSum, twinSum);
39 }
40
41 return maxSum;
42 }
43}
44
1/**
2 * Definition for singly-linked list.
3 * struct ListNode {
4 * int val;
5 * ListNode *next;
6 * ListNode() : val(0), next(nullptr) {}
7 * ListNode(int x) : val(x), next(nullptr) {}
8 * ListNode(int x, ListNode *next) : val(x), next(next) {}
9 * };
10 */
11class Solution {
12public:
13 int pairSum(ListNode* head) {
14 // Store all node values in a vector for easy access
15 vector<int> values;
16
17 // Traverse the linked list and collect all values
18 ListNode* current = head;
19 while (current != nullptr) {
20 values.push_back(current->val);
21 current = current->next;
22 }
23
24 // Initialize the maximum twin sum
25 int maxTwinSum = 0;
26 int n = values.size();
27
28 // Calculate twin sums for each pair (i-th and (n-1-i)-th nodes)
29 // Only need to check the first half of nodes
30 for (int i = 0; i < n / 2; ++i) {
31 int twinSum = values[i] + values[n - 1 - i];
32 maxTwinSum = max(maxTwinSum, twinSum);
33 }
34
35 return maxTwinSum;
36 }
37};
38
1/**
2 * Definition for singly-linked list.
3 * class ListNode {
4 * val: number
5 * next: ListNode | null
6 * constructor(val?: number, next?: ListNode | null) {
7 * this.val = (val===undefined ? 0 : val)
8 * this.next = (next===undefined ? null : next)
9 * }
10 * }
11 */
12
13/**
14 * Finds the maximum twin sum in a linked list.
15 * Twin sum is defined as the sum of a node at position i and the node at position (n-1-i),
16 * where n is the total number of nodes in the list.
17 *
18 * @param head - The head of the singly-linked list
19 * @returns The maximum twin sum found in the list
20 */
21function pairSum(head: ListNode | null): number {
22 // Convert linked list to array for easier access to elements
23 const values: number[] = [];
24 let currentNode: ListNode | null = head;
25
26 // Traverse the linked list and store all values in the array
27 while (currentNode !== null) {
28 values.push(currentNode.val);
29 currentNode = currentNode.next;
30 }
31
32 // Get the total number of elements
33 const totalElements: number = values.length;
34 let maxTwinSum: number = 0;
35
36 // Calculate twin sums for the first half of elements paired with their twins
37 // n >> 1 is equivalent to Math.floor(n / 2)
38 for (let i = 0; i < totalElements >> 1; i++) {
39 // Calculate twin sum: element at index i + element at index (n-1-i)
40 const twinSum: number = values[i] + values[totalElements - 1 - i];
41 // Update maximum twin sum if current twin sum is larger
42 maxTwinSum = Math.max(maxTwinSum, twinSum);
43 }
44
45 return maxTwinSum;
46}
47
Time and Space Complexity
Time Complexity: O(n)
where n
is the number of nodes in the linked list.
- The first while loop traverses the entire linked list once to store all values in the array
s
, which takesO(n)
time. - The
max()
function with generator expression iterates through half of the array (n >> 1
which isn/2
iterations), performing constant time addition and comparison operations in each iteration, which takesO(n/2) = O(n)
time. - Overall time complexity:
O(n) + O(n) = O(n)
Space Complexity: O(n)
where n
is the number of nodes in the linked list.
- The array
s
stores alln
values from the linked list, requiringO(n)
additional space. - The generator expression in
max()
usesO(1)
space as it generates values one at a time. - Overall space complexity:
O(n)
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Attempting In-Place Solution Without Proper List Reversal
A common mistake is trying to optimize space by avoiding the array conversion and instead attempting to find twins directly in the linked list. Developers might try to use two pointers without properly handling the list structure:
Incorrect Approach:
def pairSum(self, head: Optional[ListNode]) -> int:
slow = fast = head
# Try to find middle
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# Problem: Can't access twins without reversing!
max_sum = 0
current = head
while current != slow:
# We can't access the twin node from the second half
# without additional data structure or reversal
current = current.next
return max_sum
Solution: If you want to avoid using extra array space, you need to:
- Find the middle of the linked list
- Reverse the second half
- Compare pairs from both halves
- (Optional) Restore the original list structure
def pairSum(self, head: Optional[ListNode]) -> int:
# Find middle using slow/fast pointers
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# Reverse second half
prev = None
current = slow
while current:
next_temp = current.next
current.next = prev
prev = current
current = next_temp
# Calculate max twin sum
max_sum = 0
first_half = head
second_half = prev
while second_half:
max_sum = max(max_sum, first_half.val + second_half.val)
first_half = first_half.next
second_half = second_half.next
return max_sum
2. Off-by-One Errors in Index Calculation
When manually calculating twin indices, developers often make mistakes with the formula:
Incorrect:
# Wrong twin calculation
max_sum = max(values[i] + values[n - i] for i in range(n // 2)) # Off by one!
Correct:
# Correct twin calculation
max_sum = max(values[i] + values[n - 1 - i] for i in range(n // 2))
The twin of index i
is at position n - 1 - i
, not n - i
. Remember that array indices go from 0
to n-1
.
3. Not Handling Edge Cases Properly
While the problem guarantees an even number of nodes, defensive programming suggests validating assumptions:
def pairSum(self, head: Optional[ListNode]) -> int:
if not head or not head.next:
return 0 # Handle edge case gracefully
values = []
current = head
while current:
values.append(current.val)
current = current.next
n = len(values)
# Verify even length (as per problem constraints)
assert n % 2 == 0, "List must have even number of nodes"
return max(values[i] + values[n - 1 - i] for i in range(n // 2))
What is an advantages of top-down dynamic programming vs bottom-up dynamic programming?
Recommended Readings
Stack Intro Imagine you have a pile of books on your desk If you want to add a new book you place it on top If you want to read a book you take it from the top And if you simply want to see which book is on the top you
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
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!