leetcode-pp / 91alg-6-daily-check

91 算法第六期打卡仓库
28 stars 0 forks source link

【Day 6 】2021-12-17 - 768. 最多能完成排序的块 II #10

Open azl397985856 opened 2 years ago

azl397985856 commented 2 years ago

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]之间。

fredxxj commented 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
uniqlell commented 2 years ago

思路:单调栈


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();
    }
}
HWFrankFung commented 2 years ago

Codes

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
};
ZZRebas commented 2 years ago

思路

使用类似计数排序的技巧来完成

代码(Python)

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

复杂度分析

linyang4 commented 2 years ago

思路

滑动窗口, 把原数组从小到大排序, 遍历数组, 如果排序后数组的前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
}

复杂度

Hacker90 commented 2 years ago

思路

不知道思路

代码

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;
    }
};

复杂度分析

ninghuang456 commented 2 years ago
// 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();
    }
}
RMadridXDH commented 2 years ago

代码

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
Okkband commented 2 years ago
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
chenyaohn commented 2 years ago

思路

题目要求分成的块升序排序,则可知后面的块里的值必然大于等于前面的块的最大值。
由此如果遍历到后面的元素如果大于或等于前一块的最大值,则有可能组成一个新块,但如果遍历的元素小于前面块的最大值,则无法组成新块将此值加入到上一个块中。然后则需要判断这个值是否比前面得所有块的最小值小。如小则需要删除块的数量。
我自己的代码太过于复杂,查看题解可知可使用滑动窗口处理

代码

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)

last-Battle commented 2 years ago

思路

关键点

使用栈
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 为数组长度。

xuhzyy commented 2 years ago

思路

排序后的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

复杂度分析

coder123xt commented 2 years ago

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
};
revisegoal commented 2 years ago

思路

首先还是要找到从左边开始最小的块。

代码

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;
    }
}

复杂度

gova-i267 commented 2 years ago

题目:

https://leetcode-cn.com/problems/max-chunks-to-make-sorted-ii/

思路:

Java 代码

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;
    }
}

复杂度分析:

declan92 commented 2 years ago

思路: 从左往右同时遍历两个数组时,计数信息一致,则可以分块; 遍历过程中计数信息一致的次数,为最多可分块数; 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)

liuajingliu commented 2 years ago

解题思路

单调栈

代码实现

