6361. Prime In Diagonal

给你一个下标从 0 开始的二维整数数组 nums 。

返回位于 nums 至少一条 对角线 上的最大 质数 。如果任一对角线上均不存在质数,返回 0 。

注意:

  • 如果某个整数大于 1 ,且不存在除 1 和自身之外的正整数因子,则认为该整数是一个质数。
  • 如果存在整数 i ,使得 nums[i][i] = val 或者 nums[i][nums.length - i - 1]= val ,则认为整数 val 位于 nums 的一条对角线上。

在上图中,一条对角线是 [1,5,9] ,而另一条对角线是 [3,5,7] 。

测试样例

输入:nums = [[1,2,3],[5,6,7],[9,10,11]]

输出:11

解释:数字 1、3、6、9 和 11 是所有 "位于至少一条对角线上" 的数字。由于 11 是最大的质数,故返回 11 。

解答:这题就是暴力枚举所有对角线的数字,如果是质数就更新result

class Solution {
    public int diagonalPrime(int[][] nums) {
        int n = nums.length, res = 0;
        for (int i = 0; i < n; ++i) {
            if (isPrime(nums[i][i])) {
                res = Math.max(res, nums[i][i]);
            }
            if (isPrime(nums[i][n - i - 1])) {
                res = Math.max(res, nums[i][n - i - 1]);
            }
        }
        return res;
    }

    private boolean isPrime(int n) {
        if (n <= 1) return false;
        for (int i = 2; i * i <= n; ++i) {
            if (n % i == 0) return false;
        }
        return true;
    }
}

6360. Sum of Distances

给你一个下标从 0 开始的整数数组 nums 。现有一个长度等于 nums.length 的数组 arr 。对于满足 nums[j] == nums[i] 且 j != i 的所有 j ,arr[i] 等于所有 |i - j| 之和。如果不存在这样的 j ,则令 arr[i] 等于 0 。

返回数组 arr 。

请注意,二维数组的每一行上可以存在不同数量的元素。

测试样例:

输入:nums = [1,3,1,1,2]

输出:[5,0,3,4,0]

解释:

  • i = 0 ,nums[0] == nums[2] 且 nums[0] == nums[3] 。因此,arr[0] = |0 - 2| + |0 - 3| = 5 。
  • i = 1 ,arr[1] = 0 因为不存在值等于 3 的其他下标。
  • i = 2 ,nums[2] == nums[0] 且 nums[2] == nums[3] 。因此,arr[2] = |2 - 0| + |2 - 3| = 3 。i = 3 ,nums[3] == nums[0] 且 nums[3] == nums[2] 。因此,arr[3] = |3 - 0| + |3 - 2| = 4 。
  • i = 4 ,arr[4] = 0 因为不存在值等于 2 的其他下标。

解答: 哈希表聚合所有相同数字的位数,然后变化一下前缀和计算绝对值差之和。注意返回的是long[], 所以计算和的时候使用int可能有超出范围的风险。

class Solution {
    public long[] distance(int[] nums) {
        int len = nums.length;
        long[] res = new long[len];
        HashMap<Integer, ArrayList<Integer>> mem = new HashMap<Integer, ArrayList<Integer>>();
        for (int i = 0; i < len; ++i) {
            if (!mem.containsKey(nums[i])) {
                mem.put(nums[i], new ArrayList<>());
            }
            mem.get(nums[i]).add(i);
        }
        for (Map.Entry<Integer, ArrayList<Integer>> kv : mem.entrySet()) {
            if (kv.getValue().size() != 1) {
                long rightSum = 0, leftSum = 0;
                for (int i : kv.getValue()) {
                    rightSum += i;
                }
                long rightCount = kv.getValue().size(), leftCount = 0;
                for (int i : kv.getValue()) {
                    leftSum += i;
                    rightSum -= i;
                    ++leftCount;
                    --rightCount;
                    res[i] = leftCount * i - leftSum + rightSum - i * rightCount;
                }
            }
        }
        return res;
    }
}

6359. Minimize the Maximum Difference of Pairs

给你一个下标从 0 开始的整数数组 nums 和一个整数 p 。请你从 nums 中找到 p 个下标对,每个下标对对应数值取差值,你需要使得这 p 个差值的 最大值 最小。同时,你需要确保每个下标在这 p 个下标对中最多出现一次。

对于一个下标对 i 和 j ,这一对的差值为 |nums[i] - nums[j]| ,其中 |x| 表示 x 的 绝对值 。

请你返回 p 个下标对对应数值 最大差值 的 最小值 。

测试样例

输入:nums = [4,2,1,2], p = 1

输出:0

解释:

选择下标 1 和 3 构成下标对。差值为 |2 - 2| = 0 ,这是最大差值的最小值。

