問題描述
在一個二維整數數組中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,
輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數。
參數說明
int[][] array:二維數組
target:整數
存在返回true,否則返回false
暴力直接遍歷整個二維數組
不做解釋
public boolean Find1(int[][] array, int target) {
for (int arraya[] : array) {
for (int b : arraya) {
if (target == b) {
return true;
}
}
}
return false;
}
二分法
對於有序的數組,二分法無疑是最優的算法。將每一行的元素使用二分法查找元素。
// 將每一行的元素進行二分查找
public boolean Find2(int[][] array, int target) {
for (int i = 0; i < array.length; i++) {
int low = 0;
int high = array[i].length - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (target > array[i][mid])
low = mid + 1;
else if (target < array[i][mid])
high = mid - 1;
else
return true;
}
}
return false;
}
左下角元素開始遍歷
將每一列視爲整體,每一列中最大的元素爲最下面的一個。所以我們只需比較每一列的最大的元素,當小於這個元素時,向上用二分法查找這一列的元素。
// 從左下角開始遍歷,元素大於target時向上遍歷,小於則向右遍歷
public boolean Find3(int[][] array, int target) {
int len = array.length - 1;
int i = 0;
while ((len >= 0) && (i < array[0].length)) {
if (array[len][i] > target) {
len--;
} else if (array[len][i] < target) {
i++;
} else {
return true;
}
}
return false;
}
分模塊二分+遞歸查找
而且這樣的矩陣有個性質,最左上角的元素必定是最小值,最右下角的是最大值,在一個
nn的矩陣中,對角線的元素也是排好序的,找到對角線上的一個元素,使得這個元素小於
待查找的key,並且下一元素大於待查找的key,那麼只要在這個元素的左下角矩陣和右上角
矩陣遞歸繼續對角線查找就可以了,例如上圖例子裏查找7,只要找到對角線的元素4,然後
遞歸查找紅圈的矩陣就可以了,左上角矩陣最大值4<7,右下角
矩陣最小值10>7,無需查找了,但是此題並沒有告訴我們原始矩陣是nn的,這是比較麻煩的
地方,不過思路是一樣的,無非不能用對角線查找這樣簡單的辦法了,假設m*n的矩陣,對角線
查找的辦法改進爲i = (m1+m2)/2,j = (n1+n2)/2 進行查找就可以了,(m1,n1)爲矩陣最左上角
元素下標,(m2,n2)爲最右下角元素下標
假設查找17,第一次比較10,然後比較25,然後比較13,返回元素13,這時候再遞歸查找13
左下角的矩陣和右上角的矩陣就可以了(紅色橢圓部分);如果是查找9,第一次比較10,然後比較4,
然後比較6,返回元素6,這時候遞歸查找6左下角的矩陣和右上角矩陣(綠色橢圓部分)。