class Solution:
def maxChunksToSorted(self, arr):
n = len(arr)
max_left = [0] * n
min_right = [0] * n
max_left[0] = arr[0]
for i in range(1, n):
max_left[i] = max(max_left[i-1], arr[i])
min_right[-1] = arr[-1]
for i in range(n-2, -1, -1):
min_right[i] = min(min_right[i+1], arr[i])
chunks = 0
for i in range(n-1):
if max_left[i] <= min_right[i+1]:
chunks += 1
return chunks + 1
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
int n = arr.size();
vector<int> maxLeft(n), minRight(n);
maxLeft[0] = arr[0];
for (int i = 1; i < n; ++i)
maxLeft[i] = max(maxLeft[i-1], arr[i]);
minRight[n-1] = arr[n-1];
for (int i = n-2; i >= 0; --i)
minRight[i] = min(minRight[i+1], arr[i]);
int chunks = 0;
for (int i = 0; i < n-1; ++i) {
if (maxLeft[i] <= minRight[i+1])
++chunks;
}
return chunks + 1;
}
};
class Solution {
public int maxChunksToSorted(int[] arr) {
int n = arr.length;
int[] maxLeft = new int[n];
int[] minRight = new int[n];
maxLeft[0] = arr[0];
for (int i = 1; i < n; i++) {
maxLeft[i] = Math.max(maxLeft[i-1], arr[i]);
}
minRight[n-1] = arr[n-1];
for (int i = n-2; i >= 0; i--) {
minRight[i] = Math.min(minRight[i+1], arr[i]);
}
int chunks = 0;
for (int i = 0; i < n-1; i++) {
if (maxLeft[i] <= minRight[i+1]) {
chunks++;
}
}
return chunks + 1;
}
}
var maxChunksToSorted = function(arr) {
const n = arr.length;
const maxLeft = Array(n);
const minRight = Array(n);
maxLeft[0] = arr[0];
for (let i = 1; i < n; i++) {
maxLeft[i] = Math.max(maxLeft[i-1], arr[i]);
}
minRight[n-1] = arr[n-1];
for (let i = n-2; i >= 0; i--) {
minRight[i] = Math.min(minRight[i+1], arr[i]);
}
let chunks = 0;
for (let i = 0; i < n-1; i++) {
if (maxLeft[i] <= minRight[i+1]) {
chunks++;
}
}
return chunks + 1;
};
You are given an array arr
of integers, which may contain duplicates and are not necessarily in order. Your task is to split arr
into the maximum number of "chunks" such that after sorting each chunk individually and concatenating them in order, the result is the same as sorting the entire array.
Key constraints:
At first glance, it might seem that we could simply cut the array at every point where the current prefix is sorted, but with duplicate values or unsorted elements, that doesn't always work.
A brute-force approach would be to check every possible way to split the array and see if sorting the chunks and concatenating gives the sorted array. However, this is computationally expensive and not feasible for large arrays.
To optimize, we need a way to decide efficiently where we can safely "cut" the array into chunks. The key insight is to look for positions where everything to the left is less than or equal to everything to the right. If so, sorting the two parts separately and concatenating will give the correct order.
The core idea is to find all positions where the maximum element on the left is less than or equal to the minimum element on the right. At these positions, it is safe to split the array into chunks.
max_left
).
min_right
).
max_left[i] <= min_right[i+1]
. If true, a chunk can end at i
.
This approach ensures that after sorting each chunk and concatenating, the result will be the same as sorting the entire array.
Consider the input arr = [5,4,3,2,1]
.
- The sorted array is [1,2,3,4,5]
.
- Let's compute max_left
and min_right
:
max_left[i] > min_right[i+1]
, so no valid split. Therefore, only one chunk is possible (the whole array).
Now consider arr = [2,1,3,4,4]
.
- The sorted array is [1,2,3,4,4]
.
- max_left: [2,2,3,4,4]
- min_right: [1,1,3,4,4]
- Check splits:
max_left
and min_right
both take O(n) time.The key to solving "Max Chunks To Make Sorted II" is to recognize that a chunk can end where all elements to the left are less than or equal to all elements to the right. By precomputing the maximums to the left and minimums to the right, we can efficiently find all valid split points in linear time. This approach is both elegant and efficient, transforming a seemingly complex problem into a straightforward linear scan with auxiliary arrays.