剑指 offer 第一题: 二维数组中的查找

打算写 图解剑指 offer 66 题 的系列文章,不知道大家有没有兴趣 ??

题目描述

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

题目分析

图 1

如果没有头绪的话,很显然使用 暴力解法 是完全可以解决该问题的。

即遍历二维数组中的每一个元素,时间复杂度:O(n^2)。

其实到这里我们就可以发现,使用这种暴力解法并没有充分利用题目给出的信息。这个二维数组是有特点的。

  • 每一行都是递增
  • 每一列都是递增

图 2

解法

解法一:二分法

对于有序数组的查找问题而言,二分法是最容易想到的一个解法。

在这里,对每一行使用二分查找,时间复杂度为 O(nlogn) 。二分查找复杂度 O(logn),一共 n 行,所以是总体的时间复杂度是 O(nlogn) 。

解法二:规律法

根据二维数组由上到下,由左到右递增的规律。

从左下角开始遍历,如果当前值比 target 小则往右找,如果比 target 大则往上找,如果存在,必然可以找到目标数字。

即选取右上角或者左下角的元素 a[row] [col] 与 target 进行比较, 当 target 小于元素 a[row] [col] 时,那么 target 必定在元素 a 所在行的左边,让 col-- ;当 target 大于元素 a[row] [col] 时,那么 target 必定在元素 a 所在列的下边,让 row++ ;

图 3

代码如下:

public class Solution {     public boolean Find(int target, int [][] array) {        int row = 0;        int col = array[0].length - 1;        while(row <= array.length - 1 && col >= 0){            if(target == array[row][col])                return true;            else if(target > array[row][col])                row++ ;            else                col-- ;        }        return false;    }}

解法三:二分规律法

将解法一和解法二进行结合:对每行每列都使用二分查找,此时的时间复杂度为 O(logn * logm)

图 4

比如查找数字 9,首先使用用二分查找选出一行,总共有 5 行,那么( 0 + 5 ) / 2 = 2,所以我们找出了第 2 行为基准行。

图 5

接下来对这一行(即第 2 行)又使用二分查找, 找出这一行(即第 2 行)中最后一个比目标值小的值,这里是 6。

图 6

6 及其所在的行和列把这个矩形划分为 4 部分:

图 7

  1. 左上部分(图 7 灰色部分),包括所在行的左边部分和所在列的上边部分:这一部分是绝对不会有目标数字的。因为这部分数字肯定比 6 小,而 6 又是小于目标数字的,所以左上部分全部小于目标数字。也就是说这个区域的数字不需要再进行判断了。
  2. 右下部分(图 7 绿色部分),包括所在行的右边部分,但不包括所在列的下面部分, 这一部分也是绝对不会有目标数字的。因为这部分都比 6 右边的数字 11 大,而 11 又比目标数字 9 更大,所以右下部分全部都比目标数字大。也就是说这个区域的数字也不需要再进行判断了。
  3. 左下部分(图 7 蓝色部分),可能含有目标数字。
  4. 右上部分(图 7 棕色部分),可能含有目标数字。

这样,实际上筛选的区域就只剩下左下部分(图 7 蓝色部分)右上部分(图 7 棕色部分)这两块区域了,相比于解法二而言,使用这种解法平均情况下每一次查找,都可以把行和列的长度减少一半

代码如下:

public class Solution {       public boolean Find(int target, int [][] array) {       // 特殊情况处理       if (array == null || array.length == 0 || array[0].length == 0) {            return false;        }

        int h = array.length - 1;        int w = array[0].length - 1;

        // 如果目标值小于最小值 或者 目标值大于最大值,那肯定不存在        if (array[0][0] > target || array[h][w] < target) {            return false;        }        return binarySearchIn2DArray(array, target, 0, h, 0, w);    }

