[Leetcode934]最短的桥
1.题目
给你一个大小为 n x n
的二元矩阵 grid
,其中 1
表示陆地,0
表示水域。
岛 是由四面相连的 1
形成的一个最大组,即不会与非组内的任何其他 1
相连。grid
中 恰好存在两座岛 。
你可以将任意数量的 0
变为 1
,以使两座岛连接起来,变成 一座岛 。
返回必须翻转的 0
的最小数目。
示例 1:
输入:grid = [[0,1],[1,0]]
输出:1
示例 2:
输入:grid = [[0,1,0],[0,0,0],[0,0,1]]
输出:2
示例 3:
输入:grid = [[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]]
输出:1
提示:
n == grid.length == grid[i].length
2 <= n <= 100
grid[i][j]
为0
或1
grid
中恰有两个岛
2.思路
本题的思路为使用并查集划分岛屿,及使用广度搜索找到2个岛的路径。
2.1 并查集的实现
2.1.1 初始化
初始时,每个元素都位于一个单独的集合,表示为一棵只有根节点的树。方便起见,我们将根节点的父亲设为自己。
public void init(int nums[])
{
int length=nums.length;
for(int i=0;i<length;i++)
nums[i]=i;
}
2.1.2 合并
如果两个元素原先是在两个不同集合,经过判断是在同一个集合,则需要将两个集合进行合并。Notes:合并需要改动他们的根节点的指向即可,否则单纯改动叶子结点会成环。
public void union(int nums[],int m,int n)//合并
{
find(n,nums)=find(m,nums);
}
2.1.3 查询
找到集合中的根节点,查询过程中经过的每个元素都属于该集合,我们可以将其直接连到根节点以加快后续查询。
public int find(int n,int nums[])//查询
{
return n==nums[n] ? n:(nums[n]=find(nums[n],nums));
}
2.2 广度搜索
需要设置每个元素是否有被遍历,及一个初始值为岛1的队列,从岛1出发找到岛2的值,找到即停止,返回路径最小值。在广度遍历的过程中,将遍历的值加入队列。并更新到达这个值的距离。
//BFS
int min=0;
while(!List1.isEmpty())
{
int index=List1.poll();
int i=index/len;
int j=index%len;
if((j+1)<len && fw[i][j+1] == false)
{
int a=i*len+j+1;
List1.offer(i*len+j+1);
dis[i][j+1]=dis[i][j]+1;
fw[i][j+1]=true;
if(List2.indexOf(a)!=-1)
{
System.out.println("j+1:"+i+j);
return dis[i][j+1]-1;
}
}
if((i+1)<len && fw[i+1][j] == false)
{
int a=(i+1)*len+j;
List1.offer((i+1)*len+j);
dis[i+1][j]=dis[i][j]+1;
fw[i+1][j]=true;
if(List2.indexOf(a)!=-1)
{
System.out.println("i+1:"+i+j);
return dis[i+1][j]-1;
}
}
if((i-1)>=0 && fw[i-1][j]==false)
{
int a=(i-1)*len+j;
List1.offer(a);
fw[i-1][j]=true;
dis[i-1][j]=dis[i][j]+1;
if(List2.indexOf(a)!=-1)
{
System.out.println("i-1:"+i+j);
return dis[i-1][j]-1;
}
}
if((j-1)>=0 && fw[i][j-1]==false)
{
int a=i*len+j-1;
fw[i][j-1]=true;
List1.offer(i*len+j-1);
dis[i][j-1]=dis[i][j]+1;
if(List2.indexOf(a)!=-1)
{
System.out.println("j-1:"+i+j);
return dis[i][j-1]-1;
}
}
}
3.实现代码
class Solution {
public void init(int nums[])
{
int length=nums.length;
for(int i=0;i<length;i++)
nums[i]=i;
}
public int find(int n,int nums[])//查询
{
return n==nums[n] ? n:(nums[n]=find(nums[n],nums));
}
public void union(int nums[],int m,int n)//合并
{
//nums[find(n,nums)]=nums[m];
// nums[n]=nums[m];
int length=nums.length;
for(int i=0;i<length;i++)
if(nums[i] ==nums[n])
nums[i]=nums[m];
}
public int shortestBridge(int[][] grid) {
int len=grid.length;
int length=len*len;
int nums[]=new int[length];
init(nums);
int flag=0;
for(int i=0;i<len;i++)
for(int j=0;j<len;j++)
{
int m=i*len+j;
if(grid[i][j] ==1 && flag==0)//岛内第一个元素
flag=1;
else if(grid[i][j] ==1 && flag==1)
{
if(i==0 && grid[0][j-1] == 1)
union(nums,j-1,m);
else if(j==0 && grid[i-1][0]==1)
union(nums,(m-len),m);
else if(i>0 && j>0)
{
int x=(i-1)*len+j;
if(grid[i-1][j]==1)
union(nums,x,m);
if(grid[i][j-1]==1)
union(nums,m-1,m);
}
//System.out.println("m:"+m+"nums:"+nums[m]);
}
else if(grid[i][j] == 0)nums[m]=-1;
}
Queue<Integer> List1=new LinkedList<Integer>();
ArrayList<Integer> List2=new ArrayList<Integer>();
flag=-2;
int dis[][]=new int[len][len];
boolean fw[][]=new boolean[len][len];
for(int i=0;i<length;i++)
{
if(nums[i]!=-1 && flag==-2 || nums[i] == flag)
{
List1.offer(i);
flag=nums[i];
int x=i/len;
int y=i%len;
fw[x][y]=true;
}
else if(nums[i]!=-1 && nums[i]!=flag)
{
List2.add(i);
}
}
int List1Lens=List1.size();
//BFS
int min=0;
while(!List1.isEmpty())
{
int index=List1.poll();
int i=index/len;
int j=index%len;
if((j+1)<len && fw[i][j+1] == false)
{
int a=i*len+j+1;
List1.offer(i*len+j+1);
dis[i][j+1]=dis[i][j]+1;
fw[i][j+1]=true;
if(List2.indexOf(a)!=-1)
{
System.out.println("j+1:"+i+j);
return dis[i][j+1]-1;
}
}
if((i+1)<len && fw[i+1][j] == false)
{
int a=(i+1)*len+j;
List1.offer((i+1)*len+j);
dis[i+1][j]=dis[i][j]+1;
fw[i+1][j]=true;
if(List2.indexOf(a)!=-1)
{
System.out.println("i+1:"+i+j);
return dis[i+1][j]-1;
}
}
if((i-1)>=0 && fw[i-1][j]==false)
{
int a=(i-1)*len+j;
List1.offer(a);
fw[i-1][j]=true;
dis[i-1][j]=dis[i][j]+1;
if(List2.indexOf(a)!=-1)
{
System.out.println("i-1:"+i+j);
return dis[i-1][j]-1;
}
}
if((j-1)>=0 && fw[i][j-1]==false)
{
int a=i*len+j-1;
fw[i][j-1]=true;
List1.offer(i*len+j-1);
dis[i][j-1]=dis[i][j]+1;
if(List2.indexOf(a)!=-1)
{
System.out.println("j-1:"+i+j);
return dis[i][j-1]-1;
}
}
}
return 0;
}
}