Leetcode - 周赛431

发布于:2025-02-10 ⋅ 阅读:(30) ⋅ 点赞:(0)

目录

一,3411. 最长乘积等价子数组

二,3412. 计算字符串的镜像分数

三,3413. 收集连续 K 个袋子可以获得的最多硬币数量

四,3414. 不重叠区间的最大得分


一,3411. 最长乘积等价子数组

本题数据范围小,直接暴力枚举,代码如下:

class Solution {
    public int maxLength(int[] nums) {
        int n = nums.length;
        int ans = 0;
        for(int l=0; l<n; l++){
            for(int r=l; r<n; r++){
                int p = 1, g = 0, lc = 1;
                for(int i=l; i<=r; i++){
                    p *= nums[i];
                    g = gcd(nums[i], g);
                    lc = lcm(nums[i], lc);
                }
                if(p == g * lc) ans = Math.max(ans, r-l+1);
            }
        }
        return ans;
    }
    int gcd(int a, int b){
        return b==0?a:gcd(b,a%b);
    }
    int lcm(int a, int b){
        return a*b/gcd(a,b);
    }
}

二,3412. 计算字符串的镜像分数

本题就是要存储26个字母的出现的所有下标,对于 s[i] 来说,需要找到相应镜像的字母 c,然后返回字母 c 最近的下标,也就是说,需要一个先进后出的数据结构——栈来存储 26 个字母的下标,代码如下:

class Solution {
    public long calculateScore(String s) {
        Stack<Integer>[] st = new Stack[26];
        Arrays.setAll(st, e->new Stack<>());
        long ans = 0;
        for(int i=0; i<s.length(); i++){
            int c = s.charAt(i) - 'a';
            if(!st[25-c].isEmpty()){
                ans += i - st[25-c].pop();
            }else{
                st[c].push(i);
            }
        }
        return ans;
    }
}

三,3413. 收集连续 K 个袋子可以获得的最多硬币数量

本题求连续 k 个袋子可获得的最多硬币数量,就是维护一个长度为 k 的滑动窗口,关键的问题就变成了如何维护窗口的更新(进/出),求最多,贪心的想对于一个区间 [L,R],需要尽可能多的包含这个区间,那么有两种情况——以 L 为左端点,向右维护一个长为 k 的窗口;以 R 为右端点,向左维护一个长为 k 的窗口。需要分别求出上述两种情况,取最大值。

这里写以 L 为左端点,向右维护一个长为 k 的窗口的维护方法,另一种可以通过镜像的方式,复用此代码。如图所示:

代码如下:

class Solution {
    long window(int[][] f, int k){
        int n = f.length;
        long ans = 0;
        long cover = 0, uncover = 0;
        for(int i=0, j=0; i<n; i++){
            long l = f[i][0], r = f[i][1], c = f[i][2];
            cover += (r - l + 1) * c;
            while(f[j][1] < r - k + 1){
                cover -= (long)(f[j][1] - f[j][0] + 1) * f[j][2];
                j++;
            }
            uncover = Math.max((long)(r - k + 1 - f[j][0]) * f[j][2], 0) ;
            ans = Math.max(ans, cover - uncover);
        }
        return ans;
    }
    public long maximumCoins(int[][] coins, int k) {
        Arrays.sort(coins, (x, y) -> x[0] - y[0]);
        long ans = window(coins, k);
        for(int[] c : coins){
            int t = -c[0];
            c[0] = -c[1];
            c[1] = t;
        }
        int n = coins.length;
        for(int i=0; i<n/2; i++){
            int[] t = coins[i];
            coins[i] = coins[n-1-i];
            coins[n-1-i] = t;
        }
        return Math.max(ans, window(coins, k));
    }
}

四,3414. 不重叠区间的最大得分

定义f[i][j]: 在前 i 个区间选出 j 个不重叠区间的最大得分和此时字典序最小的区间下标顺序。标准的0-1背包做法,难点在于维护字典序最小的区间下标顺序。

代码如下:

class Solution {
    private record Tuple(long w, List<Integer> id){}
    private record Info(int l, int r, int w, int i){}
    public int[] maximumWeight(List<List<Integer>> intervals) {
        int n = intervals.size();
        Info[] t = new Info[n];
        for(int i=0; i<n; i++){
            List<Integer> x = intervals.get(i);
            int l = x.get(0), r = x.get(1), w = x.get(2);
            t[i] = new Info(l, r, w, i);
        }
        Arrays.sort(t, (x, y) -> x.r - y.r);

        Tuple[][] f = new Tuple[n+1][5];
        Arrays.setAll(f[0], e->new Tuple(0, new ArrayList<>()));

        for(int i=0; i<n; i++){
            int l = t[i].l, r = t[i].r, w = t[i].w;
            int k = search(t, l-1, i);
            f[i+1][0] = new Tuple(0, new ArrayList<>());
            for(int j=1; j<5; j++){
                long s1 = f[i][j].w;
                long s2 = f[k+1][j-1].w + w;
                if(s1 > s2){
                    f[i+1][j] = f[i][j];
                    continue;
                }
                List<Integer> tmp = new ArrayList<>(f[k+1][j-1].id);
                tmp.add(t[i].i);
                Collections.sort(tmp);
                if(s1 == s2 && compareLists(tmp, f[i][j].id) > 0){
                    tmp = f[i][j].id;
                }
                f[i+1][j] = new Tuple(s2, tmp);
            }
        }
        return f[n][4].id.stream().mapToInt(v->v).toArray();
    }
    int compareLists(List<Integer> a, List<Integer> b){
        for(int i=0; i<Math.min(a.size(), b.size()); i++){
            if(!a.get(i).equals(b.get(i)))
                return a.get(i) - b.get(i);
        }
        return a.size() - b.size();
    }
    int search(Info[] t, int k, int r){
        int l = 0;
        while(l <= r){
            int mid = (l + r) >>> 1;
            if(t[mid].r <= k){
                l = mid + 1;
            }else{
                r = mid - 1;
            }
        }
        return l - 1;
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到