岛屿的个数12 · Number of Islands12
[抄题]:
给一个01矩阵,求不同的岛屿的个数。
0代表海,1代表岛,如果两个1相邻,那么这两个1属于同一个岛。我们只考虑上下左右为相邻。
[
[1, 1, 0, 0, 0],
[0, 1, 0, 0, 1],
[0, 0, 0, 1, 1],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 1]
]
[暴力解法]:
时间分析:
空间分析:
[思维问题]:
[一句话思路]:
找到一个岛,用dfs沉没一片岛。
[输入量]:空: 正常情况:特大:特小:程序里处理到的特殊情况:异常情况(不合法不合理的输入):
[画图]:
[一刷]:
- for (i = 0; i < n; i++)留头去尾,保持n个数,真要理解
- DFS的循环退出条件中,边界条件在前 作为前提 先控制,题目自身的循环条件后控制
- 数组的length不要括号,别顺手敲成习惯了
[二刷]:
[三刷]:
[四刷]:
[五刷]:
[五分钟肉眼debug的结果]:
[总结]:
[复杂度]:Time complexity: O(m*n)每个点触及1次 Space complexity: O(m* n)
一般情况下每个点都要找,为n
压缩情况下仅保存终点,为1 。
本来都是爷爷传给爸爸,现在爸爸直接指向祖宗,不用再爷爷传给爸爸了。
[英文数据结构或算法,为什么不用别的数据结构或算法]:
DFS
[关键代码]:
if (i < 0 || j< 0 || i >= n || j >= m || grid[i][j] != true) {//qiatouquwei,youxianhou
return ;
}
//dfs
grid[i][j] = false;
dfs(grid, i + 1, j);
dfs(grid, i - 1, j);
dfs(grid, i, j + 1);
dfs(grid, i, j - 1);
先退出,再扩展
[其他解法]:
bfs,union find
[Follow Up]:
[LC给出的题目变变变]:
[代码风格] :
public class Solution { private int n;
private int m; public int numIslands(char[][] grid) {
int count = 0;
n = grid.length;
if (n == 0) return 0;
m = grid[0].length;
for (int i = 0; i < n; i++){
for (int j = 0; j < m; j++)
if (grid[i][j] == '1') {
DFSMarking(grid, i, j);
++count;
}
}
return count;
} private void DFSMarking(char[][] grid, int i, int j) {
if (i < 0 || j < 0 || i >= n || j >= m || grid[i][j] != '1') return;
grid[i][j] = '0';
DFSMarking(grid, i + 1, j);
DFSMarking(grid, i - 1, j);
DFSMarking(grid, i, j + 1);
DFSMarking(grid, i, j - 1);
}
}
[抄题]:
给定 n,m,分别代表一个2D矩阵的行数和列数,同时,给定一个大小为 k 的二元数组A。起初,2D矩阵的行数和列数均为 0,即该矩阵中只有海洋。二元数组有 k 个运算符,每个运算符有 2 个整数 A[i].x, A[i].y,你可通过改变矩阵网格中的A[i].x],[A[i].y] 来将其由海洋改为岛屿。请在每次运算后,返回矩阵中岛屿的数量。
给定 n
= 3
, m
= 3
, 二元数组 A = [(0,0),(0,1),(2,2),(2,1)]
.
返回 [1,1,2,2]
.
[暴力解法]:
时间分析:
空间分析:
[思维问题]:
(单一责任原则)用一个函数功能处理完所有数据,再用下一个函数功能处理所有数据。
需要把二维坐标转换为一维节点,才能用并查集,这一步没想到。
用island[x][y] 标记某小岛是否出现过,若第一次出现则标记为1。棋盘形的题可以用数组标记1表示某元素是否出现过,以前做过但是没总结,忘了。
[一句话思路]:
用union find,不重复地添加其周围的岛。
[输入量]:空: 正常情况:特大:特小:程序里处理到的特殊情况:异常情况(不合法不合理的输入):
[画图]:
应该用big father合并,防止节点从属关系的丢失
[一刷]:
- UnionFind中的UnionFind方法的目的是预处理,把所有的二维节点生成一维id,放在hashmap中等待查询。需要把二维坐标转换为一维节点,才能用并查集,这一步没有理解其意义。
[二刷]:
[三刷]:
[四刷]:
[五刷]:
[五分钟肉眼debug的结果]:
[总结]:
棋盘形的题可以用数组标记1表示某元素是否出现过,如果不是岛,变成岛并且统计四周的扩展。
[复杂度]:Time complexity: O(最坏m*n每个点都是*4*1) Space complexity: O(m*n)
[英文数据结构或算法,为什么不用别的数据结构或算法]:
- class是关键字 一般新定义的类要用,Class是一个单独的包
- uf.compressed_find(id); 由于系统import的包中没有需要的类,就自己写了个unifind class,新方法也是新类自带的,系统没有,所以要指明所属的类。
[关键模板化代码]:
for (int j = 0; j < 4; j++) {
int nx = x + dx[j];
int ny = y + dy[j];
if (0 <= nx && nx < n && 0 <= ny && ny < m
&& islands[nx][ny] == 1) {
棋盘图向四周扩展
[其他解法]:
[Follow Up]:
[LC给出的题目变变变]:
721. Accounts Merge 邮件合并
[代码风格] :
/**
* Definition for a point.
* class Point {
* int x;
* int y;
* Point() { x = 0; y = 0; }
* Point(int a, int b) { x = a; y = b; }
* }
*/ public class Solution {
/*
* @param n: An integer
* @param m: An integer
* @param operators: an array of point
* @return: an integer array
*/
//covertToID
public int covertToID (int x, int y, int m) {
return x * m + y;
} class UnionFind {//xiaoxie
HashMap<Integer, Integer> father = new HashMap<>();
//find, pre-storage for m * n
UnionFind(int n, int m) {//n first m second
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
int id = covertToID(i, j, m);
father.put(id, id);
}
}
}
//compressed_find
int compressed_find (int x) {
//find ultimate parent
int parent = father.get(x);
while (parent != father.get(parent)) {
parent = father.get(parent);
}
//covert the grandfather to ultimate parent
int temp = -1;
int fa = x;
while (fa != father.get(fa)) {
temp = father.get(fa);
father.put(fa, parent);
fa = temp;
}
return parent;
}
//union
void union(int x, int y) {
int fa_x = compressed_find(x);
int fa_y = compressed_find(y);
if (fa_x != fa_y) {
father.put(fa_x, fa_y);
}
}
}
public List<Integer> numIslands2(int n, int m, Point[] operators) {
List<Integer> ans = new ArrayList<Integer>();
//corner case
if (operators == null) {
return ans;
}
int[] dx = {0, 1, 0, -1};
int[] dy = {1, 0, -1, 0};
int count = 0;
int[][] islands = new int[n][m];
UnionFind uf = new UnionFind(n, m);
//for lop
for (int i = 0; i < operators.length; i++) {
//get an island from list
int x = operators[i].x;
int y = operators[i].y;
//check whether is not island before, but is island now
if (islands[x][y] != 1) {
int id = covertToID(x, y, m);
islands[x][y] = 1;
count++;
//expand to check
for (int j = 0; j < 4; j++) {
int nx = x + dx[j];
int ny = y + dy[j];
int nid = covertToID(nx, ny, m);
if (0 <= nx && nx < n && 0 <= ny && ny < m
&& islands[nx][ny] == 1) {
int fa = uf.compressed_find(id);//new obeject's method
int nfa = uf.compressed_find(nid);
if (fa != nfa) {
uf.union(id, nid);
count--;
}
}
}
}
ans.add(count);
}
return ans;
}
}
[抄题]:
A 2d grid map of m
rows and n
columns is initially filled with water. We may perform an addLand operation which turns the water at position (row, col) into a land. Given a list of positions to operate, count the number of islands after each addLand operation. 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 water.
Example:
Input: m = 3, n = 3, positions = [[0,0], [0,1], [1,2], [2,1]]
Output: [1,1,2,3] 加点,返回岛屿个数
[暴力解法]:
时间分析:
空间分析:
[优化后]:
时间分析:
空间分析:
[奇葩输出条件]:
[奇葩corner case]:
向四周添加的时候,可能会出现x y 超出范围或者之前没有岛屿的情况,要注意
[思维问题]:
[英文数据结构或算法,为什么不用别的数据结构或算法]:
[一句话思路]:
roots[root] = root; 靠一个id数组不断合并,每次合并都返回count
[输入量]:空: 正常情况:特大:特小:程序里处理到的特殊情况:异常情况(不合法不合理的输入):
[画图]:
[一刷]:
- m行 n列,x表示行数 不超过m,y表示列数 不超过n
[二刷]:
find函数,不管是否用路径压缩,都用的是while循环,表示从x结点搜索到祖先结点所经过的结点都指向该祖先结点
public int find (int id, int[] roots) {
while (id != roots[id])
id = roots[roots[id]];
return id;
}
[三刷]:
[四刷]:
[五刷]:
[五分钟肉眼debug的结果]:
[总结]:
简化版的精髓就是:由root找next_id,由next_id找real_root(三连击),然后一言不合就合并。
[复杂度]:Time complexity: O(n) Space complexity: O(n)
[算法思想:迭代/递归/分治/贪心]:
[关键模板化代码]:
[其他解法]:
[Follow Up]:
[LC给出的题目变变变]:
[代码风格] :
[是否头一次写此类driver funcion的代码] :
// package whatever; // don't place package name! import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.lang.*; class MyCode {
public static void main (String[] args) {
int [][]positions = {{0, 0},{0, 1},{1, 2},{2, 1}};
int m = 3, n = 3;
Solution rst = new Solution();
System.out.println(rst.numIslands2(m, n, positions));
}
} class Solution {
int[][] dirs = {{0, 1},{0, -1},{1, 0},{-1, 0}}; public ArrayList<Integer> numIslands2(int m, int n, int[][] positions) {
//ini
int count = 0;
int[] roots = new int[m * n];
ArrayList<Integer> result = new ArrayList<Integer>();
Arrays.fill(roots, -1); //cc
if (m <= 0 || n <= 0 || positions == null) return result; //one island
for (int[] pos : positions) {
int root = n * pos[0] + pos[1];
roots[root] = root;
count++; for (int[] dir : dirs) {
int nx = pos[0] + dir[0];
int ny = pos[1] + dir[1];
int next_id = nx * n + ny; if (nx < 0 || nx >= m || ny < 0 || ny >= n || roots[next_id] == -1) continue;//?
int real_root = find(next_id, roots);//find next
if(real_root != root) {
roots[root] = real_root;
root = real_root;
count--;
}
}
result.add(count);
} return result; } public int find (int id, int[] roots) {
while (id != roots[id])
id = roots[roots[id]];
return id;
}
}
import java.util.*;
import java.lang.*;
[台词]:
for this problem we have to do it with UnionFind, since this is a dynamic process to add all the island, and we need to return the number of islands during the process.
if we still use DFS (sinking method), then for every new island, we need to do the DFS again (O(mn)), as if we never had any information before.
but if we use UionFind, we could optimize the process to O(1), because we already stored the information about already existing islands.
real_root不同,但是可以合并成为同一组。
Then when we merge two cells belong to previously separated components, count—.
x coordinate
岛屿的个数12 · Number of Islands12的更多相关文章
- 岛屿的个数12 · Number of Islands 12
[抄题]: [思维问题]: [一句话思路]: [输入量]:空: 正常情况:特大:特小:程序里处理到的特殊情况:异常情况(不合法不合理的输入): [画图]: [一刷]: [二刷]: [三刷]: [四刷] ...
- LintCode 433. 岛屿的个数(Number of Islands)
LintCode 433. 岛屿的个数(Number of Islands) 代码: class Solution: """ @param grid: a boolean ...
- [Swift]LeetCode305. 岛屿的个数 II $ Number of Islands II
A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand oper ...
- LeetCode 200. 岛屿的个数(Number of Islands)
题目描述 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量.一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的.你可以假设网格的四个边均被水包围. 示例 1 ...
- [LeetCode] Number of Distinct Islands II 不同岛屿的个数之二
Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) conn ...
- [LeetCode] Number of Distinct Islands 不同岛屿的个数
Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) conn ...
- [LeetCode] 711. Number of Distinct Islands II 不同岛屿的个数之二
Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) conn ...
- [LeetCode] 694. Number of Distinct Islands 不同岛屿的个数
Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) conn ...
- lintcode:Number of Islands 岛屿的个数
题目: 岛屿的个数 给一个01矩阵,求不同的岛屿的个数. 0代表海,1代表岛,如果两个1相邻,那么这两个1属于同一个岛.我们只考虑上下左右为相邻. 样例 在矩阵: [ [1, 1, 0, 0, 0], ...
随机推荐
- SoftMax多分类器原理及代码理解
关于多分类 我们常见的逻辑回归.SVM等常用于解决二分类问题,对于多分类问题,比如识别手写数字,它就需要10个分类,同样也可以用逻辑回归或SVM,只是需要多个二分类来组成多分类,但这里讨论另外一种方式 ...
- PyQt5 中调用MySql接口失败 ( QSqlDatabase 组件) 在Linux环境下如何修改
最近在跑下面这么一个代码,怎么跑都无法连通服务器,如下: # -*- coding: utf-8 -*- ''' [简介] PyQt5中 处理database 例子 ''' import sys fr ...
- Jmeter-线程组执行顺序控制
线程组按顺序来执行,大概思路, 1.需要控制线程组内的操作在满足某一条件才执行,那么就需要使用if或者while: 2.要使用if或者while都需要一个变量,而这个变量要在两个或多个线程组内使用,那 ...
- .NET4.0中使用4.5中的 async/await 功能实现异步
在.NET Framework 4.5中添加了新的异步操作库,但是在.NET Framework 4.0中却无法使用.这时不免面临着抉择,到底是升级整个解决方案还是不使用呢? 如果你的软件还没发布出去 ...
- Hystrix已经停止开发,官方推荐替代项目Resilience4j
随着微服务的流行,熔断作为其中一项很重要的技术也广为人知.当微服务的运行质量低于某个临界值时,启动熔断机制,暂停微服务调用一段时间,以保障后端的微服务不会因为持续过负荷而宕机.本文介绍了新一代熔断器R ...
- [C++ Primer] 第3章: 字符串, 向量和数组
标准库类型string string初始化 string s2(s1); string s2 = s1; string s3("value"); string s3 = " ...
- OpenLTE安装教程
安装需求: USB3 interface Modern multicore CPU (Intel Core i5, Core i7 or equivalent with SSE4.1 SSE4.2 a ...
- web常用测试点记录
输入框 1.字符型输入框: 单行文本输入框:英文全角.英文半角.数字.空或者空格.特殊字符“~!@#¥%……&*?[]{}”,特别要注意单引号和&符号.如果禁止直接输入特殊字符时,使用 ...
- ASP.NET 执行bat文件。
参考代码: http://blog.csdn.net/youngivan/article/details/7722384 在VS开发环境上是 网站应用程序能够正常执行bat,在winServer服务器 ...
- gmake与make的区别
gnu make在linux下一般是叫make但是如果是在其他的unix系统下,因为有一个原生的makegnu make就改个名字叫gmake了.就这们简单 当port一个老的unix程序,如老的Su ...