1. 程式人生 > >Leetcode: 240. Search a 2D Matrix II (week2 --- medium)

Leetcode: 240. Search a 2D Matrix II (week2 --- medium)

 題目

題意

題解

最簡單(實現最簡單)的方法  複雜度:O()

找特殊位置元素法  複雜度:O(n+m)

歸併方法 

總結


 題目

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 in ascending from left to right.
  • Integers in each column are sorted in ascending from top to bottom.

題意

這是一個比較特別的矩陣,這個矩陣滿足以下兩個條件:從左到右是有序的,從上到下也是有序的。而這一道題是為了判斷某個元素是否存在於這一個矩陣中。

題解

最簡單(實現最簡單)的方法  複雜度:O(n*m)

也就是遍歷了。本來沒有想過這種方法可以過檢測的,結果試了一下居然是Accept。因為Vector實際上跟陣列是非常相像的,所以在進行遍歷的時候是可以進行下標訪問的。當然啦,也是可以使用vector的find函式進行查詢,find函式是優化過的,所以執行的時間會更加短。

簡單的遍歷演算法(1384ms)

for(int i = 0; i < matrix.size(); i++){
    for(int j = 0; j < matrix[0].size(); j++){
        if(matrix[i][j] == target)
        {
            return true;
        }
    }
}
return false;

使用了find演算法函式之後,(628 ms),不知道這個函式的演算法實現是怎麼寫的,但是看C++ -- Reference網站的時候,裡面只是提到了跟前面的實現是等同的。

for(int i = 0; i < matrix.size(); i++){
    vector<int>::iterator j = find(matrix[i].begin(), matrix[i].end(), target);
    if(j != matrix[i].end()){
        return true;
    }
}
return false;

找特殊位置元素法  複雜度:O(n+m)

這一道題的好處在於元素從左到右以及從上到下都是有序的。

而壞處也同樣在於在每一個節點大於該節點的方向存在兩個,所以就不好進行決策。但是我們可以發現在下邊界以及有邊界上的點的特性確實比較好的,因為大於該元素的方向只有一個,而小於該元素的方向則可以依據一定的規則而變為一個,這裡是採用第一行的最後的元素作為最開始的起點,然後根據該點值與目標值之間的大小關係,當目標值大於該元素的時候便進行縱座標的下移操作。相反則進行橫座標的左移操作。這樣的話,演算法的複雜度便會下降很多,也就是則壞的情況下複雜度為O(m+n)

一下方法的時間消耗為:36ms

int m = matrix.size();
if(m == 0){
    return false;
}
int n = matrix[0].size();
int i = 0;
int j = n - 1;
while(i < m && j >= 0){
    if(matrix[i][j] == target){
        return true;
    }
    else if(matrix[i][j] < target ){
        i++;
    }
    else{
        j--;
    }
}
return false;

歸併方法 

以下方法的時間是200ms,比起前面的找特殊元素的演算法時間消耗也是比較大的了。主要的步驟在與每次對行和列進行二分操作,那麼久會分成四個部分,然後在跟據這四個部分的首位元素進行大小的比較然後判斷這個元素是否存在與這個矩陣之中。

bool divide(vector<vector<int>>& matrix, int target, int row1, int col1, int row2, int col2){
    if(row1 > row2 || col1 > col2){
        return false;
    }
    else if(row1 == row2 && col1 == col2){
        return matrix[row1][col1] == target;
    }
    else if(target < matrix[row1][col1] || target > matrix[row2][col2]){
        return false;
    }
    int row_mid = row1 + (row2 - row1)/2;
    int col_mid = col1 + (col2 - col1)/2;
    return (
            divide(matrix, target, row1, col1, row_mid, col_mid) ||
            divide(matrix, target, row1, col_mid + 1, row_mid, col2) ||
            divide(matrix, target, row_mid + 1, col1, row2, col_mid) ||
            divide(matrix, target, row_mid + 1, col_mid, row2, col2)
            );
}
bool searchMatrix(vector<vector<int>>& matrix, int target) {
    if(matrix.size() == 0 || matrix[0].size() == 0){
        return false;
    }
    return divide(matrix, target, 0, 0, matrix.size() - 1, matrix[0].size()- 1);
}

總結

上面總共提供了三種方法,但是還是有其他優化方法的,比如:由於每一行每一列是有序的,所以可以利用查詢演算法進行復雜度的優化,可以利用二分查詢等。這道題還提示了我們以後再做題的時候可以進行一番觀察之後找到特殊的位置的元素然後進行突破。