• 【数组】最多能完成排序的块 数学


    题目描述

    给定一个长度为 n 的整数数组 arr ,它表示在 [0, n - 1] 范围内的整数的排列。

    我们将 arr 分割成若干 块 (即分区),并对每个块单独排序。将它们连接起来后,使得连接的结果和按升序排序后的原数组相同。

    返回数组能分成的最多块数量。

    示例 1:

    输入: arr = [1, 4, 0, 2, 3, 5]
    输出: 2
    解释:
    我们可以把它分成两块,例如 [1, 4, 0, 2, 3], [5]。

    解题思路

    这道题给定的数组里面的数字是唯一的,范围: [0, N-1]。

    参考其他人的解决思路如下,这里使用 [1, 4, 0, 2, 3, 5] 举例:

    1. 找出指定范围内的最小值,从0开始查找;
    2. 找到最小值的下标:i,以及最大值:max;
    3. 从 i 到 max 继续遍历,找到里面的最大值;
    4. 使用max+1作为最小值,重复第1、2、3、4步骤,直到所有数字均遍历完成。

    按照上述思路代码实现如下:

    1. class Solution {
    2. public int maxChunksToSorted(int[] arr) {
    3. int count = 0;
    4. int targetValue = 0;
    5. int i = 0;
    6. while (i < arr.length) {
    7. int max = arr[i];
    8. int index = findNextIndex(i, targetValue, arr, max);
    9. if (index > arr.length - 1) {
    10. break;
    11. }
    12. targetValue = index + 1;
    13. i = index + 1;
    14. count++;
    15. }
    16. return count;
    17. }
    18. private int findNextIndex(int i, int targetValue, int[] arr, int max) {
    19. for (; i < arr.length; i++) {
    20. max = Math.max(arr[i], max);
    21. if (targetValue == arr[i]) {
    22. return i > max ? i : queryMax(i, arr, max);
    23. }
    24. }
    25. return arr.length;
    26. }
    27. private int queryMax(int i, int[] arr, int max) {
    28. while (i <= max) {
    29. max = Math.max(arr[i], max);
    30. i++;
    31. }
    32. return i - 1;
    33. }
    34. public static void main(String[] args) {
    35. Solution solution = new Solution();
    36. System.out.println(solution.maxChunksToSorted(new int[]{4, 3, 2, 1, 0}));
    37. System.out.println(solution.maxChunksToSorted(new int[]{1, 0, 2, 3, 4}));
    38. System.out.println(solution.maxChunksToSorted(new int[]{1, 0, 3, 2, 4}));
    39. System.out.println(solution.maxChunksToSorted(new int[]{2, 0, 1}));
    40. System.out.println(solution.maxChunksToSorted(new int[]{2, 0, 1, 3}));
    41. System.out.println(solution.maxChunksToSorted(new int[]{2, 0, 1, 3, 4}));
    42. System.out.println(solution.maxChunksToSorted(new int[]{2, 0, 1, 4, 3}));
    43. System.out.println(solution.maxChunksToSorted(new int[]{2, 0, 1, 4, 3, 5}));
    44. System.out.println(solution.maxChunksToSorted(new int[]{2, 0, 1, 5, 3, 4}));
    45. System.out.println(solution.maxChunksToSorted(new int[]{1, 2, 0, 3}));
    46. System.out.println(solution.maxChunksToSorted(new int[]{1, 4, 0, 2, 3, 5}));
    47. System.out.println(solution.maxChunksToSorted(new int[]{1, 5, 3, 0, 2, 8, 7, 6, 4}));
    48. }
    49. }

    上述代码复杂度比较高,理解成本很高,于是考虑使用其他的方案:

    1. 从下标0开始,找这个下标对应value的最大值;
    2. 完成上述操作后,重复执行,直到遍历完成。

    代码实现如下:

    1. class Solution {
    2. public int maxChunksToSorted(int[] arr) {
    3. int max = arr[0];
    4. int count = 0;
    5. for (int i = 0; i < arr.length; i++) {
    6. max = Math.max(max, i);
    7. if (max == arr[i]) {
    8. count++;
    9. }
    10. }
    11. return count;
    12. }
    13. public static void main(String[] args) {
    14. Solution solution = new Solution();
    15. System.out.println(solution.maxChunksToSorted(new int[]{4, 3, 2, 1, 0}));
    16. System.out.println(solution.maxChunksToSorted(new int[]{1, 0, 2, 3, 4}));
    17. System.out.println(solution.maxChunksToSorted(new int[]{1, 0, 3, 2, 4}));
    18. System.out.println(solution.maxChunksToSorted(new int[]{2, 0, 1}));
    19. System.out.println(solution.maxChunksToSorted(new int[]{2, 0, 1, 3}));
    20. System.out.println(solution.maxChunksToSorted(new int[]{2, 0, 1, 3, 4}));
    21. System.out.println(solution.maxChunksToSorted(new int[]{2, 0, 1, 4, 3}));
    22. System.out.println(solution.maxChunksToSorted(new int[]{2, 0, 1, 4, 3, 5}));
    23. System.out.println(solution.maxChunksToSorted(new int[]{2, 0, 1, 5, 3, 4}));
    24. System.out.println(solution.maxChunksToSorted(new int[]{1, 2, 0, 3}));
    25. System.out.println(solution.maxChunksToSorted(new int[]{1, 4, 0, 2, 3, 5}));
    26. System.out.println(solution.maxChunksToSorted(new int[]{1, 5, 3, 0, 2, 8, 7, 6, 4}));
    27. }
    28. }

    总结

    这道题是一个中等难度题目,第一种方案自己想到了,最终完成了代码。第二种方案,代码非常简单,但最终还是看其他人的代码实现才解决了。这道题的解决方案欢迎大家回复,给出更加优秀和简单的解法。 


    新版题目描述

    下面加大这道题的难度,下面是题目描述:

    arr是一个可能包含重复元素的整数数组,我们将这个数组分割成几个“块”,并将这些块分别进行排序。之后再连接起来,使得连接的结果和按升序排序后的原数组相同。

    示例1:

    输入: arr = [2,1,3,4,4]
    输出: 4
    解释:
    我们可以把它分成两块,例如 [2, 1], [3, 4, 4]。
    然而,分成 [2, 1], [3], [4], [4] 可以得到最多的块数。 

    新版题目解题思路

    由于这道题是之前题目的增强版本,我这边思路是复用上面的解题思路:

    1. 将arr拷贝到copy中;
    2. 对copy进行排序;
    3. 记录排序后copy的位置;
    4. 按照arr的顺序对arr的位置进行还原;
    5. 按照非重复的数组,获得数组能分成的最多块数量。

    按照上述思路代码实现如下:

    1. import java.util.*;
    2. class Solution {
    3. public int maxChunksToSorted(int[] arr) {
    4. // 拷贝数组
    5. int[] copy = Arrays.copyOf(arr, arr.length);
    6. // 对数组排序
    7. Arrays.sort(copy);
    8. // 记录数组位置
    9. Map<Integer, List<Integer>> map = new HashMap<>();
    10. for (int i = 0; i < copy.length; i++) {
    11. List<Integer> list = map.get(copy[i]);
    12. if (list == null) {
    13. list = new LinkedList<>();
    14. map.put(copy[i], list);
    15. }
    16. list.add(i);
    17. }
    18. // 还原数组index
    19. int[] array = new int[arr.length];
    20. for (int i = 0; i < arr.length; ) {
    21. List<Integer> list = map.get(arr[i]);
    22. array[i] = list.remove(0);
    23. i++;
    24. }
    25. // array就是从[0,N-1]的数组
    26. int count = 0;
    27. int max = array[0];
    28. for (int i = 0; i < array.length; i++) {
    29. max = Math.max(array[i], max);
    30. if (max == i) {
    31. count++;
    32. }
    33. }
    34. return count;
    35. }
    36. public static void main(String[] args) {
    37. Solution solution = new Solution();
    38. System.out.println(solution.maxChunksToSorted(new int[]{2, 1, 3, 4, 4}));
    39. }
    40. }

    使用单调栈解决

    case1:

    case2: 将这个位置的2替换成0,如下图:

    思路如下:

    1. 确保每一组数中,第一个数都是最大的;
    2. 利用单调栈来处理,如果value比栈顶数据大则入栈,否则记录出栈记录该值为current,用value和剩余栈中元素比较,如果. value<剩余栈中元素  那么元素出栈;

    代码实现如下:

    1. import java.util.*;
    2. class Solution {
    3. public int maxChunksToSorted(int[] arr) {
    4. Deque deque = new ArrayDeque<>();
    5. for (int value : arr) {
    6. if (deque.isEmpty() || deque.peek() <= value) {
    7. deque.push(value);
    8. } else {
    9. // 栈顶元素
    10. int current = deque.pop();
    11. // 决策是不是要融合
    12. while (!deque.isEmpty() && deque.peek() > value) {
    13. deque.pop();
    14. }
    15. deque.push(current);
    16. }
    17. }
    18. return deque.size();
    19. }
    20. public static void main(String[] args) {
    21. Solution solution = new Solution();
    22. System.out.println(solution.maxChunksToSorted(new int[]{2, 1, 3, 4, 4}));
    23. System.out.println(solution.maxChunksToSorted(new int[]{2, 1, 5, 2, 3, 4, 7, 8}));
    24. }
    25. }

     

    新版题目总结

    这道题是一个复杂题目,在原来题目上增加了还原数组下标的操作,目前的解决方案耗时还是很高的,如果有更加快速、简洁的思路欢迎回复。

  • 相关阅读:
    Elasticsearch-01-es概念及安装
    【机器学习】实验4布置:AAAI会议论文聚类分析
    快手伸手“供给侧”,找到直播电商的“源头活水”?
    通过配置文件导入自己的jar包(Eclipse,包括打jar包)
    炫酷登录注册界面【超级简单 jQuery+JS+HTML+CSS实现】
    Python1 文件读写操作
    获取到Nginx默认反向后的端口为80导致请求失败、Get请求取不到参数问题
    SQL 语句的执行顺序
    期货平盘(期货大单压盘)
    11 【Teleport CSS功能】
  • 原文地址:https://blog.csdn.net/weiliuhong1/article/details/126316202