6430. Find the Losers of the Circular Game

n 个朋友在玩游戏。这些朋友坐成一个圈,按 顺时针方向 从 1 到 n 编号。从第 i 个朋友的位置开始顺时针移动 1 步会到达第 (i + 1) 个朋友的位置(1 <= i < n),而从第 n 个朋友的位置开始顺时针移动 1 步会回到第 1 个朋友的位置。

游戏规则如下:

第 1 个朋友接球。

  • 接着,第 1 个朋友将球传给距离他顺时针方向 k 步的朋友。
  • 然后,接球的朋友应该把球传给距离他顺时针方向 2 * k 步的朋友。
  • 接着,接球的朋友应该把球传给距离他顺时针方向 3 * k 步的朋友,以此类推。

换句话说,在第 i 轮中持有球的那位朋友需要将球传递给距离他顺时针方向 i * k 步的朋友。

当某个朋友第 2 次接到球时,游戏结束。

在整场游戏中没有接到过球的朋友是 输家 。

给你参与游戏的朋友数量 n 和一个整数 k ,请按升序排列返回包含所有输家编号的数组 answer 作为答案。

测试样例:

输入:n = 5, k = 2

输出:[4,5]

解释:
以下为游戏进行情况:

  1. 第 1 个朋友接球,第 1 个朋友将球传给距离他顺时针方向 2 步的玩家 —— 第 3 个朋友。
  2. 第 3 个朋友将球传给距离他顺时针方向 4 步的玩家 —— 第 2 个朋友。
  3. 第 2 个朋友将球传给距离他顺时针方向 6 步的玩家 —— 第 3 个朋友。
  4. 第 3 个朋友接到两次球,游戏结束。

解答:提示有:1 <= k <= n <= 50。这个范围实在是太小了,直接按照要求暴力运算就行了

class Solution {
    public int[] circularGameLosers(int n, int k) {
        boolean[] isVisit = new boolean[n];
        int cur = 0, add = 0, step = 1;
        while (!isVisit[cur]) {
            isVisit[cur] = true;
            ++add;
            cur = (cur + step * k) % n;
            ++step;
        }
        int[] res = new int[n - add];
        int p = 0;
        for (int i = 0; i < n; ++i) {
            if (!isVisit[i]) {
                res[p++] = i + 1;
            }
        }
        return res;
    }
}

6431. Neighboring Bitwise XOR

下标从 0 开始、长度为 n 的数组 derived 是由同样长度为 n 的原始 二进制数组 original 通过计算相邻值的 按位异或(⊕)派生而来。

特别地,对于范围 [0, n - 1] 内的每个下标 i :

  • 如果 i = n - 1 ,那么 derived[i] = original[i] ⊕ original[0]
  • 否则 derived[i] = original[i] ⊕ original[i + 1]

给你一个数组 derived ,请判断是否存在一个能够派生得到 derived 的 有效原始二进制数组 original 。

如果存在满足要求的原始二进制数组,返回 true ;否则,返回 false 。

  • 二进制数组是仅由 0 和 1 组成的数组。

测试样例:

输入:derived = [1,1,0]

输出:true

解释:
能够派生得到 [1,1,0] 的有效原始二进制数组是 [0,1,0]

解答:这题需要用到异或特性: A ⊕ A = 0。按照题意所有元素都会出现2次,所以对derived数组全部异或一下,结果应该为0

class Solution {
    public boolean doesValidArrayExist(int[] derived) {
        int res = 0;
        for (int d : derived) {
            res ^= d;
        }
        return res == 0;
    }
}

6433. Maximum Number of Moves in a Grid

给你一个下标从 0 开始、大小为 m x n 的矩阵 grid ,矩阵由若干 正 整数组成。

你可以从矩阵第一列中的 任一 单元格出发,按以下方式遍历 grid :

  • 从单元格 (row, col) 可以移动到 (row - 1, col + 1)、(row, col + 1) 和 (row + 1, col + 1) 三个单元格中任一满足值 严格 大于当前单元格的单元格。