解答:注意这个:确保每个下标在这 p 个下标对中最多出现一次,一开始我没认真看条件直接Wrong Answer了一次。有这个条件之后,题目就变得容易很多了,排序之后,利用折半搜索可以寻找到答案。

折半搜索的时候,需要判断当前的mid是否满足要求。这个时候用贪婪即可以了。因为队列已经排序好,那么当前的数字能够找到pair就最好,否则继续寻找下一个数。因为下一个数一定比当前数字更大,所以能够配对的希望也会更大。

class Solution {
    public int minimizeMax(int[] nums, int p) {
        Arrays.sort(nums);
        int min = 0, max = 1_000_000_000;
        while (min < max) {
            int mid = (min + max) / 2;
            if (count(nums, mid) < p) {
                min = mid + 1;
            } else {
                max = mid;
            }
        }
        return min;
    }

    private long count(int[] nums, int target) {
        int res = 0;
        int pos = 0;
        while (pos + 1 < nums.length) {
            if (nums[pos + 1] - nums[pos] <= target) {
                ++res;
                ++pos;
            }
            ++pos;
        }
        return res;
    }
}

6353. Minimum Number of Visited Cells in a Grid

给你一个下标从 0 开始的 m x n 整数矩阵 grid 。你一开始的位置在 左上角 格子 (0, 0) 。

当你在格子 (i, j) 的时候,你可以移动到以下格子之一:

  • 满足 j < k <= grid[i][j] + j 的格子 (i, k) (向右移动),或者
  • 满足 i < k <= grid[i][j] + i 的格子 (k, j) (向下移动)。

请你返回到达 右下角 格子 (m - 1, n - 1) 需要经过的最少移动格子数,如果无法到达右下角格子,请你返回 -1 。

测试样例

输入:grid = [[3,4,2,1],[4,2,3,1],[2,1,0,0],[2,4,0,0]]

输出:4

解答:这道题目的难点在于寻找能够到达当前位置的最小次数。我们可以利用TreeMap来存储可以到达当前位置的所有可能次数。那么map的firstKey就是最小次数。

然后我们可以利用优先队列在储存一个点可以到达的位置,如果当前位置不满足要求,那就出队并更新TreeMap。因为我们的遍历方式是从小到大遍历,如果当前节点不满足,之后的节点也不可能满足。出队就是安全的。

最后一个注意点,二维计算比较麻烦,所以我们将行列分开记忆计算。

class Solution {
    public int minimumVisitedCells(int[][] grid) {
        int col = grid[0].length;
        TreeMap<Integer, Integer>[] colMems = new TreeMap[col];
        PriorityQueue<int[]>[] colMarks = new PriorityQueue[col];
        for (int i = 0; i < col; ++i) {
            colMems[i] = new TreeMap<>();
            colMarks[i] = new PriorityQueue<>((a, b) -> (a[0] - b[0]));
        }

        colMarks[0].add(new int[]{0, 0});
        colMems[0].put(0, 1);

        int offset = 0;
        for (int[] row : grid) {
            TreeMap<Integer, Integer> rowMem = new TreeMap<>();
            PriorityQueue<int[]> rowMark = new PriorityQueue<>((a, b) -> (a[0] - b[0]));
            for (int i = 0; i < col; ++i) {
                while (!colMarks[i].isEmpty() && colMarks[i].peek()[0] < offset) {
                    int r = colMarks[i].poll()[1];
                    remove(colMems[i], r);
                }
                int min = Integer.MAX_VALUE;
                if (!colMems[i].isEmpty()) {
                    min = Math.min(min, colMems[i].firstKey());
                }

                while (!rowMark.isEmpty() && rowMark.peek()[0] < i) {
                    int r = rowMark.poll()[1];
                    remove(rowMem, r);
                }
                if (!rowMem.isEmpty()) {
                    min = Math.min(min, rowMem.firstKey());
                }

                if (min != Integer.MAX_VALUE) {
                    ++min;
                    int maxRowDis = row[i] + i, maxColDis = row[i] + offset;
                    rowMark.add(new int[]{maxRowDis, min});
                    add(rowMem, min);

                    colMarks[i].add(new int[]{maxColDis, min});
                    add(colMems[i], min);

                    if (offset == grid.length - 1 && i == col - 1) {
                        return min;
                    }
                }
            }
            ++offset;
        }
        return -1;
    }

    private void remove(Map<Integer, Integer> map, int key) {
        int c = map.get(key);
        if (c == 1) {
            map.remove(key);
        } else {
            map.put(key, c - 1);
        }
    }

    private void add(Map<Integer, Integer> map, int key) {
        map.put(key, map.getOrDefault(key, 0) + 1);
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *