【问题标题】:Find a number in sorted multidimentional array with binary search使用二进制搜索在排序多维数组中查找数字
【发布时间】:2014-01-08 07:25:56
【问题描述】:

我们得到了一个递增排序的多维数组,例如:

int[][] mat = {{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,16}};

如何使用二分法查找特定数字?假设我正在寻找 3。

【问题讨论】:

  • 先向我们展示您的尝试
  • 我尝试使用 NXM 计算数组中元素的数量,然后尝试在数组上找到正确的位置并使用它进行排序,但它无法正常工作。跨度>
  • 你能澄清你的“排序多维数组”的约束吗?例如,第 2 行的第一个元素是否需要大于第 2 行的最后一个元素,如您的示例代码中那样,还是仅被限制为 > 第 1 行的第一个元素? (换句话说,这真的是一个被分成几部分的排序列表,还是对数组的排序约束仅仅是必须对每一行和每一列进行排序?)

标签: java algorithm binary-search


【解决方案1】:

二维数组可以通过以下方式用作一维数组,使用以下索引公式:-

假设您需要在一维数组中找到第 k 个索引,那么它是具有 i= k/nj = k%n 的元素,其中 n 是二维数组中矩阵的顺序。在结束索引为 n*n-1 的一维数组中使用二分查找。

替代方法:-

1.> 对arr[i][0] 的每个一维数组的第一个元素进行二分搜索。

2.> 然后使用上面的方法得到包含元素 k 的一维数组,然后对 arr[k] 进行二分搜索。

【讨论】:

    【解决方案2】:

    您可以通过将一维索引转换为二维索引来实现此目的。例如,索引0 映射到0, 0,但索引4 将映射到1, 0,而索引15 将映射到3, 3

    这样您就可以使用标准的二分搜索算法,而您所要做的就是在需要查找特定索引处的值时调用转换函数。

    将一维索引转换为二维索引的公式为:

    row = floor(index / columns);
    column = index % columns;
    

    这假定每个数组都已排序,并且在展平时,结果数组也已排序。

    【讨论】:

      【解决方案3】:

      在二维数组中定义“顺序”有不同的方法。对于您示例中的顺序,对每行的第一个元素进行 bin 搜索,以找到该行,然后在该行内再次进行 bin 搜索。如果行数 >= 列数,您可以优化对从 (0,0) 开始的对角线元素进行二分搜索,然后对行的其余部分进行另一次二分搜索。

      【讨论】:

        【解决方案4】:

        您可以为每个子数组使用Arrays.binarySearch()

        private static int[] binarySearch2d(int[][] arr, int toFind) {
            int[] index2d = new int[] { -1, -1 };
        
            // find the row
            int row = -1;
            for (int i = 0; i < arr.length; i++) {
                if (arr[i][0] > toFind) {
                    break;
                }
                row = i;
            }
        
            if (row > -1) {
                int indexInSecond = Arrays.binarySearch(arr[row], toFind);
                if (indexInSecond > -1) {
                    index2d[0] = row;
                    index2d[1] = indexInSecond;
                }
            }
            return index2d;
        }
        
        private static void test() {
            int[][] mat = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 },
                    { 13, 14, 15, 16 } };
        
            int[] found = binarySearch2d(mat, 12);
            int element = mat[found[0]][found[1]];
            System.out.println("Found: " + element + " at mat[" + found[0] + "]["
                    + found[1] + "]");
        }
        

        会输出

        Found: 12 at mat[2][3]
        

        【讨论】:

        • 这将具有 O(n/w) 的复杂度,其中 w 是数组的宽度。因此,如果您有 1000 行,每行 1000 列,则平均需要 500 次比较才能找到该行。最好对第一列进行二分查找以找出哪一行包含该元素,然后对该行进行二分查找。
        • @JimMischel 我更新了我的答案以首先找到该行
        【解决方案5】:

        使用java.util.Arrays。在展平矩阵上使用Arrays.binarySearch() 函数:

        int[][] mat = {{1,2,3,4},
        {5,6,7,8},
        {9,10,11,12},
        {13,14,15,16}};
        
        
        int key = 3;
        int[] oneDArray = new int[mat[0].length*mat[0].length];
        
        int s = 0;
        for(int i = 0; i < mat[0].length; i ++) 
            for(int j = 0; j < mat[0].length; j ++){                           
                oneDArray[s] = mat[i][j];
                s++;
            } 
        
        
        int found = Arrays.binarySearch(oneDArray, key);
        if(found > -1){
             System.out.println(found/ mat[0].length + "," + found % mat[0].length);    
        }
        

        还有演示:https://ideone.com/bFZVMs

        【讨论】:

          【解决方案6】:
          public boolean Find(int[][] array, int number) { 
              int find = -1;
              for(int i = 0; i < N; i++) {
                  find = binarySearch(array[i], number, 0, N);
                  if(find != -1) { 
                     return true; //the element is exist
                  }
               }
               return false;//the element is not exist
          }
          

          或者你可以修改this question对你有很大帮助

          【讨论】:

          • 我不喜欢外面的滚轮。做到这一点的最好方法(不与数组索引纠缠不清)是运行两次二进制搜索;在外部,然后是适当的内部尺寸。所以 +-1
          • “与数组索引的总纠结”不是问题。将数字转换为行/列是微不足道的。
          【解决方案7】:

          您可以只使用每个内部数组的第一个元素进行二进制搜索,以查找它所在的行。然后在该行内执行二进制搜索以查找列。

          如果您的矩阵支持重复,您可能需要更多逻辑。

          【讨论】:

            【解决方案8】:

            您可以使用每个数组的第一个数字(或最后一个数字)来查找您的数字可能存在的元素,然后对该元素使用二进制搜索来查找它是否确实存在。

            【讨论】:

              【解决方案9】:

              您可以创建一维 array 并使用 binary 搜索。

                  int[] arr = new int[]{1, 5, 6};// your converted array
                  int index = Arrays.binarySearch(arr, 1);
                  if (index >= 0) {
                      System.out.println("found ");
                  } else {
                      System.out.println("not found");
                  }
              

              【讨论】:

              • 如果我希望它在 O(logn) 上怎么办,这意味着我无法创建一维数组,因为它的效率会降低
              【解决方案10】:

              如果多维数组是排序的,你可以将二分查找算法分成两部分。首先,您将执行二进制搜索以找到包含您要查找的数字的多维数组中的数组。然后,您在该数组中执行搜索。

              希望对您有所帮助。

              【讨论】:

                猜你喜欢
                • 2019-07-15
                • 1970-01-01
                • 2019-07-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多