BM18 二维数组中的查找
知识点数组
描述
在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。[[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]
]
给定 target = 7,返回 true。
给定 target = 3,返回 false。
数据范围:矩阵的长宽满足  , 矩阵中的值满足 
进阶:空间复杂度  ,时间复杂度 
示例1
输入:
7,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]复制返回值:
true复制说明:
存在7,返回true示例2
输入:
1,[[2]]复制返回值:
false复制
示例3
输入:
3,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]复制返回值:
false复制说明:
不存在3,返回false题解
思路:
根据前面的[查找]BM17 二分查找-I-简单 实现,我们可以很容易的想到对二维数组进行遍历,然后在一维上使用二分查找实现。但是题目要求最佳的时间复杂度为O(M+N),该如何实现呢?
其实解法也和一维数组的二分查找类似,我们先定义一个结构体point来表示坐标。按照一维数组的二分查找我们可以进行以下推导:
- 一维数组我们是先获取了起始、结尾坐标,同样的二维数组我们也先获取起始、结尾坐标
- 一维数组二分的时候是先查找中间节点,比较中间节点和目标值的大小,然后根据大小选取左右区间,同样的,我们先获取二维数组的中间节点,然后根据大小选取左右节点进行查找。根据二维数组的有序特点,我们可以使用中间节点根据大小将数组划分成2个区间,然后再在我们需要的区间中进行查找。
注意:
一定要注意数组边界的选取,如果没有使用数组边界进行判断,那么可能导致递归~~~
代码如下:
using namespace std;
// 定义的坐标
// x:横坐标
// y:纵坐标
struct point
{
  int x;
  int y;
  point()
  {
    x = 0;
    y = 0;
  }
  point(int x, int y) : x(x), y(y) {}
};
// 一维数组的二分查找,成功返回下标,失败返回-1
int binary_search(const std::vector<int> &nums, int left, int right, int target)
{
  while (left <= right)
  {
    int mid = (left + right) / 2;
    if (nums[mid] == target)
    {
      return mid;
    }
    if (nums[mid] < target)
    {
      left = mid + 1;
    }
    else
    {
      right = mid - 1;
    }
  }
  return -1;
}
// 对二维数组的二分查找实现
// array:二维数组
// left:坐标下限
// right:坐标上限
// target:目标值
bool search_array(const vector<vector<int>> &array, const point &left, const point &right, int target)
{
  if (left.y > right.y || left.x > right.x)
  {
    return false;
  }
  if (left.y == right.y)
  {
    return binary_search(array[left.y], left.x, right.x, target) != -1;
  }
  int max_x = right.x;
  int max_y = right.y;
  int min_x = left.x;
  int min_y = left.y;
  point mid((left.x + right.x) / 2, (left.y + right.y) / 2);
  int value = array[mid.y][mid.x];
  if (value == target)
  {
    return true;
  }
  if (value < target)
  {
    if ((mid.x + 1 <= max_x) && search_array(array, point(mid.x + 1, left.y), point(max_x, mid.y), target))
    {
      return true;
    }
    if ((mid.y + 1 <= max_y) && search_array(array, point(left.x, mid.y + 1), right, target))
    {
      return true;
    }
    return false;
  }
  if (mid.x > min_x && search_array(array, point(left.x, mid.y), point(mid.x - 1, right.y), target))
  {
    return true;
  }
  if ((mid.y > min_y) && search_array(array, left, point(max_x, mid.y - 1), target))
  {
    return true;
  }
  return false;
}
bool Find(int target, vector<vector<int>> array)
{
  if (array.empty() || (array.size() == 1 && array[0].size() == 0))
  {
    return false;
  }
  point left(0, 0);
  point right(array[0].size() - 1, array.size() - 1);
  return search_array(array, left, right, target);
}
int main()
{
  // std::vector<std::vector<int>> nums = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
  std::vector<std::vector<int>> nums = {{1, 2, 8, 9}, {4, 7, 10, 13}};
  int target = 7;
  std::cout << (Find(target, nums) ? "true" : "false") << std::endl;
  return 0;
}









