[Leetcode Weekly Contest]299

链接:LeetCode

[Leetcode]2319. 判断矩阵是否是一个 X 矩阵

如果一个正方形矩阵满足下述 全部 条件,则称之为一个 X 矩阵 :

  1. 矩阵对角线上的所有元素都 不是 0
  2. 矩阵中所有其他元素都是 0

给你一个大小为 n x n 的二维整数数组 grid ,表示一个正方形矩阵。如果 grid 是一个 X 矩阵 ,返回 true ;否则,返回 false 。

模拟遍历即可。

class Solution {
    public boolean checkXMatrix(int[][] grid) {
        int n = grid.length;
        for(int i=0;i<n;++i) {
            for(int j=0;j<n;++j) {
                int val = grid[i][j];
                if(i==j || i==n-1-j) {
                    if(val==0) return false;
                }
                else {
                    if(val!=0) return false;
                }
            }
        }
        return true;
    }
}

[Leetcode]2320. 统计放置房子的方式数

一条街道上共有 n * 2 个 地块 ,街道的两侧各有 n 个地块。每一边的地块都按从 1 到 n 编号。每个地块上都可以放置一所房子。
现要求街道同一侧不能存在两所房子相邻的情况,请你计算并返回放置房屋的方式数目。由于答案可能很大,需要对 1E9 + 7 取余后再返回。
注意,如果一所房子放置在这条街某一侧上的第 i 个地块,不影响在另一侧的第 i 个地块放置房子。

单独考虑一侧的房子,定义 \(f[i]\) 表示前 i 个地块的放置方案数,其中第 i 个地块可以放房子,也可以不放房子。
考虑第 i 个地块:

  • 若不放房子,那么第 i-1 个地块可放可不放,则有 \(f[i] = f[i-1]\)
  • 若放房子,那么第 i-1 个地块无法放房子,第 i-2 个地块可放可不放,则有 \(f[i] = f[i-2]\)
    因此

\[f[i] = f[i-1] + f[i-2] \]

边界为

  • \(f[0]=1\),空也是一种方案;
  • \(f[1]=2\),放与不放两种方案。
    由于两侧的房屋互相独立,根据乘法原理,答案为 \(f[n]^2\)
class Solution {
    static final int MOD = (int) 1e9 + 7, MX = (int) 1e4 + 1;
    static final int[] f = new int[MX];

    static {
        f[0] = 1;
        f[1] = 2;
        for (var i = 2; i < MX; ++i)
            f[i] = (f[i - 1] + f[i - 2]) % MOD;
    }

    public int countHousePlacements(int n) {
        return (int) ((long) f[n] * f[n] % MOD);
    }
}

[Leetcode]2321. 拼接数组的最大分数

给你两个下标从 0 开始的整数数组 nums1 和 nums2 ,长度都是 n 。

你可以选择两个整数 left 和 right ,其中 0 <= left <= right < n ,接着 交换 两个子数组 nums1[left...right] 和 nums2[left...right] 。

  • 例如,设 nums1 = [1,2,3,4,5] 和 nums2 = [11,12,13,14,15] ,整数选择 left = 1 和 right = 2,那么 nums1 会变为 [1,12,13,4,5] 而 nums2 会变为 [11,2,3,14,15] 。

你可以选择执行上述操作 一次 或不执行任何操作。
数组的 分数 取 sum(nums1) 和 sum(nums2) 中的最大值,其中 sum(arr) 是数组 arr 中所有元素之和。
返回 可能的最大分数 。
子数组 是数组中连续的一个元素序列。arr[left...right] 表示子数组包含 nums 中下标 left 和 right 之间的元素(含 下标 left 和 right 对应元素)。

转化为最大子数组和求解。

class Solution {
    public int maximumsSplicedArray(int[] nums1, int[] nums2) {
        return Math.max(solve(nums1, nums2), solve(nums2,nums1));
    }

    public int solve(int[] nums1, int[] nums2) {
        int curSum = 0, res = 0;
        int cur = 0, n = nums1.length;
        for(int i=0;i<n;++i) {
            curSum += nums1[i];
            cur = Math.max(0, cur + nums2[i]-nums1[i]);
            res = Math.max(cur, res);
        }
        return curSum + res;
    }
}

[Leetcode]2322. 从树中删除边的最小分数

存在一棵无向连通树,树中有编号从 0 到 n - 1 的 n 个节点, 以及 n - 1 条边。
给你一个下标从 0 开始的整数数组 nums ,长度为 n ,其中 nums[i] 表示第 i 个节点的值。另给你一个二维整数数组 edges ,长度为 n - 1 ,其中 edges[i] = [ai, bi] 表示树中存在一条位于节点 ai 和 bi 之间的边。
删除树中两条 不同 的边以形成三个连通组件。对于一种删除边方案,定义如下步骤以计算其分数:

  1. 分别获取三个组件 每个 组件中所有节点值的异或值。
  2. 最大 异或值和 最小 异或值的 差值 就是这一种删除边方案的分数。
  • 例如,三个组件的节点值分别是:[4,5,7]、[1,9] 和 [3,3,3] 。三个异或值分别是 4 ^ 5 ^ 7 = 6、1 ^ 9 = 8 和 3 ^ 3 ^ 3 = 3 。最大异或值是 8 ,最小异或值是 3 ,分数是 8 - 3 = 5 。

