消消乐算法

博客围绕二维数组炮弹打砖问题展开,给定nm维度二维数组和K2位置数组,1为砖0为空,炮弹打砖会使相连砖落下。采用并查集算法解决,设置父子树数组建立位置关联,每发炮弹重置天花板砖数,根据位置情况计算打落砖数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题
给定一个二维数组,nm维度和一个K2的位置数组,1表示砖,0表示空,用炮弹去打砖,打中砖会打碎来变为空,并且和它连着的砖也会落下来,问每发炮打落几块砖,返回每个位置的最佳结果值。

思想
并查集来做,通过设置父子书数组记录谁是谁的父节点将各个位置建立关联,每打一发炮弹就重置天花板砖数,然后查看是否是顶点位置如果是则返回差值,如果不是则继续下一位置。
并查集需要参数:
N:行
M:列
CellingAll:有多少块砖连到天花板上
Grid:原始矩阵,值会变
cellingSet:boolean矩阵true表示该位置是头节点,为天花板集合,false不是天花板集合。
FatherMap:每个位置他的头节点是谁(每个位置进行编号)
SizeMap:每个头节点集合大小
Stack:用来辅助查找父节点

代码

public class Code04_BricksFallingWhenHit {
	
	public static int[] hitBricks(int[][]gird,int[][] hits) {
		int N = hits.length;
		for(int i = 0;i<N;i++) {
			if(gird[hits[i][0]][hits[i][1]] == 1) {
				gird[hits[i][0]][hits[i][1]] = 2;
			}
		}
		int[] ans = new int[N];
		FindUnion findUnion = new FindUnion(gird);
		for(int i = N-1;i>=0;i--) {
			if(gird[hits[i][0]][hits[i][1]] == 2) {
				ans[i] = findUnion.finger(hits[i][0], hits[i][1]);
			}
		}
		return ans;
	}
	public static class FindUnion{
		private int N;
		private int M;
		private int cellingAll;
		private int[] fatherMap;
		private int[] sizeMap;
		private int[] stack;
		private boolean[] isFather;
		private int[][] grid;
		public FindUnion(int[][] matrix) {
			initSpace(matrix);
			inintConnect();
		}
		private void initSpace(int[][] matrix) {
			grid = matrix;
			N = grid.length;
			M = grid[0].length;
			int all = N * M;
			fatherMap = new int[all];
			sizeMap = new int[all];
			stack = new int[all];
			isFather = new boolean[all];
			for(int row = 0;row<N;row++) {
				for(int col = 0;col<M;col++) {
					int index = row * M + col;	
					if(row == 0) {
						fatherMap[index] = index;
						sizeMap[index] = 1;
						isFather[index] = true;
					}
				}
			}
		}
		private void inintConnect() {
			for(int row = 0;row<N;row++) {
				for(int col = 0;col<M;col++) {
					union(row,col,row+1,col);
					union(row,col,row-1,col);
					union(row,col,row,col+1);
					union(row,col,row,col-1);
				}
			}
		}
		private void union(int r1,int c1,int r2,int c2) {
			if(isVaild(r1,c1)&&isVaild(r2,c2)) {
				int father1 = find(r1,c1);
				int father2 = find(r2,c2);
				if(father1!=father2) {
					int size1 = sizeMap[father1];
					int size2 = sizeMap[father2];
					boolean status1 = isFather[father1];
					boolean status2 = isFather[father2];
					if(size1<size2) {
						fatherMap[father1] = father2;
						sizeMap[father2] = size1 + size2;
						if(status1^status2) {
							isFather[father2] = true;
							cellingAll += status1? size2:size1;
 						}
					}else {
						fatherMap[father2] = father1;
						sizeMap[father1] = size1 + size2;
						if(status1^status2) {
							isFather[father1] = true;
							cellingAll += status1? size2:size1;
						}
					}
				}
				
			}
		}
		private int find(int row,int col) {
			int index = row * M + col;
			int stacksize = 0;
			while(index!=fatherMap[index]) {
				stack[stacksize++] = index;
				index = fatherMap[index];
			}
			if(stacksize!=0) {
				fatherMap[stack[--stacksize]] = index;
			}
			return index;
		}
		private boolean isVaild(int r1,int c1) {
			return (r1>=0&&r1<N)&&(c1>=0&&c1<M)&&grid[r1][c1] == 1;
		}
		public int finger(int row,int col) {
			grid[row][col] = 1;
			int cur = row * M + col;
			if(row == 0 ) {
				cellingAll = 0;
				isFather[cur] = true;
			}
			fatherMap[cur] = cur;
			sizeMap[cur] = 1;
			int pre = cellingAll;
			union(row,col,row+1,col);
			union(row,col,row-1,col);
			union(row,col,row,col+1);
			union(row,col,row,col-1);
			int now = cellingAll;
			if(row == 0) {
				return now - pre;
			}else {
				return now == pre?0:now -pre -1;
			}
		}
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值