2130. Maximum Twin Sum Of A Linked List - Explanation
Description
In a linked list of size n, where n is even, the i-th node (0-indexed) of the linked list is known as the twin of the (n-1-i)-th node, if 0 <= i <= (n / 2) - 1.
- For example, if
n = 4, then node0is the twin of node3, and node1is the twin of node2. These are the only nodes with twins forn = 4.
The twin sum is defined as the sum of a node and its twin.
You are given the head of a linked list with even length, return the maximum twin sum of the linked list.
Example 1:
Input: head = [5,4,2,1]
Output: 6Explanation:
Nodes 0 and 1 are the twins of nodes 3 and 2, respectively. All have twin sum = 6.
There are no other nodes with twins in the linked list.
Thus, the maximum twin sum of the linked list is 6.
Example 2:
Input: head = [4,2,2,3]
Output: 7Explanation:
The nodes with twins present in this linked list are:
- Node 0 is the twin of node 3 having a twin sum of 4 + 3 = 7.
- Node 1 is the twin of node 2 having a twin sum of 2 + 2 = 4.
Thus, the maximum twin sum of the linked list is max(7, 4) = 7.
Example 3:
Input: head = [1,100000]
Output: 100001Explanation:
There is only one node with a twin in the linked list having twin sum of 1 + 100000 = 100001.
Constraints:
- The number of nodes in the list is an even integer in the range
[2, 100,000]. 1 <= Node.val <= 100,000
Topics
Prerequisites
Before attempting this problem, you should be comfortable with:
- Linked List Basics - Understanding node structure and traversal techniques
- Two Pointers - Using two pointers to traverse from opposite ends of a data structure
- Slow/Fast Pointer Technique - Finding the middle of a linked list using two pointers moving at different speeds
- Linked List Reversal - Reversing a linked list in-place by manipulating node pointers
1. Convert To Array
Intuition
A twin sum pairs the i-th node from the start with the i-th node from the end. Since linked lists do not support random access, we first convert the list into an array. With an array, we can use two pointers starting at opposite ends to easily compute each twin sum and track the maximum.
Algorithm
- Traverse the linked list and store each node's value in an array
arr. - Initialize two pointers:
iat the start andjat the end of the array. - While
i < j:- Compute
arr[i] + arr[j]and updateresif this sum is larger. - Move
iforward andjbackward.
- Compute
- Return
res.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def pairSum(self, head: Optional[ListNode]) -> int:
arr = []
cur = head
while cur:
arr.append(cur.val)
cur = cur.next
i, j = 0, len(arr) - 1
res = 0
while i < j:
res = max(res, arr[i] + arr[j])
i, j = i + 1, j - 1
return resTime & Space Complexity
- Time complexity:
- Space complexity:
2. Reverse the Second Half
Intuition
To avoid extra space from converting to an array, we can modify the list itself. Using the slow and fast pointer technique, we find the middle of the list. Then we reverse the second half in place. Now the first half and the reversed second half can be traversed simultaneously, allowing us to compute twin sums directly without extra storage.
Algorithm
- Use
slowandfastpointers to find the start of the second half. Whenfastreaches the end,slowis at the midpoint. - Reverse the second half of the list starting from
slow. - Initialize
firstat the head andsecondat the head of the reversed second half. - While
secondis not null:- Compute
first.val + second.valand updateresif larger. - Advance both
firstandsecond.
- Compute
- Return
res.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def pairSum(self, head: Optional[ListNode]) -> int:
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
prev, cur = None, slow
while cur:
nxt = cur.next
cur.next = prev
prev = cur
cur = nxt
res = 0
first, second = head, prev
while second:
res = max(res, first.val + second.val)
first, second = first.next, second.next
return resTime & Space Complexity
- Time complexity:
- Space complexity: extra space.
3. Reverse the First Half
Intuition
Instead of reversing the second half after finding the middle, we can reverse the first half as we go. While traversing with slow and fast pointers, we reverse the links behind slow. By the time slow reaches the middle, the first half is already reversed. Now slow points to the start of the second half, and prev points to the end of the reversed first half. We can traverse both halves in parallel to find the maximum twin sum.
Algorithm
- Initialize
slowandfastat head, andprevas null. - While
fastandfast.nextare not null:- Move
fasttwo steps ahead. - Reverse the link: save
slow.next, pointslow.nexttoprev, updateprevtoslow, and moveslowforward.
- Move
- Now
prevpoints to the tail of the reversed first half, andslowpoints to the head of the second half. - Traverse both halves together, computing twin sums and tracking the maximum.
- Return
res.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def pairSum(self, head: Optional[ListNode]) -> int:
slow, fast = head, head
prev = None
while fast and fast.next:
fast = fast.next.next
tmp = slow.next
slow.next = prev
prev = slow
slow = tmp
res = 0
while slow:
res = max(res, prev.val + slow.val)
prev = prev.next
slow = slow.next
return resTime & Space Complexity
- Time complexity:
- Space complexity: extra space.
Common Pitfalls
Incorrect Middle Detection with Fast/Slow Pointers
A common mistake is using the wrong loop condition for finding the middle. For this problem, when fast and fast.next are both not null, slow advances. If you use fast.next and fast.next.next, you may stop one node too early or too late, causing incorrect pairing of twin nodes.
Reversing the Wrong Half
When reversing in-place, some developers accidentally reverse the first half when they intended to reverse the second half, or vice versa. This leads to incorrect twin pairings. Ensure you clearly track which portion of the list you are reversing and where the boundary lies after finding the middle.
Losing Track of Pointers During Reversal
While reversing, failing to save the next pointer before modifying cur.next causes you to lose access to the rest of the list. Always store nxt = cur.next before setting cur.next = prev, then advance using the saved reference.
Sign in to join the discussion