Leetcode - 112双周赛

一,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;
    }
}
相关推荐
Rain的Java大神之路1 小时前
LeetCode 37 解数独面试攻略:回溯 + 位掩码 + MRV,从暴力到毫秒级求解
java·后端·leetcode
NEFU_Jyj1 小时前
贝尔数(组合数学)
算法
希和20272 小时前
C语言程序设计题|有序数组插入数字冒泡排序
c语言·数据结构·算法
Pniubi2 小时前
力扣73 矩阵置零
算法·leetcode·矩阵
布莱克60512 小时前
C++ 中 map 的 insert 与 emplace:key 已存在时会覆盖吗?
开发语言·数据结构·c++·算法·map
D e re k ZH15 小时前
C++ 系统学习手记:从语法细节到工程实践
开发语言·数据结构·c++·算法
石小石Orz16 小时前
AI 正在蚕食我们的编码能力
前端·后端·算法
民乐团扒谱机18 小时前
【微实验】NSGA-II(非支配排序遗传算法)——解决多目标优化问题的“自然选择模拟器”
linux·人工智能·算法
青少儿编程课堂18 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:中缀表达式求值解析
c++·python·算法·bfs·信息学竞赛