Open azl397985856 opened 2 years ago
class Solution:
def maxChunksToSorted(self, arr: List[int]) -> int:
arr2 = sorted(arr)
s1 = s2 = result = 0
for a, b in zip(arr, arr2):
s1 += a
s2 += b
if s1 == s2:
result += 1
return result
class Solution {
public int maxChunksToSorted(int[] arr) {
Deque<Integer>st = new ArrayDeque<>();
for(int num:arr){
if(!st.isEmpty()&&num<st.peek()){
int cur = st.pop();
while(!st.isEmpty()&&num<st.peek()){
st.pop();
}
st.push(cur);
}else{
st.push(num);
}
}
return st.size();
}
}
var maxChunksToSorted = function(arr) {
let stack = [arr[0]];
for (let i=1; i< arr.length; i++){
if(arr[i] >= stack[stack.length-1]){stack.push(arr[i]);}
else {
const cur = stack[stack.length-1];
while(stack.length > 0 && arr[i] < stack[stack.length-1]){
stack.pop();
}
stack.push(cur);
}
}
return stack.length
};
使用类似计数排序的技巧来完成
class Solution(object):
def maxChunksToSorted(self, arr):
count_a = collections.defaultdict(int)
count_b = collections.defaultdict(int)
ans = 0
for a, b in zip(arr, sorted(arr)):
count_a[a] += 1
count_b[b] += 1
if count_a == count_b: ans += 1
return ans
滑动窗口, 把原数组从小到大排序, 遍历数组, 如果排序后数组的前n项与原数组的前n项相等, 那么这n项就可以作为一个组, 然后继续遍历, 找下一个符合条件的组
const maxChunksToSorted = function(arr) {
const sortedArr = [...arr].sort((left, right) => left - right)
let result = sum1 = sum2 = 0
for (let i = 0; i < arr.length; i++) {
sum1 += arr[i]
sum2 += sortedArr[i]
if (sum1 === sum2) {
result++
}
}
return result
}
不知道思路
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
int n = arr.size();
vector<int> lMax(n,INT_MIN),rMin(n,INT_MAX);
lMax[0] = arr[0];
rMin[n-1] = arr[n-1];
for(int i=1; i<n; i++){
lMax[i] = max(lMax[i-1],arr[i]);
rMin[n-i-1] = min(rMin[n-i],arr[n-i-1]);
}
int ans = 1; //起始块为1块
for(int i=0; i<n-1; i++){
if(lMax[i] <= rMin[i+1]) ans ++;
}
return ans;
}
};
复杂度分析
// sliding window
class Solution {
public int maxChunksToSorted(int[] arr) {
int[] sortArr = arr.clone();
Arrays.sort(sortArr);
int arrSum = 0, sortedSum = 0, res = 0;
for (int i = 0; i < arr.length; i ++){
arrSum += arr[i];
sortedSum += sortArr[i];
if(arrSum == sortedSum) res ++;
}
return res;
}
}
// Time: O(nlogn). Space:O(n)
/*借鉴其他人的
单调栈:要想保证每一个块拼接后单调递增,就要保证每一个块的最大值是单调递增的,这时候就可以构建一个单调栈。
具体做法:
1.遍历数组arr中的每一个num
2.当stack为空或者num>=栈顶值时:入栈(相当于添加了新的元素块)
3.当栈 stack 不为空且数字 num<栈顶值 时:
(1)保存栈顶值head
*(2)当栈 stack 不为空且数字 num<栈顶值 时:循环出栈(此步是关键,因为num>=栈顶值时才能保证有序,所以要将前面所有的大于num的块儿合成一个)
(3)将head入栈(当前块的最大值)
4.遍历结束后,stack的长度就是块的个数
*/
class Solution {
public int maxChunksToSorted(int[] arr) {
Stack<Integer> stack = new Stack<>();
for (int num : arr) {
if (!stack.isEmpty() && num < stack.peek()) {
int current = stack.pop();
while(!stack.isEmpty() && num < stack.peek()) {
stack.pop();
}
stack.push(current);
} else {
stack.push(num);
}
}
return stack.size();
}
}
class Solution(object):
def maxChunksToSorted(self, arr):
count = collections.Counter()
counted = []
for x in arr:
count[x] += 1
counted.append((x, count[x]))
ans, cur = 0, None
for X, Y in zip(counted, sorted(counted)):
cur = max(cur, X)
if cur == Y:
ans += 1
return ans
class Solution(object):
def maxChunksToSorted(self, arr):
count = collections.defaultdict(int)
ans = nonzero = 0
for x, y in zip(arr, sorted(arr))
count[x] += 1
if count[x] == 0: nonzero -= 1
if count[x] == 1: nonzero += 1
count[y] -= 1
if count[y] == -1: nonzero += 1
if count[y] == 0: nonzero -= 1
if nonzero == 0: ans += 1
return ans
题目要求分成的块升序排序,则可知后面的块里的值必然大于等于前面的块的最大值。
由此如果遍历到后面的元素如果大于或等于前一块的最大值,则有可能组成一个新块,但如果遍历的元素小于前面块的最大值,则无法组成新块将此值加入到上一个块中。然后则需要判断这个值是否比前面得所有块的最小值小。如小则需要删除块的数量。
我自己的代码太过于复杂,查看题解可知可使用滑动窗口处理
class Solution {
class Solution {
public int maxChunksToSorted(int[] arr) {
int[] cloneArray = arr.clone();
Arrays.sort(cloneArray);
long arrSum = 0;
long cloneSum = 0;
int sum = 0;
for (int i = 0; i < arr.length; i++) {
arrSum += arr[i];
cloneSum += cloneArray[i];
if(arrSum == cloneSum) sum++;
}
return sum;
}
}
}
时间复杂度:O(n)
空间复杂度:O(n)
使用栈
1、先把第1个元素放入栈中
2、后面遍历arr的时候和栈顶比较
(1)大于栈顶就放入栈中,表示可以他们之间可以切分
(2)小于栈顶说明不能切分,那么保存下栈顶元素,再出栈直到栈顶元素小于遍历的元素或者栈为空,再把保存的元素放入栈中,这是为了后面在遍历的时候依旧用它作为分界点去决定是否可以切分
C++ Code:
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
if (arr.empty()) {
return 0;
}
stack<int> st;
st.push(arr[0]);
for (int i = 1; i < arr.size(); ++i) {
if (st.empty() || st.top() < arr[i]) {
st.push(arr[i]);
} else {
auto maxtop = st.top();
while (!st.empty() && st.top() > arr[i]) {
st.pop();
}
st.push(maxtop);
}
}
return st.size();
}
};
复杂度分析
令 n 为数组长度。
排序后的arr的前缀和与arr的前缀和相等时,结果+1
class Solution(object):
def maxChunksToSorted(self, arr):
"""
:type arr: List[int]
:rtype: int
"""
res = 0
prea = 0
preb = 0
for (a,b) in zip(arr, sorted(arr)):
prea += a
preb += b
if prea == preb:
res += 1
return res
复杂度分析
var maxChunksToSorted = function(arr) {
let sortedArr = [...arr]
sortedArr.sort((a, b) => a - b)
let sum1 = sum2 = count = 0
for(let i = 0; i < arr.length; i++){
sum1 += arr[i]
sum2 += sortedArr[i]
if(sum1 === sum2){
count++
sum1 = sum2 = 0
}
}
return count
};
首先还是要找到从左边开始最小的块。
class Solution {
public int maxChunksToSorted(int[] arr) {
Map<Integer, Integer> count = new HashMap();
int ans = 0, nonzero = 0;
int[] expect = arr.clone();
Arrays.sort(expect);
for (int i = 0; i < arr.length; ++i) {
int x = arr[i], y = expect[i];
count.put(x, count.getOrDefault(x, 0) + 1);
if (count.get(x) == 0) nonzero--;
if (count.get(x) == 1) nonzero++;
count.put(y, count.getOrDefault(y, 0) - 1);
if (count.get(y) == -1) nonzero++;
if (count.get(y) == 0) nonzero--;
if (nonzero == 0) ans++;
}
return ans;
}
}
https://leetcode-cn.com/problems/max-chunks-to-make-sorted-ii/
class Solution {
public int maxChunksToSorted(int[] arr) {
int n = arr.length;
int[] clone = arr.clone();
Arrays.sort(clone);
Map<Integer,Integer> map = new HashMap<>();
int count = 0, sum = 0;
for (int i=0;i<n;i++)
{
int ar = arr[i], cl = clone[i];
map.put(ar, map.getOrDefault(ar,0)+1);
if (map.get(ar) == 0) count--;
if (map.get(ar) == 1) count++;
map.put(cl, map.getOrDefault(cl,0)-1);
if (map.get(cl) == -1) count++;
if (map.get(cl) == 0) count--;
if (count == 0) sum++;
}
return sum;
}
}
思路: 从左往右同时遍历两个数组时,计数信息一致,则可以分块; 遍历过程中计数信息一致的次数,为最多可分块数; java
class Solution {
public int maxChunksToSorted(int[] arr) {
int ans = 0;
int count = 0;
Map<Integer,Integer> map = new HashMap();
int[] arrSort = arr.clone();
Array.sort(arrSort);
for(int i = 0;i < arr.length;i++){
int x = arr[i];
int y = arrSort[i];
map.put(x,map.getOrDefault(x,0)+1);
if(map.get(x) == 0){
count--;
}
if(map.get(x) ==1){
count++;
}
map.put(y,map.getOrDefault(y,0)-1);
if(map.get(y) == 0){
count--;
}
if(map.get(y) == -1){
count++;
}
if(count == 0){
ans++;
}
}
return ans;
}
}
时间:O(nlogn),瓶颈在排序 空间:O(1)
单调栈
/**
* @param {number[]} arr
* @return {number}
*/
var maxChunksToSorted = function(arr) {
//定义最大数据栈
let res=[]
for(let i = 0; i < arr.length; i++) {
if(res.length==0){
res.push(arr[i])
}else{
if(arr[i]>=res[res.length-1]){
res.push(arr[i])
}else{
let max=res[res.length-1]
while(arr[i]<res[res.length-1]){
res.pop()
}
res.push(max)
}
}
}
return res.length
};
var maxChunksToSorted = function(arr) { let stack = [];
for (let val of arr) {
// 大于栈顶元素,直接入栈,算一个块
if (!stack.length || stack[stack.length - 1] <= val) {
stack.push(val);
} else {
let curMax = stack.pop();
// val和这些弹出的元素算一个块
while (stack.length && stack[stack.length - 1] > val) {
stack.pop();
}
// 保存块中的最大值
stack.push(curMax);
}
}
return stack.length;
};
滑动窗口
class Solution { public int maxChunksToSorted(int[] arr) { Map<Integer, Integer> count = new HashMap(); int ans = 0, nonzero = 0;
int[] expect = arr.clone();
Arrays.sort(expect);
for (int i = 0; i < arr.length; ++i) {
int x = arr[i], y = expect[i];
count.put(x, count.getOrDefault(x, 0) + 1);
if (count.get(x) == 0) nonzero--;
if (count.get(x) == 1) nonzero++;
count.put(y, count.getOrDefault(y, 0) - 1);
if (count.get(y) == -1) nonzero++;
if (count.get(y) == 0) nonzero--;
if (nonzero == 0) ans++;
}
return ans;
}
}
var maxChunksToSorted = function(arr) {
let sorted = arr.slice().sort((a, b) => a - b);
let indexs = [];
for (let i = 0; i < sorted.length; i++) {
let c = arr.indexOf(sorted[i]);
arr[c] = null;
indexs.push(c);
};
let max = -1, num = 0;
for (let i = 0; i < indexs.length; i++) {
max = Math.max(max, indexs[i]);
if (max === i) num++;
};
return num;
};
在遍历过程中,当遇到更小的元素时,就将之前的稍大的栈中的元素融合为这几个元素的最大值,输入到栈中。
class Solution:
def maxChunksToSorted(self, arr: List[int]) -> int:
stack = []
for e in arr:
if stack and stack[-1] > e:
rec = stack[-1]
while stack and stack[-1] > e:
stack.pop()
stack.append(rec)
else:
stack.append(e)
return len(stack)
Thoughts
Using a LinkedList as a Stack, always add the new element to the tail of the LinkedList.
Traversing arr, if num >= peek of stack, push num to stack; if num < peek of stack, keep popping till num >= peek, push the first peek back.
After all, the stack will save the greatest num for each chunk of the arr, size of stack indicates how many chunks we have.
Code
public int maxChunksToSorted(int[] arr) {
LinkedList<Integer> stack = new LinkedList<>();
for (int num: arr) {
if (!stack.isEmpty() && num < stack.getLast()) {
int head = stack.removeLast();
while (!stack.isEmpty() && num < stack.getLast()) {
stack.removeLast();
}
stack.addLast(head);
} else {
stack.addLast(num);
}
}
return stack.size();
}
Complexity
··· class Solution(object): def maxChunksToSorted(self, arr): count = collections.defaultdict(int) ans = nonzero = 0
for x, y in zip(arr, sorted(arr))
count[x] += 1
if count[x] == 0: nonzero -= 1
if count[x] == 1: nonzero += 1
count[y] -= 1
if count[y] == -1: nonzero += 1
if count[y] == 0: nonzero -= 1
if nonzero == 0: ans += 1
return ans
···
直接看题解了,排序块(单调栈)
class Solution:
def maxChunksToSorted(self, arr: [int]) -> int:
stack = []
for num in arr:
if stack and num < stack[-1]:
head = stack.pop()
while stack and num < stack[-1]: stack.pop()
stack.append(head)
else: stack.append(num)
return len(stack)
复杂度分析
class Solution: def maxChunksToSorted(self, arr: List[int]) -> int: A = arr stack = [] for a in A:
# 而栈中每一个元素都是一个块,并且栈的存的是块的最大值,因此栈中比 a 小的值都需要 pop 出来
if stack and stack[-1] > a:
# 我们需要将融合后的区块的最大值重新放回栈
# 而 stack 是递增的,因此 stack[-1] 是最大的
cur = stack[-1]
# 维持栈的单调递增
while stack and stack[-1] > a: stack.pop()
stack.append(cur)
else:
stack.append(a)
# 栈存的是块信息,因此栈的大小就是块的数量
return len(stack)
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
int max_c = 1;
for(int i =0 ;i<arr.size()-1;i++){
if(*max_element(arr.begin(),arr.begin()+i+1)<=*(min_element(arr.begin()+i+1,arr.end()))){
auto v2 = vector<int>(arr.begin()+i+1,arr.end());
max_c= max(1+maxChunksToSorted(v2),max_c);
break;
}
}
return max_c;
}
};
这道题目理解比较难。
但一个简单的解题思路是:既然分组后的数组和排序后的切片数组是相等的,那无论这两个数组的顺序如何打乱,它们的和都一定是相等的。
根据这个思路,我们只要额外定义两个数进行遍历即可:
var maxChunksToSorted = function (arr) {
const sorted_arr = [...arr].sort((a, b) => a - b)
let ans = 0
let sum1 = 0
let sum2 = 0
for (let i = 0; i < arr.length; i++) {
sum1 += arr[i]
sum2 += sorted_arr[i]
if (sum1 === sum2) ans += 1
}
return ans
}
滑动窗口
class Solution {
public int maxChunksToSorted(int[] arr) {
Map<Integer, Integer> count = new HashMap();
int ans = 0, nonzero = 0;
int[] expect = arr.clone();
Arrays.sort(expect);
for (int i = 0; i < arr.length; ++i) {
int x = arr[i], y = expect[i];
count.put(x, count.getOrDefault(x, 0) + 1);
if (count.get(x) == 0) nonzero--;
if (count.get(x) == 1) nonzero++;
count.put(y, count.getOrDefault(y, 0) - 1);
if (count.get(y) == -1) nonzero++;
if (count.get(y) == 0) nonzero--;
if (nonzero == 0) ans++;
}
return ans;
}
}
时间 O(NLogN) 空间 O(N)
public int maxChunksToSorted(int[] arr) {
LinkedList<Integer> stack = new LinkedList<Integer>();
for (int num : arr) {
if (!stack.isEmpty() && num < stack.getLast()) {
int cur = stack.removeLast();
while (!stack.isEmpty() && num < stack.getLast()) {
stack.removeLast();
}
stack.addLast(cur);
} else {
stack.addLast(num);
}
}
return stack.size();
}
思路 找到从左边开始最小的块
代码
class Solution(object):
def maxChunksToSorted(self, arr):
count = collections.Counter()
counted = []
for x in arr:
count[x] += 1
counted.append((x, count[x]))
ans, cur = 0, None
for X, Y in zip(counted, sorted(counted)):
cur = max(cur, X)
if cur == Y:
ans += 1
return ans
复杂度
时间 O(NlogN) 空间 O(N)
//思路一:单调递增栈
class Solution {
public int maxChunksToSorted(int[] arr) {
int max = Integer.MIN_VALUE / 2;
Deque
//最外层的合并了,先出栈
int temp = stack.removeFirst();
//继续看更前面的块,如果arr[i]比它还要小,继续合并,只要stack不为空
while(!stack.isEmpty() && stack.peekFirst() > arr[i]){
//继续出栈
temp = stack.removeFirst();
}
//把最后出栈合并的那个块补回来
stack.addFirst(temp);
}
}
//返回stack的元素个数
return stack.size();
}
}
//采用递归的思想,每一步递归判断能否分块,能分块则加一,然后判断剩下的能否分块,使递归不管逼近整个数组。
class Solution {
int i =0;
public int maxChunksToSorted(int[] arr) {
can(arr,0);
if(i==0)
i++;
return i;
}
public boolean can(int[] arr,int num){
if(num==arr.length){
return true;
}else{
boolean check = true;
for(int i =0;i<=num;i++){
for(int k = num;k<arr.length;k++){
if(arr[i]>=arr[k])
return false;
}
}
if(check){
i++;
if(can(arr , num +1)){
return true;}
else{
return false;
}
}
}
return false; } }
//时间复杂度O(n2) //空间复杂度O(n)
使用栈,入栈的时候与栈顶的元素进行比较,如果大于栈顶元素则直接入栈,如果比栈顶元素小,则需要将栈中小于入栈的元素都出栈,最后栈中剩余的元素就是所需要的结果。
class Solution { public int maxChunksToSorted(int[] arr) { Stack<Integer> stack=new Stack<Integer>(); // int []arr={2,1,3,4,4}; int res=0; for (int i = 0; i<arr.length; i++ ){ if(stack.isEmpty()){ stack.push(arr[i]); }else { if(stack.peek()>arr[i]){ int cur = stack.pop(); while (!stack.isEmpty() && arr[i] < stack.peek()){ stack.pop(); } stack.push(cur); }else { stack.push(arr[i]); } } } return stack.size(); } }
思路:看题解了,用单调栈的方法
语言:js
var maxChunksToSorted = function (arr) {
const stack = [];
for (let i = 0; i < arr.length; i++) {
a = arr[i];
if (stack.length > 0 && stack[stack.length - 1] > a) {
const cur = stack[stack.length - 1];
while (stack && stack[stack.length - 1] > a) stack.pop();
stack.push(cur);
} else {
stack.push(a);
}
}
return stack.length;
};
复杂度分析
C++ Code:
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
int n = arr.size();
vector<int> premax(n), sumin(n);
for (int i = 0; i < n; i++)
if (i == 0)
premax[i] = arr[i];
else
premax[i] = max(premax[i - 1], arr[i]);
for (int i = n - 1; i >= 0; i--)
if (i == n - 1)
sumin[i] = arr[i];
else
sumin[i] = min(sumin[i + 1], arr[i]);
int ans = 1;
for (int i = 0; i < n - 1; i++)
if (premax[i] <= sumin[i + 1])
ans++;
return ans;
}
};
use the max of the chunk as the representative and store them in the stack. check if current val can be merged with the existing chunks on the stack.
0 2 9 1 2
0 2 9
0 9
0 9
0 2 9
0 9
0 9
Time: O(arr.length)
best case, insert once, no popping
Space: O(arr.length)
class Solution {
public int maxChunksToSorted(int[] arr) {
Stack<Integer> chunks = new Stack<>();
for (int i = 0; i < arr.length; i++) {
int representative = arr[i];
boolean flag = true;
while (!chunks.isEmpty() && chunks.peek() > arr[i]) {
if (flag) {
representative = chunks.peek();
flag = false;
}
chunks.pop();
}
chunks.push(representative);
}
return chunks.size();
}
}
class Solution {
public int maxChunksToSorted(int[] arr) {
Stack
int preMax = maxs.peek();
int preMin = mins.peek();
if(arr[i] < preMin){
mins.pop();
mins.push(i);
}else if(arr[i] >= preMax){
maxs.push(arr[i]);
mins.push(arr[i]);
}
}
while (!maxs.isEmpty()){
int min = mins.pop();
int max = maxs.pop();
if(maxs.isEmpty()){
break;
}
int preMax = maxs.peek();
int preMin = mins.peek();
if(min>= preMax){
count++;
}else if(min < preMin){
mins.pop();
mins.push(min);
}
}
return count;
}
}
优化一下内存
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
return maxChunksToSorted2(arr.begin(),arr.end()-1);
}
// [begin,end]
int maxChunksToSorted2(vector<int>::iterator begin ,vector<int>::iterator end) {
int max_c =1;
for(auto b =begin; b!= end;b++){
if(*max_element(begin,b+1)<=*(min_element(b+1,end+1))){
max_c= max(max_c,1+maxChunksToSorted2(b+1,end));
break;
}
}
return max_c;
}
};
Iterate through the array, keep tracking of the max element of the left side and the min element of the right side. When maxleft <= minright, we can increase the count by one.
class Solution(object):
def maxChunksToSorted(self, arr):
"""
:type arr: List[int]
:rtype: int
53421
[5 1 3 4 4]
[1 2 5 2 1]
count = 0
iterate through array:
when max(arr[:i+1]) <= min(arr[i+1]):
split the array.
"""
count = 0
start = 0
for i in range(len(arr)):
if i == len(arr) - 1 or max(arr[start:i + 1]) <= min(arr[i + 1:]):
count += 1
start = i + 1
return count
T: O(N) S: O(1)
class Solution:
def maxChunksToSorted(self, arr: List[int]) -> int:
maxNum = [0 for i in arr]
maxNum[0] = arr[0]
minNum = [0 for i in arr]
minNum[-1] = arr[-1]
chunks = 1
for i in range(1, len(arr)):
maxNum[i] = max(maxNum[i-1], arr[i])
for i in reversed(range(0, len(arr)-1)):
minNum[i] = min(minNum[i+1], arr[i])
for i in range(len(arr)-1):
if maxNum[i] <= minNum[i+1]:
chunks += 1
return chunks
class Solution:
def maxChunksToSorted(self, arr: List[int]) -> int:
stack = []
for num in arr:
if stack and num < stack[-1]:
top = stack.pop()
# 区块的融合
while stack and num < stack[-1]:
stack.pop()
stack.append(top)
else:
stack.append(num)
return len(stack)
--python
1. 最容易想到的前缀和比较
class Solution:
def maxChunksToSorted(self, arr: List[int]) -> int:
pre1, pre2=0,0
res=0
for a,b in zip(arr, sorted(arr)):
pre1 += a
pre2 += b
if pre1 == pre2:
res+=1
return res
时间复杂度:O(NlogN)
空间复杂度:O(N)
2. 前缀和变体,空间换时间
class Solution:
def maxChunksToSorted(self, arr: List[int]) -> int:
n=len(arr)
left=[0]*n
right=[0]*n
premax=arr[0]
# 前缀最大值
for i in range(n):
if i == 0:
left[0]=arr[0]
else:
left[i] = max(left[i-1], arr[i])
# 后缀最小值
for i in range(n-1, -1, -1):
if i == n-1:
right[i] = arr[i]
else:
right[i] = min(right[i+1], arr[i])
res=1
for i in range(0, n-1):
if left[i] <= right[i+1]:
res+=1
return res
时间复杂度:O(N)
空间复杂度:O(N)
# 单调栈
class Solution:
def maxChunksToSorted(self, arr: List[int]) -> int:
curMax = arr[0]
stack = [curMax]
for i in range(1, len(arr)):
if arr[i] >= curMax:
curMax = arr[i]
stack.append(curMax)
else:
while stack and stack[-1] > arr[i]:
stack.pop()
stack.append(curMax)
return len(stack)
时间复杂度:O(N)
空间复杂度:O(N)
需要合并后能够升序,即后面的chunks里面的数都要完全大于前面chunks里面的数。维护一个单调栈,栈内元素是当前chunk的最大数。具体方法:遍历arr,当前数如果比chunk-1大,则可以入栈(开启一个新的chunk,因为之前所有chunks里的元素都比当前值小)。如果比chunk[-1]小,则说明该值需要融入之前的chunk,具体有几个chunks需要合并,要看栈头的值,一直往外pop直到栈头的值不再比当前值大。(要记录一下最初的chunk[-1],作为当前chunk的最大值,需要再push回去)。最后栈里保留了多少元素,说明有多少chunks。
class Solution:
def maxChunksToSorted(self, arr: List[int]) -> int:
"""
monotonic stack
"""
stack = []
for a in arr:
if stack and stack[-1] > a:
"""
that means a and some previous chunks should be merged.
how many chunks should be merged? That depends on
"""
curr = stack[-1]
while stack and stack[-1] > a:
stack.pop()
stack.append(curr)
else:
stack.append(a)
return len(stack)
"""
class Solution:
def maxChunksToSorted(self, arr: List[int]) -> int:
res = 0
c1 = collections.Counter()
c2 = collections.Counter()
for a, b in zip(arr, sorted(arr)):
c1[a] += 1
c2[b] += 1
if c1 == c2:
res += 1
return res
"""
Time Complexity: O(N)
Space Complexity: O(N)
class Solution:
def maxChunksToSorted(self, arr: List[int]) -> int:
pre1,pre2=0,0
res=0
for a,b in zip(arr,sorted(arr)):
pre1+=a
pre2+=b
if pre1==pre2:
res+=1
return res
题目有一个提示:
提示的意思是:如果将原数组进行分块,再将排序数据进行相同的分块,每个对应的分块中数字种类是相同的,仅仅是数字的排序不同。
既然每个分块中拥有的数字是一样的,那数字的和也是一样的。
我们可以用一个滑动窗口同时扫描原数组和排序数组,当窗口中包括的数字和一样时,贪心地进行分块(滑动窗口就是下图的色块)。
至于为什么要用到贪心,是因为题目问的是我们最多能将数组分成多少块?要获得尽量多的分块,那分块的大小就要尽量小,所以能分块的时候就要分块。
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
int n = arr.size();
vector<int> sorted = arr;
sort(sorted.begin(), sorted.end());
long int arrSum = 0;
long int sortedSum = 0;
int chunkCount = 0;
for (int i = 0; i < n; i++) {
arrSum += arr[i];
sortedSum += sorted[i];
if (arrSum == sortedSum) chunkCount++;
}
return chunkCount;
}
};
/**
* @param {number[]} arr
* @return {number}
*/
var maxChunksToSorted = function (arr) {
const sorted = [...arr];
sorted.sort((a, b) => a - b);
let count = 0,
sum1 = 0,
sum2 = 0;
for (let i = 0; i < arr.length; i++) {
sum1 += arr[i];
sum2 += sorted[i];
if (sum1 === sum2) {
count++;
sum1 = sum2 = 0; // 这行不要也可以啦
}
}
return count;
};
根据题意,将原数组进行分块后,对各分块分别进行排序后的结果等于原数组排序后的结果。
可以得到的一个结论是,每个分块中的数字相对于前一个分块都是递增的(因为有重复数字,所以也可能是相同),第 i+1 个分块中的所有数字会大于等于 第 i 个分块中的所有数字。
另一个例子:
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
stack<int> blocks;
for (int i = 0; i < arr.size(); i++) {
if (blocks.empty() || blocks.top() <= arr[i]) {
// a new chunk
blocks.push(arr[i]);
}
else {
int topNum = blocks.top();
blocks.pop();
// combine chunks
while (!blocks.empty() && blocks.top() > arr[i]) {
blocks.pop();
}
blocks.push(topNum);
}
}
return blocks.size();
}
};
class Stack {
constructor() {
this.list = [];
}
push(val) {
this.list.push(val);
}
pop() {
return this.list.pop();
}
empty() {
return this.list.length === 0;
}
peek() {
return this.list[this.list.length - 1];
}
size() {
return this.list.length;
}
}
/**
* @param {number[]} arr
* @return {number}
*/
var maxChunksToSorted = function (arr) {
const stack = new Stack();
for (let i = 0; i < arr.length; i++) {
if (stack.empty() || stack.peek() <= arr[i]) {
stack.push(arr[i]);
} else {
const temp = stack.pop();
while (stack.peek() > arr[i]) {
stack.pop();
}
stack.push(temp);
}
}
return stack.size();
};
单调栈
class Solution:
def maxChunksToSorted(self, arr: List[int]) -> int:
stack = []
for i in arr:
if not stack:
stack.append(i)
continue
if i >= stack[-1]:
stack.append(i)
else:
tmp = stack.pop()
while stack and i < stack[-1]:
stack.pop()
stack.append(tmp)
return len(stack)
class Solution:
def maxChunksToSorted(self, arr: List[int]) -> int:
chunk = []
for val in arr:
if chunk:
if chunk[-1] <= val:
chunk.append(val)
else:
max = chunk[-1]
while len(chunk)>0 and chunk[-1] > val:
chunk.pop()
chunk.append(max)
else:
chunk.append(val)
return len(chunk)
time O(N) space O(N)
768. 最多能完成排序的块 II
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/max-chunks-to-make-sorted-ii/
前置知识
题目描述
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]之间。