zoukankan      html  css  js  c++  java
  • 剑指offer——二维数组中的查找问题

    今天开始刷剑指offer,首先是关于数组的问题,原题目链接:二维数组中的查找问题

    我们把题目在此处重新复述一遍:

    题目描述:

    在一个二维数组中(每一个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否有该整数。

    题目分析:

    据题可以得到如下几个条件:1.二维数组是有序的;2.从该数组中查找某个数是否存在。

     有序二维数组

    如果只看第2个条件,那肯定会直观的想到挨个取出数组中的每个元素,比较是否存在。很明显,这种方法不是最好的;因为如果数组中不存在该数值,则需要把所有的元素都取出来比较。

    那么对于有序的数组,我们可以进行哪些查找操作呢?

    1.如果是一维数组,那肯定是要用效率最高的二分查找;那么在二维数组中可不可以用二分呢?该怎么用呢?

    2.直接考虑二维数组,有没有什么好的方法呢?

    先看一下二分方法

    对于一维有序递增数组,二分便是拿出中间位置的元素比较;若该数值大于中间元素;说明该数值不会出现在前一半位置;所以可能在后一半元素中,对后一半元素依然使用该方法,直到只剩下一个元素为止。

    一维二分查找示意图

     二维有序数组如何使用二分?

    我们可以简单的把二维数组当作多个一维有序数组;分别对每个一维数组使用二分查找即可。此种方法的实现代码如下:

    //使用二分
        public boolean Find(int target, int [][] array) {
            // 二维数组有m行n列
            int m = array.length;
            int n = array[0].length;
            // 数组需非空
            if(m <= 0 || n <= 0){
                return false;
            }
            // 目标数也不能越界
            if(target < array[0][0] || target > array[m-1][n-1]){
                return false;
            }
    
            // 对m行分别使用二分
            for(int i=0; i<m; i++){
                
                int left = 0;
                int right = n-1;
                int middle = 0;
                
                while(left <= right){
                    middle = (left + right) / 2;
                    if(target < array[i][middle]){
                        right = middle - 1;
                    }else if(target >array[i][middle]){
                        left = middle + 1;
                    }else{
                        return true;
                    }
                }
            }
            return false;
        }
    View Code

    此代码在牛客网上运行时间为149ms。

    再看一下直接考虑二维数组

     上面的算法虽然还不错,但是该算法基本是对每一行都进行二分查找操作;这样肯定不是最好的。那么再来观察一下数组的特性:

    1.从左到右是递增的

    2.从上到下是递增的

    再观察一下图形:

    有序二维数组

    仔细观察可以发现,左下角的元素,向右是增加,向上是减小右上角的元素,向下是增加,向左是减小

    假如选择这两个特殊点作为起始比较点,那么比较一次就可以直接排除一行或者一列元素

    左下角为例,如果目标数值大于6,则第1列不可能有该目标数值;那么待比较数组就变成了3行3列再选取新待比较数组的左下角元素7;若目标数值小于7,则最后一行不可能有该目标数值新的待比较数组又变成了2行3列。持续下去,直至新的待比较数组不存在或者找到该目标元素为止。

    此种方法的实现代码如下:

    public boolean Find(int target, int [][] array) {
            // 二维数组有m行n列
            int m = array.length;
            int n = array[0].length;
            // 数组需非空
            if(m <= 0 || n <= 0){
                return false;
            }
            // 目标数也不能越界
            if(target < array[0][0] || target > array[m-1][n-1]){
                return false;
            }
    
            // 从左下角开始比较
            int row = m-1;
            int col = 0;
            while(row >= 0 && col < n){
                if(target > array[row][col]){
                    col++;
                }else if(target < array[row][col]){
                    row--;
                }else{
                    return true;
                }
            }
            return false;
        }
    View Code

    此代码在牛客网上运行时间为117ms。

    目前为止只想到这两种方法,更高效的暂时还没想到。先这样吧,继续刷起。

  • 相关阅读:
    17字符串函数
    16数学函数
    计算文件的相对路径
    PHP生成唯一ID的方法
    PHP高效产生m个n范围内的不重复随机数(m<=n)
    随机红包
    约瑟夫环问题
    求n以内的质数(质数的定义:在大于1的自然数中,除了1和它本身意外,无法被其他自然数整除的数)
    10个值得深思的_PHP_面试问题
    PHP中被忽略的性能优化利器:生成器
  • 原文地址:https://www.cnblogs.com/shengguilv/p/12769280.html
Copyright © 2011-2022 走看看