• 面试题04:二维数组中的查找(C++)


    题目地址:https://leetcode-cn.com/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/

    题目描述

    在一个 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。

    解题思路

    思路1:暴力遍历查找,时间复杂度O(row*col),空间复杂度O(1),二维数组中的每个元素都被访问。

    思路2:分析题目可以发现,数组元素之间存在一种特殊关系,即从左至右,从上至下都是递增的,因此我们选择以矩阵的右上角作为起点,并与target相比较,小于target则向下遍历,大于target则向左遍历,遍历完还没有则返回false。当然,我们也可以选择矩阵左下角为起点,与target相比较,大于target,则向上遍历,小于target,则向右遍历。时间复杂度O(row+col),空间复杂度O(1),因为访问到的下标的行最多增加row次,减少的列最多col次,因此,循环体最多执行row+col次。

    思路3:二分搜索树思路。将矩阵右上角当作二叉搜索树的根节点,其左侧数字小于它,因此将左侧数字当做左子树,下侧数字当做右子树,满足二叉搜索树的”左子树小于根节点,根节点大于右子树“的条件,最后递归调用即可。时间复杂度O(nlogm),空间复杂度O(1)。

    思路4:二分查找,这个方法可以是堆暴力遍历的一种优化,因为给定的数组是有序的,所以可以考虑二分查找。具体分析见文末参考文章。时间复杂度O(logn*logm),在行上查找一次的时间复杂度为O(logN),因为待查找的列的范围平均每次减少一半,故在行上查找logN次后列的范围就没有了,循环结束。同理,列上查找为O(log M)。

    程序源码

    class Solution {
    public:
        bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
            //方法1:暴力法
            if(matrix.empty()) return false;
            int row = matrix.size(), col = matrix[0].size();
            for(int i = 0; i < row; i++)
            {
                for(int j = 0; j < col; j++)
                {
                    if(matrix[i][j] == target) return true;
                }
            }
            return false;
            /*方法2:矩阵右上角开始
            if(matrix.empty()) return false;
            int row = 0, col = matrix[0].size() - 1;//右上角开始
            while(row < matrix.size() && col >= 0)
            {
                if(matrix[row][col] > target)
                    col--;
                else if(matrix[row][col] < target)
                    row++;
                else
                    return true;
            }
            return false;
            */
            /*方法3:矩阵左下角开始
            if(matrix.empty()) return false;
            int row = matrix.size() - 1, col = 0;
            while(row >= 0 && col < matrix[row].size())
            {
                if(matrix[row][col] > target)
                    row--;
                else if(matrix[row][col] < target)
                    col++;
                else
                    return true;
            }
            return false;
            */
    
        }
    };

     思路3

    class Solution {
    public:
        bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
            int rows = matrix.size();
            if(rows == 0) return false;
            int cols = matrix[0].size();
            if(cols == 0) return false;
            return binarySearch(matrix, target, 0, cols - 1, rows, cols);
        }
        bool binarySearch(vector<vector<int>> matrix, int target, int i, int j, int rows, int cols)
        {
            if(i >= rows || j < 0) return false; //越界
            int root = matrix[i][j]; //将右上角元素作为根节点
            if(root == target) return true;
            if(root > target) 
            {
                return binarySearch(matrix, target, i, j - 1, rows, cols); //遍历左子树 
            }
            else 
            {
                return binarySearch(matrix, target, i + 1, j, rows, cols); //遍历右子树
            }
        }
    };

    思路4:

    class Solution {
    public:
        bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
            int rows = matrix.size();
            if(rows == 0) return false;
            int cols = matrix[0].size();
            if(cols == 0) return false;
            if(target < matrix[0][0] || target > matrix[rows - 1][cols - 1]) return false; //越界
            for(int i = 0; i < rows; ++i) //按行二分查找
            {
                int left = 0, right = cols - 1;
                while(left <= right)
                {
                    int mid = left + (right - left) / 2;
                    if(matrix[i][mid] == target) return true;
                    if(matrix[i][mid] > target) 
                    {
                        right = mid - 1;
                    }
                    else
                    {
                        left = mid + 1;
                    }
                }
            }
            return false;
        }
    };

    参考文章

    https://leetcode-cn.com/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/solution/cong-liang-ge-wei-du-jin-xing-er-fen-cha-zhao-by-w/

    ----------------------------------- 心之所向,素履所往;生如逆旅,一苇以航。 ------------------------------------------
  • 相关阅读:
    概述各种事务隔离级别发生的影响
    linux内核的经典书籍
    sso 登录,网页跳转的实现方式
    初探移动网站的架构和设计
    C# PrintDocument 打印
    .Text分页技术(1)分页的存储过程分析
    SQL2008使用CTE递归查询批量插入500万数据
    自己写的Web服务器
    OMCS 语音视频框架
    ESFramework4.x
  • 原文地址:https://www.cnblogs.com/wzw0625/p/12502045.html
Copyright © 2020-2023  润新知