• 【数组】非递增的最小子序列 计数排序


    题目描述

    给你一个数组nums,请你从中抽取一个子序列,满足该子序列的元素之和严格大于未包含在该子序列中的各元素之和。

    如果存在多个解决方案,只需返回长度最小的子序列。如果仍然有多个解决方案,则返回元素之和最大的子序列。

    示例1:

    输入:nums=[4,4,7,6,7]

    输出:[7,7,6]

    解释:子序列[7,7]之和是14,[4,4,6]之和是14,不满足条件,所以返回[7,7,6]

    解法思路

    这道题就是一道排序题,整体流程如下:

    • 先对这个数组进行排序;
    • 对排序结果求和,即sum;
    • 对求和结果除以2,并且+1,halfSum=sum/2+1;
    • 从后到前进行遍历,添加到list中,并且求和,如果发现结果大于halfSum,则退出循环;
    • 返回list,代码执行结束。

    基本代码实现如下:

    1. import java.util.ArrayList;
    2. import java.util.Arrays;
    3. import java.util.List;
    4. class Solution1 {
    5. public List minSubsequence(int[] nums) {
    6. List list = new ArrayList<>();
    7. Arrays.sort(nums);
    8. int sum = 0;
    9. for(int i=0;i
    10. sum += nums[i];
    11. }
    12. int rightSum = 0;
    13. for(int i=nums.length-1;i>=0;i--) {
    14. rightSum += nums[i];
    15. list.add(nums[i]);
    16. if(sum - rightSum< rightSum) {
    17. return list;
    18. }
    19. }
    20. return list;
    21. }
    22. }

    上述代码实现是标准的解法,但是还可以做优化,降低耗时。这里我使用计数排序,通过计数排序,降低时间复杂度。

    要使用计数排序,需要先知道整个数据规模,题目给定的数据规模:

    • 1 <= nums.length <= 500
    • 1 <= nums[i] <= 100

    下面来看看计数排序算法的实现思路:

     

    如上图所示,由于上述代码的最大值是14,所以准备长度为15的数组。计数统计代码如下:

     


        public int[] countSort(int[] array, int max) {
            // 做频次统计
            int[] countArray = new int[max + 1];
            for (int num : array) {
                countArray[num]++;
            }

            // 还原排序结果
            int[] res = new int[array.length];
            int index = 0;
            for (int j = 0; j < countArray.length; j++) {
                int count = countArray[j];
                if (count > 0) {
                    for (int i = 0; i < count; i++) {
                        res[index++] = j;
                    }
                }
            }
            return res;
        }

        //1,8,9,14,7,6,9,12,10,13,8,4,2,9,8
        public static void main(String[] args) {
            Solution1 solution = new Solution1();
            int max = 14;
            int[] array = new int[]{1, 8, 9, 14, 7, 6, 9, 12, 10, 13, 8, 4, 2, 9, 8};
            System.out.println(Arrays.toString(solution.countSort(array, max)));
        }

    根据上述排序代码实现,可以对这道题代码实现做优化,优化思路就是通过计数排序,降低时间复杂度。代码实现如下:

    1. import java.util.ArrayList;
    2. import java.util.Arrays;
    3. import java.util.List;
    4. class Solution {
    5. public List minSubsequence(int[] nums) {
    6. // 直接取长度为101的数组
    7. int[] array = new int[101];
    8. // 计数总和
    9. int sum = 0;
    10. for (int num : nums) {
    11. array[num]++;
    12. sum += num;
    13. }
    14. int half = sum / 2 + 1;
    15. int halfSum = 0;
    16. List res = new ArrayList<>();
    17. for (int i = 100; i >= 0; i--) {
    18. if (array[i] > 0) {
    19. for (int j = 0; j < array[i]; j++) {
    20. halfSum += i;
    21. res.add(i);
    22. if (halfSum >= half) {
    23. break;
    24. }
    25. }
    26. if (halfSum >= half) {
    27. break;
    28. }
    29. }
    30. }
    31. return res;
    32. }
    33. }

    总结

    这道题是一道普通的排序题目,但如果要时间复杂度最优,还是需要调优排序算法;我这里使用了计数排序,将O(n*log n) 的时间复杂度降低到了O(n),完成对代码的优化。优化效果如下:

    欢迎有更好解法的同学回复解题思路。

     

  • 相关阅读:
    Doris学习--1、Doris简介、操作Doris、Doris架构(数据模型)
    在springboot框架中用Configuration注解的方式写一个java过滤器的详细实例?
    Unity Metaverse(三)、Protobuf & Socket 实现多人在线
    系统集成项目管理总结(笔记)
    Java字符串(String类)
    shopee买家通系统一款全自动化操作的软件
    同城预约上门服务APP小程序开发 打造快捷便利生活
    SpringMvc的第二天
    1211、PXC集群、mysql存储引擎
    Django高级之-forms组件
  • 原文地址:https://blog.csdn.net/weiliuhong1/article/details/126167563