图-dfs-连通分量-旋转变换-804. 不同岛屿的数量II

2020-04-04 18:25:18

问题描述:

给定一个01的非空的二维数组网格,一个岛是一个1(表示陆地)的组,4个方向(水平或垂直)连接。你可以假设网格的所有四条边都被水包围。
计算不同岛屿的数量。当一个岛被认为与另一个岛相同时,它们有相同的形状,或在旋转后的形状相同(90,180,或270度)或翻转(左/右方向或向上/向下方向)。

样例

Example 1:

Input: [[1,1,0,0,0],[1,0,0,0,0],[0,0,0,0,1],[0,0,0,1,1]]
Output: 1
Explanation:
The island is look like this:
11000
10000
00001
00011

Notice that:
11
1
and
 1
11
are considered same island shapes. Because if we make a 180 degrees clockwise rotation on the first island, then two islands will have the same shapes.

Example 2:

Input: [[1,1,1,0,0],[1,0,0,0,1],[0,1,0,0,1],[0,1,1,1,0]]
Output: 2
Explanation:
The island is look like this:
11100
10001
01001
01110

Here are the two distinct islands:
111
1
and
1
1

Notice that:
111
1
and
1
111
are considered same island shapes. Because if we flip the first array in the up/down direction, then they have the same shapes.

注意事项

每个维度在给定网格的长度不超过50

问题求解:

    public int numDistinctIslands2(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return 0;
        }
        int m = grid.length, n = grid[0].length;
        Set<String> res = new HashSet<>();

        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == 1) {
                    List<int[]> island = new ArrayList<>();
                    dfs(grid, i, j, island);
                    res.add(getUnique(island));
                }
            }
        }

        return res.size();
    }

    private void dfs(int[][]grid, int x, int y, List<int[]> island) {
        int m = grid.length, n = grid[0].length;

        island.add(new int[]{x, y});
        grid[x][y] = 0;

        int[] dirs = {-1, 0, 1, 0, -1};
        for (int i = 0; i < 4; ++i) {
            int nx = x + dirs[i];
            int ny = y + dirs[i + 1];
            if (nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] == 1) {
                dfs(grid, nx, ny, island);
            }
        }
    }

    private String getUnique(List<int[]> island) {
        List<String> sameIslands = new ArrayList<>();

        int[][] trans={{1, 1}, {1, -1}, {-1, 1}, {-1, -1}};

        for (int i = 0; i < 4; ++i) {
            List<int[]> l1 = new ArrayList<>(), l2 = new ArrayList<>();

            for (int[] is : island) {
                int x = is[0], y = is[1];
                l1.add(new int[]{x * trans[i][0], y * trans[i][1]});
                l2.add(new int[]{y * trans[i][0], x * trans[i][1]});
            }
            sameIslands.add(getStr(l1));
            sameIslands.add(getStr(l2));
        }

        Collections.sort(sameIslands);
        return sameIslands.get(0);
    }

    private String getStr(List<int[]> island) {

        Collections.sort(island, (int[] o1, int[] o2) -> o1[0] == o2[0] ? Integer.compare(o1[1], o2[1]) : Integer.compare(o1[0], o2[0]));

        StringBuilder sb = new StringBuilder();
        int x = island.get(0)[0], y = island.get(0)[1];

        for (int[] point : island) {
            sb.append((point[0] - x) + " " + (point[1] - y) + " ");
        }
        return sb.toString();
    }

  

原文地址:https://www.cnblogs.com/hyserendipity/p/12633097.html

时间: 2024-10-18 14:55:42

图-dfs-连通分量-旋转变换-804. 不同岛屿的数量II的相关文章

c2java 第7篇 图的连通分量,关节点和桥

图的连通分量,关节点和桥 ==== 对于有向图,我们称其一个子图是强连通分量,是指任意两点u,v, 都有两条路径u到v和v到u. 对于连通无向图,我门称其一个子图是双连通分量,是指任意两点u,v,存在一个圈包含u,v.与无向图相关联的还有关节点x,是指去掉x,图不连通:桥(u,v)是指去掉这条边,图不连通. 求解算法的要义在于首先要理解: 树边-前向边-后向边-交叉边 "Consider what happens when a depth-first search is performed on

