LCP 40. 心算挑战
题目链接
https://leetcode.cn/problems/uOAnQW/
相关算法
贪心、排序
题目描述
「力扣挑战赛」心算项目的挑战比赛中,要求选手从 N
张卡牌中选出 cnt
张卡牌,若这 cnt
张卡牌数字总和为偶数,则选手成绩「有效」且得分为 cnt
张卡牌数字总和。 给定数组 cards
和 cnt
,其中 cards[i]
表示第 i
张卡牌上的数字。 请帮参赛选手计算最大的有效得分。若不存在获取有效得分的卡牌方案,则返回 0
。
- 数据范围:
1 <= cnt <= cards.length <= 10^5
1 <= cards[i] <= 1000
解题思路
本题显然可以用贪心的思路,无论是否满足条件,先尽可能将最大的卡牌加到结果中,然后如果不满足总和为偶数的情况,再进行调整。因此,优先将数组进行排序,并求出前 cnt
大的卡牌数字总和。
Arrays.sort(cards);
int sum = 0;
for (int i = cards.length - 1; i >= cards.length - cnt; i--) {
sum += cards[i];
}
然后,如果结果为偶数,就可以直接进行返回,而如果结果为奇数,则需要进行处理:将结果中的一个偶数移除,替换成一个奇数,或者移除一个奇数,换上一个偶数。根据贪心算法,我们移除的数应该尽可能小,换上的数应该尽可能大。
首先,我们调整一下前面的部分,在计算和的时候,同时把结果中最小的奇数和偶数记录下来,此处分别使用变量 min0
和 min1
存储结果中最小的偶数和奇数
int min0 = Integer.MAX_VALUE, min1 = Integer.MAX_VALUE;
for (int i = cards.length - 1; i >= cards.length - cnt; i--) {
sum += cards[i];
if (cards[i] % 2 == 0) {
min0 = Math.min(min0, cards[i]);
} else {
min1 = Math.min(min1, cards[i]);
}
}
接下来,统计数组剩余部分中最大的奇数和偶数,此处分别使用变量 max0
和 max1
存储
int max0 = Integer.MIN_VALUE, max1 = Integer.MIN_VALUE;
for (int i = cards.length - cnt - 1; i >= 0; i--) {
if (max0 != Integer.MIN_VALUE && max1 != Integer.MIN_VALUE) {
break;
}
if (cards[i] % 2 == 0) {
max0 = Math.max(max0, cards[i]);
} else {
max1 = Math.max(max1, cards[i]);
}
}
最后就是进行替换操作,将两种情况中的最大值返回。但是此处有陷阱:可能存在min0
、min1
、max0
、max1
表示的值不存在的情况,即中间遍历的部分数组是纯奇数或纯偶数,因此要进行详细的判断
int result = Integer.MIN_VALUE;
if (min0 != Integer.MAX_VALUE && max1 != Integer.MIN_VALUE) {
result = Math.max(result, sum - min0 + max1);
}
if (min1 != Integer.MAX_VALUE && max0 != Integer.MIN_VALUE) {
result = Math.max(result, sum - min1 + max0);
}
return result == Integer.MIN_VALUE ? 0 : result;
至此,题目完成
完整代码
class Solution {
public int maxmiumScore(int[] cards, int cnt) {
Arrays.sort(cards);
int sum = 0;
int min0 = Integer.MAX_VALUE, min1 = Integer.MAX_VALUE;
for (int i = cards.length - 1; i >= cards.length - cnt; i--) {
sum += cards[i];
if (cards[i] % 2 == 0) {
min0 = Math.min(min0, cards[i]);
} else {
min1 = Math.min(min1, cards[i]);
}
}
if (sum % 2 == 0) {
return sum;
}
int max0 = Integer.MIN_VALUE, max1 = Integer.MIN_VALUE;
for (int i = cards.length - cnt - 1; i >= 0; i--) {
if (max0 != Integer.MIN_VALUE && max1 != Integer.MIN_VALUE) {
break;
}
if (cards[i] % 2 == 0) {
max0 = Math.max(max0, cards[i]);
} else {
max1 = Math.max(max1, cards[i]);
}
}
int result = Integer.MIN_VALUE;
if (min0 != Integer.MAX_VALUE && max1 != Integer.MIN_VALUE) {
result = Math.max(result, sum - min0 + max1);
}
if (min1 != Integer.MAX_VALUE && max0 != Integer.MIN_VALUE) {
result = Math.max(result, sum - min1 + max0);
}
return result == Integer.MIN_VALUE ? 0 : result;
}
}
- 时间复杂度:
O(nlogn)
- 空间复杂度:
O(1)