题目描述
arr
是一个可能包含重复元素的整数数组,我们将这个数组分割成几个“块”,并将这些块分别进行排序。之后再连接起来,使得连接的结果和按升序排序后的原数组相同。我们最多能将数组分成多少块?
输入: arr = [2,1,3,4,4]
输出: 4
解释:
我们可以把它分成两块,例如 [2, 1], [3, 4, 4]。
然而,分成 [2, 1], [3], [4], [4] 可以得到最多的块数。
解题思路
京东笔试题《合唱队》,单调栈解决。
- 贪心解法:只有对于某个位置,其左边(包括该数本身)的最大值不大于位置右侧的最小值,在该处就可以分段。
- 辅助栈解法:直接看代码就好。(如何想到的不太好理解,推荐另两种解法)
- 哈希表法:对序列A来说,如果知道其排序后的序列B。然后将序列A与序列B对比,容易分析出各个块。那么,对于可分的块,其满足两个特点(之一即可):
- 块的位置和长度,在序列A和序列B中,相同。
- 块中的数字,在序列A和序列B中,相同,但顺序可能不同。(哈希表可以用
==
比较)
参考代码
辅助栈解法
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
stack<int> s;
for(auto &x:arr){
if(s.empty()||x>=s.top()){
s.push(x);
}else{
auto top = s.top();//保留栈顶最大值
s.pop();
while(!s.empty()&&x<s.top()){
//小的话,一直pop
s.pop();
}
s.push(top);
}
}
return s.size();
}
};
哈希表解法
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
vector<int> B(arr);
sort(B.begin(),B.end());
unordered_map<int,int> hasha;
unordered_map<int,int> hashb;
int ans=0;
for(int i = 0; i < arr.size(); ++i){
++hasha[arr[i]];
++hashb[B[i]];
if(hasha==hashb){
++ans;
hasha.clear(); // 这里不clear也行
hashb.clear();
}
}
return ans;
}
};
“排序 + 累加和”解法(更简单,推荐!)
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
vector<int> tmp = arr;
sort(tmp.begin(), tmp.end());
int res = 0;
long sum1 = 0, sum2 = 0;
for (int i = 0; i < arr.size(); i++){
sum1 += tmp[i];
sum2 += arr[i];
if (sum1 == sum2)
res++;
}
return res;
}
};