返回在给定树上执行任意删除边方案可能的 最小 分数。

DFS.由于需要求出子树的异或和,不妨以 00 为根,DFS 这棵树,在求出时间戳的同时,求出每棵以 xx 为根的子树的异或和 \(\textit{xor}[x]\)
由于 n 比较小,我们可以用 \(O(n^2)\)的时间枚举要删除的两条边 \(x_1\text{-}y_1\) 和 $ x_2\text{-}y_2$,并假设 x 是 y 的父节点,这会产生以下三种情况:

  1. 删除的两条边在同一颗子树内,且 \(y_1\)\(x_2\) 的祖先节点(或重合)。这三个连通块的异或和分别为 \(\textit{xor}[y_2]\)\(\textit{xor}[y_1]\oplus\textit{xor}[y_2]\)\(\textit{xor}[0]\oplus\textit{xor}[y_1]\)\(\oplus\) 表示异或运算)。
  2. 删除的两条边在同一颗子树内,且 \(y_2\)\(x_1\) 的祖先节点(或重合)。
    同上,这三个连通块的异或和分别为 \(\textit{xor}[y_1]\)\(\textit{xor}[y_1]\oplus\textit{xor}[y_2]\)\(\textit{xor}[0]\oplus\textit{xor}[y_2]\)
  3. 删除的两条边分别属于两颗不相交的子树。
    这三个连通块的异或和分别为 \(\textit{xor}[y_1]\)\(\textit{xor}[0]\oplus\textit{xor}[y_1]\oplus\textit{xor}[y_2]\)\(\textit{xor}[y_2]\)

此关键之处在于判断这两条边的关系,这里可以通过DFS来维护一个children的字典,也可以通过时间戳的方式.
代码实现时,由于不知道 \(\textit{edges}[i]\) 两个点的父子关系,枚举边的写法需要额外的判断。我们可以改为枚举不是根的两个点,删除这两个点及其父节点形成的边,这样代码更简洁,效率也略优于枚举边的写法。

class Solution {
    HashMap<Integer, Integer> xor = new HashMap<>();
    HashMap<Integer, HashSet<Integer>> graph = new HashMap<>();
    HashMap<Integer, HashSet<Integer>> children = new HashMap<>();
    int clock = 0;
    int[] in;
    int[] out;

    public int minimumScore(int[] nums, int[][] edges) {
        int n = nums.length;
        in = new int[n];
        out = new int[n];
        int res = Integer.MAX_VALUE;
        for(var edge:edges) {
            if(!graph.containsKey(edge[0])) graph.put(edge[0], new HashSet<Integer>());
            if(!graph.containsKey(edge[1])) graph.put(edge[1], new HashSet<Integer>());
            graph.get(edge[0]).add(edge[1]);
            graph.get(edge[1]).add(edge[0]);
        }

        dfs(0, -1, nums);
        // dfs2(0, -1);
        int a,b,c;
        for(int i=1;i<n;++i) {
            for(int j=i+1;j<n;++j) {
                //if(children.get(i).contains(j)) {
                if (in[i] < in[j] && out[j] <= out[i]) { // i 是 j 的祖先节点
                    a = xor.get(0) ^ xor.get(i);
                    b = xor.get(i) ^ xor.get(j);
                    c = xor.get(j);
                }
                //else if(children.get(j).contains(i)) {
                else if (in[j] < in[i] && out[i] <= out[j]) { // i 是 j 的祖先节点
                    a = xor.get(0) ^ xor.get(j);
                    b = xor.get(j) ^ xor.get(i);
                    c = xor.get(i);
                }
                else {
                    a = xor.get(0) ^ xor.get(i) ^ xor.get(j);
                    b = xor.get(i);
                    c = xor.get(j);
                }
                res = Math.min(res, Math.max(c,Math.max(a,b)) - Math.min(c,Math.min(a,b)));
            }
        }
        return res;
    }

    public int dfs(int node, int preNode, int[] nums) {
        clock ++ ;
        in[node] = clock;
        xor.put(node, nums[node]);
        for(var child:graph.get(node)) {
            if(child!=preNode) xor.put(node, xor.get(node) ^ dfs(child, node, nums));
        }
        out[node] = clock;
        return xor.get(node);
    }

    public HashSet<Integer> dfs2(int node, int preNode) {
        children.put(node, new HashSet<Integer>());
        for(var child:graph.get(node)) {
            if(child!=preNode) {
                children.get(node).add(child);
                for(var childNode: dfs2(child, node)) {
                    children.get(node).add(childNode);
                }
            }
        }
        return children.get(node);
    }
}

参考:LeetCode
LeetCode
LeetCode

posted @ 2022-07-12 21:01  Jamest  阅读(35)  评论(0编辑  收藏  举报