欢迎大家加QQ群:623375442,可以方便群里面交流。以后太难的双周赛就不打了,之后有时间会补上题解。真的不想做纯数学的题目。

100561. Maximum Difference Between Adjacent Elements in a Circular Array

给你一个 循环 数组 nums ,请你找出相邻元素之间的 最大 绝对差值。

注意:一个循环数组中,第一个元素和最后一个元素是相邻的。

测试样例:

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

输出:3

解释:由于 nums 是循环的,nums[0] 和 nums[2] 是相邻的,它们之间的绝对差值是最大值 |4 - 1| = 3 。

解答:暴力运算。

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

3424. Minimum Cost to Make Arrays Identical

给你两个长度都为 n 的整数数组 arr 和 brr 以及一个整数 k 。你可以对 arr 执行以下操作任意次:

  • 将 arr 分割成若干个 连续的 子数组,并将这些子数组按任意顺序重新排列。这个操作的代价为 k 。
  • 选择 arr 中的任意一个元素,将它增加或者减少一个正整数 x 。这个操作的代价为 x 。

请你返回将 arr 变为 brr 的 最小 总代价。

子数组 是一个数组中一段连续 非空 的元素序列。

测试样例:

输入:arr = [-7,9,5], brr = [7,-2,-5], k = 2

输出:13

解释:

  • 将 arr 分割成两个连续子数组:[-7] 和 [9, 5] 然后将它们重新排列成 [9, 5, -7] ,代价为 2 。
  • 将 arr[0] 减小 2 ,数组变为 [7, 5, -7] ,操作代价为 2 。
  • 将 arr[1] 减小 7 ,数组变为 [7, -2, -7] ,操作代价为 7 。
  • 将 arr[2] 增加 2 ,数组变为 [7, -2, -5] ,操作代价为 2 。

将两个数组变相等的总代价为 2 + 2 + 7 + 2 = 13 。

解答:有两种情况。一种是不做任何shuffle,直接计算代价。还有一种情况是,做一次shuffle,然后计算代价。第二种情况,我们可以认为两个数组都是从小到大排序,取最小的代价(这个时候,其实就是子数组长度都是1,然后任意排序)。

class Solution {
    public long minCost(int[] arr, int[] brr, long k) {
        long noShuffle = 0;
        for (int i = 0; i < arr.length; ++i) {
            noShuffle += Math.abs(arr[i] - brr[i]);
        }
        Integer[] sort1 = getSort(arr), sort2 = getSort(brr);
        long oneShuffle = k;
        boolean isShuffle = false;
        for (int i = 0; i < arr.length; ++i) {
            oneShuffle += Math.abs(arr[sort1[i]] - brr[sort2[i]]);
        }
        return Math.min(noShuffle, oneShuffle);
    }

    private Integer[] getSort(int[] arr) {
        Integer[] res = new Integer[arr.length];
        for (int i = 0; i < arr.length; ++i) {
            res[i] = i;
        }
        Arrays.sort(res, (a, b) -> (arr[a] != arr[b] ? Integer.compare(arr[a], arr[b]) : Integer.compare(a, b)));
        return res;
    }
}

3425. Longest Special Path

给你一棵根节点为节点 0 的无向树,树中有 n 个节点,编号为 0 到 n - 1 ,这棵树通过一个长度为 n - 1 的二维数组 edges 表示,其中 edges[i] = [ui, vi, lengthi] 表示节点 ui 和 vi 之间有一条长度为 lengthi 的边。同时给你一个整数数组 nums ,其中 nums[i] 表示节点 i 的值。

特殊路径 指的是树中一条从祖先节点 往下 到后代节点且经过节点的值 互不相同 的路径。

注意 ,一条路径可以开始和结束于同一节点。

请你返回一个长度为 2 的数组 result ,其中 result[0] 是 最长 特殊路径的 长度 ,result[1] 是所有 最长特殊路径中的 最少 节点数目。

测试样例:

输入:edges = [[0,1,2],[1,2,3],[1,3,5],[1,4,4],[2,5,6]], nums = [2,1,2,1,3,1]

输出:[6,2]

解释:最长特殊路径为 2 -> 5 和 0 -> 1 -> 4 ,两条路径的长度都为 6 。所有特殊路径里,节点数最少的路径含有 2 个节点。

解答:DFS题目,但是DFS过程中需要记录一下中间情况。

