跳至主要內容

力扣第 400 场周赛

大约 3 分钟

力扣第 400 场周赛

比赛时间 2024-06-02。本场周赛国服共 627 人 AK。

其实 咱们只要足够努力,机会就一直会在 不是的,我努力过无数次了,但我知道,机会只会出现在 这其中的一两次。

——《飞驰人生 2》

T1. 候诊室中的最少椅子数(3 分)

解题思路

遍历,将 E 看成 1,将 L 看成 -1,和取最大值即可。

时间复杂度:O(n)

参考代码

class Solution {
    public int minimumChairs(String s) {
        int ans = 0, sum = 0;
        for (char c : s.toCharArray()) {
            if (c == 'E') sum++;
            else sum--;
            ans = Math.max(ans, sum);
        }
        return ans;
    }
}

T2. 无需开会的工作日(4 分)

解题思路

合并区间后,再统计即可。

赛时想用差分解决,但并不顺利,用动态开点线段树水过。。

时间复杂度:O(nlogn)

参考代码

class Solution {
    public int countDays(int days, int[][] meetings) {
        DynamicSegTreeUpd_sum seg = new DynamicSegTreeUpd_sum();
        for (int[] p : meetings) {
            int st = p[0], end = p[1];
            seg.update(st, end, 1);
        }
        return (int) (days - seg.getSum(1, days));
    }

    static class DynamicSegTreeUpd_sum {
        static final int N = Integer.MAX_VALUE;
        final Node root = new Node();

        private static class Node {
            Node ls, rs;
            long sum, lazy;
        }

        void update(int ql, int qr, int val) {
            this.update(root, 0, N, ql, qr, val);
        }

        void update(Node p, int l, int r, int ql, int qr, int val) {
            if (ql <= l && r <= qr) {
                p.sum = (r - l + 1L) * val;
                p.lazy = val;
                return;
            }
            pushDown(p, l, r);
            int mid = l + (r - l) / 2;
            if (ql <= mid) update(p.ls, l, mid, ql, qr, val);
            if (qr > mid) update(p.rs, mid + 1, r, ql, qr, val);
            pushUp(p);
        }

        long getSum(int ql, int qr) {
            return this.getSum(root, 0, N, ql, qr);
        }

        long getSum(Node p, int l, int r, int ql, int qr) {
            if (ql <= l && r <= qr) {
                return p.sum;
            }
            pushDown(p, l, r);
            int mid = l + (r - l) / 2;
            long sum = 0;
            if (ql <= mid) sum = getSum(p.ls, l, mid, ql, qr);
            if (qr > mid) sum += getSum(p.rs, mid + 1, r, ql, qr);
            return sum;
        }

        void pushDown(Node p, int l, int r) {
            if (p.ls == null) p.ls = new Node();
            if (p.rs == null) p.rs = new Node();
            if (p.lazy != 0) {
                int mid = l + (r - l) / 2;
                p.ls.sum = p.lazy * (mid - l + 1L);
                p.rs.sum = p.lazy * (r - mid);
                p.ls.lazy = p.lazy;
                p.rs.lazy = p.lazy;
                p.lazy = 0;
            }
        }

        void pushUp(Node p) {
            p.sum = p.ls.sum + p.rs.sum;
        }
    }
}

T3. 删除星号以后字典序最小的字符串(5 分)

解题思路

贪心。想明白有多个字典序最小的字符时,要使字典序最小,删下标最大的字符即可。

可以开 26 个栈,但感觉用优先队列好写一点。

时间复杂度:O(nlogn)

参考代码

class Solution {
    public String clearStars(String s) {
        int n = s.length();
        PriorityQueue<Node> pq = new PriorityQueue<>((o1, o2) -> {
            if (o1.ch == o2.ch) {
                return Integer.compare(o2.i, o1.i);
            }
            return Character.compare(o1.ch, o2.ch);
        });
        for (int i = 0; i < n; i++) {
            char ch = s.charAt(i);
            if (ch == '*') {
                pq.remove();
            } else {
                pq.add(new Node(ch, i));
            }
        }

        List<Node> list = new ArrayList<>(pq);
        list.sort(Comparator.comparingInt(o -> o.i));
        StringBuilder ans = new StringBuilder();
        for (Node node : list) {
            ans.append(node.ch);
        }
        return ans.toString();
    }

    static class Node {
        char ch;
        int i;

        public Node(char ch, int i) {
            this.ch = ch;
            this.i = i;
        }
    }
}

T4. 找到按位与最接近 K 的子数组(6 分)

解题思路

按位与显然是存在单调性的(单调减),因此可用拆位 + 二分答案。

时间复杂度:O(nlogn)

参考代码

class Solution {
    public int minimumDifference(int[] nums, int k) {
        int n = nums.length;
        int[][] ps = new int[n + 1][31];
        for (int bit = 0; bit < 31; bit++) {
            for (int i = 0; i < n; i++) {
                ps[i + 1][bit] = ps[i][bit];
                if ((nums[i] >> bit & 1) == 1) {
                    ps[i + 1][bit] += 1;
                }
            }
        }

        int ans = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            int l = i, r = n;
            while (l < r) {
                int mid = l + (r - l) / 2;
                if (bitwiseAnd(ps, i, mid) <= k) r = mid;
                else l = mid + 1;
            }

            if (l < n) ans = Math.min(ans, k - bitwiseAnd(ps, i, l));
            if (l - 1 >= 0) ans = Math.min(ans, bitwiseAnd(ps, i, l - 1) - k);
        }
        return ans;
    }

    private int bitwiseAnd(int[][] ps, int l, int r) {
        int res = 0;
        for (int bit = 0; bit < 31; bit++) {
            int s = ps[r + 1][bit] - ps[l][bit];
            if (s == r - l + 1) {
                res |= 1 << bit;
            }
        }
        return res;
    }
}

(全文完)