題目地址: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; } };
參考文章