算法——海岛问题

题目:海岛面积计算题,给一个矩阵,0表示还睡,相连的1表示海岛,上下左右表示相连。
要求:
(0)求有几座岛
(1)求最大海岛的面积
(2)求最大海岛的面积和对应海岛的所有坐标
(3)求所有海岛的所有坐标,按海岛分。

这道题首先就是要求海岛,我们可以用一个感染思想,当读到的坐标为1的时候,就把他改为2,然后以这个坐标做递归,把他周围所有的1都改为2,然后计数器+1,就能把第一题解决了。
我们设计一个结构,有areas代表海岛面积,每次把1修改为2的时候+1;index代表这一座岛的编号证明是同一座岛;islandIndex为一个String的list,存于存储海岛的坐标。有了这个结构,后三道题也就解决了。

import java.util.ArrayList;
import java.util.List;

public class Island {

	static class IslandNode {
		public IslandNode(int areas) {
			this.areas = areas;
			this.index = 0 + "";
		}

		@Override
		public String toString() {
			return areas + "-" + index;
		}

		int areas;
		String index;
		List<String> islandIndex = new ArrayList<>();
	}

	static List<IslandNode> list = new ArrayList<IslandNode>();

	public static int countIslands(int[][] arr) {

		int row = arr.length;// hang
		int col = arr[0].length;// lie
		int res = 0;
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < col; j++) {
				if (arr[i][j] == 1) {
					res++;
					IslandNode node = new IslandNode(0);
					infaction(arr, i, j, row, col, node);
				}
			}
		}
		return res;
	}

	private static void infaction(int[][] arr, int i, int j, int row, int col, IslandNode node) {
		if (i < 0 || j < 0 || i >= row || j >= col || arr[i][j] != 1) {
			return;
		}
		arr[i][j] = 2;
		// 海岛面积+1
		node.areas++;
		// 保存海岛的坐标
		node.islandIndex.add("(" + i + "," + j + ")");
		// 判断这个海岛是否是第一次找到,我们初始海岛标记为0的字符串
		if (node.index.equals("0")) {
			// 修改海岛坐标,根据你数据量可以调整随机数的范围,这里取值范围是1-10
			node.index = (int) (Math.random() * 10 + 1) + "";
			// 将这个海岛的相应数据保存到一个全局list
			list.add(node);
		}
		infaction(arr, i + 1, j, row, col, node);
		infaction(arr, i - 1, j, row, col, node);
		infaction(arr, i, j + 1, row, col, node);
		infaction(arr, i, j - 1, row, col, node);
	}

	/**
	 * 获得最大岛面积
	 * 
	 * @param nodes
	 * @return
	 */
	public static int maxIslandAreas(List<IslandNode> nodes) {
		int maxx = Integer.MIN_VALUE;
		for (IslandNode islandNode : nodes) {
			if (islandNode.areas > maxx) {
				maxx = islandNode.areas;
			}
		}
		return maxx;
	}

	/**
	 * 获得最大岛面积和对应坐标
	 * 
	 * @param nodes
	 * @return
	 */
	public static String maxIsland(List<IslandNode> nodes) {
		int maxx = Integer.MIN_VALUE;
		List<String> areaIndex = null;
		for (IslandNode islandNode : nodes) {
			if (islandNode.areas > maxx) {
				maxx = islandNode.areas;
				areaIndex = islandNode.islandIndex;
			}
		}
		return "最大岛面积:" + maxx + ",对应坐标:" + areaIndex;
	}

	/**
	 * 获得所有岛和岛面积
	 * 
	 * @param nodes
	 */
	public static void getIslands(List<IslandNode> nodes) {
		for (IslandNode islandNode : nodes) {
			System.out.println("岛面积:" + islandNode.areas + ",岛坐标:" + islandNode.islandIndex);
		}
	}

	public static void main(String[] args) {
		int[][] m1 = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0
				{ 0, 1, 1, 1, 0, 1, 1, 1, 0 }, // 1
				{ 0, 1, 1, 1, 0, 0, 0, 1, 0 }, // 2
				{ 0, 1, 1, 0, 0, 0, 0, 0, 0 }, // 3
				{ 0, 0, 0, 0, 0, 1, 1, 0, 0 }, // 4
				{ 0, 0, 0, 0, 1, 1, 1, 0, 0 }, // 5
				{ 0, 0, 0, 0, 0, 0, 0, 0, 0 }, };// 6
		System.out.println("==================第零题==================");
		System.out.println("一共有:" + countIslands(m1) + "座岛");
		System.out.println("==================第一题==================");
		System.out.println("最大岛面积:" + maxIslandAreas(list));
		System.out.println("==================第二题==================");
		System.out.println(maxIsland(list));
		System.out.println("==================第三题==================");
		getIslands(list);
	}
}

对应输出如下:

==================第零题==================
一共有:3座岛
==================第一题==================
最大岛面积:8
==================第二题==================
最大岛面积:8,对应坐标:[(1,1), (2,1), (3,1), (3,2), (2,2), (1,2), (1,3), (2,3)]
==================第三题==================
岛面积:8,岛坐标:[(1,1), (2,1), (3,1), (3,2), (2,2), (1,2), (1,3), (2,3)]
岛面积:4,岛坐标:[(1,5), (1,6), (1,7), (2,7)]
岛面积:5,岛坐标:[(4,5), (5,5), (5,6), (4,6), (5,4)]

进阶

题目不变,要求变为用多台机器来解决这个问题,那么最主要的问题就在于怎么合并每台机器的数据了。
分治思想,首先还是用感染思想,先找到每个板块的岛数量,并且每一座岛需要有一个唯一标识来区别。然后合并的时候,就只需要看边界,我们先以两台机器为例。
在这里插入图片描述
如上图,一个颜色代表一座岛,首先各自找到自己的数据中有几座岛,左边区域有5座岛,右边区域有1座岛,都有自己的唯一标识(这里假设用ABCDEF标识)。

然后就开始比较边界,这里只需要比较左区域的右边界,右区域的左边界。从上往下找,找到左区域的第一个1,并读取标识,然后去右区域找第一个1读取标识。发现他们是连着的,那么记录一下他们的标识,然后岛的数量-1,然后往下找,当找到B的时候,发现右区域的D连着,那么总岛数-1,再继续往下看到C ,并没有相连,所以继续往下走。所以最后得出一共有4座岛。

在比较边界的时候,第一次AD查重的时候数量-1了,如果往下找,发现还是AD相连,就不用再-1了,就像下图这种情况。也就是说我们需要把AD放到一个集合里面,每次需要做一个判断来确定是否-1。
在这里插入图片描述
这种题可以用一种叫做并查集的结构来处理,会相当方便。后面再补并查集的说明吧

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值