跳至主要內容

力扣第 85 场双周赛

大约 3 分钟

力扣第 85 场双周赛

比赛时间 2022-08-20。本场周赛国服共 571 人 AK。

T1. 得到 K 个黑块的最少涂色次数(3 分)

解题思路

前缀和 + 贪心。

时间复杂度:O(n)

参考代码

class Solution {
    public int minimumRecolors(String blocks, int k) {
        int len = blocks.length();

        // 预处理
        int[] nums = new int[len];
        for (int i = 0; i < len; i++) {
            if (blocks.charAt(i) == 'B') {
                nums[i] = 1;
            }
        }
        // 前缀和
        int[] preSum = new int[len + 1];
        for (int i = 0; i < len; i++) {
            preSum[i + 1] = preSum[i] + nums[i];
        }

        // 贪心
        int max = 0;
        for (int i = k - 1; i < len; i++) {
            max = Math.max(max, preSum[i + 1] - preSum[i + 1 - k]);
        }
        return k - max;
    }
}

T2. 二进制字符串重新安排顺序需要的时间(4 分)

解题思路

观察到数据范围较小,暴力模拟。

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

(本题另有线性时间复杂度的解法。

参考代码

class Solution {
    public int secondsToRemoveOccurrences(String s) {
        int cnt = 0;
        while (s.contains("01")) {
            s = s.replace("01", "10");
            cnt++;
        }
        return cnt;
    }
}

T3. 字母移位 II(5 分)

解题思路

差分模拟。在原数组 [i, j] 内加上 inc,等价于在差分数组 diff[i] += inc; diff[j + 1] -= inc;

时间复杂度:O(n)

参考代码

class Solution {
    public String shiftingLetters(String s, int[][] shifts) {
        int len = s.length();

        // 差分
        int[] diff = new int[len + 1];
        for (int[] shift : shifts) {
            int i = shift[0];
            int j = shift[1];
            int inc = shift[2] == 0 ? -1 : 1;

            diff[i] += inc;
            diff[j + 1] -= inc;
        }
        // 原数组
        int[] res = new int[len];
        res[0] = diff[0];
        for (int i = 1; i < len; i++) {
            res[i] = res[i - 1] + diff[i];
        }

        char[] chars = s.toCharArray();
        for (int i = 0; i < len; i++) {
            chars[i] = (char) ((((chars[i] - 'a') + res[i]) % 26 + 26) % 26 + 'a');
        }
        return new String(chars);
    }
}

T4. 删除操作后的最大子段和(6 分)

解题思路

比赛时候没想到并查集的做法(在春季赛跌倒的地方(LCP 52. 二叉搜索树染色)又跌倒了一次),套了个最大字段和线段树模板(CF1962H 的简化版)。

时间复杂度:O(nlogn)

参考代码

class Solution6159 {
    private static final long INF = 100000L * 1000000000L + 10L;

    public long[] maximumSegmentSum(int[] nums, int[] removeQueries) {
        SegmentTree segmentTree = new SegmentTree(nums.length);
        for (int i = 0; i < nums.length; i++) {
            segmentTree.modify(i + 1, nums[i]);
        }

        int len = removeQueries.length;
        long[] res = new long[len];
        for (int i = 0; i < len - 1; i++) {
            segmentTree.modify(removeQueries[i] + 1, -INF);
            res[i] = segmentTree.query().maxSum;
        }
        return res;
    }

    private static class SegmentTree {
        private static class Node {
            // lSum 表示 [l,r] 内以 l 为左端点的最大子段和
            long lSum;
            // rSum 表示 [l,r] 内以 r 为右端点的最大子段和
            long rSum;
            // maxSum 表示 [l,r] 内的最大子段和
            long maxSum;
            // itSum 表示 [l,r] 的区间和
            long itSum;

            public Node(long lSum, long rSum, long maxSum, long itSum) {
                this.lSum = lSum;
                this.rSum = rSum;
                this.maxSum = maxSum;
                this.itSum = itSum;
            }
        }

        private final int N;
        private final Node[] tree;

        public SegmentTree(int n) {
            N = n;
            tree = new Node[4 * N];
            for (int i = 0; i < 4 * N; i++) {
                tree[i] = new Node(0, 0, 0, 0);
            }
            build(1, N, 1);
        }

        private void build(int s, int t, int p) {
            if (s == t) {
                tree[p].lSum = -1;
                tree[p].rSum = -1;
                tree[p].maxSum = -1;
                tree[p].itSum = -1;
                return;
            }
            int mid = s + (t - s) / 2;
            build(s, mid, p * 2);
            build(mid + 1, t, p * 2 + 1);
            tree[p] = pushUp(tree[p * 2], tree[p * 2 + 1]);
        }

        private Node pushUp(Node a, Node b) {
            long lSum = Math.max(a.lSum, a.itSum + b.lSum);
            long rSum = Math.max(b.rSum, b.itSum + a.rSum);
            long maxSum = Math.max(Math.max(a.maxSum, b.maxSum), a.rSum + b.lSum);
            long itSum = a.itSum + b.itSum;
            return new Node(lSum, rSum, maxSum, itSum);
        }

        private void modify(int s, int t, int p, int pos, long val) {
            if (s > pos || t < pos) {
                return;
            }
            if (s == pos && t == pos) {
                tree[p].lSum = val;
                tree[p].rSum = val;
                tree[p].maxSum = val;
                tree[p].itSum = val;
                return;
            }
            int mid = s + (t - s) / 2;
            modify(s, mid, p * 2, pos, val);
            modify(mid + 1, t, p * 2 + 1, pos, val);
            tree[p] = pushUp(tree[p * 2], tree[p * 2 + 1]);
        }

        private Node query(int s, int t, int p, int l, int r) {
            if (s > r || t < l) {
                return new Node(0, 0, 0, 0);
            }
            if (s >= l && t <= r) {
                return tree[p];
            }
            int mid = s + (t - s) / 2;
            Node lSub = query(s, mid, p * 2, l, r);
            Node rSub = query(mid + 1, t, p * 2 + 1, l, r);
            return pushUp(lSub, rSub);
        }

        private void modify(int pos, long val) {
            modify(1, N, 1, pos, val);
        }

        private Node query() {
            return query(1, N, 1, 1, N);
        }
    }
}

(全文完)