Skip to main content

768. Max Chunks

Max Chunks To Make Sorted II​

This problem carries a very peculiar feeling for me: a sense that things have changed while the problem remains the same.

I solved it for the first time in late 2024.

Coming back in early 2026, I got AC again.

But these two solutions are based on different data structures.

I. Late 2024: Prefix and Suffix​

Sword vs. Shield​

Let's first think about two adjacent chunks.

After sorting each individually, they can be concatenated into a sorted array.

What does this imply? Quite obvious:

max⁡(Chunkleft)≤min⁡(Chunkright)\max(Chunk_{left}) \leq \min(Chunk_{right})

Think of max⁡(Chunkleft)\max(Chunk_{left}) as a sword 🗡️

and min⁡(Chunkright)\min(Chunk_{right}) as a shield 🛡.

For a shield to remain unbroken,

its weakest point must be no weaker than the sharpest tip of any sword.

Scan Right Then Left​

So for an array numsnums of length nn (the problem calls it arrarr, but I prefer numsnums),

for every index ii satisfying 1≤i<n1 \leq i < n, we check:

Does max⁡(nums[:i])≤min⁡(nums[i:])\max(nums[:i]) \leq \min(nums[i:]) hold?

If so, index ii is a cut point, meaning the array can be split into two chunks at index ii,

and sorting each chunk separately then concatenating will yield a sorted result.

This means we need to first scan left,

building a prefix_maxs array recording each max⁡(nums[:i])\max(nums[:i]),

then scan back from the right, tracking min⁡(nums[i:])\min(nums[i:]) with suffix_min.

Whenever max⁡(nums[:i])≤min⁡(nums[i:])\max(nums[:i]) \leq \min(nums[i:]) holds, increment max_chunks by 1.

But remember:

max_chunks starts at 1, not 0​

Even a strictly decreasing numsnums can count as one chunk.

def find_max_sortable_chunks(nums: list[int]) -> int:
prefix_maxs = [] # Max of each nums[:(i + 1)th idx].

for num in nums:
if not prefix_maxs:
prefix_maxs.append(num)
continue

prefix_maxs.append(max(num, prefix_maxs[-1]))

max_chunks = 1 # Base case.
suffix_min = nums[-1] # Min of nums[ith idx:].

for idx in range(len(nums) - 1, 0, -1):
if nums[idx] < suffix_min:
suffix_min = nums[idx]

if prefix_maxs[idx - 1] <= suffix_min:
max_chunks += 1

return max_chunks

Prefix Efficiency Time complexity O(n)O(n), space complexity O(n)O(n), with two passes through the array.

About a year and a half later, I thought of an alternative approach below...

II. Early 2026: Monotonic Increasing Stack​

Eligibility to Lead a Chunk​

Looking at previous code, prefix_maxs is a continuous process of expanding current leader.

Can you sense what situation would a leader get ineligible to be maximum of its chunk?

Consider this scenario: 0≤j<k<l<n0 \leq j < k < l < n

nums[j]≤nums[k]nums[j] \leq nums[k] holds.

max⁡(nums[:j+1])=nums[j]\max(nums[:j + 1]) = nums[j] holds.

max⁡(nums[:k+1])=nums[k]\max(nums[:k + 1]) = nums[k] holds.

So nums[j]nums[j] leads Chunkj=nums[:j+1]Chunk_j = nums[:j + 1],

and nums[k]nums[k] leads Chunkk=nums[j+1:k+1]Chunk_k = nums[j + 1:k + 1]. All good so far.

But Life Has Its "Buts"​

Now comes nums[l]nums[l] satisfying nums[l]<nums[j]≤nums[k]nums[l] < nums[j] \leq nums[k].

Since k<lk < l, nums[l]nums[l] lies to the right of both nums[j]nums[j] and nums[k]nums[k].

With sharp instincts, we immediately have a problem:

I. If nums[l]nums[l] is kept out of ChunkkChunk_k (led by nums[k]nums[k]),

then nums[l]nums[l] forms ChunkyChunk_y with elements to its right. After sorting,

ChunkyChunk_y meets ChunkjChunk_j from the left — nums[j]nums[j] and nums[l]nums[l] end up out of order.

II. Okay, so let nums[l]nums[l] join ChunkkChunk_k.

But after ChunkkChunk_k is sorted and meets ChunkjChunk_j from the left,

nums[j]nums[j] and nums[l]nums[l] are still out of order.

From both paths, we conclude directly:

nums[l]nums[l] and nums[j]nums[j] must be in the same chunk. Separating them causes problems.

This is precisely why nums[j]nums[j] must step down and can no longer lead any chunk.

Putting Monotonicity to Work​

So we arrive at a conclusion: whenever the current nums[i]nums[i]

is smaller than prefix_maxs[-1], we should:

(1). pop() to remove prefix_maxs[-1]

(2). If prefix_maxs is not yet empty,

keep checking whether prefix_maxs[-1] > nums[i]. If so, repeat step (2).

Otherwise, push the originally popped value back onto the right end of prefix_maxs.

Isn't this exactly the behavior of a monotonic increasing stack? 👌

After traversal, count how many elements remain in the stack, say ss. That means there are ss eligible chunk leaders. Return ss.

def find_max_sortable_chunks(nums: list[int]) -> int:
stack: list[int] = []

for num in nums:
if not stack:
stack.append(num)
continue

chunk_max = stack[-1]

while stack and stack[-1] > num:
stack.pop(-1)

stack.append(max(chunk_max, num))

return len(stack)

Both the stack and prefix approaches run in O(n)O(n) time and O(n)O(n) space, but the stack uses only a single pass.