面试题04:二维数组中的查找(C++)
题目地址:https://leetcode-cn.com/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/
题目描述
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
题目示例
现有矩阵 matrix 如下:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。
给定 target = 20,返回 false。
解题思路
思路1:暴力遍历查找,时间复杂度O(row*col),空间复杂度O(1),二维数组中的每个元素都被访问。
思路2:分析题目可以发现,数组元素之间存在一种特殊关系,即从左至右,从上至下都是递增的,因此我们选择以矩阵的右上角作为起点,并与target相比较,小于target则向下遍历,大于target则向左遍历,遍历完还没有则返回false。当然,我们也可以选择矩阵左下角为起点,与target相比较,大于target,则向上遍历,小于target,则向右遍历。时间复杂度O(row+col),空间复杂度O(1),因为访问到的下标的行最多增加row次,减少的列最多col次,因此,循环体最多执行row+col次。
思路3:二分搜索树思路。将矩阵右上角当作二叉搜索树的根节点,其左侧数字小于它,因此将左侧数字当做左子树,下侧数字当做右子树,满足二叉搜索树的”左子树小于根节点,根节点大于右子树“的条件,最后递归调用即可。时间复杂度O(nlogm),空间复杂度O(1)。
思路4:二分查找,这个方法可以是堆暴力遍历的一种优化,因为给定的数组是有序的,所以可以考虑二分查找。具体分析见文末参考文章。时间复杂度O(logn*logm),在行上查找一次的时间复杂度为O(logN),因为待查找的列的范围平均每次减少一半,故在行上查找logN次后列的范围就没有了,循环结束。同理,列上查找为O(log M)。
程序源码
class Solution { public: bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) { //方法1:暴力法 if(matrix.empty()) return false; int row = matrix.size(), col = matrix[0].size(); for(int i = 0; i < row; i++) { for(int j = 0; j < col; j++) { if(matrix[i][j] == target) return true; } } return false; /*方法2:矩阵右上角开始 if(matrix.empty()) return false; int row = 0, col = matrix[0].size() - 1;//右上角开始 while(row < matrix.size() && col >= 0) { if(matrix[row][col] > target) col--; else if(matrix[row][col] < target) row++; else return true; } return false; */ /*方法3:矩阵左下角开始 if(matrix.empty()) return false; int row = matrix.size() - 1, col = 0; while(row >= 0 && col < matrix[row].size()) { if(matrix[row][col] > target) row--; else if(matrix[row][col] < target) col++; else return true; } return false; */ } };
思路3
class Solution { public: bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) { int rows = matrix.size(); if(rows == 0) return false; int cols = matrix[0].size(); if(cols == 0) return false; return binarySearch(matrix, target, 0, cols - 1, rows, cols); } bool binarySearch(vector<vector<int>> matrix, int target, int i, int j, int rows, int cols) { if(i >= rows || j < 0) return false; //越界 int root = matrix[i][j]; //将右上角元素作为根节点 if(root == target) return true; if(root > target) { return binarySearch(matrix, target, i, j - 1, rows, cols); //遍历左子树 } else { return binarySearch(matrix, target, i + 1, j, rows, cols); //遍历右子树 } } };
思路4:
class Solution { public: bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) { int rows = matrix.size(); if(rows == 0) return false; int cols = matrix[0].size(); if(cols == 0) return false; if(target < matrix[0][0] || target > matrix[rows - 1][cols - 1]) return false; //越界 for(int i = 0; i < rows; ++i) //按行二分查找 { int left = 0, right = cols - 1; while(left <= right) { int mid = left + (right - left) / 2; if(matrix[i][mid] == target) return true; if(matrix[i][mid] > target) { right = mid - 1; } else { left = mid + 1; } } } return false; } };
参考文章