一、问题描述:
200岛屿数量
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,
并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。此外,你可以假设该网格的四条边均被水包围。
示例 1:输入:grid = [["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
输出:1
示例 2: 输入:grid = [["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
输出:3
提示: m == grid.length n == grid[i].length 1 <= m, n <= 300 grid[i][j] 的值为 '0' 或 '1'
二、题解:
思路1:
直接架构:
class Solution {
int[][] gridInt;
char[][] grid;
int flag;
Set<Integer> set;
public int numIslands(char[][] grid) {
this.grid = grid;
flag = 11;
set = new HashSet<>();
gridInt = new int[grid.length][];
for (int i = 0; i < grid.length; i++) {
gridInt[i] = new int[grid[i].length];
for (int j = 0; j < grid[i].length; j++) {
processGridInt(grid,gridInt,i,j);
}
}
return set.size() == 0 ? 0 : flag - 10;
}
private void processGridInt(char[][] grid, int[][] gridInt, int i, int j) {
if (grid[i][j] == '1'){
processGrid1(grid,gridInt,i,j);
}
}
private void processGrid1(char[][] grid, int[][] gridInt, int i, int j) {
if (gridInt[i][j] >= 11) return;
if (i > 0 ){
if ( gridInt[i - 1][j] >= 11) {
gridInt[i][j] = gridInt[i - 1][j];
return;
}
}
if (j > 0 ){
if (gridInt[i][j - 1] >= 11) {
gridInt[i][j] = gridInt[i][j - 1];
return;
}
}
if ( i + 1 < grid.length && gridInt[i + 1] != null){
if ( gridInt[i + 1][j] >= 11) {
gridInt[i][j] = gridInt[i + 1][j];
return;
}
}
if (j + 1 < grid[i].length ){
if (gridInt[i][j + 1] > 11) {
gridInt[i][j] = gridInt[i][j + 1];
return;
}
}
while (!set.add(flag)){
flag++;
}
gridInt[i][j] = flag;
}
}
不敢最后没通过:
就这个案例:
[["1","1","1"],
["0","1","0"],
["1","1","1"]]
后面再改进下发现还是没通过[["1","0","1","1","1"],["1","0","1","0","1"],["1","1","1","0","1"]]
,很难很难,类目了,现在是2023-03-27,这个题很难,很多边界,说难也不算难,就是很多情况要考虑。
再来:
题解1:
class Solution {
int[][] gridInt;
char[][] grid;
int flag;
Set<Integer> set;
public int numIslands(char[][] grid) {
this.grid = grid;
flag = 11;
set = new HashSet<>();
gridInt = new int[grid.length][];
for (int i = 0; i < grid.length; i++) {
if (gridInt[i] == null) gridInt[i] = new int[grid[i].length];
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == '1' && gridInt[i][j] < 11) processGridInt(i, j);
}
}
return set.size() == 0 ? 0 : flag - 10;
}
private void processGridInt(int i, int j) {
if (grid[i][j] == '0' || gridInt[i][j] >= 11) return;
if (i > 0) {
if (gridInt[i - 1][j] >= 11) {
gridInt[i][j] = gridInt[i - 1][j];
process1(i, j);
return;
}
}
if (j > 0) {
if (gridInt[i][j - 1] >= 11) {
gridInt[i][j] = gridInt[i][j - 1];
process1(i, j);
return;
}
}
if (i + 1 < grid.length) {
if (gridInt[i + 1] == null) gridInt[i + 1] = new int[grid[i + 1].length];
if (gridInt[i + 1][j] >= 11) {
gridInt[i][j] = gridInt[i + 1][j];
process1(i, j);
return;
}
}
if (j + 1 < grid[i].length) {
if (gridInt[i][j + 1] >= 11) {
gridInt[i][j] = gridInt[i][j + 1];
process1(i, j);
return;
}
}
while (!set.add(flag)) {
flag++;
}
gridInt[i][j] = flag;
process1(i,j);
}
private void process1(int i, int j) {
if (i > 0) processGridInt(i - 1, j);
if (j > 0) processGridInt(i, j - 1);
if (i + 1 < grid.length) {
if (gridInt[i + 1] == null) gridInt[i + 1] = new int[grid[i + 1].length];
processGridInt(i + 1, j);
}
if (j + 1 < grid[i].length) processGridInt(i, j + 1);
}
}
本地测试:
@Test
public void testSolution() {
String[][][] s = {
{{"1", "1", "1", "1", "0"}, {"1", "1", "0", "1", "0"}, {"1", "1", "0", "0", "0"}, {"0", "0", "0", "0", "0"}},//1
{{"1", "1", "0", "0", "0"}, {"1", "1", "0", "0", "0"}, {"0", "0", "1", "0", "0"}, {"0", "0", "0", "1", "1"}},//3
{{"1", "1", "1"}, {"0", "1", "0"}, {"1", "1", "1"}},//1
{{"1", "0", "1", "1", "1"}
, {"1", "0", "1", "0", "1"}
, {"1", "1", "1", "0", "1"}},//1
// {{},{},{},{}},
};
char[][][] arr = new char[s.length][][];
for (int i = 0; i < s.length; i++) {
arr[i] = new char[s[i].length][];
for (int j = 0; j < s[i].length; j++) {
arr[i][j] = new char[s[i][j].length];
for (int k = 0; k < s[i][j].length; k++) {
arr[i][j][k] = s[i][j][k].charAt(0);
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(Arrays.deepToString(arr[i]) + "` result is " + numIslands(arr[i]));
}
}
本地模拟acm模式:
就模拟牛客上面的输入输出例题吧:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
LinkedList<String[]> list = new LinkedList<>();
while (scanner.hasNext()){
String[] split = scanner.nextLine().split(",");
list.add(split);
}
char[][] grid = new char[list.size()][];
for (int i = 0; i < list.size(); i++) {
String[] strings = list.get(i);
grid[i] = new char[strings.length];
for (int j = 0; j < strings.length; j++) {
grid[i][j] = strings[j].charAt(0);
}
}
Solution solution = new Solution();
System.out.println(Arrays.deepToString(grid) + "` result is " + solution.numIslands(grid));
}
使用1和0来表示字符,每个符号用逗号隔开,因为循环条件为true时才可以不断读取字符,也就是说scanner.hasNext() == true
成立才会继续读取。那么不想继续读入字符就输入ctrl+d键即可,示例如下:
1,1,1,1,0
1,1,0,1,0
1,1,0,0,0
0,0,0,0,0^D
[[1, 1, 1, 1, 0], [1, 1, 0, 1, 0], [1, 1, 0, 0, 0], [0, 0, 0, 0, 0]]` result is 1
Process finished with exit code 0
换行结束也行:
1,1,1,1,0
1,1,0,1,0
1,1,0,0,0
0,0,0,0,0
^D
[[1, 1, 1, 1, 0], [1, 1, 0, 1, 0], [1, 1, 0, 0, 0], [0, 0, 0, 0, 0]]` result is 1
Process finished with exit code 0
有点慢,把全局变量改成局部变量吧:
class Solution {
int flag;
public int numIslands(char[][] grid) {
flag = 11;
Set<Integer> set = new HashSet<>();
int[][] gridInt = new int[grid.length][];
for (int i = 0; i < grid.length; i++) {
if (gridInt[i] == null) gridInt[i] = new int[grid[i].length];
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == '1' && gridInt[i][j] < 11) processGridInt(i, j, set, grid, gridInt);
}
}
return set.size() == 0 ? 0 : flag - 10;
}
private void processGridInt(int i, int j, Set<Integer> set, char[][] grid, int[][] gridInt) {
if (grid[i][j] == '0' || gridInt[i][j] >= 11) return;
if (i > 0) {
if (gridInt[i - 1][j] >= 11) {
gridInt[i][j] = gridInt[i - 1][j];
process1(i, j, set, grid, gridInt);
return;
}
}
if (j > 0) {
if (gridInt[i][j - 1] >= 11) {
gridInt[i][j] = gridInt[i][j - 1];
process1(i, j, set, grid, gridInt);
return;
}
}
if (i + 1 < grid.length) {
if (gridInt[i + 1] == null) gridInt[i + 1] = new int[grid[i + 1].length];
if (gridInt[i + 1][j] >= 11) {
gridInt[i][j] = gridInt[i + 1][j];
process1(i, j, set, grid, gridInt);
return;
}
}
if (j + 1 < grid[i].length) {
if (gridInt[i][j + 1] >= 11) {
gridInt[i][j] = gridInt[i][j + 1];
process1(i, j, set, grid, gridInt);
return;
}
}
while (!set.add(flag)) {
flag++;
}
gridInt[i][j] = flag;
process1(i, j, set, grid, gridInt);
}
private void process1(int i, int j, Set<Integer> set, char[][] grid, int[][] gridInt) {
if (i > 0) processGridInt(i - 1, j, set, grid, gridInt);
if (j > 0) processGridInt(i, j - 1, set, grid, gridInt);
if (i + 1 < grid.length) {
if (gridInt[i + 1] == null) gridInt[i + 1] = new int[grid[i + 1].length];
processGridInt(i + 1, j, set, grid, gridInt);
}
if (j + 1 < grid[i].length) processGridInt(i, j + 1, set, grid, gridInt);
}
}
不够快。
优化2:
优化了1ms,累死了
class Solution {
int flag;
public int numIslands(char[][] grid) {
flag = 11 + '0';
int n = 10 + '0';
Set<Integer> set = new HashSet<>();
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == '1' && grid[i][j] < n) processGridInt(i, j, set, grid,n);
}
}
return set.size() == 0 ? 0 : flag - 10 - '0';
}
private void processGridInt(int i, int j, Set<Integer> set, char[][] grid,int n) {
if (grid[i][j] == '0' || grid[i][j] > n) return;
if (i > 0) {
if (grid[i - 1][j] > n) {
grid[i][j] = grid[i - 1][j];
process1(i, j, set, grid,n);
return;
}
}
if (j > 0) {
if (grid[i][j - 1] > n) {
grid[i][j] = grid[i][j - 1];
process1(i, j, set, grid,n);
return;
}
}
if (i + 1 < grid.length) {
if (grid[i + 1][j] > n) {
grid[i][j] = grid[i + 1][j];
process1(i, j, set, grid,n);
return;
}
}
if (j + 1 < grid[i].length) {
if (grid[i][j + 1] > n) {
grid[i][j] = grid[i][j + 1];
process1(i, j, set, grid,n);
return;
}
}
while (!set.add(flag)) {
flag++;
}
grid[i][j] = (char) flag;
process1(i, j, set, grid,n);
}
private void process1(int i, int j, Set<Integer> set, char[][] grid,int n) {
if (i > 0) processGridInt(i - 1, j, set, grid,n);
if (j > 0) processGridInt(i, j - 1, set, grid,n);
if (i + 1 < grid.length) {
processGridInt(i + 1, j, set, grid,n);
}
if (j + 1 < grid[i].length) processGridInt(i, j + 1, set, grid,n);
}
}
差一点就到最优解了
应该是集合用得太多了,set集合内部排序也是有消耗得
再来:
优化3:
优化了1ms,已经累死了。
class Solution {
public int numIslands(char[][] grid) {
int myRes = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == '1' ) {
processGridInt(i, j, grid);
myRes++;
}
}
}
return myRes;
}
private void processGridInt(int i, int j, char[][] grid) {
if (grid[i][j] == '0' || grid[i][j] == '2') return;
if (i > 0) {
if (grid[i - 1][j] == '2') {
grid[i][j] = grid[i - 1][j];
process1(i, j, grid);
return;
}
}
if (j > 0) {
if (grid[i][j - 1] == '2') {
grid[i][j] = grid[i][j - 1];
process1(i, j,grid);
return;
}
}
if (i + 1 < grid.length) {
if (grid[i + 1][j] == '2') {
grid[i][j] = grid[i + 1][j];
process1(i, j, grid);
return;
}
}
if (j + 1 < grid[i].length) {
if (grid[i][j + 1] == '2') {
grid[i][j] = grid[i][j + 1];
process1(i, j, grid);
return;
}
}
grid[i][j] = '2';
process1(i, j, grid);
}
private void process1(int i, int j, char[][] grid) {
if (i > 0) processGridInt(i - 1, j, grid);
if (j > 0) processGridInt(i, j - 1, grid);
if (i + 1 < grid.length) {
processGridInt(i + 1, j, grid);
}
if (j + 1 < grid[i].length) processGridInt(i, j + 1, grid);
}
}
优化4(最优解):
class Solution {
char[][] grid;
public int numIslands(char[][] grid) {
this.grid = grid;
int myRes = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == '1'){
processGrid(i,j);
myRes++;
}
}
}
return myRes;
}
private void processGrid(int i, int j) {
if (i < 0 || i >= grid.length
|| j < 0 || j >= grid[i].length
|| grid[i][j] != '1') return;
grid[i][j] = '2';
processGrid(i,j + 1);//right
processGrid(i + 1,j);//down
processGrid(i,j - 1);//left
processGrid(i - 1,j);//up
}
}
end
ak