一,2839. 判断通过操作能否让字符串相等 I
该题的题意就是看 单数下标 和 偶数下标的 s1 和 s2 中的字母及其数量是否相等。
代码如下(也可以使用哈希表来做):
class Solution {
public boolean canBeEqual(String s1, String s2) {
int[] a = new int[26];//统计偶数下标
int[] b = new int[26];//统计奇数下标
for(int i=0; i<s1.length(); i+=2){
a[s1.charAt(i)-'a']++;
a[s2.charAt(i)-'a']--;
if(i+1 < s1.length()){
b[s1.charAt(i+1)-'a']++;
b[s2.charAt(i+1)-'a']--;
}
}
for(int i=0; i<26; i++){
if(a[i]!=0 || b[i]!=0)
return false;
}
return true;
}
}
二,2840. 判断通过操作能否让字符串相等 II
这题和上面那题是一个意思,直接复用上面的代码就行,改都不用改,这里就不在写了。
三,2841. 几乎唯一子数组的最大和
该题一看就是一道滑动窗口的题目,要找的是长度为 k 的子数组并且子数组中有 >= m 个不同的值,求满足上述条件的子数组中,最大子数组和。
代码如下:
class Solution {
public long maxSum(List<Integer> nums, int m, int k) {
long ans = 0;
long cur = 0;
Map<Integer,Integer> map = new HashMap<>();
for(int i=0; i<nums.size(); i++){
cur += nums.get(i);
map.put(nums.get(i),map.getOrDefault(nums.get(i),0)+1);
if(i >= k-1){//子数组长度已满
if(map.size() >= m){
ans = Math.max(ans,cur);
}
int out = i - k + 1;//要滑出去的下标
int val = map.get(nums.get(out));
if(val == 1){
map.remove(nums.get(out));
}else{
map.put(nums.get(out),val-1);
}
cur -= nums.get(out);
}
}
return ans;
}
}
四,2842. 统计一个字符串的 k 子序列美丽值最大的数目
这道题题目很长,我们先举几个例子来理解一下:
1. k = 1,s = "aabbbc"
ans = 3
2. k = 1,s = "aaabbb"
ans = 3^k*C(2,k) = 6
3. k = 2, s = "aaabbb"
ans = 2*3 = 6
//乘法原理
4. k = 2, s = "aaabbbccc"
ans = 3^k*C(3,k)
//C(3,k)实际就是从a,b,c中选两个有多少选法,就是数学中的排列组合
5. k = 4, s = "aabbbccdd"
先选择b,ans = 3,k -= 1
然后变成 k = 3,s = "aaccdd"
ans = ans * 2^3 * C(3,3)
根据上面举的例子可知,我们需要知道:
1. 每个字母的出现次数
2. 出现次数相同的字母个数
3. 按照出现次数从大到小枚举
class Solution {
private static final long MOD = (long) 1e9 + 7;
/**
TreeMap中存储是有顺序的!!!
TreeMap使用Map.entrySet()是从小到大输出的!!!
HashMap使用Map.entrySet()是随机输出的!!!
*/
public int countKSubsequencesWithMaxBeauty(String s, int k) {
int[] cnt = new int[26];
for(int i=0; i<s.length(); i++){
cnt[s.charAt(i)-'a']++;//统计每个字母的出现次数
}
Map<Integer,Integer> map = new TreeMap<>();
for(int x : cnt){
if(x > 0)//TreeMap是从小到大存储数据,我们要从大到小枚举,因此存-x,取-x
map.put(-x,map.getOrDefault(-x,0)+1);
}
//aaabbbcccddd
//<3,4>
//<出现次数,出现次数相同的字母有几个>
long ans = 1;
for(Map.Entry<Integer,Integer> entry : map.entrySet()){
int key = -entry.getKey();//出现次数
int value = entry.getValue();//出现次数相同的字母有几个
if(value >= k)
return (int)(ans*pow(key,k)%MOD*comb(value,k)%MOD);//key^k*C(value,k)
ans = ans*pow(key,value)%MOD;
k -= value;
}
return 0;
}
long pow(long x, int n){//快速幂算法 x^n
long res = 1;
while(n != 0){
if(n%2 != 0){
res = res*x%MOD;
}
x = x*x%MOD;
n/=2;
}
return res;
}
long comb(long n, int k){//数学中的组合排序算法 C(n,k)
long res = n;
for(int i=2; i<=k; i++){
res = res*(--n)/i;
}
return res%MOD;
}
}