leetcode
leetcode 2651 ~ 2700
由斜杠划分区域

由斜杠划分区域

难度:

标签:

题目描述

An n x n grid is composed of 1 x 1 squares where each 1 x 1 square consists of a '/', '\', or blank space ' '. These characters divide the square into contiguous regions.

Given the grid grid represented as a string array, return the number of regions.

Note that backslash characters are escaped, so a '\' is represented as '\\'.

 

Example 1:

Input: grid = [" /","/ "]
Output: 2

Example 2:

Input: grid = [" /","  "]
Output: 1

Example 3:

Input: grid = ["/\\","\\/"]
Output: 5
Explanation: Recall that because \ characters are escaped, "\\/" refers to \/, and "/\\" refers to /\.

 

Constraints:

  • n == grid.length == grid[i].length
  • 1 <= n <= 30
  • grid[i][j] is either '/', '\', or ' '.

代码结果

运行时间: 53 ms, 内存: 16.2 MB


/*
 * 思路:
 * 使用与Java解法相同的并查集思想,但利用Java Stream API来进行部分操作。
 * 由于并查集的操作本质上是基于数组的操作,使用Stream处理会稍显复杂,这里演示部分Stream用法。
 */

import java.util.stream.IntStream;

class Solution {
    public int regionsBySlashes(String[] grid) {
        int n = grid.length;
        int size = 4 * n * n;
        UnionFind uf = new UnionFind(size);

        IntStream.range(0, n).forEach(i -> {
            IntStream.range(0, n).forEach(j -> {
                int index = 4 * (i * n + j);
                char c = grid[i].charAt(j);

                if (c == '/') {
                    uf.union(index, index + 3);
                    uf.union(index + 1, index + 2);
                } else if (c == '\\') {
                    uf.union(index, index + 1);
                    uf.union(index + 2, index + 3);
                } else { // ' '
                    uf.union(index, index + 1);
                    uf.union(index + 1, index + 2);
                    uf.union(index + 2, index + 3);
                }

                if (j + 1 < n) {
                    uf.union(index + 1, index + 4 + 3);
                }
                if (i + 1 < n) {
                    uf.union(index + 2, index + 4 * n);
                }
            });
        });

        return uf.getCount();
    }

    class UnionFind {
        int[] parent;
        int count;

        public UnionFind(int n) {
            parent = IntStream.range(0, n).toArray();
            count = n;
        }

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

        public void union(int x, int y) {
            int rootX = find(x);
            int rootY = find(y);
            if (rootX != rootY) {
                parent[rootX] = rootY;
                count--;
            }
        }

        public int getCount() {
            return count;
        }
    }
}

解释

方法:

该题解使用并查集(Union Find)算法来解决问题。思路是将每个小方格的四个角视为独立的点,通过斜线将这些点连接起来。如果两个点被同一条斜线连接,则它们属于同一个区域。为了处理边界情况,将网格的四条边界也视为被连接起来的。遍历整个网格,根据斜线的位置将点进行合并,如果发现两个点已经在同一个集合中,则说明形成了一个新的区域。

时间复杂度:

O(n^2α(n))

空间复杂度:

O(n^2)

代码细节讲解

🦆
如何理解这个问题中每个小方格的四个角被视为独立点,并通过斜线连接的处理方式?这种处理对解题有什么帮助?
在这个问题中,每个小方格被视为由其四个角(左上、右上、左下、右下)组成的独立单元。将这些角视为独立点可以帮助我们更准确地模拟斜线如何将空间分割成不同的区域。斜线连接了某两个角点,将这两个点视为相连的一部分。这种处理方式允许我们使用并查集数据结构来有效地管理和查找哪些点是通过斜线直接或间接相连的。具体来说,通过这种方式,每次插入斜线时,我们只需考虑连接或合并两个角点的集合,这样可以简化问题的空间和逻辑复杂度,使得问题变得更易解决。
🦆
并查集中的路径压缩技术是如何具体实现的?这种方法对提高算法性能有什么影响?
路径压缩是并查集优化技术中的一种。在执行 find 操作时,路径压缩技术确保每个节点直接指向其根节点。这是通过在 find 函数中,当我们递归地查找一个节点的根节点时,将该节点及其所有祖先节点直接链接到根节点上实现的。在代码中,每次我们查找节点的根时,我们遍历该节点到根节点的路径,并更新路径上所有节点的父节点为根节点。这种方法显著减少了查找根节点的时间,因此在执行多次 union 和 connected 操作时,可以大幅提高并查集的效率。整体上,路径压缩将 find 操作的平摊时间复杂度降低到接近 O(1),极大地提高了数据结构的性能。
🦆
题解中提到,如果两个点已经在同一个集合中,则形成一个新的区域。这种情况是如何在代码中检测和处理的?
在题解中,检测两个点是否在同一个集合中是通过并查集的 connected 方法实现的。当我们尝试通过斜线连接网格中两个角点时,首先使用 connected 方法检查这两个点是否已经属于同一个集合。如果是,这意味着在连接这两个点之前,它们已经通过其他路径被连接,因此连接这两个点将会形成一个封闭区域,即形成一个新的区域。代码中对此情况的处理是,如果 connected 方法返回 true,表示这两个点已经连接,我们就将区域数量 num_area 增加 1。然后继续执行后续的连接操作,或者遍历其他的斜线。这样能确保我们正确计算了由斜线引起的所有区域的数量。

相关问题