剑指offer-二维数组中的查找

题目描述

  • 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
  • 地址:牛客链接

解决方法

  • 方法1:遍历整个二维数组,O(M*N)的时间复杂度,显然是不得分的答案
  • 方法2:注意题干,每一行与每一列都是排好序的,看到排序与查找这两个字眼,自然想到二分查找,可以外层循环遍历行,然后对每一行进行二分查找,也可以外层循环遍历列,然后对每一列进行二分查找,时间复杂度都是 O(M*logN)的形式,那么为了更优化一点,可以让M等于 min(行数,列数)
  • 方法3: 利用行列都排好序的特点,从右上角开始,用 row 与 col 标志当前数所在的行数与列数:

    • 如果当前数字比 target大,说明当前列都不符合标准,那么向左移动,col–;
    • 如果当前数字比 target 小,说明当前行都不符合标准,那么向下移动, row++;
    • 如果两者相等,那么直接 return true
      上述策略也有种缩小问题规模的思想,每一次淘汰一行或者一列,然后对新“形成”的二维数组进行迭代查找,row 与 col 始终标志新“形成”的二维数组的右上角元素。
      但是要注意数组越界问题,所以当数组发生越界时,直接结束循环,返回 false
      该方法时间复杂度为 O(M+N)。当然,也可以从左下角元素向右或者向上查找,同样的思想。
  • 方法2与3根据数据规模而定,哪一个更优

经验教训

  • 看到排序与查找这两个字眼,自然想到二分查找
  • 如何一步步缩小问题规模(方法3),进而迭代或者递归

代码实现

  • 方法2:
 public boolean Find(int target, int [][] array) {
        //二维数组基本判断
        if (array == null || array.length == 0 || array[0] == null || array[0].length == 0) {
            return false;
        }
        int m = 0;
        int n = 0;
        //以min(m,n)作为外循环次数,时间复杂度为O(m*longn)
        if (array.length < array[0].length) {
            m = array.length;
            n = array[0].length;
            for (int row = 0; row < m; row++) {
                int left = 0;
                int right = n - 1;
                while ( left <= right) {
                    int mid = ((left + right) >> 1);
                    if (array[row][mid] > target) {
                        right = mid - 1;
                    }else if (array[row][mid] < target) {
                        left = mid + 1;
                    }else {
                        return true;
                    }
                }
            }
        }else {
             m = array[0].length;
             n = array.length;
            for (int col = 0; col < m; col++) {
                int left = 0;
                int right = n - 1;
                while ( left <= right) {
                    int mid = ((left + right) >> 1);
                    if (array[mid][col] > target) {
                        right = mid - 1;
                    }else if (array[mid][col] < target) {
                        left = mid + 1;
                    }else {
                        return true;
                    }
                }
            }
        }

        return false;
    }
  • 方法3:
 public boolean Find(int target, int [][] array) {
        //二维数组基本判断
        if (array == null || array.length == 0 || array[0] == null || array[0].length == 0) {
            return false;
        }
        //从右上角开始查找
        int row = 0;
        int col = array[0].length - 1;
        while (row < array.length && col >= 0) {
            //当前元素大于target,向左移动
            if (array[row][col] > target) {
                col--;
            }else if (array[row][col] < target) {
                //当前元素大于target,向下移动
                row++;
            }else {
                //找到target
                return true;
            }
        }
        //未找到
        return false;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值