1. 题目来源
链接:LCP 40. 心算挑战
2. 题目解析
挺有意思的一道分类讨论题目。如果纯是分类讨论的话,细节比较多,讨论清楚进行代码实现即可。
看到有一个前缀和解法的,也比较有意思。奇偶完全分类讨论,一直枚举偶数个奇数,保证结果是 偶数个奇数+偶数,用前缀和 O(1) 算出其和。挺不错的思路
见:
官方题解写了有哈希啥的,暂时没想看,跟题目给出的值域有关,通过哈希的方式,避免了排序,将时间复杂度做到了 O(n),但感觉在这没太大必要,有兴趣去研究下吧。
- 时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
- 空间复杂度: O ( 1 ) O(1) O(1)
class Solution {
public:
int maxmiumScore(vector<int>& cards, int cnt) {
int n = cards.size();
sort(cards.begin(), cards.end());
int i = n - 1;
int res = 0;
for (int j = 0; j < cnt; j ++ , i -- ) res += cards[i]; // 先统计最大的 cnt 个
if ((res & 1) == 0) return res; // 如果是偶数的话,直接返回
// 统计前段的最大奇数、最大偶数
// 替换逻辑是:
// 找到后端最小的偶数,将它替换成前段的最大的奇数
// 或者 找到后端最小的奇数,将它替换成前段的最大的偶数
int ou = -1, ji = -1;
for (int j = i; j >= 0; j -- ) {
if (cards[j] & 1) ji = max(ji, cards[j]);
else ou = max(ou, cards[j]);
}
int tou = -1, tji = -1;
if (ou != -1) {
// 去掉一个奇数,用前段最大偶数替换
for (int j = i + 1; j < n; j ++ )
if (cards[j] & 1) {
tou = res - cards[j] + ou;
break;
}
}
if (ji != -1) {
// 去掉一个偶数,用前段最大奇数替换
for (int j = i + 1; j < n; j ++ )
if ((cards[j] & 1) == 0) {
tji = res - cards[j] + ji;
break;
}
}
// 如果没有执行替换逻辑,说明两个策略都没有满足执行条件,结果无法变成偶数,返回 0
if (tou == -1 && tji == -1) return 0;
// 执行替换逻辑,直接取 max 返回即可
return max(tou, tji);
}
};