原题链接
一. 题目描述
「力扣挑战赛」心算项目的挑战比赛中,要求选手从 N
张卡牌中选出 cnt
张卡牌,若这 cnt
张卡牌数字总和为偶数,则选手成绩「有效」且得分为 cnt
张卡牌数字总和。 给定数组 cards
和 cnt
,其中 cards[i]
表示第 i
张卡牌上的数字。 请帮参赛选手计算最大的有效得分。若不存在获取有效得分的卡牌方案,则返回 0。
示例 1:
输入:
cards = [1,2,8,9], cnt = 3
输出:
18
解释:选择数字为 1、8、9 的这三张卡牌,此时可获得最大的有效得分 1+8+9=18。
示例 2:
输入:
cards = [3,3,1], cnt = 1
输出:
0
解释:不存在获取有效得分的卡牌方案。
提示:
1 <= cnt <= cards.length <= 10^5
1 <= cards[i] <= 1000
二. 解题思路
1. 本题意思非常简单,需要从 cards 数组中选择 cnt 个数字相加,使得最后的结果为偶数的最大值。一看到最值问题,脑子一转—贪心!!!没错,就是它!
2. 既然要最大值,我们先给数组进行一个排序,从数组末尾累加 cnt 个值就可以了,但是还是要注意一个问题!如果累加之后的结果是偶数直接输出就好了,但是如果是奇数怎么办呢?
3. 这里聪明的小伙伴就会意识到,如果是奇数简单啊,我们只需要在剩余的数组中挑选一个最大的奇数和最大的偶数,然后在后面 cnt 个里面挑出来一个最小的奇数和最小的偶数,然后:
(1). 将在数组前面找到的最大奇数与后 cnt 个数中最小的偶数进行替换;
(2). 将在数组前面找到的最大偶数与后 cnt 个数中最小的奇数进行替换。
4. 上面两步骤执行之后结果就会成偶数了,然后判断一下哪个最大输出就可以了!!
话不多说!!!上代码!!
三. 代码
class Solution {
public:
int maxmiumScore(vector<int>& cards, int cnt) {
sort(cards.begin(), cards.end());
int res = 0, ans = 0;
int n = cards.size();
int ji = -1, ou = -1;
for(int i = n - 1; i >= n - cnt; i--){
ans += cards[i];
if(cards[i] % 2) ji = cards[i]; // 记录后 cnt 个中最小的奇数
else ou = cards[i]; // 记录后 cnt 个中最小的偶数
}
if(ans % 2 == 0) return ans; // 如果是偶数直接输出
else{
for(int i = n - cnt - 1; i >= 0; i--){
if(cards[i] % 2) { // 前面部分的最大奇数
if(ou != -1) { // 前提是必须保证后面 cnt 个数中必须有偶数,不然无法计算出偶数
res = max(res, ans - ou + cards[i]);
}
}else{ // 同上
if(ji != -1){
res = max(res, ans - ji + cards[i]);
}
}
}
return res;
}
}
};
四. 总结
本题考查贪心思想,是一道很好的题目,建议练习!!!
时间复杂度:O(n*logn)(其中n为数组长度);
空间复杂度:O(1);