Tips:
LCP“力扣杯”的题目,难度比正常题库题高一个级别,这道题算是中等题。
题目:
题目解读:
题目意思简单,就是在n张卡牌中找cnt张卡牌的数值总和最大值,且该最大值为偶数。
思路:
1.
第一眼看到这道题就想暴力枚举来解决,但是看到提示:1 <= cnt <= cards.length <= 10^5
可知数据量达到10的5次方,可知暴力枚举不可行。
2.
我按照我们老师提供的思路以及我根据这个思路写的c++代码进行思路解析:
首先将数组排序,取最大的cnt个求和,如果为偶数,则可以直接返回。如果为奇数的话则先找出已选卡牌的最小奇数牌和最小偶数牌(存在的话),再找出未选卡牌的最大奇数牌和最大偶数牌(存在的话)。之后就可以进行替换了,找到最小偶数(已选)的话就替换最大奇数(未选),找到最小奇数(已选)的话就替换最大偶数(未选)。替换之后更新他们的和,然后返回更新后的和即可。
这里我对我们老师的思路进行了一个通俗化的讲解,接下来展示代码。
代码:
class Solution {
public:
int maximumScore(vector<int>& cards, int cnt) {
//排序
sort(cards.begin(),cards.end());
// 取最大的 cnt 个数进行求和
int sum=0;
for(int i=cards.size()-cnt;i<cards.size();i++)
{
sum+=cards[i];
}
//如果和是偶数,直接返回
if (sum%2==0)
{
return sum;
}
//如果不是则进行以下操作
int minOddSelected = INT_MAX, minEvenSelected = INT_MAX;//已选卡牌的最小奇数和最小偶数
int maxOddUnselected = INT_MIN, maxEvenUnselected = INT_MIN;//未选卡牌的最大奇数和最大偶数
//遍历已选的 cnt 个卡牌
for(int i=cards.size()-cnt;i<cards.size();i++)
{
if (cards[i]%2==0)
{
minEvenSelected = min(minEvenSelected, cards[i]);
}
else
{
minOddSelected = min(minOddSelected, cards[i]);
}
}
//遍历未选的卡牌
for (int i=0;i<cards.size()-cnt;i++)
{
if (cards[i]%2==0)
{
maxEvenUnselected = max(maxEvenUnselected, cards[i]);
}
else
{
maxOddUnselected = max(maxOddUnselected, cards[i]);
}
}
//初始化 bestSum 为 0
int bestSum = 0;
// 替换方案1: 替换最小偶数 (已选) 为 最大奇数 (未选)
if (minEvenSelected != INT_MAX && maxOddUnselected != INT_MIN)
{
int newSum = sum - minEvenSelected + maxOddUnselected;
if (newSum % 2 == 0)
{
bestSum = max(bestSum, newSum);
}
}
// 替换方案2: 替换最小奇数 (已选) 为 最大偶数 (未选)
if (minOddSelected != INT_MAX && maxEvenUnselected != INT_MIN)
{
int newSum = sum - minOddSelected + maxEvenUnselected;
if (newSum % 2 == 0)
{
bestSum = max(bestSum, newSum);
}
}
return bestSum;
}
};
代码按照思路写的比较通俗易懂了。
注:
初始化bestsum为0那里,一开始写的初始化bestsum为sum,但是只通过了一部分用例。
如果我们初始化bestsum为sum,那么如果原始的sum不是偶数,我们会错误地将其作为潜在的最佳和,这会导致错误的结果。
初始化bestsum为0是一种更安全的方法,因为这样1.可以确保我们始终能找到一个有效的偶数和,即使所有可能的替换操作都没有提供更大的偶数和。2.可以确保在没有任何有效的偶数和时,bestsum也不会比实际找到的和更小。