跳至主要內容

力扣第 334 场周赛

大约 3 分钟

力扣第 334 场周赛

比赛时间 2023-02-26。本场周赛国服共 360 人 AK。

T1. 左右元素和的差值(3 分)

解题思路

前缀和。leftSum[i] = [0,i-1] 区间和rightSum[i] = [i+1,n-1] 区间和

时间复杂度:O(n)

参考代码

class Solution {
    public int[] leftRigthDifference(int[] nums) {
        int n = nums.length;

        // 前缀和
        int[] preSum = new int[n + 1];
        for (int i = 0; i < n; i++) {
            preSum[i + 1] = preSum[i] + nums[i];
        }

        int[] ans = new int[n];
        for (int i = 0; i < n; i++) {
            int leftSum = preSum[i];
            int rightSum = preSum[n] - preSum[i + 1];
            ans[i] = Math.abs(leftSum - rightSum);
        }
        return ans;
    }
}

T2. 找出字符串的可整除数组(4 分)

解题思路

贪心。如果 x 可以整除 m,那么 x * 10 也必然可以整除 m。取余之后不影响结果。

时间复杂度:O(n)

参考代码

class Solution {
    public int[] divisibilityArray(String word, int m) {
        int n = word.length();

        long x = 0L;
        int[] div = new int[n];
        for (int i = 0; i < n; i++) {
            x = x * 10 + (word.charAt(i) - '0');
            if (x % m == 0) {
                div[i] = 1;
            }
            x %= m;
        }
        return div;
    }
}

T3. 求出最多标记下标(5 分)

解题思路

二分 + 贪心。二分查找转化为判定问题:是否可以构造 k 对匹配。根据贪心:当最小 k 个数和最大 k 个数一一匹配时,配对数最大。

时间复杂度:O(nlogn)

参考代码

class Solution {
    public int maxNumOfMarkedIndices(int[] nums) {
        int n = nums.length;
        Arrays.sort(nums);

        int left = 1;
        int right = n / 2 + 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            // 边界二分 F, F,..., F, [T, T,..., T]
            // ----------------------^
            if (!checkMid(nums, mid)) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return (left - 1) * 2;
    }

    // 是否可以构造 k 对匹配(最小 k 个数和最大 k 个数 一一匹配)
    private boolean checkMid(int[] nums, int k) {
        int n = nums.length;
        for (int i = 0; i < k; i++) {
            if (nums[i] * 2 > nums[n - k + i]) {
                return false;
            }
        }
        return true;
    }
}

T4. 在网格图中访问一个格子的最少时间(6 分)

解题思路

堆优化 Dijkstra 最短路。

首先,特判 grid[0][1] > 1 && grid[1][0] > 1 情况,此时“困毙”(“困毙”:中国象棋术语。指轮到行棋的一方,棋子没有被将军,但所有棋子被困在原地无子可动,即被困毙)。

否则,可以通过“走闲”来凑时间,总能到达终点(“走闲”:中国象棋术语。表示行棋方无意进攻,走闲是用于等待时机或用于防守的战术)。

注意时间奇偶性:因“走闲”一次时间 +2。如:3->5 需要 t+2+13->6 同样需要 t+2+1

最后 dijkstra 求最短路即可。

时间复杂度:O(mnlogmn)

参考代码

class Solution {
    private static final int[][] DIRECTIONS = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

    public int minimumTime(int[][] grid) {
        int M = grid.length;
        int N = grid[0].length;

        // “困毙”
        if (grid[0][1] > 1 && grid[1][0] > 1) {
            return -1;
        }

        PriorityQueue<int[]> queue = new PriorityQueue<>(Comparator.comparingInt(o -> o[2]));
        queue.add(new int[]{0, 0, 0});
        boolean[][] visited = new boolean[M][N];
        // 到达 grid[i][j] 所需的最少时间
        int[][] t = new int[M][N];
        for (int i = 0; i < M; i++) {
            Arrays.fill(t[i], Integer.MAX_VALUE);
        }
        t[0][0] = 0;
        while (!queue.isEmpty()) {
            int[] tuple = queue.remove();
            int cx = tuple[0], cy = tuple[1], ct = tuple[2];
            if (visited[cx][cy]) {
                continue;
            }
            visited[cx][cy] = true;

            for (int[] dir : DIRECTIONS) {
                int nx = cx + dir[0];
                int ny = cy + dir[1];
                if (nx >= 0 && nx < M && ny >= 0 && ny < N) {
                    // “走闲”
                    int nt = ct + 1 + (Math.max(0, grid[nx][ny] - ct) / 2 * 2);
                    if (t[nx][ny] > nt) {
                        t[nx][ny] = nt;
                        queue.add(new int[]{nx, ny, nt});
                    }
                }
            }
        }
        return t[M - 1][N - 1];
    }
}

(全文完)