二维数组查找是否包含数字,时间复杂度优化

在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。
请完成一个函数,输入这样的一个二维数组和一个整数.返回在二维数组是否包含此数字.

例如下面的二维数组就是每行、每列都递增排序。如果在这个数组中查找数字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(@"没找到");

}

 

 

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