[剑指Offer]二维数组中的查找[java]

来源:互联网 发布:货运平台软件下载 编辑:程序博客网 时间:2024/05/23 15:07

题目描述

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

输入描述

array: 待查找的二维数组 
target:查找的数字

输出描述

查找到返回true,查找不到返回false

思路一

  • 查找的方法一般就是顺序查找、二分查找、哈希表查找、二叉排序树查找。
  • 根据该二维数组的特征,即行、列有序,我们可以首先想到使用二分查找,但这里是二维数组,至少要遍历一遍数组的长度,对每一行或者每一列进行二分查找,此时的时间复杂度将近是O(nlogn),我们可以继续优化。
  • 二分查找的过程中,会产生一棵二叉判定树,二叉判定树的特点就是,左子树小于根节点,右子树大于根节点。利用这个性质,我们可以将二维数组模拟成一个二叉判定树,此时就需要找出根节点,使得左子树小于根节点,右子树大于根节点,并且它的孩子节点也符合这种特性。根据给定条件,可以看到有两个点符合要求,即左下角和右上角。
  • 以左下角来说,往上数值递减,相当于左子树,往右递增,相当于右子树。所以,我们可以定义左右两个指针,初始时指向左下角节点作为根节点,当我们需要查找的数字比当前数组节点大的时候,右指针往右移一位,当需要查找的数字小于当前节点时,左指针往上移一位。代码如下:
    public static boolean Find2(int [][] array,int target) {        int rowsNum = array.length;//行的数量        int colsNum = array[0].length;//列的数量        int i = rowsNum - 1;        int j = 0;        while(i >= 0 && j < colsNum){            if(array[i][j] > target){                i--;            }else if(array[i][j] < target){                j++;            }else{                return true;            }        }        return false;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

思路二

如前面所说的,最先能想到的二分查找法,我们稍作一点点优化,即将二维数组以对角线划分为上三角很下三角数组,再分别对上三角和下三角进行二分查找。如下图: 
二分查找过程 
代码如下:

    public static boolean Find(int [][] array,int target) {        if(array == null || array.length == 0 || array[0] == null || array[0].length == 0){            return false;        }        int low,high,mid;        for(int j = 0; j < array.length; j++){            low = j;            high = array.length - 1;            mid = (low + high) / 2;            while(low <= high){                System.out.println(array[mid][j]);                if(array[mid][j] == target){                    return true;                }                if(array[mid][j] > target){                    high = mid - 1;                }else{                    low = mid + 1;                }                mid = (low + high) / 2;            }        }        for(int i = 0; i < array.length - 1; i++){            low = i + 1;            high = array[i].length -1;            mid = (low + high) / 2;            while(low <= high){                System.out.println(array[i][mid]);                if(array[i][mid] == target){                    return true;                }                if(array[i][mid] > target){                    high = mid - 1;                }else{                    low = mid + 1;                }                mid = (low + high) / 2;            }        }        return false;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

个人理解,应该是要比直接全部遍历二分查找好一点点…

0 0
原创粉丝点击