【C/C++】1403. 非递增顺序的最小子序列
题目链接:1403. 非递增顺序的最小子序列
题目描述
给你一个数组 nums
,请你从中抽取一个子序列,满足该子序列的元素之和 严格 大于未包含在该子序列中的各元素之和。
如果存在多个解决方案,只需返回 长度最小 的子序列。如果仍然有多个解决方案,则返回 元素之和最大 的子序列。
与子数组不同的地方在于,「数组的子序列」不强调元素在原数组中的连续性,也就是说,它可以通过从数组中分离一些(也可能不分离)元素得到。
注意,题目数据保证满足所有约束条件的解决方案是 唯一 的。同时,返回的答案应当按 非递增顺序 排列。
提示:
- 1⩽nums.length⩽5001 \leqslant nums.length \leqslant 5001⩽nums.length⩽500
- 1⩽nums[i]⩽1001 \leqslant nums[i] \leqslant 1001⩽nums[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
,要求在数组中选取多个元素,使得选取的元素和大于未选取的元素和,同时要求选取的元素个数要最少且元素和要最大。返回的答案应当按 非递增顺序 排列。
解题思路分析
由于题目要求选取的元素个数最少且还要元素和最大,那么我们可以 贪心 的选择数组中最大的元素即可,不断选取数组中未选取的元素中数值最大的元素,直至元素和大于剩下未选取的元素和即可。
具体实现
- 求数组
nums
的所有元素和sum
; - 对数组
nums
进行降序排序处理; - 按照元素值从大到小遍历数组
nums
,在遍历的过程中不断将元素加入答案数组ans
,同时记录前缀和pre
,当pre > sum - pre
时返回ans
数组即可。
复杂度分析
- 时间复杂度:O(nlogn)O(n \log n)O(nlogn),其中
n
为 数组的长度。需要对数组进行排序,因此时间复杂度为 O(nlogn)O(n \log n)O(nlogn)。 - 空间复杂度:O(logn)O(\log n)O(logn),其中
n
为 数组的长度。排序需要的栈空间为 O(logn)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;
}
};
总结
- 该题核心思想为取最大元素,不断选取未选取元素中最大元素,直至大小超过剩余元素总和即可。
- 测试结果:
结束语
人生路漫漫,我们最能把握的是实实在在的眼前和当下。只有把今天该做好的事做好了,才算没有辜负光阴;只有把今天过好了,才有更足的底气去面对未知的明天。愿你在最美好的此刻,不辜负时光,不辜负自己。新的一天,加油!
转载自:https://juejin.cn/post/7153062968459001887