LeetCode240. Search a 2D Matrix II题解

本文详细解析LeetCode240题,介绍四种搜索算法:直接搜索、优化后的直接搜索、优化后的二分搜索及右上角开始的搜索。每种方法都分析了时间复杂度,并提供了执行速度。最优解为右上角开始的搜索,时间复杂度为O(m+n)。
摘要由CSDN通过智能技术生成

1. 题目描述

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties: Integers in each row are sorted in ascending from left to right. Integers in each column are sorted in ascending from top to bottom.

2. 样例

For example, consider the following 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]
]

Given target = 5, return true;
Given target = 20, return false.

3. 分析

拿到题目,首先理解题意:非常简单,给了一个二维的矩阵,这个矩阵具有很好的性质:每一行从左到右按照升序排列,每一列从上到下按照升序排列,给定了一个目标数,我们的任务就是要判断这个矩阵中有没有这个数。看起来很简单,思路也很简单,我在这里用以下4种方法给大家分享一下。

3.1. 直接搜索

时间复杂度O(n^2)
简单粗暴,能直接想到的思路:二维数组的每一行是一个一维数组,对每个一维数组进行最普通的遍历寻找。也就是说,直接两层循环嵌套,时间复杂度O(n^2)。我的代码执行结果如下:用了569ms跑完了所有的测试样例。
这里写图片描述

3.2. 优化后的直接搜索

时间复杂度O(n^2)
由于原来的数组具有很好的性质:即是有一定的顺序排列,那么我们用这个性质可以对代码进行优化。首先判断数组的每一维长度,如果发现每一行长度仅为1,那么我们就可以将原数组化简为一个一维数组,然后调用遍历寻找。其他情况下,我们判断目标数target是否在每一行数组之内(即大于等于最左边的元素,小于等于最右边的元素),如果在的话,才调用遍历搜索,不在的话,就跳过此行数组,节约了某些不必要的时间。我的代码执行结果如下:用了352ms跑完了所有的测试样例。
这里写图片描述

3.3. 优化后的二分搜索

时间复杂度O(nlogn)
主题的搜索部分同上,但是在搜索每一行元素的时候,将原来的直接遍历改为二分查找,由于二分查找的时间复杂度是O(logn),加上嵌套的外层循环,所以时间复杂度降为O(nlogn)。我的代码执行结果如下:用了142ms跑完了所有的测试样例。
这里写图片描述

3.4. 右上角开始的搜索

时间复杂度O(m+n)
非常巧妙的方法,充分利用了给出的矩阵性质。我们从右上角开始搜索,一旦发现当前元素等于目标元素,就是找到了。
没发现的话:如果当前元素大于目标元素,说明目标元素应该在当前元素的左上方,因为是从右上角开始,所以搜索方向只能向左继续;如果当前元素小于目标元素:说明目标元素应该在当前元素右下方,因为是从右上角开始,所以搜索方向只能向下继续,很快遍历整个矩阵。时间复杂度O(m+n),m和n分别代表矩阵的行数和列数。我的代码执行结果如下:用了102ms跑完了所有的测试样例。
这里写图片描述

4. 源码

4.1. 直接搜索
class Solution {
public:
    bool subSearchMatrix(vector<int>& m, int target) {
        int length = m.size();
        for (int i = 0; i < length; i++) {
            if (m[i] == target) {
                return true;
            }
        }
        return false;
    }
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int length = matrix.size();
        for (int i = 0; i < length; i++) {
            bool result = subSearchMatrix(matrix[i], target);
            if (result == true) {
                return true;
            }
        }
        return false;
    }
};
4.2. 优化后的直接搜索
class Solution {
public:
    bool subSearchMatrix(vector<int>& m, int target) {
        int length = m.size();
        for (int i = 0; i < length; i++) {
            if (m[i] == target) {
                return true;
            }
        }
        return false;
    }
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int length_col = matrix.size();
        bool result;
        if (length_col == 0) {
            return false;
        }
        int length_row = matrix[0].size();
        if (length_row == 0) {
            return false;
        }
        if (length_row == 1){
            for (int i = 0; i < length_col; i++) {
                matrix[0].push_back(matrix[i][0]);
            }
            result = subSearchMatrix(matrix[0], target);
            return result;
        }
        else {
            int i;
            for (i = 0; i < length_col; i++) {
                if (matrix[i][0] <= target && matrix[i][length_row-1] >= target) {
                    result = subSearchMatrix(matrix[i], target);
                    if (result == true) {
                        return true;
                    }
                };
            }
        }
        return false;
    }
};
4.3. 优化后的二分搜索
class Solution {
public:
    bool subSearchMatrix(vector<int>& m, int target) {
        int left, right, mid;
        left = 0, right = m.size()-1;
        while(left <= right) {
            mid = (left + right) / 2;
            if (m[mid] == target) {
                return true;
            }
            else if (m[mid] > target) {
                right = mid - 1;
            }
            else {
                left = mid + 1;
            }
        }
        return false;
    }
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int length = matrix.size();
        for (int i = 0; i < length; i++) {
            bool result = subSearchMatrix(matrix[i], target);
            if (result == true) {
                return true;
            }
        }
        return false;
    }
};
4.4. 右上角开始的搜索
class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int length_col = matrix.size();
        if (length_col == 0) {
            return false;
        }
        int length_row = matrix[0].size();
        if (length_row == 0) {
            return false;
        }
        int i = 0, j = length_row - 1;
        while(i < length_col && j >= 0) {
            if (matrix[i][j] == target) {
                return true;
            }
            else if (matrix[i][j] > target) {
                j--;
            }
            else {
                i++;
            }
        }
        return false;
    }
};

5. 心得

本题虽然不难,但是学到了比较多的东西。一道题可有很多种方法去解,往往最容易想到的方法是耗时最长的算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值