• 二维数组(矩阵)元素查找


    题目描述

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

    思考

    1. 二分查找
    a1 a2 a3 a4 a5 a6
    b1
    c1
    d1
    e1
    f1

    总结

    题目的理解错了,错误的认为,矩阵满足这样的规律:

    1 2 3 4
    5 6 7 8
    9 10 11 12
    13 14 15 16

    其实这只是一个特例,题目只说举证中的元素满足“左小右大,上小下大”的特点,更一般的矩阵是这样的:

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

    正确理解的题目的意思以后,我编写出了满足题目要求的代码。具体的思路是:遍历每一行,对每一行进行二分查找。

    package com.learn.java;
    
    import java.util.Arrays;
    
    /**
     * @author xzy
     * @date 2020-03-25 18:56
     * 说明:
     */
    public class Main {
        public static void main(String[] args) {
            Main main = new Main();
            int[][] array = new int[][]{
                    {1, 2, 8, 9},
                    {2, 4, 9, 12},
                    {4, 7, 10, 13},
                    {6, 8, 11, 15}
            };
            for (int i = 0; i < 40; i++) {
                System.out.println("target:" + i + " find:" + main.find(i, array));
            }
        }
    
        /**
         * @param target - 查找目标
         * @param array  - 查找数组
         * @return 找到:元素下标  找不到:-1
         */
        public int binarySearch(int target, int[] array) {
            // head:查找区间头 middle:查找区间中 end:查找区间尾
            int head = 0;
            int end = array.length - 1;
            int middle = end / 2;
    
            //1. 不可能找得到
            if (target < array[head] || target > array[end]) {
                return -2;
            }
    
            //2. 二分查找
            while (head <= end) {
                if (target == array[middle]) {
                    //1. 找到
                    return middle;
                } else if (target < array[middle]) {
                    //2.向左侧继续找
                    end = middle - 1;
                    middle = (end - head) / 2 + head;
                } else {
                    //3.向右侧继续找
                    head = middle + 1;
                    middle = (end - head) / 2 + head;
                }
            }
            return -1;
        }
    
        public boolean find(int target, int[][] array) {
            for (int row = 0; row < array[0].length; row++) {
                if (binarySearch(target, array[row]) >= 0) {
                    return true;
                }
            }
            return false;
        }
    }
    

    优化

    仔细的琢磨“左小右大,上小下大”

    1 2 3 9
    2 4 9 12
    4 7 10 13
    7 8 15 15
    1. 行角度
    第1行最右边的元素,是第一行最大的。
    
    第2行最右边的元素,是前两行最大的。
    
    第3行最右边的元素,是前三行最大的。
    
    第4行最右边的元素,是前四行最大的。
    
    1. 列角度
    第1列最后一个元素,是第一列最大的。
    
    第2列最后一个元素,是前两列最大的。
    
    第3列最后一个元素,是前三列最大的。
    
    第4列最后一个元素,是前四列最大的。
    

    新的算法思想:从行列角度出发,从第一行开始,将target与每一行最后一个元素比较,排除target不可能存在的行,同时排除target不可能存在的列。

    以target == 11为例,将target与第一行最后一个元素9比较,发现target > 9,而9又是第1行最大的元素,显然,target不可能存在于第一行。继续将target与第二行最后一个元素12比较,发现target<12,而12又是第4列后3行中最小的元素,显然,target不可能存在于第4列。
    

    上述算法不断缩小元素可能存在的范围,范围的缩小过程是这样的:

    1. target > 9
    1 2 3 9
    2 4 9 12
    4 7 10 13
    7 8 15 15
    1. target < 12
    2 4 9 12
    4 7 10 13
    7 8 15 15
    1. target > 9
    2 4 9
    4 7 10
    7 8 15
    1. target > 10
    4 7 10
    7 8 15
    1. target < 15

      7 8 15
    2. target > 8

      7 8
    3. 已经没有范围缩小到0,可以确认,矩阵中不存在target。

    利用新的思想,新的实现代码:

    public boolean find2(int target, int[][] array) {
    
        //rowMax:行坐标最大值 columnMax:列坐标最大值
        int rowMax = array.length - 1;
        int columnMax = array[0].length - 1;
    
        //空矩阵判断
        if (rowMax < 0 || columnMax < 0) {
            return false;
        }
    
        //target是否有可能存在于矩阵
        if (target < array[0][0] || target > array[rowMax][columnMax]) {
            return false;
        }
    
        //(rowPoint,columnPoint)当前检查元素的坐标
        int rowPoint = 0;
        int columnPoint = columnMax;
        while (rowPoint <= rowMax && columnPoint >= 0) {
            if (target == array[rowPoint][columnPoint]) {
                return true;
            } else if (target > array[rowPoint][columnPoint]) {
                //不可能在这一行
                rowPoint++;
            } else {
                //不可能在这一列
                columnPoint--;
            }
        }
        return false;
    }
    
  • 相关阅读:
    SendMessage 和 SendMessageTimeout 可能存在异常(除超时)
    类型强制转换符 与 + 符的优先级
    茵茵的第一课
    C小加 之 随机数
    16进制的简单运算
    交换输出
    计算球体积
    a letter and a number
    A problem is easy
    Coin Test
  • 原文地址:https://www.cnblogs.com/XiaoZhengYu/p/12573856.html
Copyright © 2020-2023  润新知