Max Chunks To Make Sorted LT769

Given an array arr that is a permutation of [0, 1, ..., arr.length - 1], we split the array into some number of "chunks" (partitions), and individually sort each chunk.  After concatenating them, the result equals the sorted array.

What is the most number of chunks we could have made?

Example 1:

Input: arr = [4,3,2,1,0]
Output: 1
Explanation:
Splitting into two or more chunks will not return the required result.
For example, splitting into [4, 3], [2, 1, 0] will result in [3, 4, 0, 1, 2], which isn't sorted.

Example 2:

Input: arr = [1,0,2,3,4]
Output: 4
Explanation:
We can split into two chunks, such as [1, 0], [2, 3, 4].
However, splitting into [1, 0], [2], [3], [4] is the highest number of chunks possible.

Note:

  • arr will have length in range [1, 10].
  • arr[i] will be a permutation of [0, 1, ..., arr.length - 1].


1. Iterate the array, if all the elements on the left are smaller than the elements on the left, there is a new chunk. The first solution use two arrays, leftMax[i] to record the max element ending at i and starting from 0, rightMin[i] to record element starting at i and ending at 0. 

Time complexity: O(n)

Space complexity: O(n)

class Solution {
    public int maxChunksToSorted(int[] arr) {
        if(arr == null) return 1;
        
        int sz = arr.length;
        int[] leftMax = new int[sz];
        int[] rightMin = new int[sz];
        
        leftMax[0] = arr[0];
        for(int i = 1; i < sz; ++i) {
            leftMax[i] = Math.max(leftMax[i-1], arr[i]);
        }
        
        rightMin[sz-1] = arr[sz-1];
        for(int i = sz-2; i >= 0; --i) {
            rightMin[i] = Math.min(rightMin[i+1], arr[i]);            
        }

        int count = 1;
        for(int i = 0; i < sz-1; ++i) {
            if(leftMax[i] < rightMin[i+1] ) ++count;
        }
        
        return count;
    }
}

1a. Since we iterate either from left to right or right to left, we do not need two arrays to keep all the previous record and can use one varible to record the max element from the left so far, as long as the max element is smaller than the min element on the right, there is a new chunk

class Solution {
    public int maxChunksToSorted(int[] arr) {
        if(arr == null) return 1;
        
        int sz = arr.length;
        int[] rightMin = new int[sz];
        rightMin[sz-1] = arr[sz-1];
        for(int i = sz-2; i >= 0; --i) {
            rightMin[i] = Math.min(rightMin[i+1], arr[i]);
        }
        
        int max = arr[0];
        int count = 1;
        for(int i = 0; i < sz-1; ++i) {
            max = Math.max(max, arr[i]);
            if(max < rightMin[i+1]) ++count;
        }
        
        return count;
    }
}

1b. Iterate from right to left:

class Solution {
    public int maxChunksToSorted(int[] arr) {
        if(arr == null) return 1;
        
        int sz = arr.length;
        int[] leftMax = new int[sz];
        leftMax[0] = arr[0];
        for(int i = 1; i < sz; ++i) {
            leftMax[i] = Math.max(leftMax[i-1], arr[i]);
        }
        
        int rightMin = arr[sz-1];
        int count = 1;
        for(int i = sz-1; i >= 1; --i) {
            rightMin = Math.min(rightMin, arr[i]);
            if(leftMax[i-1] < rightMin) {
                ++count;   
            }
        }
        return count;
    }
}

2. Since arr[i] will be a permutation of [0, 1, ..., arr.length - 1], each element is unique and after sorted, arr[i] = i, the elements on the left will be smaller than the elemnts on the right, as long as the max element at index i is arr[i].

Time complexity: O(n)

Space complexity: O(1)

class Solution {
    public int maxChunksToSorted(int[] arr) {
        if(arr == null) return 1;
        
        int maxSoFar = arr[0];
        int count = 0;
        for(int i = 0; i < arr.length; ++i) {
            maxSoFar = Math.max(maxSoFar, arr[i]);
            if(maxSoFar == i) ++count;
        }
        
        return count;
    }
}

2a Another slightly optimisation to terminate the loop early if the max element arr[arr.length-1] is found

class Solution {
    public int maxChunksToSorted(int[] arr) {
        if(arr == null) return 1;
        
        int maxSoFar = arr[0];
        int count = 0;
        for(int i = 0; i < arr.length; ++i) {
            maxSoFar = Math.max(maxSoFar, arr[i]);
            if(maxSoFar == arr.length-1) return count+1;
            if(maxSoFar == i) ++count;
        }
        
        return count;
    }
}

3. Another way to think, if we consider each chunk, as a range [min, max] ended at max, if the next element is smaller than the previous max, we need to merge the range by poping up the max element of chunks which max element is bigger, we need to include the new element in the poped up chunks, otherwise, push the new max element. The number of elements on the stack means the number of chunks.

[4, 3, 2, 1, 0] -> [4] for 4 -> [4] for 3 -> [4] for 2 -> [4] for 1 -> [0] 

[1, 0, 2, 3, 4] -> [1] -> [1] -> [1, 2] -> [1, 2, 3] -> [1, 2, 3, 4]

[1, 2, 0, 3] -> [1] -> [1, 2] -> [2] -> [2, 3]

Time complexity: O(n)

Space complexity: O(n)

class Solution {
    public int maxChunksToSorted(int[] arr) {
        Deque<Integer> maxStack = new LinkedList<Integer>();
        
        for(int num: arr) {
            if(maxStack.isEmpty() || num > maxStack.peek()) {
                maxStack.push(num);
            }
            else {
                int max = maxStack.peek();
                while(!maxStack.isEmpty() && num < maxStack.peek()) {
                    maxStack.pop();
                }
                maxStack.push(max);
            }
        }
        
        return maxStack.size();
    }
}

3a It can be observed from the code that we always push the current max as where the range ends.

public class Solution {

    public int maxChunksToSorted(int[] arr) {
        Deque<Integer> maxStack = new LinkedList<Integer>();

        for(int num: arr) {
            int currMax = maxStack.isEmpty()? num: Math.max(num, maxStack.peek());

            while(!maxStack.isEmpty() && num < maxStack.peek()) {
                maxStack.pop();
            }
            
            maxStack.push(currMax);
        }

        return maxStack.size();
    }
}

4. Another way is to caculate the distance between the current index with the expected sorted index, if the sum is 0, the whole chunk could be a sorted array.

Time complexity: O(n)

Space complexity: O(1)

public class Solution {

    public int maxChunksToSorted(int[] arr) {

        int count = 0, sum = 0;
        for(int i = 0; i < arr.length; ++i) {
            sum += arr[i] - i;
            if(sum == 0) ++count;
        }
       return count;
    }

}

猜你喜欢

转载自www.cnblogs.com/taste-it-own-it-love-it/p/10357864.html