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 1≤i<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=1n−11(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′=max⁡jΣi=1n−11(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 nums′nums' 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 n−1n - 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 C′C' 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 0≤l<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 k−nums[l]k - nums[l].

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

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

Cl′C'_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) {
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.