二維數組查找是否包含數字,時間複雜度優化

在一個二維數組中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。
請完成一個函數,輸入這樣的一個二維數組和一個整數.返回在二維數組是否包含此數字.

例如下面的二維數組就是每行、每列都遞增排序。如果在這個數組中查找數字7,則返回true;
如果査找數字5,由於數組不含有該數字,則返回false。

1   2    8   9
2   4    9   12
4   7   10  13
6    8  11   15


最簡單,也是最不得分的思路,遍歷唄,如果是a[n][m], 那麼時間複雜度就是O(n*m),

- (void)fun1 {
    const int section = 4;
    const int row = 4;

    int a[section][row] ={
        {1,2,8,9},
        {2,3,9,12},
        {4,7,10,13},
        {6,8,11,15},
    };
    // 找出7
    int result = 7;
    for (int i = 0; i<section; i++) {
        
        for (int j=0; j<row; j++) {
            
            if (a[i][j] == result) {
                NSLog(@"找到了 在%d行 第%d列",i,j);
                break;
            }
            
        }
        
    }
    
    NSLog(@"沒找到");

}

 


在上面的基礎上開始優化, 可以對每一行或者每一列進行優化,來一個二分查找,可以降低時間複雜度,這樣的話就是O(nlogm)或者O(mlogn),

- (void)fun1 {
    const int section = 4;
    const int row = 4;

    int a[section][row] ={
        {1,2,8,9},
        {2,3,9,12},
        {4,7,10,13},
        {6,8,11,15},
    };
    // 找出7
    int result = 7;
    for (int i = 0; i<section; i++) {
        
        int line = findIn(a[i], row, result);
        if (line>0) {
            NSLog(@"找到了  在%d %d",i,line);
        }
        
    }
    
    NSLog(@"沒找到");

}

// 二分查找,在長度爲count的有序遞增array中查找num,返回下標,-1表示沒有這個num
int findIn(int array[],int count,int num) {
    
    if (count<=0 || array == NULL) {
        NSLog(@"不合法");
        return -1;
    }
    int begin = 0;
    int end = count-1;
    
    while (begin<=end) {
        
        // 最小數>num,這個數不存在
        if (array[begin]>num) {
            break;
        }
        // 最大數<num,這個數不存在
        if (array[end]<num) {
            break;
        }
        
        // 說明在begin和end中間,二分查找
        int mid = (begin+end)/2;
        if (array[mid] > num) {
            end = mid-1;
        } else if (array[mid] < num) {
            begin = mid+1;
        } else if (array[mid] == num) {
            NSLog(@"找到了 %d在下標爲%d的位置",num,mid);
            return mid;
        }
        
    }
    
    NSLog(@"沒找到%d",num);
    return -1;
}

這個是看了劍指offer中的做法, 選取右上角,左下角都可以,但是左上角和右下角是不可以的.
首先選取數組中右上角的數字。

  • 如果該數字等於要查找的數字,查找過程結束;
  • 如果該數字大於要査找的數字,剔除這個數字所在的列;
  • 如果該數字小於要查找的數字,剔除這個數字所在的行。   

也就是說如果要查找的數字不在數組的右上角,則每一次都在數組的查找範圍中別除一行或者一列,這樣每一步都可以縮小査找的範圍,直到找到要査找的數字,或者查找範圍爲空。一次比較可以處理一行或者一列,整體下來,時間複雜度是O(n+m), 時間複雜度已經到線性級別了.


這樣一條線也是單調遞增的,所以右上角這個位置可以一次處理一行或者一列數據.


- (void)fun1 {
    const int section = 4;
    const int row = 4;

    int a[section][row] ={
        {1,2,8,9},
        {2,3,9,12},
        {4,7,10,13},
        {6,8,11,15},
    };
    // 找出7
    int result = 7;
    // 從右上角開始
    int i = 0;
    int j = row-1;
    while (i<section && j>=0) {
        // 取右上角的數字
        // 右上角>result,說明這一列是不會有了,j--
        if (a[i][j] > result) {
            j--;
            // 右上角<result,說明這一行是不會有了,i++
        } else if(a[i][j] < result) {
            i++;
        }else {
            NSLog(@"找到了 在(%d,%d)位置",i,j);
            return;
        }
    }
    /*
    // 從左下角開始
    int i = section-1;
    int j = 0;
    while (i>=0 && j<row) {
        // 取左下角的數字
        // 左下角>result,說明這一行是不會有了,i--
        if (a[i][j] > result) {
            i--;
            // 左下角<result,說明這一列是不會有了,j++
        } else if(a[i][j] < result) {
            j++;
        }else {
            NSLog(@"找到了 在a[%d][%d]位置",i,j);
            return;
        }
    }
    */
    NSLog(@"沒找到");

}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章