1. 程式人生 > 實用技巧 >leetcode 劍指offer 4 二維陣列中的查詢

leetcode 劍指offer 4 二維陣列中的查詢

問題:在一個 n * m 的二維陣列中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個高效的函式,輸入這樣的一個二維陣列和一個整數,判斷陣列中是否含有該整數。

解題思路:
若使用暴力法遍歷矩陣 matrix ,則時間複雜度為 O(NM)O(NM) 。暴力法未利用矩陣 “從上到下遞增、從左到右遞增” 的特點,顯然不是最優解法。

如下圖所示,我們將矩陣逆時針旋轉 45° ,並將其轉化為圖形式,發現其類似於 二叉搜尋樹 ,即對於每個元素,其左分支元素更小、右分支元素更大。因此,通過從 “根節點” 開始搜尋,遇到比 target 大的元素就向左,反之向右,即可找到目標值 target 。

“根節點” 對應的是矩陣的 “左下角” 和 “右上角” 元素,本文稱之為 標誌數 ,以 matrix 中的 左下角元素 為標誌數 flag ,則有:

  • 若 flag > target ,則 target 一定在 flag 所在 行的上方 ,即 flag 所在行可被消去。
  • 若 flag < target ,則 target 一定在 flag 所在 列的右方 ,即 flag 所在列可被消去。

演算法流程:

  • 從矩陣 matrix 左下角元素(索引設為 (i, j) )開始遍歷,並與目標值對比:
  • 當 matrix[i][j] > target 時,執行 i-- ,即消去第 i 行元素;
  • 當 matrix[i][j] < target 時,執行 j++ ,即消去第 j 列元素;
  • 當 matrix[i][j] = target 時,返回 truetrue ,代表找到目標值。
  • 若行索引或列索引越界,則代表矩陣中無目標值,返回 falsefalse 。
  • 每輪 i 或 j 移動後,相當於生成了“消去一行(列)的新矩陣”, 索引(i,j) 指向新矩陣的左下角元素(標誌數),因此可重複使用以上性質消去行(列)。

複雜度分析:
時間複雜度 O(M+N)O(M+N) :其中,NN 和 MM 分別為矩陣行數和列數,此演算法最多迴圈 M+NM+N 次。
空間複雜度 O(1)O(1) : i, j 指標使用常數大小額外空間。

class Solution {
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
        int i = matrix.size() - 1, j = 0;
        while(i >= 0 && j < matrix[0].size())
        {
            if(matrix[i][j] > target) --i;
            else if(matrix[i][j] < target) ++j;
            else return true;
        }
        return false;
    }
};