返回你在矩阵中能够 移动 的 最大 次数。

测试样例

输入:grid = [[2,4,3,5],[5,4,9,3],[3,4,2,11],[10,9,13,15]]

输出:3

解释:
可以从单元格 (0, 0) 开始并且按下面的路径移动:

  • (0, 0) -> (0, 1).
  • (0, 1) -> (1, 2).
  • (1, 2) -> (2, 3).

可以证明这是能够移动的最大次数。

解答:这道题目是一道动态规划题目。如果某一个位置(i,j),它的前驱节点(i-1,j-1), (i,j-1), (i+1,j-1)可达,且某一个前驱节点小于当前单元格,那么当前单元格也可达。加之按照列的视角观看,列只会单调递增。所以一列一列动态规划的计算一下,就能知道多少列可达,即最大的自动次数。

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

    public int maxMoves(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        int res = 0;
        boolean[] last = new boolean[m];
        Arrays.fill(last, true);
        for (int i = 1; i < n; ++i) {
            boolean[] next = new boolean[m];
            boolean isAdd = false;
            for (int j = 0; j < m; ++j) {
                for (int[] mv : moves) {
                    int xb = j + mv[0], yb = i + mv[1];
                    if (xb >= 0 && xb < m && yb >= 0 && yb < n && grid[xb][yb] < grid[j][i] && last[xb]) {
                        next[j] = true;
                        isAdd = true;
                    }
                }
            }
            if (isAdd) {
                ++res;
                last = next;
            } else {
                break;
            }
        }
        return res;
    }
}

6432. Count the Number of Complete Components

给你一个整数 n 。现有一个包含 n 个顶点的 无向 图,顶点按从 0 到 n - 1 编号。给你一个二维整数数组 edges 其中 edges[i] = [ai, bi] 表示顶点 ai 和 bi 之间存在一条 无向 边。

返回图中 完全连通分量 的数量。

如果在子图中任意两个顶点之间都存在路径,并且子图中没有任何一个顶点与子图外部的顶点共享边,则称其为 连通分量 。

如果连通分量中每对节点之间都存在一条边,则称其为 完全连通分量 。

测试样例

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

输出:3

解释:

所有分量都是完全连通分量。

解答:这道题目可以先利用并查集寻找出所有联通分量。由于条件:1 <= n <= 50,范围也是非常小。对每个联通分量暴力运算任意2定点是否有边就行了

class Solution {
    private class DSU{
        int[] parent;

        public DSU(int N) {
            parent = new int[N];
            for (int i = 0; i < N; ++i) {
                parent[i] = i;
            }
        }

        public int find(int x) {
            if (parent[x] != x) parent[x] = find(parent[x]);
            return parent[x];
        }

        public void union(int x, int y) {
            parent[find(x)] = find(y);
        }
    }

    public int countCompleteComponents(int n, int[][] edges) {
        DSU uf = new DSU(n);
        HashSet<Integer> edgeSet = new HashSet<>();
        for (int[] e : edges) {
            uf.union(e[0], e[1]);
            edgeSet.add(e[0] * 100 + e[1]);
            edgeSet.add(e[1] * 100 + e[0]);
        }
        List<Integer>[] connected = new List[n];
        for (int i = 0; i < n; ++i) {
            int p = uf.find(i);
            if (connected[p] == null) {
                connected[p] = new ArrayList<>();
            }
            connected[p].add(i);
        }

        int res = 0;
        for (int i = 0; i < n; ++i) {
            if (connected[i] != null) {
                boolean isFull = true;
                out:
                for (int l = 0; l < connected[i].size(); ++l) {
                    for (int r = l + 1; r < connected[i].size(); ++r) {
                        if (!edgeSet.contains(connected[i].get(l) * 100 + connected[i].get(r))) {
                            isFull = false;
                            break out;
                        }
                    }
                }
                if (isFull) {
                    ++res;
                }
            }
        }
        return res;
    }
}

着实究极手速场了。

Leave a Reply

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