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;
    }
}

猜你喜欢

转载自blog.csdn.net/m0_74859835/article/details/132716313