題目:
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:
- Integers in each row are sorted from left to right.
- The first integer of each row is greater than the last integer of the previous row.
For example,
Consider the following matrix:
[ [1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 50] ]
Given target = 3
, return true
.
題解:
雖然本題看似是矩陣問題,但是本著搜尋題目關鍵字為第一步的原則,可以找到:each row are sorted,每一行按照順序也是sorted。同時也是陣列儲存。
但是本題的難點就是如何將2D矩陣轉換成1D,然後利用二分查詢法來解決問題。轉換的重點就在於每個點的位置,在矩陣表示中,我們習慣用(i,j)來表示一個點,所以這就有礙於我們使用low high mid來指向需要的位置。為了解決問題,第一步就是需要將這個矩陣按照順序拉成一條線。
像題中的例子我可以將其轉化為:
position: 0 1 2 3 4 5 6 7 8 9 10 11
values: 1 3 5 7 10 11 16 20 23 30 34 50
row: 0 0 0 0 1 1 1 1 2 2 2 2
column: 0 1 2 3 0 1 2 3 0 1 2 3
其中:行數rows=3,列數columns=4
如上,這個就是將2D矩陣轉化成1行陣列的對應表。所以對於二分查詢法的初始值為:low=0,high=rows*columns-1(總共數值的個數,因為從0開始所以減1)。而為了能夠方便在given 2D matrix找到需要比對的值,我們還是需要確定行數和列數,通過上表可以看出,行數是position/columns,而列數是position%columns, 這樣一來,就能很容易的在原矩陣中定位到所需要的值。剩下其他的解題思路,就與二分查詢法一模一樣了。
時間複雜度O(log(rows*columns))
程式碼如下:
2 if(matrix.length==0||matrix[0].length==0||matrix==null)
3 return false;
4
5 int rows = matrix.length;
6 int cols = matrix[0].length;
7
8 int low = 0;
9 int high = rows*cols-1;
10
11 while(low<=high){
12 int mid = (low+high)/2;
13 int midValue = matrix[mid/cols][mid%cols];
14 if(midValue == target)
15 return true;
16 else if(midValue < target)
17 low = mid+1;
18 else
19 high = mid-1;
20 }
21 return false;
22 }
同時,也有另外一個解決該題的方法,就是利用兩次二分查詢法。因為所給矩陣第一列也是升序排列的,所以可以先對第一列進行二分查詢,鎖定該元素所在行數,然後再對列進行二分查詢,即可判斷target是否存在。這個的演算法時間複雜度是O(log(rows)+log(columns))。
程式碼如下:
2 if(matrix == null || matrix.length==0 || matrix[0].length==0)
3 return false;
4 int low = 0;
5 int high = matrix.length-1;
6 while(low<=high){
7 int mid = (low+high)/2;
8 if(matrix[mid][0] == target)
9 return true;
10 else if(matrix[mid][0] > target)
11 high = mid-1;
12 else
13 low = mid+1;
14 }
15
16 int row = high; //當從while中跳出時,low指向的值肯定比target大,而high指向的值肯定比target小
17
18 if(row<0)
19 return false;
20
21 low = 0;
22 high = matrix[0].length-1;
23 while(low<=high){
24 int mid = (low+high)/2;
25 if(matrix[row][mid] == target)
26 return true;
27 else if(matrix[row][mid] > target)
28 high = mid-1;
29 else
30 low = mid+1;
31 }
32 return false;
33 }
Reference:
http://www.programcreek.com/2013/01/leetcode-search-a-2d-matrix-java/
http://blog.csdn.net/linhuanmars/article/details/24216235