题目
这个问题和“最多能完成排序的块”相似,但给定数组中的元素可以重复,输入数组最大长度为2000,其中的元素最大为10**8。
arr是一个可能包含重复元素的整数数组,我们将这个数组分割成几个“块”,并将这些块分别进行排序。之后再连接起来,使得连接的结果和按升序排序后的原数组相同。
我们最多能将数组分成多少块?
示例 1:
输入: arr = [5,4,3,2,1]
输出: 1
解释:
将数组分成2块或者更多块,都无法得到所需的结果。
例如,分成 [5, 4], [3, 2, 1] 的结果是 [4, 5, 1, 2, 3],这不是有序的数组。
示例 2:
输入: arr = [2,1,3,4,4]
输出: 4
解释:
我们可以把它分成两块,例如 [2, 1], [3, 4, 4]。
然而,分成 [2, 1], [3], [4], [4] 可以得到最多的块数。
注意:
- arr的长度在[1, 2000]之间。
- arr[i]的大小在[0, 10**8]之间。
解决
思路
恕我愚钝,没想出来,看了题解才做出来的
可以注意到,如果
a
1
,
a
2
,
…
,
a
m
a_1, a_2, \dots, a_m
a1,a2,…,am是一个分块,同时
a
1
,
a
2
,
…
,
a
n
a_1, a_2, \dots, a_n
a1,a2,…,an也是一个分块 (m < n),那么
a
m
+
1
,
a
m
+
2
,
…
,
a
n
a_{m+1}, a_{m+2}, \dots, a_n
am+1,am+2,…,an 一定是一个分块。对于这种形式的问题,实际是可以用贪心算法来找到最多的块数的。
我们知道数组 a r r arr arr 在排序之后一定跟整个数组排序后相应的地方完全相同,即 e x p e c t = s o r t e d ( a r r ) expect = sorted(arr) expect=sorted(arr)。如果前 k k k 个元素的个数减去排序后前 k k k 个元素的个数都为 0 的话,那这前 k k k 个元素是可以成为一个合法的分块的。对于整个数组可以重复这一过程。
用变量
n
o
t
z
e
r
o
notzero
notzero 来计数目前差值不等于 0 的字符的个数。
代码
class Solution {
public int maxChunksToSorted(int[] arr) {
Map<Integer,Integer> map=new HashMap();
int res=0,notzero=0,x=0;
int[] expect=arr.clone();
Arrays.sort(expect);
for(int i=0;i<arr.length;i++){
x=arr[i];
map.put(x,map.getOrDefault(x,0)+1);
if(map.get(x)==0) notzero--;
if(map.get(x)==1) notzero++;
x=expect[i];
map.put(x,map.getOrDefault(x,0)-1);
if(map.get(x)==0) notzero--;
if(map.get(x)==-1) notzero++;
if(notzero==0) res++;
}
return res;
}
}
复杂度分析
- 时间复杂度: O ( N log N ) O(N \log N) O(NlogN),其中 N 为 arr 的长度。
- 空间复杂度: O ( N ) O(N) O(N)