【问题标题】:Given a 2D array of numbers, find clusters给定一个二维数组,找到簇
【发布时间】:2012-01-29 16:35:29
【问题描述】:

给定一个二维数组,例如:

0 0 0 0 0
0 2 3 0 1
0 8 5 0 7
7 0 0 0 4

输出应该是集群组:

集群 1:<2,3,8,5,7>

集群 2:<1,7,4>

【问题讨论】:

  • 大集群中有零。允许子矩阵有多少个零才能使其仍被视为一个簇?
  • 如果在面试中问到这个问题,面试官想要洪水填充算法的变体

标签: algorithm matrix


【解决方案1】:

一种方法是使用图表。以某种顺序遍历矩阵(我会从左到右,从上到下)。当您遇到非零元素时,将其添加到图表中。然后检查它的所有邻居(看起来你想要 8 个连接的邻居),对于每个非零的邻居,将其节点添加到图中,并将其连接到当前元素。图表中的元素可能必须跟踪它们的坐标,以便您可以查看是否添加了重复项。当您完成遍历矩阵时,您将得到一个包含一组集群的图。集群应该是连通元素的子图。

【讨论】:

    【解决方案2】:

    您的问题似乎是寻找连接的组件。您应该使用遍历方法(BFS 或 DFS 都可以完成工作)。遍历所有元素,对于每个非零元素开始遍历并记录您在该遍历中看到的所有元素,并将每个访问的元素变为零。类似于下面的代码:

    void DFS(int x, int y)
    {
      printf("%d ", g[x][y]);
      g[x][y] = 0;
      // iterate over neighbours
      for(dx=-1; dx<=1; dx++)
        for(dy=-1; dy<=1; dy++)
          if (g[x+dx][y+dy]) DFS(x+dx, y+dy);
    }
    
    for(i=0; i<n; i++)
      for(j=0; j<n; j++)
        if (g[i][j])
        {
          DFS(i, j);
          printf("\n");
        }
    

    【讨论】:

      【解决方案3】:

      如果您知道组数或希望将数据拟合到静态组数,则可以使用 k-means。

      http://en.wikipedia.org/wiki/K-means_clustering

      【讨论】:

        【解决方案4】:

        你想做Connected Component Labeling。这通常被认为是一种图像处理算法,但它与您描述的相符。

        您还将获得 K-means 的推荐,因为您说过 二维数字数组,很容易将其解释为 二维数字数组。 K-means 查找平面中的点簇,而不是您要求的二维数组中的连接组。

        【讨论】:

          【解决方案5】:

          代码示例:

          using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Text;
          
          namespace Practice
          {
              class Program
              {
                  static void Main()
                  {
                      var matrix = new[] { new StringBuilder("00000"), new StringBuilder("02301"), new StringBuilder("08507"), new StringBuilder("70004") };
                      var clusters = 0;
                      for (var i = 0; i < matrix.Length; i++)
                          for (var j = 0; j < (matrix.Any() ? matrix[i].Length : 0); j++)
                              if (matrix[i][j] != '0')
                              {
                                  Console.Write("Cluster {0}: <", ++clusters);
                                  var cluster = new List<char>();
                                  Traverse(matrix, i, j, ref cluster);
                                  Console.WriteLine("{0}>", string.Join(",", cluster));
                              }
                      Console.ReadKey();
                  }
          
                  private static void Traverse(StringBuilder[] matrix, int row, int col, ref List<char> cluster)
                  {
                      cluster.Add(matrix[row][col]);
                      matrix[row][col] = '0';
                      for (var i = -1; i <= 1 && row + i >= 0 && row + i < matrix.Length; i++)
                          for (var j = -1; j <= 1 && col + j >= 0 && col + j < (matrix.Any() ? matrix[row + i].Length : 0); j++)
                              if(matrix[row + i][col + j] != '0')
                                  Traverse(matrix, row + i, col + j, ref cluster);
                  }
              }
          }
          

          算法解释:

          • 对于每一行:
            • 对于该行中的每一列:
              • 如果项目是未访问的非零:
                1. 保存找到的集群成员;
                2. 将 [row, column] 处的位置标记为已访问;
                3. 在矩阵边界内检查任何未访问的非零邻居:
                  • [行 - 1,列 - 1];
                  • [行 - 1,列];
                  • [行 - 1,列 + 1];
                  • [行,列 - 1];
                  • [行、列+1];
                  • [行 + 1,列 - 1];
                  • [行+1,列];
                  • [行 + 1,列 + 1]。
                4. 如果任何邻居是未访问的非零,则递归地重复步骤 1-4,直到所有邻居都被访问为零(已找到所有集群成员)。

          【讨论】:

          • 这是一个algorithm 问题,而不是c#.net 问题。此外,除了代码之外什么都没有的转储很少是好的答案。请参阅this Meta question and its answers 了解更多信息。
          猜你喜欢
          • 1970-01-01
          • 2021-12-10
          • 1970-01-01
          • 2022-12-07
          • 2021-04-03
          • 1970-01-01
          • 1970-01-01
          • 2019-10-09
          • 2021-12-31
          相关资源
          最近更新 更多