【LeetCode每日一题】【贪心】2022-10-13 769. 最多能完成排序的块 Java实现


题目

在这里插入图片描述

我的思路(错误)

根据提示The first chunk can be found as the smallest k for which A[:k+1] == [0, 1, 2, ...k]; then we repeat this process.,先找到最小的值,包括该值的之前的那一段为一个block,不断重复上述过程,可以确定把数组分成几个block

class Solution {
    public int maxChunksToSorted(int[] arr) {

        int cnt = 0;
        int minIdx = -1;
        do {
            cnt++;
            minIdx = findMin(arr, minIdx+1, arr.length);
        } while (minIdx != arr.length - 1);
        return cnt;
    }

    private int findMin(int[] arr, int start, int end) {
        int min = 11;
        int idx = -1;
        for (int i = start; i < end; i++) {
            if (arr[i] < min) {
                idx = i;
                min = arr[i];
            }
        }
        return idx;
    }
}

在这里插入图片描述
加上一个判断条件,如果该数组中的最大值就在第一位,那么只能分一个block

class Solution {
    public int maxChunksToSorted(int[] arr) {

        int maxIdx = findMax(arr, 0, arr.length);
        if (maxIdx == 0) {
            return 1;
        }

        int cnt = 0;
        int minIdx = -1;
        do {
            cnt++;
            minIdx = findMin(arr, minIdx + 1, arr.length);
        } while (minIdx != arr.length - 1);
        return cnt;
    }

    private int findMin(int[] arr, int start, int end) {
        int minValue = 11;
        int idx = -1;
        for (int i = start; i < end; i++) {
            if (arr[i] < minValue) {
                idx = i;
                minValue = arr[i];
            }
        }
        return idx;
    }

    private int findMax(int[] arr, int start, int end) {
        int maxValue = -1;
        int idx = -1;
        for (int i = start; i < end; i++) {
            if (arr[i] > maxValue) {
                idx = i;
                maxValue = arr[i];
            }
        }
        return idx;
    }
}

在这里插入图片描述

官方思路 贪心

根据题意我们可以得到以下两个定理:

  • 定理一:对于某个块A,它由块B和块C组成,即A=B+C。如果块B和块C分别排序后都与原数组排序后的结果一致,那么块A排序后与原数组排序后的结果一致

证明:因为块B和块C分别排序后都与原数组排序后的结果一致,所以块B的元素和块C的元素的并集为原始数组排序后在对应区间的所有元素。而A=B+C,因此将块A排序后与原数组排序后的结果一致

  • 定理二:对于某个块A,它由块B和块C组成,即A=B+C。如果块A和块B分别排序后都与原数组排序后一致,那么块C排序后与原数组排序后的结果一致

如果块C排序后与原数组排序后的结果不一致,那么块B的元素和块C的元素的并集不等同于原数组排序后在对应区间的所有元素。而块A排序后与原数组排序后的结果一致,说明块A的元素等同于原数组排序后在对应区间的所有元素。这与块A元素由块B和块C的元素组成矛盾,因此块C排序后与原数组排序后结果一致

假设数组arr一种分割方案为 [ a 0 , a i 1 ] , [ a i 1 + 1 , a i 2 ] , . . . , [ a i m + 1 , a n − 1 ] [a_0,a_{i1}],[a_{i1+1},a_{i2}],...,[a_{im+1},a_{n-1}] [a0,ai1],[ai1+1,ai2],...,[aim+1,an1],那么由定理一可知, [ a 0 , a i 1 ] , [ a 0 , a i 2 ] , . . . , [ a 0 , a n − 1 ] [a_0,a_{i1}],[a_0,a_{i2}],...,[a_0,a_{n-1}] [a0,ai1],[a0,ai2],...,[a0,an1]分别排序后与原数组排序后的结果一致。反之,如果 [ a 0 , a i 1 ] , [ a 0 , a i 2 ] , . . . , [ a 0 , a n − 1 ] [a_0,a_{i1}],[a_0,a_{i2}],...,[a_0,a_{n-1}] [a0,ai1],[a0,ai2],...,[a0,an1]分别排序后与原数组排序后的结果一致,那么,由定理二可知 [ a 0 , a i 1 ] , [ a i 1 + 1 , a i 2 ] , . . . , [ a i m + 1 , a n − 1 ] [a_0,a_{i1}],[a_{i1+1},a_{i2}],...,[a_{im+1},a_{n-1}] [a0,ai1],[ai1+1,ai2],...,[aim+1,an1]是数组arr一种分割方案

因此,只要找到 [ a 0 , a i 1 ] , [ a 0 , a i 2 ] , . . . , [ a 0 , a n − 1 ] [a_0,a_{i1}],[a_0,a_{i2}],...,[a_0,a_{n-1}] [a0,ai1],[a0,ai2],...,[a0,an1]的最大数目,就能找到最大分割块数目。因为数组arr的元素在区间 [ 0 , n − 1 ] [0,n-1] [0,n1]之间且互不相同,所以,数组排序后有 a r r [ i ] = i arr[i]=i arr[i]=i。如果数组arr的某个长为i+1的前缀块 [ a 0 , a i ] [a_0,a_i] [a0,ai]的最大值等于i,那么说明它排序后与原数组排序后的结果一致。统计这些前缀块的数目,就可以得到最大分割块数目

class Solution {
    public int maxChunksToSorted(int[] arr) {
        int cnt = 0;
        int maxValue = -1;
        for (int i = 0; i < arr.length; i++) {
            maxValue = Math.max(maxValue, arr[i]);
            if (maxValue == i) {
                cnt++;
            }
        }
        return cnt;
    }

}

其他解法

最多能完成排序的块【栈模拟 + 一次遍历】

我们定义每个块所处的区间为 [min,max]

遍历时,认为每个数组都是一个单独的块,区间为[num,num]

然后比较当前栈顶快的区间,判断当前num是否包含在块中

设栈顶元素为curInterval

  • 若当前num小于nurInterval[0],则进行块合并,合并为[num,curInterval[1]],循环遍历栈顶元素直到大于curInterval[1]
    • Q:为什么进行块合并?
    • A:若当前元素小于栈顶块的最小值,意味着这排序后会调整到栈顶块中元素的前面,所以必须合并成一个块才能保证所处的位置是正确的。栈内存储的块是严格递增的

在这里插入图片描述

  • 若当前num大于curInterval[0],且小于curInterval[1],直接合并到栈顶元素的块
    在这里插入图片描述

  • 若当前num大于curInterval[1],入栈

在这里插入图片描述

当可以合并的时候,需要弹出栈中元素

原文中使用的是ArrayDeque,我这里使用Stack

import java.util.Stack;

class Solution {
    public int maxChunksToSorted(int[] arr) {
        Stack<int[]> stack = new Stack<>();
        int maxValue, minValue;
        int[] curInterval;
        for (int num : arr) {
            minValue = num;
            maxValue = num;
            while (!stack.isEmpty() && (num < stack.peek()[0] || num < stack.peek()[1])) {
                curInterval = stack.pop();
                minValue = Math.min(minValue, curInterval[0]);
                maxValue = Math.max(maxValue, curInterval[1]);
            }
            stack.add(new int[]{minValue, maxValue});
        }
        return stack.size();
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值