Two-Letter Card Game
Two-Letter Card Game
You are given a deck of cards represented by a string array cards
, and each card displays two lowercase letters.
You are also given a letter x
. You play a game with the following rules:
- Start with 0 points.
- On each turn, you must find two compatible cards from the deck that both contain the letter
x
in any position. - Remove the pair of cards and earn 1 point.
- The game ends when you can no longer find a pair of compatible cards.
Return the maximum number of points you can gain with optimal play.
Two cards are compatible if the strings differ in exactly 1 position.
Example 1:
Input: cards = ["aa","ab","ba","ac"], x = "a"
Output: 2
Explanation:
- On the first turn, select and remove cards
"ab"
and"ac"
, which are compatible because they differ at only index 1. - On the second turn, select and remove cards
"aa"
and"ba"
, which are compatible because they differ at only index 0.
Because there are no more compatible pairs, the total score is 2.
Example 2:
Input: cards = ["aa","ab","ba"], x = "a"
Output: 1
Explanation:
- On the first turn, select and remove cards
"aa"
and"ba"
.
Because there are no more compatible pairs, the total score is 1.
Example 3:
Input: cards = ["aa","ab","ba","ac"], x = "b"
Output: 0
Explanation:
The only cards that contain the character 'b'
are "ab"
and "ba"
. However, they differ in both indices, so they are not compatible. Thus, the output is 0.
Constraints:
2 <= cards.length <= 105
cards[i].length == 2
- Each
cards[i]
is composed of only lowercase English letters between'a'
and'j'
. x
is a lowercase English letter between'a'
and'j'
.
解题思路
这周末打的 atc 和两场 lc 都莫名其妙爆 0 了,不知道为什么做题一点思路都没有。也许是因为最近心情不好导致整个人变傻了,不过最近不愉快的事情确实有点多就是了。一眨眼都 9 月,时间过得真快啊。
这题的做法也是经典中的经典了,不过最逆天的是每次我遇到这类题都想不到这个结论。比如 A. Cards Partition,小L的位运算,甚至是上周的题 Partition Array Into K-Distinct Groups。这些问题抽象出来都是,给定 $n$ 个元素,每次从中选出 $m$ 个互不相同的元素,问是否能将所有元素选完。对应的结论为,首先需要满足 $m \mid n$。其次,如果某个元素的出现次数最大,并且该次数大于 $\tfrac{n}{m}$,则无解;否则有解。
回到这题,由于每张牌必须包含字符 $x$,意味着符合要求的牌要么是 $i \, x$ 的形式,要么是 $x \, i$ 的形式,其中 $i \in \{ \text{'a'},\text{'b'},\ldots,\text{'j'} \}$。同时,由于只有在恰好一个位置上的字符相同的两张牌才兼容,因此每次要么在 $i \, x$ 或 $x \, i$ 同一形式的牌中选择两张 $i$ 不同的牌,要么一张在 $i \, x$ 形式的牌中选(且 $i \ne x$)另一张在 $x \, i$ 形式的牌中选 $x \, x$(同理 $x \, i$ 的情况)。
为了简单假设我们现在不考虑 $x \, x$ 的牌,此时问题就被限定为只能从同一形式的牌中选择两张不同的牌。这就是上面提到的经典结论了,不过本题要求的是最多能选多少次,而不是是否存在合法的选择。一样的,如果出现次数最多的元素的出现次数为 $c$,那么如果 $c \leq \left\lfloor \tfrac{n}{m} \right\rfloor$,则对多能选的次数就是 $\left\lfloor \tfrac{n}{m} \right\rfloor$,否则最能选择的次数是 $n - c$。本题中 $m = 2$,$n$ 就是 $i \, x$ 或 $x \, i$ 形式的牌的数量。
再把 $x \, x$ 的牌考虑进来,一个简单的做法就是枚举将多少张 $x \, x$ 的牌归为 $i \, x$ 形式的牌,剩下的则归为 $x \, i$ 形式的牌,这样可以保证了每次都是在同一形式的牌中选择,然后就可以使用上述的方法来计算答案。在枚举的过程中为了能快速求解答案,需要维护每一类型的牌的总数,以及最大的出现次数。
AC 代码如下,时间复杂度为 $O(n)$:
class Solution {
public:
int score(vector<string>& cards, char x) {
array<array<int, 10>, 10> c({});
for (auto &s : cards) {
c[s[0] - 'a'][s[1] - 'a']++;
}
array<array<int, 2>, 2> p({});
for (int i = 0; i < 10; i++) {
if (i == x - 'a') continue;
p[0][0] += c[x - 'a'][i];
p[0][1] = max(p[0][1], c[x - 'a'][i]);
p[1][0] += c[i][x - 'a'];
p[1][1] = max(p[1][1], c[i][x - 'a']);
}
int ret = 0;
for (int i = 0; i <= c[x - 'a'][x - 'a']; i++) {
auto get = [&](int a, int b) {
if (2 * b > a) return a - b;
return a >> 1;
};
int j = c[x - 'a'][x - 'a'] - i;
ret = max(ret, get(p[0][0] + i, max(p[0][1], i)) + get(p[1][0] + j, max(p[1][1], j)));
}
return ret;
}
};
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/19067514