【Leetcode】剑指 Offer 04. 二维数组中的查找_medium

📣🥳🥳🥳📣

✨Hello! 如果这篇【文章】对你有帮助😄,希望可以给博主点个赞👍鼓励一下😘

📣🥳🥳🥳📣



🔎 题目描述

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

示例:
现有矩阵 matrix 如下:

[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]

给定 target = 5,返回 true。
给定 target = 20,返回 false。
限制:0 <= n <= 1000, 0 <= m <= 1000
注意:本题与主站 240 题相同

📝 解题方法

vector类型的题目】

📌 两层循环法(暴力法)

class Solution {
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
    	//1.开两层循环
        for (decltype(matrix.size()) i = 0; i < matrix.size(); ++i) {
            if (matrix[i].size() == 0) break;  //[[]]这种需做一个判断
            for (decltype(matrix.size()) j = 0; j < matrix[i].size(); ++j) {
                if (matrix[i][j] == target) {
                    return true;
                }
            }
        }
        //2.若从两层循环出来,说明不存在此元素,返回false
        return false;  
    }
};

在这里插入图片描述
时间复杂度O(N*M);
空间复杂度O(1)。

但这道题顺序都排好了,明显就不是给一个一个暴力找的。如果用这个方法,估计面试官:“今天就到这儿吧,回去等通知😏”。

📌 逐行二分法

class Solution {
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
        //1.逐行处理
        for (decltype(matrix.size()) i = 0; i < matrix.size(); ++i) {
            //2.对每行,即对每个matrix[i]执行二分查找,找到了返回true
            if (!matrix[i].size()) break;  //[[]]这种情况需做一个判断
            auto front = matrix[i].begin(), rear = matrix[i].end()-1;
            while (front <= rear) {
                auto mid = front + (rear - front) / 2;
                if (*mid == target) {
                    return true;
                } else if (*mid > target) {
                    rear = mid - 1;
                } else {
                    front = mid + 1;
                }
            }
        }
        //3.所有行都处理完仍没发现,返回false
        return false;  //
    }
};

在这里插入图片描述
时间复杂度O(Nlog2M),容量越大优势越明显;
空间复杂度O(1)。


📌 二叉搜索树法

从右上角开始查找,比目标值小,往左找,比目标值大,往右找。这样最多只需要找N+M次就可以得到结果,时间复杂度为O(N+M)。

class Solution {
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
        if (matrix.size() == 0 || matrix[0].size() == 0) return false;  //[]和[[]]这两种情况需做一个考虑
        //1.从右上角开始
        for (decltype(matrix.size()) i = 0, j = matrix[0].size()-1; i < matrix.size() && j >= 0;) {
            if (matrix[i][j] == target) return true;
            else if (matrix[i][j] > target) --j;
            else ++i;
        }
        //2.如果还是从循环出来了,那说明没找的,返回false
        return false;
    }
};

一开始这样写会报错:runtime error: addition of unsigned offset
想起来decltype(matrix.size())的类型是size_type,无符号类型,j不能减到-1。

class Solution {
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
        if (matrix.size() == 0 || matrix[0].size() == 0) return false;  //[]和[[]]这两种情况需额外考虑
        //1.从右上角开始
        for (decltype(matrix.size()) i = 0, j = matrix[0].size()-1; i <= matrix.size() - 1 && j >= 0;) {
            if (matrix[i][j] == target) return true;
            else if (matrix[i][j] > target) {  //比目标值大,往左走
                if (j == 0) return false;  //但得先判断再往左走会不会出界,如果出界了即j等于0直接返回false
                --j;  //往左走
            }
            else {  //比目标值小,往下走
                if (i == matrix.size() - 1) return false;  //但得先判断再往下走会不会出界,如果出界了即i等于matrix.size()-1直接返回false
                ++i;  //往下走
            };
        }
        //2.实际上下面这个return不会被执行到,但for循环体外需要有一个return
        return false;
    }
};

或者👇

class Solution {
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
        if (matrix.empty() || matrix[0].empty()) return false;
        for (auto j = static_cast<int>(matrix[0].size()) - 1, i = j - j; i <= static_cast<int>(matrix.size()) - 1 && j >= 0;) {
            if (matrix[i][j] == target) return true;
            else if (matrix[i][j] > target) j--;
            else i++;
        }
        return false;
    }
};

在这里插入图片描述
时间复杂度O(N+M),容量越大优势越明显;
空间复杂度O(1)。


✨如有问题欢迎在底下评论留言或私信!

如果这篇【文章】对你有帮助😄,希望可以给博主【点个赞👍】鼓励一下😘

❤️Thanks for your encouragement❤️

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

John Chen1223

点赞是美意!打赏是鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值