1403-非递增顺序的最小子序列

Raphael Liu Lv10

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

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

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

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

示例 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]

提示:

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

方法一:贪心

题目要求从原数组中取出部分元素,且满足取出的元素之和严格大于剩余的元素之和,且满足要求取出的元素数量尽可能的少的前提下,取出的元素之和尽可能的大。根据以上分析,我们可以利用贪心法。我们应尽量保证取出的元素尽可能的大,才能满足取出的元素尽可能的少且元素之和尽可能的大,因此我们按照从大到小的顺序依次从原始数组中取出数据,直到取出的数据之和 curr 大于数组中剩余的元素之和为止。

[sol1-Python3]
1
2
3
4
5
6
7
8
class Solution:
def minSubsequence(self, nums: List[int]) -> List[int]:
nums.sort(reverse=True)
tot, s = sum(nums), 0
for i, num in enumerate(nums):
s += num
if s > tot - s:
return nums[:i + 1]
[sol1-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
vector<int> minSubsequence(vector<int>& nums) {
int total = accumulate(nums.begin(), nums.end(), 0);
sort(nums.begin(), nums.end());
vector<int> ans;
int curr = 0;
for (int i = nums.size() - 1; i >= 0; --i) {
curr += nums[i];
ans.emplace_back(nums[i]);
if (total - curr < curr) {
break;
}
}
return ans;
}
};
[sol1-Java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public List<Integer> minSubsequence(int[] nums) {
int total = Arrays.stream(nums).sum();
Arrays.sort(nums);
List<Integer> ans = new ArrayList<Integer>();
int curr = 0;
for (int i = nums.length - 1; i >= 0; --i) {
curr += nums[i];
ans.add(nums[i]);
if (total - curr < curr) {
break;
}
}
return ans;
}
}
[sol1-C#]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Solution {
public IList<int> MinSubsequence(int[] nums) {
int total = nums.Sum();
Array.Sort(nums);
IList<int> ans = new List<int>();
int curr = 0;
for (int i = nums.Length - 1; i >= 0; --i) {
curr += nums[i];
ans.Add(nums[i]);
if (total - curr < curr) {
break;
}
}
return ans;
}
}
[sol1-C]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static inline cmp(const void *pa, const void *pb) {
return *(int *)pa - *(int *)pb;
}

int* minSubsequence(int* nums, int numsSize, int* returnSize){
int total = 0;
for (int i = 0; i < numsSize; i++) {
total += nums[i];
}
qsort(nums, numsSize, sizeof(int), cmp);
int *ans = (int *)malloc(sizeof(int) * numsSize);
int curr = 0, pos = 0;
for (int i = numsSize - 1; i >= 0; --i) {
curr += nums[i];
ans[pos++] = nums[i];
if (total - curr < curr) {
break;
}
}
*returnSize = pos;
return ans;
}
[sol1-Golang]
1
2
3
4
5
6
7
8
9
10
11
12
13
func minSubsequence(nums []int) []int {
sort.Sort(sort.Reverse(sort.IntSlice(nums)))
tot := 0
for _, num := range nums {
tot += num
}
for i, sum := 0, 0; ; i++ {
sum += nums[i]
if sum > tot-sum {
return nums[:i+1]
}
}
}
[sol1-JavaScript]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var minSubsequence = function(nums) {
const total = _.sum(nums);
nums.sort((a, b) => a - b);
const ans = [];
let curr = 0;
for (let i = nums.length - 1; i >= 0; --i) {
curr += nums[i];
ans.push(nums[i]);
if (total - curr < curr) {
break;
}
}
return ans;
};

复杂度分析

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

  • 空间复杂度:O(\log n),其中 n 为 数组的长度。排序需要的栈空间为 O(\log n)。

 Comments
On this page
1403-非递增顺序的最小子序列