【问题标题】:Binary search of a Matrix矩阵的二分搜索
【发布时间】:2017-08-25 05:46:14
【问题描述】:

编写一个高效的算法,在 m x n 中搜索一个值 矩阵。

此矩阵具有以下属性:

- 每行中的整数从左到右排序。
-第一个整数 每行大于或等于最后一个整数 上一行。

示例:

考虑以下矩阵:

[
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
给定 target = 3,返回1(1对应true)

返回 0 / 1 ( 如果元素不存在则返回 0,如果元素存在则返回 1 present ) 解决这个问题

我的解决方案适用于 NetBeans,但在网站上失败。任何帮助将不胜感激。 https://www.interviewbit.com/problems/matrix-search/

public class Solution {

    public int searchMatrix(ArrayList<ArrayList<Integer>> a, int b) {
        int r = a.size();
        int c = a.get(0).size();

        int start = 0;
        int end = r - 1;
        // default value is last row for edge case
        int biRow = r -1; // row to search column

        //binary search 1st value of rows
        while (start <= end) {
            int mid = (start + end) / 2;
            if (b == a.get(mid).get(0)) {
                return 1;
            }

            if (a.get(mid).get(0) < b && b < a.get(end).get(0)) {
                if (mid + 1 >= end) {
                    biRow = mid;
                    break;
                }
            } if (b < a.get(mid).get(0)) {
                end = mid - 1;
            } else {
                start = mid + 1;
            }
        }
        //binary search column of biRow
        start = 0;
        end = c-1;
        while (start <= end) {
            int mid = (start + end) / 2;
            if (b == a.get(biRow).get(mid)) {
                return 1;
            }
            if (b < a.get(biRow).get(mid)) {
                end = mid - 1;
            } else {
                start = mid + 1;
            }
        }
        return 0;
    }
}

【问题讨论】:

  • 只需将NxM矩阵视为N*M项的数组,具有明显的顺序,并通过坐标变换对其进行普通的二分搜索。

标签: algorithm matrix binary-search


【解决方案1】:

好的,您不得做的第一件事是,您不能将矩阵物理连接成一维向量,因为这是O(N*M),它是线性的,而不是我们想要的。

// Easy but TLE code
int Solution::searchMatrix(vector<vector<int> > &A, int B) {
    vector<int> v;
    for(auto a : A) v.insert(v.end(), a.begin(), a.end());
    return binary_search(v.begin(), v.end(), B);
}

所以重点是,你必须直接在矩阵上进行二分搜索,这几乎是一样的(除了你现在必须自己编写二分搜索)。

由于您并未真正访问所有元素,因此这里是 O(lg (N*M))

// Less Easy but AC code
int Solution::searchMatrix(vector<vector<int> > &A, int B) {
    int m = A.size(), n = A[0].size(), lo = 0, hi = m*n-1, mi, row, col;
    while(lo <= hi){
        mi = lo + ((hi-lo) >> 1);
        row = mi / n;
        col = mi % n;
        if(A[row][col] == B) return 1;
        else if(A[row][col] > B) hi = mi - 1;
        else lo = mi + 1;
    }
    return 0;
}

【讨论】:

    【解决方案2】:

    我认为共享程序似乎有逻辑错误。

    在第一个while循环更新结束值时,如果结束值等于start,则biRow不能更新。

    当我更新如下代码时效果很好。

    public class Solution {
        public int searchMatrix(ArrayList<ArrayList<Integer>> a, int b) {
            int r = a.size();
            int c = a.get(0).size();
            int start = 0;
            int end = r - 1;
            // default value is last row for edge case
            int biRow = r -1; // row to search column
    
            //binary search 1st value of rows
            int mid = 0;
            while (start <= end) {
                mid = (start + end) / 2;
                if ( b >= a.get(mid).get(0) && b <= a.get(mid).get(c-1)) {
                    break;
                }
                if (b < a.get(mid).get(0)) {
                    end = mid-1;
                } else {
                    start = mid+1;
                }
           }
    
            biRow = mid;
    
            //binary search column of biRow
            start = 0;
            end = c-1;
            while (start <= end) {
                mid = (start + end) / 2;
                if (b == a.get(biRow).get(mid)) {
                    return 1;
                }
                if (b < a.get(biRow).get(mid)) {
                    end = mid - 1;
                } else {
                    start = mid + 1;
                }
            }
            return 0;
        }
    }
    

    【讨论】:

      【解决方案3】:

      您的行搜索循环中存在逻辑错误。我做了一个更正,我还添加了边界条件。这个算法的时间复杂度是 O(logN)。

      public class Solution {
          public int searchMatrix(ArrayList<ArrayList<Integer>> a, int b) {
              int r = a.size();
              int c = a.get(0).size();
      
              // return 0 if b is less than 1st element or greater than last element
              if (b < a.get(0).get(0) || b > a.get(r - 1).get(c - 1))
                  return 0;
              int start = 0;
              int end = r - 1;
              // default value is last row for edge case
              int biRow = r - 1; // row to search column
      
              // binary search 1st value of rows
              while (start <= end) {
                  int mid = (start + end) / 2;
                  if (b == a.get(mid).get(0)) {
                      return 1;
                  }
      
                  if (b >= a.get(mid).get(0) && b <= a.get(mid).get(c - 1)) {
                      {
                          biRow = mid;
                          break;
                      }
                  }
                  if (b < a.get(mid).get(0)) {
                      end = mid - 1;
                  } else {
                      start = mid + 1;
                  }
              }
              // binary search column of biRow
              start = 0;
              end = c - 1;
              while (start <= end) {
                  int mid = (start + end) / 2;
                  if (b == a.get(biRow).get(mid)) {
                      return 1;
                  }
                  if (b < a.get(biRow).get(mid)) {
                      end = mid - 1;
                  } else {
                      start = mid + 1;
                  }
              }
              return 0;
          }
      }
      

      【讨论】:

        【解决方案4】:

        由于对行和列进行了排序,因此如您所说,二进制搜索将是正确的。这是 Ruby 中的二进制搜索(在矩阵上)实现

        def binary_search_on_matrix(matrix,target)
          row_size = matrix.size
          column_size = matrix[0].size
          left_index = 0
          right_index = (row_size * column_size) - 1  
          while (left_index <= right_index)  
            mid_point = left_index + ((right_index - left_index) / 2)
            row = mid_point / column_size
            col = mid_point % column_size
            value = matrix[row][col] 
            if (value == target)
              return true
            elsif (value > target)
              right_index = mid_point - 1
            else
              left_index = mid_point + 1
            end
         end
          return false
        end
        

        【讨论】:

          【解决方案5】:

          您可以先将您的二维数组转换为一维数组并执行二分查找操作。您可以参考下面给出的代码:

          void search(int a[][10],int search,int m,int n)
          {
              int arr[100],i=0,j=0,k=-1;
              for(i=0;i<m;i++)
              for(j=0;j<n;j++)
                  arr[++k] = a[i][j];
          
              int first = 0 , last = k-1 , middle = (first+last)/2;
          
              while (first <= last)
              {
                  if(arr[middle] < search)
                  {
                      first = middle + 1;
          
                  }
                  else if(arr[middle] == search)
                  {
                      printf("\n Element found at position:( %d , %d")",(middle/n)+1,(middle%n)+1);
                      printf(" \n Row : %d",(middle/n)+1);
                      printf("\n column : %d",(middle%n)+1);
                      break;
                  }
                  else
                  {
                       last = middle - 1;
                  }
                  middle = (first + last)/2;
              }
              if(first > last)
              {
                  printf("\n Element not found! ");
              }
          }
          

          此函数打印要搜索的元素的行和列(如果存在)。您可以修改此代码,如果您希望函数根据搜索操作返回值。

          【讨论】:

          • 二维数组转一维数组的复杂度如何?
          • 这段代码至少有两个主要问题。首先,您如何确定所有内容都适合大小为 100 的数组?其次,完全不必要地复制整个矩阵。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多