likes
comments
collection
share

【C/C++】1403. 非递增顺序的最小子序列

作者站长头像
站长
· 阅读数 10

题目链接:1403. 非递增顺序的最小子序列

题目描述

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

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

与子数组不同的地方在于,「数组的子序列」不强调元素在原数组中的连续性,也就是说,它可以通过从数组中分离一些(也可能不分离)元素得到。

注意,题目数据保证满足所有约束条件的解决方案是 唯一 的。同时,返回的答案应当按 非递增顺序 排列。

提示:

  • 1⩽nums.length⩽5001 \leqslant nums.length \leqslant 5001nums.length500
  • 1⩽nums[i]⩽1001 \leqslant nums[i] \leqslant 1001nums[i]100

示例 1:

输入:nums = [4,3,10,9,8]
输出:[10,9] 
解释:子序列 [10,9][10,8] 是最小的、满足元素之和大于其他各元素之和的子序列。但是 [10,9] 的元素之和最大。

示例 2:

输入:nums = [4,4,7,6,7]
输出:[7,7,6] 
解释:子序列 [7,7] 的和为 14 ,不严格大于剩下的其他元素之和(14 = 4 + 4 + 6)。因此,[7,6,7] 是满足题意的最小子序列。注意,元素按非递增顺序返回。 

示例 3:

输入: nums = [6]
输出: [6]

整理题意

题目给定一个整数数组 nums,要求在数组中选取多个元素,使得选取的元素和大于未选取的元素和,同时要求选取的元素个数要最少且元素和要最大。返回的答案应当按 非递增顺序 排列。

解题思路分析

由于题目要求选取的元素个数最少且还要元素和最大,那么我们可以 贪心 的选择数组中最大的元素即可,不断选取数组中未选取的元素中数值最大的元素,直至元素和大于剩下未选取的元素和即可。

具体实现

  1. 求数组 nums 的所有元素和 sum
  2. 对数组 nums 进行降序排序处理;
  3. 按照元素值从大到小遍历数组 nums,在遍历的过程中不断将元素加入答案数组 ans,同时记录前缀和 pre,当 pre > sum - pre 时返回 ans 数组即可。

复杂度分析

  • 时间复杂度:O(nlog⁡n)O(n \log n)O(nlogn),其中 n 为 数组的长度。需要对数组进行排序,因此时间复杂度为 O(nlog⁡n)O(n \log n)O(nlogn)
  • 空间复杂度:O(log⁡n)O(\log n)O(logn),其中 n 为 数组的长度。排序需要的栈空间为 O(log⁡n)O(\log n)O(logn)

代码实现

class Solution {
public:
    vector<int> minSubsequence(vector<int>& nums) {
        // 两种排序方式
        //sort(nums.begin(), nums.end(), greater<int>());
        sort(nums.begin(), nums.end(), [](int a, int b)->bool{
            return a > b;
        });
        // sum 计算数组中所有元素和
        int sum = 0;
        for(int &num : nums) sum += num;
        // pre 计算前缀和
        int pre = 0;
        // ans 记录答案数组
        vector<int> ans;
        ans.clear();
        // 当前缀和大于 sum - pre 时即满足条件输出即可
        for(int &num : nums){
            pre += num;
            ans.emplace_back(num);
            if(pre > sum - pre) break;
        }
        return ans;
    }
};

总结

  • 该题核心思想为取最大元素,不断选取未选取元素中最大元素,直至大小超过剩余元素总和即可。
  • 测试结果:

【C/C++】1403. 非递增顺序的最小子序列

结束语

人生路漫漫,我们最能把握的是实实在在的眼前和当下。只有把今天该做好的事做好了,才算没有辜负光阴;只有把今天过好了,才有更足的底气去面对未知的明天。愿你在最美好的此刻,不辜负时光,不辜负自己。新的一天,加油!