第419 场周赛

-
-
2024-10-14

第419 场周赛

RANK297

A:✅ B:✅ C:✅ T4:❌

A. 计算子数组的 x-sum I

思路:数据范围小,按照题意直接模拟。

时间复杂度:O(n^2 * logK)

public int[] findXSum(int[] nums, int k, int x) {
        int n = nums.length;
        int[] res = new int[n-k+1];
        for (int i = 0; i < n; i++) {
            var cnt = new HashMap<Integer, Integer>();
            int sum = 0;
            for (int j = i; j < n; j++) {
                cnt.merge(nums[j], 1, Integer::sum);
                sum += nums[j];
                if (j - i + 1 == k) {
                    int v = 0;
                    List<int[]> list = new ArrayList<>();
                    for (var e : cnt.entrySet()) {
                        list.add(new int[]{e.getValue(), e.getKey()});
                    }
                    list.sort((a, b) -> b[0] == a[0] ? b[1] - a[1] : b[0] - a[0]);
                    if (list.size() < x) {
                        res[i] = sum;
                    } else {
                        for (int l = 0; l < x; l++) {
                            v += list.get(l)[0] * list.get(l)[1];
                        }
                        res[i] = v;
                    }
                    break;
                }
            }
        }
        return res;
    }

B. 第 K 大的完美二叉子树的大小

思路:DFS后序遍历树,返回left和right的信息来更新root的信息,并记录到一个list里面,最后排序返回k-1即可。

算法标签:DFS、排序。

时间复杂度:O(NLogN)

 List<int[]> tset = new ArrayList<>();

    public int kthLargestPerfectSubtree(TreeNode root, int k) {
        dfs(root);
        if (tset.size() < k) {
            return -1;
        }
        List<int[]> list = new ArrayList<>();
        list.addAll(tset);
        list.sort((a, b) -> b[0] - a[0]);
        return list.get(k - 1)[0];
    }



    boolean dfs(TreeNode root) {
        if (root == null) return true;

        boolean ok1 = dfs(root.left);
        boolean ok2 = dfs(root.right);


        int v1 = root.left != null ? root.left.val : 0;
        int v2 = root.right != null ? root.right.val : 0;
        if (ok1 && ok2 && v1 == v2) {
            tset.add(new int[]{v1 + v2 + 1, root.val});
            root.val = v1 + v2 + 1;
            return true;
        } else {
            root.val = 0;
            return false;
        }
    }

C. 统计能获胜的出招序列数

思路:动态规划,定义dp[i][v][pre]表示前i个比赛,Bob获得分数差为v,并且Bob i-1场出牌为pre的出招序列数。然后就按照题意if-else模拟,注意这个分差可能为负数(Alice一直赢的情况),我们需要将v加一个OFFSET来防止越界,最后判断下分差v如果大于0,则说明是一种合法的出牌序列。

算法标签:动态规划。

时间复杂度:O(N*2)

int[][][] dp;
    static final int MOD = (int) (1e9 + 7);
    int OFFSET = 0;
    char[] a;

    public int countWinningSequences(String s) {
        int n = s.length();
        a = s.toCharArray();
        OFFSET = n + 1;
        int m = 'W'-'A';
        dp = new int[n][n+OFFSET][m+1];
        for (int[][] arr : dp) {
            for (int[] row : arr) {
                Arrays.fill(row, -1);
            }
        }
        return dfs(0, 0, 'A');
    }

    public int dfs(int i, int v, char prev) {
        if (i >= a.length) return v > 0 ? 1 : 0;
        if (dp[i][v+OFFSET][prev-'A'] != -1) return dp[i][v+OFFSET][prev-'A'];
        int ret = 0;
        if (a[i] == 'F') {
            if (prev != 'E')  ret += dfs(i + 1, v - 1, 'E');  ret %= MOD;
            if (prev != 'F') ret += dfs(i + 1, v, 'F');           ret %= MOD;
            if (prev != 'W') ret += dfs(i + 1, v + 1, 'W');   ret %= MOD;
        } else if (a[i] == 'W') {
            if (prev != 'F') ret += dfs(i + 1, v - 1, 'F');    ret %= MOD;
            if (prev != 'W') ret += dfs(i + 1, v, 'W');            ret %= MOD;
            if (prev != 'E') ret += dfs(i + 1, v + 1, 'E');    ret %= MOD;
        } else {
            if (prev != 'W') ret += dfs(i + 1, v - 1, 'W');     ret %= MOD;
            if (prev != 'E') ret += dfs(i + 1, v, 'E');             ret %= MOD;
            if (prev != 'F') ret += dfs(i + 1, v + 1, 'F');     ret %= MOD;
        }
        dp[i][v+OFFSET][prev-'A'] = ret;
        return ret;
    }

D. 计算子数组的 x-sum II

思路:两个有序集合维护前k大元素。具体看b站灵神视频讲解

算法标签:滑动窗口、有序集合。

时间复杂度:O(NLogN)

TreeSet<int[]> L = new TreeSet<>((a, b) -> a[0] != b[0] ? a[0] - b[0] : a[1] - b[1]); // 维护出现次数前x大
    TreeSet<int[]> R = new TreeSet<>(L.comparator());
    Map<Integer, Integer> cnt = new HashMap<>();
    long sumL = 0;

    public long[] findXSum(int[] nums, int k, int x) {
        int n = nums.length;
        long[] ans = new long[n - k + 1];
        for (int r = 0; r < nums.length; r++) {
            // 入
            int in = nums[r];
            del(in);
            cnt.merge(in, 1, Integer::sum);
            add(in);

            int l = r + 1 - k;
            if (l < 0) continue;

            while (!R.isEmpty() && L.size() < x) r2l();
            while (L.size() > x) l2r();
            ans[l] = sumL;
            // 出
            int out = nums[l];
            del(out);
            cnt.merge(out, -1, Integer::sum);
            add(out);
        }
        return ans;
    }

    void add(int val) {
        int c = cnt.getOrDefault(val, 0);
        if (c == 0) return;
        int[] p = new int[]{c, val};
        if (!L.isEmpty() && L.comparator().compare(p, L.first()) > 0) {
            sumL += (long) p[0] * p[1];
            L.add(p);
        } else {
            R.add(p);
        }
    }

    void del(int val) {
        int c = cnt.getOrDefault(val, 0);
        if (c == 0) return;
        int[] p = new int[]{c, val};
        if (L.contains(p)) {
            sumL -= (long) p[0] * p[1];
            L.remove(p);
        } else {
            R.remove(p);
        }
    }

    void l2r() {
        int[] p = L.pollFirst();
        sumL -= (long) p[0] * p[1];
        R.add(p);
    }

    void r2l() {
        int[] p = R.pollLast();
        sumL += (long) p[0] * p[1];
        L.add(p);
    }

梅狸猫
meilicat
公告

随便看看就好~