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

题目

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

解题思路

这题解题的关键在于数据是有序的,很自然的便想到使用二分法;在提交后在评论区发现了更优的解法(除了数据有序外,利用了数据按矩阵形式排列这一特点),会在下列代码中给出。
在使用二分法时,值得注意的是,不能将二维数组中所有元素看作单调递增排列的一维数组,从而对所有元素整体进行二分。题目仅说明数据在矩阵的每行每列各自具单调递增的性质;而行(或列)之间并没有确定的大小关系。例如,第一行可能是[4, 5, 6], 而第二行为[1, 2, 3],第二行元素可能小于第一行元素。

具体代码

1. 二分法
因为只能逐行进行二分,故算法时间复杂度为O(nlogm),n为矩阵行数,m为列数。
计算二分的中值mid时,推荐使用mid = (right - left) / 2 + left而不是mid = (left + right) / 2 ,这样能够避免加法溢出

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        // 求出矩阵行数row和列数col
        int row = array.size();
        int col = array[0].size();
        
        int left;
        int right;
        int mid;
        // 对数组逐行进行二分查找
        for (int i = 0; i < row; i++) {
            left = 0;
            right = col - 1;
            while (right >= left) {
                mid = (right - left) / 2 + left; // 防止left+right导致加法溢出
                if (array[i][mid] < target) {
                    left = mid + 1;
                } else if (array[i][mid] > target) {
                    right = mid - 1;
                } else {
                    return true;
                }
            }
        }
        
        return false;
    }
};

2. 利用元素特殊的排列
利用元素排列的性质,对于左下角的元素来说,其同列上方的元素一定是小于它,其同行右方的元素一定是大于它;能够在推导的过程中跳过更多的错误元素。易知,算法时间复杂度为O(n+m)

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        // 求出矩阵行数row和列数col
        int row = array.size();
        int col = array[0].size();
        
        // 初始从矩阵左下方开始查找
        for (int i = row - 1, j = 0; i >= 0 && j < col; ) {
            // 分三种情况
            // 1. 当前位置元素大于目标位置元素,位置上移一行(i--)
            // 2. 当前位置元素小于目标位置元素,位置右移一列(j++)
            // 3. 当前位置元素等于目标位置元素,已找到,返回true
            if (target < array[i][j]) {
                i--;
            } else if (target > array[i][j]) {
                j++;
            } else {
                return true;
            }
        }
        
        return false;
    }
};

转载于:https://www.cnblogs.com/Bylight/p/10440681.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值