hdu 2242 无向图/求用桥一分为二后使俩个bcc点权值和之差最小并输出 /缩点+2次新图dfs

题意如标题所述, 先无向图缩点,统计出每个bcc权,建新图,然后一遍dfs生成树,标记出每个点(新图)以及其子孙的权值之和.这样之后就可以dfs2来枚举边(原图的桥),更新最小即可. 调试了半天!原来是建老图时候链式前向星和新图的vector<vector< int>>俩种存图搞乱了!!!不可原谅!哎!愚蠢!愚不可及!提交后1A. 后来百度之后,发现说是用树形dp,看了代码解法,竟然和我的是一样的算法..原来这种算法可以叫树形dp...的确有点dp味道..不过感觉不太浓.. 以后多

Leetcode 200.岛屿的数量 - DFS、BFS

Leetcode 200 岛屿的数量: DFS利用函数调用栈保证了检索顺序, BFS则需要自己建立队列,把待检索对象按规则入队. class Solution { // DFS解法,8ms/10.7MB,99.7% / 92% public: /** * row,col: 坐标,以0开始. * 用row和col,而不是x,y. 否则容易写成grid[x][y],顺序不对!! */ void dfs_set_zero(vector<vector<char>>& grid, i

[LeetCode] 200. Number of Islands 岛屿的数量

Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by

[一个算法] 图DFS非递归实现

图的遍历方式当中DFS和BFS是两种主要的遍历方式.DFS主要是使用递归思想来实现的,BFS主要是使用队列来保存下面的节点.BFS的一个优势是不是非递归形式,所以栈溢出的可能性很小,相反DFS在这方面的限制比较大.因此,如何将DFS改为非递归形式意义重大. 如何将DFS变为非递归形式呢? 实际上,前面带了一个很大的帽子,对于DFS的非递归实现并不是非常的困难. 我们将访问到的节点因此放入到一个栈当中,并且标记这个节点为访问过,如果这个节点有孩子,判断其孩子还有被访问的情况下,将其一次亚茹栈当中.

算法系列之图--DFS

深度优先搜索使用的策略是,只要与可能就在图中尽量“深入”.DFS总是对最近才发现的结点v出发边进行探索,知道该结点的所有出发边都被发现为止.一旦v的所有出发边都被发现了,搜索就回溯到v的前驱结点(v是经该结点才被发现的),来搜索该前驱结点的出发边.该过程持续知道从源结点可以到达的所有结点都被发现为止.此后若还存在未被发现的结点,则DFS将从从未被发现的结点中任选一个结点作为新的源节点,并重复同样的过程. 还是老办法,上代码,可以清楚地解释: 1 #include <iostream> 2 #i

hdu 3639 Hawk-and-Chicken 【强连通分量+反向建图dfs】

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3639 题意:有n个人,m条边,每条边代表u给v投一票,票可以传递,比如A->B,B->C,这时C可以得到2票,求出得到最大票数的人有哪些. 分析:从一个强连通到另一个强连通分量的贡献为这两个强连通分量大小和减一.显然票数最大的人在图的端点. 将缩点后的图方向,可以得到一些入度为0的点,用DFS可以求出这些点的票数,最后去求出最大票数. 代码: <pre name="code"

图的连通分量(利用邻接表存储信息)

用vector实现邻接表 vector <int> G[100]; //表示有100个顶点的图的邻接表 G[u].push_back(v); //从顶点u 向顶点v 画边,即在相当于创建一个二维数组G[100][i] //搜索与顶点u 相邻的顶点v for( int i = 0; i < G[u].size(); i++) { int v = G[u][i]; ....... } 邻接表表示法的优点 只需与边数成正比的内存空间 邻接表表示法的缺点 (1)设u 的相邻顶点数量为n,那么在调

UVa 572 - Oil Deposits【图DFS】

Oil Deposits The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots. It