草庐IT

[Leetcode934]最短的桥

echoqiqi 2023-03-28 原文

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;
    }
}

 

有关[Leetcode934]最短的桥的更多相关文章

  1. ruby - 覆盖相似的方法,更短的语法 - 2

    在Ruby类中,我重写了三个方法,并且在每个方法中,我基本上做同样的事情:classExampleClassdefconfirmation_required?is_allowed&&superenddefpostpone_email_change?is_allowed&&superenddefreconfirmation_required?is_allowed&&superendend有更简洁的语法吗?如何缩短代码? 最佳答案 如何使用别名?classExampleClassdefconfirmation_required?is_a

  2. Python 刷Leetcode题库,顺带学英语单词(31) - 2

    ValidPalindromeGivenastring,determineifitisapalindrome,consideringonlyalphanumericcharactersandignoringcases. [#125]Example:"Aman,aplan,acanal:Panama"isapalindrome."raceacar"isnotapalindrome.Haveyouconsiderthatthestringmightbeempty?Thisisagoodquestiontoaskduringaninterview.Forthepurposeofthisproblem

  3. IDEA使用LeetCode插件 - 2

    前言我们习惯用idea编写、调试代码,在LeetCode上刷题时,如果能够在IDEA编写代码,并且做好代码管理,是一件事半功倍的事情。对于后续复习题目,做笔记也会非常便利。本文目的在于介绍LeetCodeEditor的使用,以及配置工具类,最终目录结构如下:note:放置笔记src:放置代码leetcode.editor.cn:插件LeetCodeEditor自动生成utils:自定义的工具包,可用于自动化输入测试用例,定义题目需要的类(结构体)out:运行测试时自动生成LeetCodeEditorGitHub:https://github.com/shuzijun/leetcode-edit

  4. ruby - 用 ruby​​ 将 2 个破折号插入这个字符串的最短方法是什么? - 2

    这是字符串:04046955104021109我需要这样格式化:040469551-0402-1109用ruby​​做到这一点的最短/最有效的方法是什么? 最佳答案 两个简单的插入就可以了:example_string.insert(-9,'-').insert(-5,'-')负数表示您从字符串末尾开始计数。如果您愿意,也可以从头数起:example_string.insert(9,'-').insert(14,'-') 关于ruby-用ruby​​将2个破折号插入这个字符串的最短方法是

  5. ruby - 确定变量是否是值列表中的任何一个的最短/最惯用的方法是什么? - 2

    这似乎是一个非常简单的问题,但是用Ruby重写它的最短/最惯用的方法是什么?ifvariable==:aorvariable==:borvariable==:corvariable==:d#etc.我看到了这个解决方案:if[:a,:b,:c,:d].include?variable但这在功能上并不总是等价的-我相信Array#include?实际上是在查看变量对象是否包含在列表中;它没有考虑到对象可以使用def==(other)实现自己的相等性测试。正如下面有帮助的评论员所说,这种解释是不正确的。include?确实使用==但它使用数组中项目的==方法。在我的示例中,它是符号,而不是

  6. ruby - RSpec 较短的测试失败回溯输出 - 2

    我正在使用RSpec(最新版本2.12.2)来测试我正在处理的一个小型Rub​​y类。我的问题是,当RSpec测试失败时,测试输出看起来非常冗长,并显示了一个巨大的错误消息列表,几乎是一个完整的回溯。这意味着我必须向上滚动才能看到实际的错误消息和跟踪的顶部。我相信默认情况下RSpec应该这样做,但它似乎并没有为我做这件事。例如,如果我运行rspecspec/my_spec.rb:132(只运行一个在L132上的测试),我得到这个输出:Failure/Error:@f.has_changed?("test").shouldbe_trueexpected:truevaluegot:fals

  7. ruby-on-rails - 在 Ruby 中生成随机 IP 地址的最短方法是什么? - 2

    正如标题所说,需要用于测试目的。 最佳答案 你可以使用IPAddrrequire'ipaddr'ipv4=IPAddr.new(rand(2**32),Socket::AF_INET)ipv6=IPAddr.new(rand(2**128),Socket::AF_INET6) 关于ruby-on-rails-在Ruby中生成随机IP地址的最短方法是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com

  8. ruby - 在 Rails 中使用 uuidtools 生成一个短的 UUID 字符串 - 2

    我必须生成一个唯一的随机字符串,并将其存储在数据库中。为此,我使用了“uuidtools”gem。然后在我的Controller中添加了以下行:require"uuidtools"然后在我的Controller创建方法中,我声明了一个“temp”变量并生成一个唯一且随机的“uuid”字符串,如下所示:temp=UUIDTools::UUID.random_create它正在创建这样一个字符串:f58b1019-77b0-4d44-a389-b402bb3e6d50现在我的问题是我必须让它简短,最好在8-10个字符以内。现在我该怎么做??是否可以传递任何参数以使其成为所需长度的字符串?提

  9. ruby - 这是静默忽略 Ruby 异常的最短方法 - 2

    我正在寻找这样的东西:raiseExceptionrescuenil但我发现的最短路径是:beginraiseExceptionrescueExceptionend 最佳答案 这是由ActiveSupport提供的:suppress(Exception)do#dangerouscodehereendhttp://api.rubyonrails.org/classes/Kernel.html#method-i-suppress 关于ruby-这是静默忽略Ruby异常的最短方法,我们在Sta

  10. ruby-on-rails - ruby 中是否有更短的方法来获取两个日期中的较晚日期? - 2

    只是好奇-是否有更短的方法来实现这一目标?latest_date=date1>date2?date1:date2谢谢 最佳答案 使用Enumerable#max:latest_date=[date1,date2].max 关于ruby-on-rails-ruby中是否有更短的方法来获取两个日期中的较晚日期?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/9475848/

随机推荐