牛客网剑指offer题目(二、 二维数组中的查找)


前言

提示:本系列所有相关代码都以C++为编程语言进行讲解。


题目

在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
例如
[
[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]
]
给定 target = 7,返回 true。
给定 target = 3,返回 false。

数据范围:矩阵的长宽满足 0 ≤ n,m ≤ 500 , 矩阵中的值满足0 ≤ val ≤ 10^9

进阶:空间复杂度 O(1) ,时间复杂度 O(n+m)

一、依次遍历的方法,时间复杂度O(nm),空间复杂度O(1)

使用两个循环嵌套,依据题目所给的信息,从左往右,从上往下都是递增,即为,当遍历第一行时,如果发现第x列,比目标数字大,则在搜索下一行时,不再搜索第x列及以后的列,重复遍历每一行直到遍历结束。

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        if(array.empty())
        {
            return false;
        }
        if(array.at(0).empty())
        {
            return false;
        }
        vector<int>::size_type x = 0;
        for(vector<int>::size_type row = 0; row < array.size(); row++)
        {
        //每行遍历(每行的列数-x)列
            for(vector<int>::size_type col = 0; col < array.at(0).size()-x; col++)
            {
                if(array.at(row).at(col) == target) return true;
                //如果x列出现比target大的数,则x增加为:每行列数减col
                if(array.at(row).at(col) > target) x = array.at(0).size()-col;
            }
        }
        return false;

    }
};

二、利用二分查找,逐行查找,时间复杂度为o(nlogm),空间复杂度为o(1)

二分查找是对于一维数组查找的常用方法,分别设置left、right、mid三个数字表示查找表的最左端,最右端、和中间部分。对于本题依次对每一行进行二分查找,可以稍微降低时间复杂度。

输入:[
[1,2,8,9], 第一次二分查找
[2,4,9,12], 第二次二分查找
[4,7,10,13],第三次二分查找
[6,8,11,15]第四次二分查找
]

那么代码如下:

class Solution {
public:
    bool binary_search(vector<int> arr,int target){//二分查找函数
        int left = 0,right = arr.size()-1;
               while(left<=right)
                {
                    int mid = (left+right)/2;
                    if(arr[mid] == target) return true;//找到了
                    else if(arr[mid] < target) left = mid+1;//往右边遍历
                    else right = mid-1;//往左边遍历
                }
                return false;
        }
    bool Find(int target, vector<vector<int> > array) {
        for(auto i : array)//c++11语法,逐行遍历;
        {
            if(binary_search(i,target)) return true;//在本行二分找到了目标值
        }
        return false;
   }

};

三、线性搜索,时间复杂度为o(n+m),空间复杂度为o(1)

再次根据题目中条件:数组中从左到右,从上到下都是递增的,那么二维数组的坐下角数组此时具有如下特性:

  • 在列中,其上的数字都比它小 在行中
  • 其右的数字都比它大

那么我们可以利用其特点,制定如下搜索流程:

  • 首先从左下角搜索
  • 如果当前数字大于target,那么下一步查找时寻找当前数组的上面的数字,如果当前数字小于target,下一步查找时寻找当前数组的右边的数字
  • 查找到target,返回true,如果越界则返回false

在这里插入图片描述
代码如下:

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        if(array.empty())
        {
            return false;
        }
        if(array.at(0).empty())
        {
            return false;
        }
        vector<int>::size_type n = array.size();
        vector<int>::size_type m = array.at(0).size();
        for(int i = n - 1, j = 0 ; i >= 0 && j < m ; )
        {
            if(target > array.at(i).at(j))
            {
                j++;
            }
            else if(target < array.at(i).at(j))
            {
                i--;
            }
            else 
            {
                return true;
            }
        }
        return false;
    }
};

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值