学习内容
778.水位上升的泳池中游泳
思路:
使用并查集.动用一个while循环,每次将水位不足某个特定值的数据进行合并.随后查询右下角的根值是否与左上角的相等,相等则跳出.
我的代码:
class Solution {public int swimInWater(int[][] grid) {int time=0;int h=grid[0].length;UnionFind unionFind=new UnionFind(grid.length*h);while(true){for (int i = 0; i < grid.length; i++) {for (int j = 0; j < h; j++) {if(grid[i][j]>time){continue;}int temp=i*h+j;if(i!=0&&grid[i-1][j]<=time){unionFind.Union(temp-h,temp);}if(i!= grid.length-1&&grid[i+1][j]<=time){unionFind.Union(temp,temp+h);}if(j!=0&&grid[i][j-1]<=time){unionFind.Union(temp-1,temp);}if(j!=h-1&&grid[i][j+1]<=time){unionFind.Union(temp,temp+1);}}}if(unionFind.parent[0]==unionFind.parent[grid.length*h-1]){break;}time++;}return time;}}class UnionFind{int[] parent;//int[] size;int n;//int sizeCount;public UnionFind(int n) {this.n = n;parent=new int[n];for (int i = 0; i < parent.length; i++) {parent[i]=i;}}public int findParent(int target){if(target==parent[target]){return target;}else{return findParent(parent[target]);}}public void Union(int a,int b){a=findParent(a);b=findParent(b);if(a!=b){parent[b]=a;}}}
结果:
超过时间限制
应该是不能使用多次的find_parent.
题目当中水位必定是从0开始,且必定是在最高点结束.
优解代码
public class Solution {private int N;public static final int[][] DIRECTIONS = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};public int swimInWater(int[][] grid) {this.N = grid.length;int len = N * N;// 下标:方格的高度,值:对应在方格中的坐标int[] index = new int[len];for (int i = 0; i < N; i++) {for (int j = 0; j < N; j++) {index[grid[i][j]] = getIndex(i, j);//将坐标放入高度的哈希表}}UnionFind unionFind = new UnionFind(len);for (int i = 0; i < len; i++) {int x = index[i] / N;int y = index[i] % N;for (int[] direction : DIRECTIONS) {int newX = x + direction[0];int newY = y + direction[1];if (inArea(newX, newY) && grid[newX][newY] <= i) {unionFind.union(index[i], getIndex(newX, newY));}if (unionFind.isConnected(0, len - 1)) {return i;}}}return -1;}private int getIndex(int x, int y) {return x * N + y;}private boolean inArea(int x, int y) {return x >= 0 && x < N && y >= 0 && y < N;}private class UnionFind {private int[] parent;public UnionFind(int n) {this.parent = new int[n];for (int i = 0; i < n; i++) {parent[i] = i;}}public int root(int x) {while (x != parent[x]) {parent[x] = parent[parent[x]];x = parent[x];}return x;}public boolean isConnected(int x, int y) {return root(x) == root(y);}public void union(int p, int q) {if (isConnected(p, q)) {return;}parent[root(p)] = root(q);}}}
心得
1.将二维数组缓存为一维数组有利于减少遍历时的内存耗费
2.尽量减少在循环内部的运算,比较.
3.并查集的最终并不是要求内部的值为同一个,而是要求root(a)==root(b)即可
4.这个方法只需要双重循环的要点是其只关注目前最小高度的那个点,刚好可以将高度最低的几个点连接在一起.我的三重循环方法,虽然会在有重复权值的平台高度的情况下有优势,但是很可惜这里没有涉及.