/**
 * @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
};

复杂度分析

1916603886 commented 2 years ago

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;

};

Brent-Liu commented 2 years ago

思路

滑动窗口

代码

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;
}

}

复杂度分析

Davont commented 2 years ago

code

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;
};
WANGDI-1291 commented 2 years ago

思路

在遍历过程中,当遇到更小的元素时,就将之前的稍大的栈中的元素融合为这几个元素的最大值,输入到栈中。

代码

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)

rzhao010 commented 2 years ago

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

bluetomlee commented 2 years ago

··· 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

···

fornobugworld commented 2 years ago

思路

直接看题解了,排序块(单调栈)

代码

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)

复杂度分析

Richard-LYF commented 2 years ago

class Solution: def maxChunksToSorted(self, arr: List[int]) -> int: A = arr stack = [] for a in A:

遇到一个比栈顶小的元素,而前面的块不应该有比 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)
tian-pengfei commented 2 years ago
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;

    }
};
yuetong3yu commented 2 years ago

这道题目理解比较难。

但一个简单的解题思路是:既然分组后的数组和排序后的切片数组是相等的,那无论这两个数组的顺序如何打乱,它们的和都一定是相等的。

根据这个思路,我们只要额外定义两个数进行遍历即可:

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
}

GaoMinghao commented 2 years ago

思路

滑动窗口

代码

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)

demo410 commented 2 years ago

思路

代码(不是自己写的)

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();
    }

复杂度

yetfan commented 2 years ago

思路 找到从左边开始最小的块

代码

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)

xinhaoyi commented 2 years ago

//思路一:单调递增栈 class Solution { public int maxChunksToSorted(int[] arr) { int max = Integer.MIN_VALUE / 2; Deque stack = new LinkedList<>(); for(int i = 0; i < arr.length; i++){ //如果当前元素比max要大,或者相等,那么就把最大值放进单调栈,代表着新建了一个块,同时保存了这个块的最大值 if(arr[i] >= max){ max = arr[i]; stack.addFirst(max); } else{ //如果当前元素的值比单调栈栈顶的max要小,那么就说明它前面的一个块要和它合并 //合并后我们会继续让单调栈再出栈一个,看是不是比新的max要小,如果小的话还要再合并 //一直合并到arr[i] >= max为止

            //最外层的合并了,先出栈
            int temp = stack.removeFirst();
            //继续看更前面的块,如果arr[i]比它还要小,继续合并,只要stack不为空
            while(!stack.isEmpty() && stack.peekFirst() > arr[i]){
                //继续出栈
                temp = stack.removeFirst();
            }
            //把最后出栈合并的那个块补回来
            stack.addFirst(temp);
        }

    }
    //返回stack的元素个数
    return stack.size();
}

}

TruenoCB commented 2 years ago

//采用递归的思想,每一步递归判断能否分块,能分块则加一,然后判断剩下的能否分块,使递归不管逼近整个数组。

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)

Zhang6260 commented 2 years ago

JAVA版本

使用栈,入栈的时候与栈顶的元素进行比较,如果大于栈顶元素则直接入栈,如果比栈顶元素小,则需要将栈中小于入栈的元素都出栈,最后栈中剩余的元素就是所需要的结果。

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();
   }
}

时间复杂度:O(n)

空间复杂度:O(n)

hoye1113 commented 2 years ago

思路:看题解了,用单调栈的方法

语言: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;
};

复杂度分析

for123s commented 2 years ago

代码

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;
    }
};
taojin1992 commented 2 years ago

Plan:

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.

Review:

0 2 9 1 2

0 2 9 
0 9
0 9

0 2 9 
0 9 
0 9

Complexity:

Time: O(arr.length)
best case, insert once, no popping

Space: O(arr.length)

Code:

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();
    }
}
ChenJingjing85 commented 2 years ago

class Solution { public int maxChunksToSorted(int[] arr) { Stack mins = new Stack(); Stack maxs = new Stack(); mins.push(arr[0]); maxs.push(arr[0]); int count = 1; for(int i = 1; i< arr.length; i ++){
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;

}

}

tian-pengfei commented 2 years ago

优化一下内存

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;

    }
};
Frederickfan commented 2 years ago

Idea

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.

Code

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 

Complexity

T: O(N) S: O(1)

q815101630 commented 2 years ago

hard 学习了

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
pangjiadai commented 2 years ago

单调栈

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)
simbafl commented 2 years ago

--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)
JudyZhou95 commented 2 years ago

思路

需要合并后能够升序,即后面的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)

chakochako commented 2 years ago
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
suukii commented 2 years ago

Link to LeetCode Problem

S1: 滑动窗口+贪心

题目有一个提示:

提示的意思是:如果将原数组进行分块,再将排序数据进行相同的分块,每个对应的分块中数字种类是相同的,仅仅是数字的排序不同。

既然每个分块中拥有的数字是一样的,那数字的和也是一样的。

我们可以用一个滑动窗口同时扫描原数组和排序数组,当窗口中包括的数字一样时,贪心地进行分块(滑动窗口就是下图的色块)。

至于为什么要用到贪心,是因为题目问的是我们最多能将数组分成多少块?要获得尽量多的分块,那分块的大小就要尽量小,所以能分块的时候就要分块。

https://camo.githubusercontent.com/85ea23d35174577a3d5e586432d6e520aa9e7582a78cf0c133389b8090ea849f/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f7375756b69692f39312d646179732d616c676f726974686d2f6173736574732f30362e6d61782d6368756e6b732d746f2d6d616b652d736f727465642d69692d30302e706e67

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;
};

S2: 单调栈

根据题意,将原数组进行分块后,对各分块分别进行排序后的结果等于原数组排序后的结果。

可以得到的一个结论是,每个分块中的数字相对于前一个分块都是递增的(因为有重复数字,所以也可能是相同),第 i+1 个分块中的所有数字会大于等于 第 i 个分块中的所有数字。

https://camo.githubusercontent.com/21ab31b6c6fa1ad43a18218aa52e2365aca0ec58f67c3c367562349280e7cdfd/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f7375756b69692f39312d646179732d616c676f726974686d2f6173736574732f30362e6d61782d6368756e6b732d746f2d6d616b652d736f727465642d69692d30312e706e67

另一个例子:

https://camo.githubusercontent.com/f6059083bac8e82906bf842a580d01d8b325669e5c482a83943084d573cb497b/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f7375756b69692f39312d646179732d616c676f726974686d2f6173736574732f30362e6d61782d6368756e6b732d746f2d6d616b652d736f727465642d69692d30322e706e67

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();
};
devosend commented 2 years ago

思路

单调栈

代码

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)

复杂度分析

zhiyuanpeng commented 2 years ago
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)