首页 > 代码库 > Leetcode: Search a 2D Matrix

Leetcode: Search a 2D Matrix

这道题本来思路并不复杂,先对第一列做binary search, 找到target所在的行,再对所在的行做binary search,找到target在或不在。但是我在编程的时候遇到了很多问题,堆栈溢出(StackOverflowError)折腾死我了,一些边界条件的考虑也颇费周折。

我之所以会碰到堆栈溢出的问题是跟我用recursion的方法来做binary search分不开的。众所周知,recursion的一大缺陷就是,浪费空间,容易递归太深造成堆栈的溢出。在这道题中可见一斑。其实它的sample input: [[1][3]], 3 递归的层次并不多,但是我要用recursion就不得不把整个矩阵作为recursion function的参数,结果虽然层次不多但是堆栈依然溢出了。后来想想那不是当然的么,每一层堆栈都要存下整个矩阵,不溢出才怪。所以,我就把方法改成了iteration, 果然就避免了堆栈溢出的问题。由此可见,recursion虽然好想,但是需要很大空间的缺点不容忽视。以后如果我发现有可能递归太深或者每一次递归的参数需要的空间很大,我就应该避免使用递归的方法。

后面我还写了一个程序验证我的想法,我在对找到的行做binary search的时候用递归,不过这一次我用的参数不再是一整个矩阵,而是矩阵的这一行。结果,这次堆栈没有溢出。accept了。这证实了我之前的想法,果然用一个矩阵做递归参数真是太天真了。教训啊,我太naive了。不过,人不是就这样一点一点经验积攒而进步的吗?

下面是我的iteration方法,是有点不甚优化,但是好歹也accept了,

 1 public class Solution {
 2     public boolean searchMatrix(int[][] matrix, int target) {
 3         int lenrow = matrix.length;
 4         int lencol = matrix[0].length;
 5         if (lenrow == lencol && lenrow == 1) {
 6             if (matrix[0][0] == target) return true;
 7             else return false;
 8         }
 9         if (target < matrix[0][0] || target > matrix[lenrow-1][lencol-1]) return false;
10         int begin = 0;
11         int end = lenrow - 1;
12         int mid = (begin + end) / 2;
13         int row = 0;        
14         if (begin == end) row = begin;
15         else {
16             while (begin < end - 1) {
17                 mid = (begin + end) / 2;
18                 if (matrix[mid][0] == target) {
19                     row = mid;
20                     break;
21                 }
22                 else if (matrix[mid][0] < target) begin = mid;
23                 else end = mid;
24             }
25             if (matrix[mid][0] != target) {
26                 if (matrix[end][0] <= target) row = end;
27                 else row = begin;
28             }
29         }
30         
31         begin = 0;
32         end = lencol - 1;
33         mid = (begin + end) / 2;
34         if (begin == end) {
35             if (matrix[row][begin] == target) return true;
36             else return false;
37         }
38         while (begin < end - 1){
39             mid = (begin + end) / 2;
40             if (matrix[row][mid] == target) return true;
41             else if (matrix[row][mid] < target) begin = mid;
42             else end = mid;
43         }
44         if (begin == end - 1) {
45             if (matrix[row][begin] == target || matrix[row][end] == target) return true;
46         }
47         return false;
48     }
49     
50 }

下面是测试的recursion方法,证实了我之前问题是出在用整个矩阵做recursion参数,导致堆栈溢出。这次用矩阵的一行recursive,就不溢出了

 1 public class Solution {
 2     public boolean searchMatrix(int[][] matrix, int target) {
 3         int lenrow = matrix.length;
 4         int lencol = matrix[0].length;
 5         if (lenrow == lencol && lenrow == 1) {
 6             if (matrix[0][0] == target) return true;
 7             else return false;
 8         }
 9         if (target < matrix[0][0] || target > matrix[lenrow-1][lencol-1]) return false;
10         int begin = 0;
11         int end = lenrow - 1;
12         int mid = (begin + end) / 2;
13         int row = 0;        
14         if (begin == end) row = begin;
15         else {
16             while (begin < end - 1) {
17                 mid = (begin + end) / 2;
18                 if (matrix[mid][0] == target) {
19                     row = mid;
20                     break;
21                 }
22                 else if (matrix[mid][0] < target) begin = mid;
23                 else end = mid;
24             }
25             if (matrix[mid][0] != target) {
26                 if (matrix[end][0] <= target) row = end;
27                 else row = begin;
28             }
29         }
30         
31         return binarysearch(matrix[row], 0, matrix[0].length-1, target);
32     }
33     
34     public boolean binarysearch(int[] vector, int begin, int end, int target) {
35         if (begin == end) {
36             if (vector[begin] == target) return true;
37             else return false;
38         }
39         if (begin == end - 1) {
40             if (vector[begin] == target || vector[end] == target) return true;
41             else return false;
42         }
43         int mid = (begin + end) / 2;
44         if (vector[mid] == target) return true;
45         else if (vector[mid] < target) {
46             return binarysearch(vector, mid, end, target);
47         }
48         else {
49             return binarysearch(vector, begin, mid, target);
50         }
51     }
52 }

贴一个思路非常好的java解法,它是对整个矩阵做binary search, 不需要先寻找所在的行

 1 public class Solution {
 2     public boolean searchMatrix(int[][] matrix, int target) {
 3         // Start typing your Java solution below
 4         // DO NOT write main() function
 5         if(matrix==null || matrix.length==0 || matrix[0].length==0) 
 6             return false;
 7         int start = 0, end = matrix.length*matrix[0].length-1;
 8         
 9         while(start<=end){
10             int mid=(start+end)/2, midX=mid/matrix[0].length,
11                 midY=mid%matrix[0].length;
12             if(matrix[midX][midY]==target) return true;
13             if(matrix[midX][midY]<target){
14                 start=mid+1;
15             }else{
16                 end=mid-1;
17             }
18         }
19         return false;
20     }
21 }

再贴个和我方法类似的c++解法,我发现不用像我那样繁琐地考虑边界问题也是可以的:

 1 class Solution {
 2 public:
 3     bool searchMatrix(vector<vector<int> > &matrix, int target) {
 4         // Start typing your C/C++ solution below
 5         // DO NOT write int main() function
 6         int m = matrix.size();
 7         int n = matrix[0].size();
 8         int left = 0;
 9         int right = m-1;
10         int mid;
11         while (left <= right) {
12             mid = (left+right)/2;
13             if (target == matrix[mid][0]) return true;
14             if (target > matrix[mid][0]) left = mid+1;
15             else right = mid-1;
16         }
17         int row = (left+right)/2;
18         left = 0;
19         right = n-1;
20         while (left <= right) {
21             mid = (left+right)/2;
22             if (target == matrix[row][mid]) return true;
23             if (target > matrix[row][mid]) left = mid+1;
24             else right = mid-1;
25         }
26         return false;
27     }
28 };