C++实现LeetCode(768.可排序的最大块数之二)

[LeetCode] 768.Max Chunks To Make Sorted II 可排序的最大块数之二

This question is the same as "Max Chunks to Make Sorted" except the integers of the given array are not necessarily distinct, the input array could be up to length 2000, and the elements could be up to 10**8.

Given an array arr of integers (not necessarily distinct), 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 = [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.

Note:

  • arr will have length in range [1, 2000].
  • arr[i] will be an integer in range [0, 10**8].

这道题是之前那道 Max Chunks To Make Sorted 的拓展,那道题说了数组是[0, n-1]中所有数字的一种全排列,n为数组的长度。而这道题的数字就没有这种限制,可以是大于n的数字,也可以有重复的数字。由于数字和坐标不再有太多的关联,所以之前那题中比较数字和坐标的大小的解法肯定行不通了。我们来看一种十分巧妙的解法,首先我们需要明确的一点是,拆分后的块儿排序后拼在一起会跟原数组相同,我们用一个例子来说明:

2  1  4  3  4

1  2  3  4  4

1  2  3  4  4

我们看到第一行是原数组,第二行是排序后并拼接在了一起的块儿,不同的颜色代表不同的块儿,而第三行是直接对原数组排序后的结果。仔细观察可以发现,能形成块儿的数字之和跟排序后的数组的相同长度的子数组的数字之和是相同的。比如第一个块儿是数字2和1,和为3,而排序后的前两个数字为1和2,和也是3,那么我们就知道原数组的前两个数字可以拆成一个块儿。同理,原数组中的第三个和第四个数字分别为4和3,和为7,而排序后的数组对应位置的数字之和也是7,说明可以拆分出块儿。需要注意的是,在累加数组和的时候有可能会超过整型最大值,所以我们用长整型来保存就可以了。就是这么简单而暴力的思路,时间复杂度为O(nlgn),主要花在给数组排序上了。由于本题是 Max Chunks To Make Sorted 的generalized的情况,所以这种解法自然也可以解决之前那道题了,不过就是时间复杂度稍高了一些,参见代码如下:

解法一:

class Solution {
public:
    int maxChunksToSorted(vector<int>& arr) {
        long res = 0, sum1 = 0, sum2 = 0;
        vector<int> expect = arr;
        sort(expect.begin(), expect.end());
        for (int i = 0; i < arr.size(); ++i) {
            sum1 += arr[i];
            sum2 += expect[i];
            if (sum1 == sum2) ++res;
        }
        return res;
    }
};

这道题的时间复杂度可以优化到线性,不过就是需要花点空间。下面这种解法也相当的巧妙,我们需要两个数组forward和backward,其中 foward[i] 表示 [0, i] 范围内最大的数字,而 backward[i] 表示 [i, n-1] 范围内最小的数字,实际上就是要知道已经遍历过的最大值,和还未遍历的到的最小值。为啥我们对这两个值感兴趣呢?这是本解法的精髓所在,我们知道可以拆分为块儿的前提是之后的数字不能比当前块儿中的任何数字小,不然那个较小的数字就无法排到前面。就像例子1,为啥不能拆出新块儿,就因为最小的数字在末尾。那么这里我们能拆出新块儿的条件就是,当前位置出现过的最大值小于等于之后还未遍历到的最小值时,就能拆出新块儿。比如例子2中,当 i=1 时,此时出现过的最大数字为2,未遍历到的数字中最小值为3,所以可以拆出新块儿,参见代码如下:

解法二:

class Solution {
public:
    int maxChunksToSorted(vector<int>& arr) {
        int res = 1, n = arr.size();
        vector<int> f = arr, b = arr;
        for (int i = 1; i < n; ++i) f[i] = max(arr[i], f[i - 1]);
        for (int i = n - 2; i >= 0; --i) b[i] = min(arr[i], b[i + 1]);
        for (int i = 0; i < n - 1; ++i) {
            if (f[i] <= b[i + 1]) ++res;
        }
        return res;
    }
};

我们可以优化一下空间复杂度,因为我们可以在遍历的过程中维护一个当前最大值curMax,所以就不用一个专门的forward数组了,但是backward数组还是要的,参见代码如下: 

解法三:

class Solution {
public:
    int maxChunksToSorted(vector<int>& arr) {
        int res = 1, n = arr.size(), curMax = INT_MIN;
        vector<int> b = arr;
        for (int i = n - 2; i >= 0; --i) b[i] = min(arr[i], b[i + 1]);
        for (int i = 0; i < n - 1; ++i) {
            curMax = max(curMax, arr[i]);
            if (curMax <= b[i + 1]) ++res;
        }
        return res;
    }
};

下面这种使用单调栈Monotonous Stack的解法的题也十分的巧妙,我们维护一个单调递增的栈,遇到大于等于栈顶元素的数字就压入栈,当遇到小于栈顶元素的数字后,处理的方法很是巧妙啊:首先取出栈顶元素,这个是当前最大值,因为我们维护的就是单调递增栈啊,然后我们再进行循环,如果栈不为空,且新的栈顶元素大于当前数字,则移除栈顶元素。这步简直绝了,这里我们单调栈的元素个数实际上是遍历到当前数字之前可以拆分成的块儿的个数,我们遇到一个大于栈顶的元素,就将其压入栈,suppose其是一个新块儿的开头,但是一旦后面遇到小的数字了,我们就要反过来检查前面的数字,有可能我们之前认为的可以拆分成块儿的地方,现在就不能拆了,举个栗子来说吧:

比如数组为 [1 0 3 3 2],我们先把第一个数字1压入栈,此时栈为:

stack:1

然后遍历到第二个数字0,发现小于栈顶元素,将栈顶元素1取出存入curMax,此时栈为空了,不做任何操作,将curMax压回栈,此时栈为:

stack:1

然后遍历到第三个数字3,大于栈顶元素,压入栈,此时栈为:

stack:1,3

然后遍历到第四个数字3,等于栈顶元素,压入栈,此时栈为:

stack:1,3,3

然后遍历到第五个数字2,小于栈顶元素,将栈顶元素3取出存入curMax,此时新的栈顶元素3,大于当前数字2,移除此栈顶元素3,然后新的栈顶元素1,小于当前数字2,循环结束,将curMax压回栈,此时栈为:

stack:1,3

所以最终能拆为两个块儿,即stack中数字的个数,参见代码如下:

解法四:

class Solution {
public:
    int maxChunksToSorted(vector<int>& arr) {
        stack<int> st;
        for (int i = 0; i < arr.size(); ++i) {
            if (st.empty() || st.top() <= arr[i]) {
                st.push(arr[i]);
            } else {
                int curMax = st.top(); st.pop();
                while (!st.empty() && st.top() > arr[i]) st.pop();
                st.push(curMax);
            }
        }
        return st.size();
    }
};

到此这篇关于C++实现LeetCode(768.可排序的最大块数之二)的文章就介绍到这了,更多相关C++实现可排序的最大块数之二内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++实现LeetCode(10.正则表达式匹配)

    [LeetCode] 10. Regular Expression Matching 正则表达式匹配 Given an input string (s) and a pattern (p), implement regular expression matching with support for '.' and '*'. '.' Matches any single character. '*' Matches zero or more of the preceding element. T

  • C++实现LeetCode(11.装最多水的容器)

    [LeetCode] 11. Container With Most Water 装最多水的容器 Given n non-negative integers a1, a2, ..., an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two

  • LeetCode 单调栈内容小结

    LeetCode Monotone Stack Summary 单调栈小结 所谓的单调栈 Monotone Stack,就是栈内元素都是单调递增或者单调递减的,有时候需要严格的单调递增或递减,根据题目的具体情况来看吧.关于单调栈,这个帖子讲的不错,而且举了个排队的例子来类比.那么,博主也举个生动的例子来说明吧:比如有一天,某家店在发 free food,很多人在排队,于是你也赶过去凑热闹.但是由于来晚了,队伍已经很长了,想着不然就插个队啥的.但发现排在队伍最前面的都是一些有纹身的大佬,惹不起,只

  • C++实现LeetCode(42.收集雨水)

    [LeetCode] 42. Trapping Rain Water 收集雨水 Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining. The above elevation map is represented by array [0,1,0,2,1,

  • C++实现LeetCode(84.直方图中最大的矩形)

    [LeetCode] 84. Largest Rectangle in Histogram 直方图中最大的矩形 Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram. Above is a histogram where width of e

  • C++实现LeetCode(验证数字)

    [LeetCode] Valid Number 验证数字 Validate if a given string can be interpreted as a decimal number. Some examples: "0" => true " 0.1 " => true "abc" => false "1 a" => false "2e10" => true "

  • C++实现LeetCode(44.外卡匹配)

    [LeetCode] 44. Wildcard Matching 外卡匹配 Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for '?' and '*'. '?' Matches any single character. '*' Matches any sequence of characters (including the empty sequenc

  • C++实现LeetCode(768.可排序的最大块数之二)

    [LeetCode] 768.Max Chunks To Make Sorted II 可排序的最大块数之二 This question is the same as "Max Chunks to Make Sorted" except the integers of the given array are not necessarily distinct, the input array could be up to length 2000, and the elements cou

  • C++实现LeetCode(769.可排序的最大块数)

    [LeetCode] 769.Max Chunks To Make Sorted 可排序的最大块数 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,

  • C++实现LeetCode(60.序列排序)

    [LeetCode] 60. Permutation Sequence 序列排序 The set [1,2,3,...,n] contains a total of n! unique permutations. By listing and labeling all of the permutations in order, we get the following sequence for n = 3: "123" "132" "213" &

  • C++实现LeetCode(75.颜色排序)

    [LeetCode] 75. Sort Colors 颜色排序 Given an array with n objects colored red, white or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white and blue. Here, we will use the integers 0, 1, and 2

  • C++实现LeetCode(148.链表排序)

    [LeetCode] 148. Sort List 链表排序 Sort a linked list in O(n log n) time using constant space complexity. Example 1: Input: 4->2->1->3 Output: 1->2->3->4 Example 2: Input: -1->5->3->4->0 Output: -1->0->3->4->5 常见排序方法有

  • C++实现LeetCode(142.单链表中的环之二)

    [LeetCode] 142. Linked List Cycle II 单链表中的环之二 Given a linked list, return the node where the cycle begins. If there is no cycle, return null. To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexe

  • C++实现LeetCode(186.翻转字符串中的单词之二)

    [LeetCode] 186. Reverse Words in a String II 翻转字符串中的单词之二 Given an input string , reverse the string word by word.  Example: Input:  ["t","h","e"," ","s","k","y"," ","i&qu

  • php自定义排序uasort函数示例【二维数组按指定键值排序】

    本文实例讲述了php自定义排序uasort函数.分享给大家供大家参考,具体如下: 项目需要风险排序,按 I(安全)<L(低风险)<M(中风险)<H(高风险) 的级别来排序 由于H排在I的前面,所以不能直接用sort来排序,要自定义. 用uasort()函数来自定义排序: /* * 二维数组按指定键值排须 */ function arr_sort($array,$key,$order="asc"){//asc是升序 desc是降序//按 I<L<M<H

  • C++实现LeetCode(210.课程清单之二)

    [LeetCode] 210. Course Schedule II 课程清单之二 There are a total of n courses you have to take, labeled from 0 to n-1. Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1] G

  • Java C++题解leetcode判定是否为字符重排

    目录 题目要求 思路一:排序 Java C++ Rust 思路二:词频统计 Java C++ Rust 总结 题目要求 思路一:排序 Java class Solution { public boolean CheckPermutation(String s1, String s2) { if(s1.length() != s2.length()) return false; char[] sort1 = s1.toCharArray(); Arrays.sort(sort1); char[]

随机推荐