     public static boolean binarySearchIn2DArray(int[][] array, int target, int startX, int endX, int startY, int endY) {        if (startX > endX || startY > endY) {            return false;        }        //首先,根据二分法找出中间行        int x = (startX + endX) / 2;        //对该行进行二分查找        int result = binarySearch(array[x], target, startY, endY);        //找到的值位于 x 行,result 列        if (array[x][result] == target) {            return true; // 如果找到则成功        }        //对剩余的两部分分别进行递归查找        return binarySearchIn2DArray(array, target, startX, x - 1, result + 1, endY)                || binarySearchIn2DArray(array, target, x + 1, endX, startY, result);    }

     public static int binarySearch(int[] array, int target, int start, int end) {        int i = (start + end) / 2;        if (array[i] == target || start > end) {             return i;        } else if (array[i] > target) {            return binarySearch(array, target, start, i - 1);        } else {            return binarySearch(array, target, i + 1, end);        }    }}

感兴趣的话可以看看我之前写的一个项目 LeetCodeAnimation,目前有 13000 star。
原文首发于公号「五分钟学算法」链接:剑指 offer 第一题: 二维数组中的查找

原文地址:https://www.cnblogs.com/fivestudy/p/10437229.html

时间: 2024-10-17 21:04:42

剑指 offer 第一题: 二维数组中的查找的相关文章

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

二维数组中的查找 题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. #include<iostream> #include<vector> using namespace std; class Solution { public: bool Find(int target, vector<vector<int> > array) {

剑指offer一:二维数组中的查找

题目: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 思路: 这是一个顺序二维数组,可以从右下角处开始查找.本题中需要注意数组下限,不要忘记减一 public class Solution { public boolean Find(int target, int [][] array) { int row = 0; int col = array[0].length -1

《剑指Offer》题目——二维数组中的查找

题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 题目分析: 暴力破解时间复杂度太高,本题有两种思路:1. 将每行看成一个有序数组,用二分查找2. 从左下角开始查找,若大于该值,右移:若小于该值,上移,直到找到为止 public class ArraySearch { public static boolean Find(int target, int [][] ar

《剑指Offer》之二维数组中的查找

1.题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 2.代码实现 1 public class Solution { 2 3 public boolean Find(int[][] array,int target) { 4 5 for(int i = 0; i < array.length; i++){ 6 for(int j = 0; j < array[i].

剑指offer刷题—二维数组的查找

最近接触到一本书叫做剑指offer,在这里准备在这个2个月左右将这本书刷完,当然,不需要每天多少道什么的,不在多,一天理解一道就好了,希望能成为一种习惯,另外,准备在github上也进行同步分享. 今天第一道题: 面试题3:二位数组中的查找 当我们需要解决一个复杂问题时,一个很有效的方法就是从具体的问题出手,通过分析具体的例子,得到规律. 再一个二维数组中,每一行都要按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排列.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含

【剑指offer】规则二维数组查找

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 思路:从数组左下角开始判断,如果目标数据大于左下角数字,则列号右移(增加),若目标数字小于左下角数字,则行号上移(减小) public class Solution {     public boolean Find(int target, int [][] array) {         int ro

[编程题]二维数组中的查找

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 备注: 因为之前学的是java,js是刚学不久,所以今天这道题让我重新了认识了数组在js中的存在形式(下面这张图用来自己记忆js中数组的结构): 这道题的思路: 举例: [1,2,3,4] [3,5,7,9] 假设二维数组是arr[x][y],要判断的整数是target=4,从最后一行第一个数开始比较,a

剑指offer python版 二维数组的查找

def find_integer(matrix, num): """ :param matrix: [[]] :param num: int :return: bool """ if not matrix: return False rows, cols = len(matrix), len(matrix[0]) row, col = rows - 1, 0 while row >= 0 and col <= cols - 1: if

【剑指Offer面试题】二维数组中的查找

下决心AC所有剑指offer面试题. 九度OJ面试题地址:http://ac.jobdu.com/hhtproblems.php 书籍:何海涛--<剑指Offer:名企面试官精讲典型编程题> 对于面试题,面试官往往更希望我们能提出优化方法,这样更能体现我们的思维能力以及传说中的"内功".所以做剑指offer要着重训练这方面,多总结多细究,总是有好处的.加油~ 二维数组中的查找 时间限制:1 秒内存限制:32 兆 特殊判题:否提交:19005解决:3642 题目描述: 在一个