当前位置: 首页 > news >正文

leetcode 并查集整理

并查集整理

  • 990. 等式方程的可满足性
  • 剑指 Offer II 116. 省份数量
  • 200.岛屿数量
  • 684. 冗余连接
  • 1319. 连接网络的操作次数
  • 299.除法求值

990. 等式方程的可满足性

  题目,这是对并查集的简单应用,并查集的套路就是实现union和find函数。
  固定模板, 路径压缩方式为隔代压缩,可以用在无带权并查集,前五道题都是使用隔代压缩的方法:

 public void union(int[] parent, int index1, int index2) {
      parent[find(parent, index1)] = find(parent, index2);
  }

  public int find(int[] parent, int index) {
      while (parent[index] != index) {
          parent[index] = parent[parent[index]];
          index = parent[index];
      }
      return index;
  }

有了并查集就很容易解决该题:

 public boolean equationsPossible(String[] equations) {
     int[] parent = new int[26];
     for (int i = 0; i < 26; i++) {
         parent[i] = i;
     }
     for (String str : equations) {
         if (str.charAt(1) == '=') {
             int index1 = str.charAt(0) - 'a';
             int index2 = str.charAt(3) - 'a';
             union(parent, index1, index2);
         }
     }
     for (String str : equations) {
         if (str.charAt(1) == '!') {
             int index1 = str.charAt(0) - 'a';
             int index2 = str.charAt(3) - 'a';
             if (find(parent, index1) == find(parent, index2)) {
                 return false;
             }
         }
     }
     return true;
 }

剑指 Offer II 116. 省份数量

  题目,还是对并查集的应用,union之后查找city数组中值和下标一致的数目就是省份数量。

 public int findCircleNum(int[][] isConnected) {
     int n = isConnected.length;
     int[] city = new int[n];
     for (int i = 0; i < n; i++) {
         city[i] = i;
     }
     for (int i = 0; i < n; i++) {
         for (int j = i + 1; j < n; j++) {
             if (isConnected[i][j] == 1) {
                 union(city, i, j);
             }
         }
     }
     int re = 0;
     for (int i = 0; i < n; i++) {
         if (city[i] == i) {
             re++;
         }
     }
     return re;
 }

200.岛屿数量

  题目,这道题使用dfs,每在循环最外边调用一次dfs就将count+1即可,并查集只是一个思路,实现起来也比较复杂,只做一个记录。

  HashMap<Integer, int[]> map;
  int[] island;

  public int numIslands(char[][] grid) {
      int n = grid.length;
      int m = grid[0].length;
      island = new int[n * m];
      for (int i = 0; i < m * n; i++) {
          island[i] = i;
      }
      map = new HashMap<>();
      int count = 0;
      for (int i = 0; i < n; i++) {
          for (int j = 0; j < m; j++) {
              if (grid[i][j] == '1') {
                  map.put(count, new int[]{i, j});
                  dfs(grid, i, j, count);
                  count++;
              } else if (grid[i][j] == '0') {
                  island[getIndex(i, j, m)] = -1;
              }
          }
      }
      int re = 0;
      for (int i = 0; i < m * n; i++) {
          if (island[i] == i) {
              re++;
          }
      }
      return re;
  }

  public void dfs(char[][] grid, int r, int c, int count) {
      if (!inArea(grid, r, c)) {
          return;
      }
      // 如果这个格子不是岛屿,直接返回
      if (grid[r][c] != '1') {
          return;
      }
      grid[r][c] = '2'; // 将格子标记为「已遍历过」
      int index1 = getIndex(r, c, grid[0].length);
      int[] tmp = map.get(count);
      int index2 = getIndex(tmp[0], tmp[1], grid[0].length);
      union(island, index1, index2);

      // 访问上、下、左、右四个相邻结点
      dfs(grid, r - 1, c, count);
      dfs(grid, r + 1, c, count);
      dfs(grid, r, c - 1, count);
      dfs(grid, r, c + 1, count);
  }

  boolean inArea(char[][] grid, int r, int c) {
      return 0 <= r && r < grid.length
              && 0 <= c && c < grid[0].length;
  }

  int getIndex(int i, int j, int m) {
      return i * m + j;
  }

684. 冗余连接

  题目,如果新加入的点,他们的parent一致,说明已经连接,就是要找到的最后出现的边。

  public int[] findRedundantConnection(int[][] edges) {
      int n = edges.length;
      int[] parent = new int[n + 1];
      for (int i = 0; i < n + 1; i++) {
          parent[i] = i;
      }
      for (int[] edge : edges) {
          if (find(parent, edge[0]) != find(parent, edge[1])) {
              union(parent, edge[0], edge[1]);
          } else {
              return edge;
          }
      }
      return null;
  }

1319. 连接网络的操作次数

  题目,这道题实际上是上一道题的改进,首先用并查集计算出网络中冗余连接数,然后再遍历parent数组,查找有多少个不相连的网络n,如果n-1 < count则说明能连接,返回n-1,否则返回-1。

  public int makeConnected(int n, int[][] connections) {
      int[] parent = new int[n];
      for (int i = 0; i < n; i++) {
         parent[i] = i;
      }
      int count = 0;
      for (int[] edge : connections) {
          if (find(parent, edge[0]) != find(parent, edge[1])) {
              union(parent, edge[0], edge[1]);
          } else {
              count++;
          }
      }
      int re = -1;
      for (int i = 0; i < n; i++) {
          if (parent[i] == i) {
              if (count-- < 0) return -1;
              re++;
          }
      }
      return re;
  }

