其他分享
首页 > 其他分享> > Max Chunks To Make Sorted II

Max Chunks To Make Sorted II

作者:互联网

Max Chunks To Make Sorted II

You are given an integer array  arr.

We split  arr into some number of chunks (i.e., partitions), and individually sort each chunk. After concatenating them, the result should equal the sorted array.

Return the largest number of chunks we can make to sort the array.

Example 1:

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

Example 2:

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

Constraints:

$1 \leq arr.length \leq 2000$
$0 \leq arr[i] \leq {10}^8$

 

解题思路

  对原数组$a$进行排序,得到数组$b$。对数组$a$进行分块,使得数组$a$中的每个块与数组$b$对应的区间是一一对应的。

  可以贪心来做,从前往后枚举来考虑,如果发现枚举到某个数时,$a$的第一个区间里面的所有数与$b$第一个区间里的数相同(每个数出现的频率相同),那么我们就选择这个区间。

  假设我们找到了第一个区间,那么我们的选择有两种,第一种是选择这个区间,第二种不选择这个区间,看看哪种方案包含最优解。假设我们不选择这个区间,未来选择的时候第一个区间就会长一些,如图:

  可以发现如果选择的是红色区间,那么由于红色区间的前部分与第一个黑色区间是一一对应的,因此可以把红色区间分成两个小区间,并且两个小区间也一一对应。因此第二种方案一定不会存在最优解。因此只要我们遇到一个$a,~ b$数组一一对应的区间,我们就直接选择它,然后再往后找下一个区间。

  可以用哈希表来找区间,动态来比较两个集合是否相同。数组$a$中的每个数在哈希表中$+1$,数组$b$中的每个数在哈希表中$-1$,如果发现哈希表为空,说明找到一个区间。

  AC代码如下:

class Solution {
public:
    int maxChunksToSorted(vector<int>& arr) {
        vector<int> backup(arr);
        sort(backup.begin(), backup.end());

        unordered_map<int, int> mp;
        int ret = 0;
        for (int i = 0; i < arr.size(); i++) {
            mp[arr[i]]++, mp[backup[i]]--;
            if (mp[arr[i]] == 0) mp.erase(arr[i]);
            if (mp[backup[i]] == 0) mp.erase(backup[i]);
            if (mp.empty()) ret++;
        }

        return ret;
    }
};

  还可以用单调栈来做。

  用一个栈来维护前面每一个块的最大值,如果来了一个新元素,且比栈顶的值要小,意味着这个元素一定要在栈顶元素的左边,与栈顶在同一个块。因此栈顶元素可以弹出,表示区间还没有完整需要继续更新。直到栈顶元素小于等于这个新元素,再把弹出的区间拼成一个区间压入栈(就是原来栈顶元素的值,即新区间的最大值)。

   放一下LeetCode的题解:

对于已经分好块的数组,若块数大于 $1$,则可以得到以下结论:右边的块的所有数字均大于或等于左边的块的所有数字。考虑这个问题:对于已经分好块的数组,若在其末尾添加一个数字,如何求得新数组的分块方式?

新添加的数字可能会改变原数组的分块方式。如果新添加的数字大于或等于原数组最后一个块的最大值,则这个新添加的数字可以自己形成一个块。如果新添加的数字小于原数组最后一个块的最大值,则它必须融入最后一个块。如果它大于或等于原数组倒数第二个块(如果有)的最大值,那么这个过程可以停止,新数组的分块方式已经求得。否则,它将继续融合原数组倒数第二个块,直到遇到一个块,使得该块的最大值小于或等于这个新添加的数,或者这个数字已经融合了所有块。

上述分析过程中,我们只用到了块的最大值来进行比较,比较过程又是从右到左,符合栈的思想,因此可以用类似单调栈的数据结构来存储块的最大值。

  AC代码如下:

 1 class Solution {
 2 public:
 3     int maxChunksToSorted(vector<int>& arr) {
 4         stack<int> stk;
 5         for (auto &it : arr) {
 6             int t = it;
 7             while (!stk.empty() && stk.top() > it) {
 8                 t = max(t, stk.top());
 9                 stk.pop();
10             }
11             stk.push(t);
12         }
13         return stk.size();
14     }
15 };

 

参考资料

  LeetCode 768. 最多能完成排序的块 II(秋招每日一题):https://www.acwing.com/video/4235/

  最多能完成排序的块 II:https://leetcode.cn/problems/max-chunks-to-make-sorted-ii/solution/zui-duo-neng-wan-cheng-pai-xu-de-kuai-ii-w5c6/

标签:arr,Max,Make,stk,区间,mp,数组,Chunks,最大值
来源: https://www.cnblogs.com/onlyblues/p/16587895.html