You are given a 0-indexed integer array nums
of length n
. The number of ways to partition nums
is the number of pivot
indices that satisfy both conditions:
1 <= pivot < n
nums[0] + nums[1] + ... + nums[pivot - 1] == nums[pivot] + nums[pivot + 1] + ... + nums[n - 1]
You are also given an integer k
. You can choose to change the value of one element of nums
to k
, or to leave the array unchanged.
Return the maximum possible number of ways to partition nums
to satisfy both conditions after changing at most one element.
Example 1:
Input: nums = [2,-1,2], k = 3 Output: 1 Explanation: One optimal approach is to change nums[0] to k. The array becomes [3,-1,2]. There is one way to partition the array: - For pivot = 2, we have the partition [3,-1 | 2]: 3 + -1 == 2.
Example 2:
Input: nums = [0,0,0], k = 1 Output: 2 Explanation: The optimal approach is to leave the array unchanged. There are two ways to partition the array: - For pivot = 1, we have the partition [0 | 0,0]: 0 == 0 + 0. - For pivot = 2, we have the partition [0,0 | 0]: 0 + 0 == 0.
Example 3:
Input: nums = [22,4,-25,-20,-15,15,-16,7,19,-10,0,-13,-14], k = -33 Output: 4 Explanation: One optimal approach is to change nums[2] to k. The array becomes [22,4,-33,-20,-15,15,-16,7,19,-10,0,-13,-14]. There are four ways to partition the array.
Constraints:
n == nums.length
2 <= n <= 105
-105 <= k, nums[i] <= 105
This problem asks to find the maximum number of ways to partition an array into two subarrays with equal sums, with the option to change at most one element to a given value k
. The solution uses a clever combination of prefix sums and hash tables for efficient counting.
Core Idea:
Prefix Sums: A prefix sum array s
is created where s[i]
represents the sum of elements from nums[0]
to nums[i-1]
. This allows for calculating the sum of any subarray in O(1) time.
Hash Tables (Dictionaries): Two hash tables, left
and right
, are used to store the counts of prefix sums. left[x]
stores how many times the prefix sum x
appears to the left of a potential pivot, and right[x]
stores the same to the right.
Partitioning Condition: A partition is valid if the sum of the left subarray equals the sum of the right subarray. Using prefix sums, this condition translates to s[pivot] == s[n] - s[pivot]
(where n
is the array length). This simplifies to 2 * s[pivot] == s[n]
, meaning s[n]
must be even for any valid partition.
Handling the Modification: The solution iterates through each element of nums
. For each element, it simulates changing it to k
. This changes the overall sum by d = k - nums[i]
. The new partitioning condition becomes:
2 * s[pivot] == s[n] + d
(if the pivot is to the left of the modified element)2 * (s[pivot] + d) == s[n] + d
(if the pivot is to the right of the modified element).Counting Partitions: After modifying the element, the algorithm checks how many ways the array can be partitioned using the updated prefix sums and hash tables.
Time and Space Complexity:
Time Complexity: O(n), where n is the length of nums
. This is because the prefix sum calculation, hash table population, and iteration over elements all take linear time.
Space Complexity: O(n), primarily due to the prefix sum array and hash tables. In the worst case, all prefix sums could be distinct, resulting in hash tables of size O(n).
Code Explanation (Python):
class Solution:
def waysToPartition(self, nums: List[int], k: int) -> int:
n = len(nums)
s = [0] * (n + 1) # Prefix sum array (s[0] is 0)
for i in range(n):
s[i + 1] = s[i] + nums[i]
right = defaultdict(int)
for i in range(n):
right[s[i]] += 1 # Count prefix sums from the right
ans = 0
if s[n] % 2 == 0:
ans = right[s[n] // 2] # Count partitions without modification
left = defaultdict(int) # Count prefix sums from the left
for i in range(n):
d = k - nums[i]
if (s[n] + d) % 2 == 0:
target_left = (s[n] + d) // 2
target_right = (s[n] - d) // 2
ans = max(ans, left[target_left] + right[target_right]) #Find max partitions after change
left[s[i+1]] += 1 # Update left count after processing each element
right[s[i]] -= 1 # Update right count as we process from left to right
return ans
The Java, C++, and Go code implementations follow the same logic, adapting the syntax and data structures for each language. The core algorithm remains consistent across all four languages.