本專題旨在分享刷Leecode過程發現的一些思路有趣或者有價值的題目。【當然是基於js進行解答】。
題目相關
- 原題地址: https://leetcode-cn.com/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/
題目描述:
在一個 n * m 的二維陣列中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個高效的函式,輸入這樣的一個二維陣列和一個整數,判斷陣列中是否含有該整數。
現有matric如下: [ [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。 限制條件 0 <= n <= 1000 0 <= m <= 1000
思路解析
首先,暴力破解肯定是最容易想到的,但是很顯然不對,如果是暴力破解,極限壞的情況複雜度是
m*n > 1000000
(如果暴力可以那題設的單調遞增條件就沒有意義了,如果面試答題用暴力破開破解,估計面試官就是這樣的表情:)然後是:
- 其次, 考慮該如何利用單調性呢,如果是一維陣列,很容易想到二分法, 但是這是二維陣列, 這個思路顯然也行不通。
這樣不行,那也不行。那麼最後就只能從樹來考慮了,注意題設裡寫到陣列的規律是:每一行從左到右遞增,每一列從上到下遞增,那麼很顯然(易知(#^.^#)),假設把右上角元素當做一棵樹的根節點,那麼以它基準,向左查詢依次遞減,向下查詢依次遞增,如下:
發現什麼了沒?
(新雞次哇一次摸hi多次!)這就是一顆二叉搜尋樹啊! 當然,可能還有同學不知道啥是二叉搜尋樹,問題不大。 簡單的來說,每個節點的左邊子節點一定小於它的右邊子節點。 那麼解法也就躍然紙上了!
從右上角節點(左下角也可以的,同理)開始搜尋:
- 如果targe < 當前節點,那麼意味著結果只可能落在左邊的子樹,右邊的子樹都不用查了,對應到二維陣列裡也就是--往左移動一列;
- 如果targe > 當前節點, 那麼意味著結果只可能落在右邊的子樹,左邊的子樹都不用查了,對應到二維陣列裡也就是--往下移動一行;
- 如果target = 當前節點, 那麼好耶! 查詢到了,返回true
如果遍歷完全部節點還是沒找到,那麼說明目標節點不存在,結束;
完整程式碼
理解了前面的核心內容,其實程式碼就不難寫了,最後貼上完成程式碼:
/**
* @param {number[][]} matrix
* @param {number} target
* @return {boolean}
*/
var findNumberIn2DArray = function(matrix, target) {
const m = matrix.length;
if(m === 0 ) {return false};
const n = matrix[0].length;
for(let i = 0,j = n-1; i < m && j >= 0;) {
if(target === matrix[i][j]){
return true;
}
if(target > matrix[i][j]) {
i++;
continue;
}
if(target < matrix[i][j]) {
j--;
}
}
return false;
};
簡簡單單一道題又搞定了!