前言
寻找0 ,1矩阵中含有连续全1块的个数(岛的个数)和0, 1矩阵中最大连续的全1块。
定义
0 ,1矩阵中含有连续全1块的个数
一个矩阵中只有0和1两种值, 每个位置都可以和自己的上、 下、 左、 右
四个位置相连, 如果有一片1连在一起, 这个部分叫做一个岛, 求一个 矩阵中有多少个岛?
举例:
0 0 1 0 1 0
1 1 1 0 1 0
1 0 0 1 0 0
0 0 0 1 0 0
这个矩阵中有三个岛。即0, 1矩阵中最大连续的全1块有三个。
在全1块中1的个数最多的块定义为0,1矩阵的最大连续全1块,上述矩阵的最大全1块是5,下图给个明显的示例:
解题思路
0 ,1矩阵中含有连续全1块的个数
运用了一些递归的思想,首先是双层for循环逐个遍历矩阵的元素.找到某个元素为1的时候,利用递归的思想将这个元素的上下左右,和它相邻的为1的上下左右元素,和相邻的相邻的…. 这些元素改为0,最后返回num
package Exercises;
import java.util.Random;
/**
* ClassName findMaxOne
* Author Lin
* Date 2019/4/16 20:43
**/
public class findMaxOne {
// 共享成员变量,矩阵
static int[][] rect = null;
// 主函数
public static void main(String[] args) {
creatRect();
}
// 生成指定的随机矩阵,计算块数
private static void creatRect() {
// 设定矩阵的高和宽
int h = 12;
int w = 12;
// 生成指定随机矩阵int[i][j],并展示在控制台;将元素值为1的元素存入List,并展示在控制台
Random rdm = new Random();
rect = new int[h][w];
System.out.println("随机生成矩阵如下图:");
for (int i = 0; i < rect.length; i++) {
for (int j = 0; j < rect[i].length; j++) {
int k = rdm.nextInt(2);
rect[i][j] = k;
System.out.print(" " + rect[i][j]);
}
System.out.println();
}
System.out.println("开始进行计算");
// 开始计时
long time = System.currentTimeMillis();
// 计数
int count = 0;
// 遍历矩阵找1,块的定位
for (int i = 0; i < rect.length; i++) {
for (int j = 0; j < rect[i].length; j++) {
// 当找到1时,开始处理其所在的块
if (rect[i][j] == 1) {
block(i, j);
count++;
}
}
}
// 输出块数
// System.out.println("计算结束");
System.out.println("该矩阵中,共有" + count + "块");
// 输出计时结果
System.out.println("计算用时(ms):" + (System.currentTimeMillis() - time));
System.out.println("最终结果如下图:");
for (int i = 0; i < rect.length; i++) {
for (int j = 0; j < rect[i].length; j++) {
System.out.print(" " + rect[i][j]);
}
System.out.println();
}
}
// 判断连续块,递归
private static void block(int i, int j) {
// 修改(i,j)坐标对应的数组元素的值(避免递归时反复判断相邻元素)
rect[i][j] = 4;
/*System.out.println("结果如下图:");
for (int ii = 0; ii < rect.length; ii++) {
for (int jj = 0; jj < rect[ii].length; jj++) {
System.out.print(" " + rect[ii][jj]);
}
System.out.println();
}*/
// 分别判断上下左右
if (i < rect.length - 1 && rect[i + 1][j] == 1) {
block(i + 1, j);
}
if (i > 0 && rect[i - 1][j] == 1) {
block(i - 1, j);
}
if (j < rect[i].length - 1 && rect[i][j + 1] == 1) {
block(i, j + 1);
}
if (j > 0 && rect[i][j - 1] == 1) {
block(i, j - 1);
}
}
}
并查集思想
0,1矩阵的最大连续全1块
对矩阵做三次扫描, 扫描的次序都是从左到右,从上到下.第一遍将所有为1的元素,依次标一个值,这个值从1开始 例如:
0 0 0 0 0 // 0 0 0 0 0标注成这样
0 1 1 0 0 // 0 1 2 0 0
0 1 0 0 0 // 0 3 0 0 0
0 0 0 1 0 // 0 0 0 4 0
0 0 0 1 0 // 0 0 0 5 0
对应并查集的初始化:
if( nums[i][j] == 1){
Len[i][j]++;
Set[i][j] = index++;
}
第二遍 如果 遇到不为0 的元素, 考虑这个元素以及它周围四个元素中,不为0的元素标,求他们的最小值,并将这些元素通标注为这个最小值 像上面,遇到了1 那么将 2和3 标注成 1 。就变成下面这样
0 0 0 0 0
0 1 1 0 0
0 1 0 0 0
0 0 0 4 0
0 0 0 4 0
对应并查集的合并操作
if(Set[i[j] != Set[i+offsetx][j+offsety]){
if(Set[i][j] < Set[i+offsetx][j+offsety]){
Set[i+offsetx][j+offsety] = Set[i][j];
Len[i][j] += Len[i+offsetx][y+offsety];
}
else{
Set[i][j] = Set[i+offsetx][j+offsety];
Len[i+offsetx][y+offsety] += Len[i][j] ;
}
}
最后一遍 数一下各种数字的个数,最多的,就是最大全1子块的面积。(注,这样做,结果是连续的全1区域,很可能是不规则的)
Max = Math.max(Len[i[j], max);