299.除法求值

  题目这道题是带权重的并查集,并查集中需要维护节点的权重,使用递归的方式进行路径压缩,使每一个节点都直接指向父节点,并在路径压缩中更新权值。

  public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
      int equationsSize = equations.size();

      UnionFind unionFind = new UnionFind(2 * equationsSize);
      // 第 1 步:预处理,将变量的值与 id 进行映射,使得并查集的底层使用数组实现,方便编码
      Map<String, Integer> hashMap = new HashMap<>(2 * equationsSize);
      int id = 0;
      for (int i = 0; i < equationsSize; i++) {
          List<String> equation = equations.get(i);
          String var1 = equation.get(0);
          String var2 = equation.get(1);

          if (!hashMap.containsKey(var1)) {
              hashMap.put(var1, id);
              id++;
          }
          if (!hashMap.containsKey(var2)) {
              hashMap.put(var2, id);
              id++;
          }
          unionFind.union(hashMap.get(var1), hashMap.get(var2), values[i]);
      }

      // 第 2 步:做查询
      int queriesSize = queries.size();
      double[] res = new double[queriesSize];
      for (int i = 0; i < queriesSize; i++) {
          String var1 = queries.get(i).get(0);
          String var2 = queries.get(i).get(1);

          Integer id1 = hashMap.get(var1);
          Integer id2 = hashMap.get(var2);

          if (id1 == null || id2 == null) {
              res[i] = -1.0d;
          } else {
              res[i] = unionFind.isConnected(id1, id2);
          }
      }
      return res;
  }

  private class UnionFind {

      private int[] parent;

      /**
       * 指向的父结点的权值
       */
      private double[] weight;


      public UnionFind(int n) {
          this.parent = new int[n];
          this.weight = new double[n];
          for (int i = 0; i < n; i++) {
              parent[i] = i;
              weight[i] = 1.0d;
          }
      }

      public void union(int x, int y, double value) {
          int rootX = find(x);
          int rootY = find(y);
          if (rootX == rootY) {
              return;
          }

          parent[rootX] = rootY;
        	// 关系式的推导请见「参考代码」下方的示意图
          weight[rootX] = weight[y] * value / weight[x];
      }

      /**
       * 路径压缩
       *
       * @param x
       * @return 根结点的 id
       */
      public int find(int x) {
          if (x != parent[x]) {
              int origin = parent[x];
              parent[x] = find(parent[x]);
              weight[x] *= weight[origin];
          }
          return parent[x];
      }

      public double isConnected(int x, int y) {
          int rootX = find(x);
          int rootY = find(y);
          if (rootX == rootY) {
              return weight[x] / weight[y];
          } else {
              return -1.0d;
          }
      }
  }

相关文章:

  • 前端 | 50天50个前端项目把握基础知识 - 持续更新中
  • 【智能优化算法-凌日搜索算法】基于凌日搜索算法求解单目标优化问题附matlab代码
  • C++11重写muduo网络库5——Thread,EventLoopThread,EventLoopThreadPool
  • NISP的渗透测试怎么操作的
  • 安装Nginx教程
  • Java_接口基本介绍
  • 16、Java——QuickHit游戏
  • SpringBoot--Controller获取HttpServletRequest
  • 牛客刷题笔记
  • 我把华为云的Ubuntu 18.04升级到了Ubuntu 22.04
  • Google Earth Engine-02(主界面介绍)
  • 5.java数据结构与算法 ---- 第七章 八大排序(冒泡;选择;插入/希尔;快排;归并;基数)
  • 新学期你立一个什么样的FLAG?
  • 【数据结构与算法】第九篇:哈希表原理
  • 自动驾驶江湖重新排位:毫末智行“重感知、轻地图”优势初现
  • 收藏网友的 源程序下载网
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • es6(二):字符串的扩展
  • interface和setter,getter
  • Java|序列化异常StreamCorruptedException的解决方法
  • JS+CSS实现数字滚动
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • Vue UI框架库开发介绍
  • 代理模式
  • 订阅Forge Viewer所有的事件
  • 前端之React实战:创建跨平台的项目架构
  • 使用common-codec进行md5加密
  • 7行Python代码的人脸识别
  • Nginx惊现漏洞 百万网站面临“拖库”风险
  • Semaphore
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • (1)虚拟机的安装与使用,linux系统安装
  • (52)只出现一次的数字III
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (html5)在移动端input输入搜索项后 输入法下面为什么不想百度那样出现前往? 而我的出现的是换行...
  • (poj1.3.2)1791(构造法模拟)
  • (rabbitmq的高级特性)消息可靠性
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (板子)A* astar算法,AcWing第k短路+八数码 带注释
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (一)认识微服务
  • (转)JAVA中的堆栈
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • ***利用Ms05002溢出找“肉鸡
  • **python多态
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .Net core 6.0 升8.0
  • .NET 中使用 Mutex 进行跨越进程边界的同步
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值