1. 程式人生 > >劍指offer-03:二維陣列(行列遞增)的查詢

劍指offer-03:二維陣列(行列遞增)的查詢

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

這裡寫圖片描述

初看題目,容易想到既然是有序陣列,可按二分的思想查詢。選取某個數字剛和和要查數相等時返回;選取數字小於要查詢的數字,查詢放到當前位置的右方或者下方;若大於要查詢的數字,查詢放在當前位置的上方或者左方。

然而分割槽域後,情況變得複雜,要查詢的區域變成L折行,雖然減小了查詢範圍,但並沒有清晰辦法下一步查詢。陷入其中。

根據二分查詢,第一次砍去一半,剩下的一半在第二次中可以繼續“砍半”操作,這問題逐次是類似的。上述失敗的地方在於兩次問題完全不一樣,越搞越複雜。

考慮:每一行,每一列都是從小到大排列。

我們以每次陣列的第一行的最大值MAX為例討論。

  • 當其大於查詢數N時,則MAX為首的列必然都大於N,該列可捨去得到新陣列。
  • 當其小於N時,則MAX所在的行可捨去,因為它是該行最大值。

這樣,我們不斷砍去當前陣列的最後一列,或第一行,不斷縮小陣列範圍,直到某次MAX=N找到,或者陣列玩完了沒找到。

同樣,以每一列的最大值查詢,查詢過程和上述方向不一樣罷了。上述從右上角往左下角前進,本段則從左下角往右上角前進。

我們不能從左上角,右下角找起,因為這樣帶來不確定。

實際上述查詢思想正是二分法。這樣來看待陣列:

這裡寫圖片描述

9恰好是紅線序列的中值,捨去後新的藍線序列也是增序。我們始終在做二分查詢。所以效率很高。

程式碼:

#include "stdafx.h"
#include <iostream>

using namespace std;

bool Find(int * matrix, int rows, int columns, int number)
{
    bool found = false;

    if (matrix != nullptr && rows > 0 && columns > 0)
    {
        int row = 0;
        int column = columns - 1;
        // 迴圈到頭沒找到返回
while (row < rows && column >= 0) { // 找到返回 if (matrix[row*columns + column] == number) { found = true; break; } // 大於查詢值,該列捨去,仍為二維陣列 else if (matrix[row*columns + column] > number) --column; // 小於查詢值,該行捨去,仍為二維陣列 else ++row; } } return found; } int main() { int a[4][4] = { {1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15} }; cout << Find((int *)a, 4, 4, 3) << endl; return 0; }