Skip to main content

2025. Partitions Count

Maximum Number of Ways to Partition an Array

An extremely brain-burning problem. I got it wrong on my first eight attempts 😆

Back then, facing an obviously complex problem like problem 2025 with only around a 36% acceptance rate,

I was quite easy to fall into a shotgun approach.

I later learned to hit the brakes, observe calmly, then react.

Default Max Partitions Count

The problem says we can choose to leave every element unchanged.

So first, look at original array of length nn:

how many indices ii with 1i<n1 \leq i < n satisfy

sum(nums[:i])=sum(nums[i:])\text{sum}(nums[:i]) = \text{sum}(nums[i:])?

Default value of max partitions count is:

C=Σi=1n11(sum(nums[:i])=sum(nums[i:]))C = \Sigma_{i = 1}^{n - 1} \mathbf{1}(\text{sum}(nums[:i]) = \text{sum}(nums[i:]))

Hard Part: Changing One Element

The problem also allows us to pick exactly one index jj and replace nums[j]nums[j] with input kk.

This means we need to find which jj maximizes:

C=maxjΣi=1n11(sum(nums[:i])=sum(nums[i:]))C' = \max_{j} \Sigma_{i = 1}^{n - 1} \mathbf{1}(\text{sum}(nums'[:i]) = \text{sum}(nums'[i:]))

where numsnums' differs from numsnums only in that nums[j]=knums'[j] = k.

The final answer is max(C,C)\max(C, C').

Find C'

Concept of Prefix-Suffix Difference

First, prepare a hash map called rightDiffCounts, and a pivot index pivotIdx. As defined by the problem, pivotIdx must start from 1 and < nn.

As pivotIdx traverses from 1 to n1n - 1,

compute prefix-suffix difference D=sum(nums[:pivotIdx])sum(nums[pivotIdx:])D = \text{sum}(nums[:\text{pivotIdx}]) - \text{sum}(nums[\text{pivotIdx}:]),

and record count of each DD in rightDiffCounts.

What is this difference good for? Imagine:

if some index ll less than pivotIdx is selected,

nums[l]nums[l] changes to kk, and nums[l]k=Dnums[l] - k = D,

then sum(nums[:pivotIdx])sum(nums[pivotIdx:])\text{sum}(nums[:\text{pivotIdx}]) - \text{sum}(nums[\text{pivotIdx}:]) becomes zero!

pivotIdx becomes a valid split point due to this change, and CC' increases by 1.

The Symmetric Trap

one more thing to pay attention to:

when some index ll has nums[l]nums[l] changed to kk,

the valid split points it creates can be to the left or to the right of ll.

Using only rightDiffCounts (which tracks prefix-suffix differences for split points to the right of ll) is not enough.

We also need leftDiffCounts to manage differences for split points to the left of ll.

Traversal Logic for Final Counting

Prefix Perspective

The traversal index ll, where 0l<n0 \leq l < n,

checks: after changing nums[l]nums[l] to kk,

how many split points to the right of ll have a prefix-suffix difference of nums[l]knums[l] - k?

The change to nums[l]nums[l] affects the prefix sum from the perspective of split points to ll's right.

Look up nums[l]knums[l] - k in rightDiffCounts for the count.

Suffix Perspective

By symmetric reasoning, changing nums[l]nums[l] to kk

affects the suffix sum from the perspective of potential split points to ll's left.

Count how many split points to the left of ll have a prefix-suffix difference of knums[l]k - nums[l].

Look up knums[l]k - nums[l] in leftDiffCounts for the count.

Number of perfect split points created by changing nums[l]nums[l] to kk is:

ClC'_l = leftDiffCounts[k - nums[l]] + rightDiffCounts[nums[l] - k]

Compare this with the current best CC and update if it's larger.

Note that since we're dealing with prefix and suffix perspectives, the queried differences differ by exactly a sign flip.

Update Both Hash Maps at Each Step

After visiting index ll, compute Dl=sum(nums[:l+1])sum(nums[l+1:])D_l = \text{sum}(nums[:l + 1]) - \text{sum}(nums[l + 1:]).

Decrement DlD_l's count in rightDiffCounts.

Increment DlD_l's count in leftDiffCounts.

Because from the perspective of all indices larger than ll, ll can only be a left split point, never a right one.

#include <unordered_map>
#include <vector>
using namespace std;

int countMaxPartitions(vector<int>& nums, int k) // LeetCode Q.2025.
{
long long totalSum = 0; // Prevents overflow.
for (const auto& num : nums)
totalSum += num;

// Left diff: only consider potential pivot indices at left side.
// Right diff: only consider potential pivot indices at right side.
// Map key: diff = prefix sum - suffix sum.
unordered_map<long long, int> leftDiffCounts, rightDiffCounts;

// Default to natural value: leave entire array unchanged.
int maxPartitionWays = 0;

long long prefixSum = 0;
for (int pivotIdx = 1; pivotIdx < nums.size(); pivotIdx++) {
prefixSum += nums[pivotIdx - 1];
long long suffixSum = totalSum - prefixSum;
rightDiffCounts[prefixSum - suffixSum]++;

// Born as a great partition. No need to change.
if (prefixSum == suffixSum)
maxPartitionWays++;
}

prefixSum = 0; // Reset to let next for loop sweep again.

for (int idx = 0; idx < nums.size(); idx++) {
int num = nums[idx];
prefixSum += num;

int partitionWays = 0;

// Potential pivot idx is at the right of current idx.
partitionWays += rightDiffCounts[num - k];

// Potential pivot idx is at the left of current idx.
partitionWays += leftDiffCounts[k - num];

if (partitionWays > maxPartitionWays)
maxPartitionWays = partitionWays;

long long diff = 2 * prefixSum - totalSum; // Prefix - suffix.

// For future indices, this diff is only available as left side.
leftDiffCounts[diff]++;
rightDiffCounts[diff]--;
}

return maxPartitionWays;
}

Prefix_Sum Efficiency Time complexity O(n)O(n), space complexity O(n)O(n).

Logic here is genuinely complex. Think it through several times before key insight clicks.