“一个能思想的人,才真是一个力量无边的人。”——巴尔扎克
题目
「力扣挑战赛」心算项目的挑战比赛中,要求选手从 N
张卡牌中选出 cnt
张卡牌,若这 cnt
张卡牌数字总和为偶数,则选手成绩「有效」且得分为 cnt
张卡牌数字总和。 给定数组 cards
和 cnt
,其中 cards[i]
表示第 i
张卡牌上的数字。 请帮参赛选手计算最大的有效得分。若不存在获取有效得分的卡牌方案,则返回 0。
难度:简单
分析
此题虽然标的简单,但是难度不小(做得人晕了😵),故此不得不记录,而且笔者的思路似乎不太好,没有官方的巧妙,受教了。
笔者思路:由于偶数并不影响和的奇偶性,所以可以将奇数和偶数分开存储,将数值从大到小排序,开始时全部选择偶数(不够则加上奇数),每次加入一个大的奇数,移除一个小的偶数,判断总和的奇偶性更新结果。
官方题解:将数组从大到小排列,取前cnt值的和,如果总和为偶数,直接返回;否则取以下两种情况中的较大值:cnt中最小的奇数与后面最大的偶数替换;cnt中最小的偶数与后面最大的奇数替换。
解答
奇偶分组
class Solution {
public:
int maxmiumScore(vector<int>& cards, int cnt) {
sort(cards.begin(),cards.end(),greater<int>());
vector<int> odd,even;
for (int i:cards){
if (i%2==1){
odd.push_back(i);
}else{
even.push_back(i);
}
}
int i=0; // odd
int j=0; // even
int ans=0;
int m=odd.size();
int n=even.size();
int cur=0;
while (cnt&&j<n){
cur+=even[j++];
cnt--;
}
while (cnt&&i<m){
cur+=odd[i++];
cnt--;
}
if (cur%2==0){
ans=cur;
}
while (i<m&&j-1>=0){
cur+=odd[i++]-even[--j];
if (cur%2==0){
ans=max(ans,cur);
}
}
return ans;
}
};
奇偶替换
class Solution {
public:
int maxmiumScore(vector<int>& cards, int cnt) {
sort(cards.begin(),cards.end(),greater<int>());
int ans=0;
int cur=0;
int minOdd=-1,minEven=-1;
for (int i=0;i<cnt;i++){
cur+=cards[i];
if (cards[i]%2==1){
minOdd=cards[i];
}else{
minEven=cards[i];
}
}
if (cur%2==0){
return cur;
}
for (int i=cnt;i<cards.size();i++){
if (cards[i]%2==1){
if (minEven!=-1){
ans=max(ans,cur-minEven+cards[i]);
}
}else{
if (minOdd!=-1){
ans=max(ans,cur-minOdd+cards[i]);
}
}
}
return ans;
}
};