class Solution {
    private class Data {
        // 记录一下路径上的num和edge长度信息
        int[] nums, numStack, edgeStack;
        List<int[]>[] edges;
        // 记录路径上重复数情况
        HashMap<Integer, Stack<Integer>> map;

        public Data(int[][] _edges, int[] nums) {
            this.nums = nums;
            edges = new List[nums.length];
            for (int i = 0; i < nums.length; ++i) {
                edges[i] = new ArrayList<>();
            }
            for (int[] e : _edges) {
                edges[e[0]].add(new int[]{e[1], e[2]});
                edges[e[1]].add(new int[]{e[0], e[2]});
            }
            numStack = new int[nums.length];
            edgeStack = new int[nums.length];
            map = new HashMap<>();
        }
    }

    public int[] longestSpecialPath(int[][] _edges, int[] nums) {
        Data data = new Data(_edges, nums);
        int[] res = {0,1};
        int[] numStack = new int[nums.length], edgeStack = new int[nums.length];
        dfs(0, -1, data, res, -1, 0);
        return res;
    }

    private void dfs(int pos, int last, Data data, int[] res, int left, int depth) {
        if (data.map.containsKey(data.nums[pos]) && !data.map.get(data.nums[pos]).isEmpty()) {
            left = Math.max(left, data.map.get(data.nums[pos]).peek());
        } else {
            data.map.put(data.nums[pos], new Stack<>());
        }
        if (depth >= 1) {
            int curLength = data.edgeStack[depth - 1] - (left >= 0 ? data.edgeStack[left] : 0);
            if (curLength > res[0]) {
                res[0] = curLength;
                res[1] = depth - left;
            } else if (curLength == res[0]) {
                res[1] = Math.min(res[1], depth - left);
            }
        }
        data.map.get(data.nums[pos]).push(depth);
        data.numStack[depth] = data.nums[pos];
        for (int[] ne : data.edges[pos]) {
            if (ne[0] == last) continue;
            // edgeStack是对edge的前缀和
            data.edgeStack[depth] = (depth == 0 ? 0 : data.edgeStack[depth - 1]) + ne[1];
            dfs(ne[0], pos, data, res, left, depth + 1);
        }
        data.map.get(data.nums[pos]).pop();
    }
}

100555. Manhattan Distances of All Arrangements of Pieces

给你三个整数 m ,n 和 k 。

给你一个大小为 m x n 的矩形格子,它包含 k 个没有差别的棋子。请你返回所有放置棋子的 合法方案 中,每对棋子之间的曼哈顿距离之和。

一个 合法方案 指的是将所有 k 个棋子都放在格子中且一个格子里 至多 只有一个棋子。

由于答案可能很大, 请你将它对 10^9 + 7 取余 后返回。

两个格子 (xi, yi) 和 (xj, yj) 的曼哈顿距离定义为 |xi - xj| + |yi - yj| 。

测试样例:

输入:m = 2, n = 2, k = 2

输出:8

解释:所以所有方案的总曼哈顿距离之和为 1 + 1 + 1 + 1 + 2 + 2 = 8 。

输出为 max(4, 4, 7, 4, 2) = 7 。

解答:竞赛的时候,看了一眼不会做就溜了。纯纯数学题目。利用组合计算所有情况。

class Solution {
    private static int mod = 1_000_000_007;

    public int distanceSum(int m, int n, int k) {
        long[] fact = new long[m * n];
        fact[0] = 1;
        for (int i = 1; i < m * n; i++) fact[i] = fact[i - 1] * i % mod;
        long c = fact[m * n - 2] * fastMod(fact[k - 2], mod - 2, mod) % mod * fastMod(fact[m * n - k], mod - 2, mod) % mod;
        long[] suma = getSum(n);
        long[] sumb = getSum(m);
        long res = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                res += n * sumb[j] + m * suma[i];
                res %= mod;
            }
        }
        res = res * fastMod(2, mod - 2, mod) % mod;
        res = res * c % mod;
        return (int) res;
    }

    private long[] getSum(int n) {
        long[] res = new long[n];
        res[0] = (long) n * (n - 1) / 2;
        for (int i = 1; i < n; i++) {
            res[i] = res[i - 1] - (n - i) + i;
        }
        return res;
    }

    private long fastMod(long base, long r, long mod) {
        long res = 1;
        long p = 1;
        while (p <= r) {
            if ((r & p) != 0) {
                res = res * base % mod;
            }
            base = base * base % mod;
            p = p << 1;
        }
        return res;
    }
}

Leave a Reply

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