LeetCode : Search a 2D Matrix 解析
来源:互联网 发布:linux sd卡自动挂载 编辑:程序博客网 时间:2024/05/29 09:48
leetcode : Search a 2D matrix
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.
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.
2.题目分析
题目意思很明确,要求我们从给定的矩阵(二维数组)中判断输入的目标值(target)是否存在。而且,这个二维数组有两个特殊的地方,它的列和行都是按照升序排列的,也就是说,每一个数都比它前面的数小,比它后面的数大,比它上面的数大,比它下面的数小。
知道题目的意思后,大家头脑里面应该都有一个很简单的方法了,那就是暴力求解,搜索整个矩阵,有就是有,没有那就是没有。这个解法是最简单的,但是它有个问题,这样求解会导致算法在最坏的情况下要搜索整个矩阵,而且还有很大可能性是找不到的,所以说这样做不够聪明。
要想用一个更好的办法,那我们就充分利用题目的条件:所有列和行都是按照升序排列。根据之前的几篇博客,我们可以尝试一下用分治的思想来解决。但是这个分治不是将问题分解,而是将问题规模变小。
通过观察我们可以发现,左上角的数是整个矩阵中最小的,而右下角的数是整个矩阵中最大的,我们要思考的问题是怎么利用已知条件。
通过对题目仔细盯着看(确实是这样,没办法解释这个想法),我发现:对于右上角的数来说,它前面(同一列)的数都比它小,它下面的数都比它大;对于左下角的数来说,它上面的数都比它小,它后面的数都比它大;这是一个很重要的发现,我们可以通过判断target与左下角(或者右下角)的数之间的大小关系,来不断精确定位。
比如在题目所给的矩阵中,如果target = 5,与左下角的数相比,target < left_down,那target如果存在就一定在上四行中,第五行就不用理会了;如果target = 20,与左下角的数相比,target > left_down,那target如果存在就一定在后四列中,第一列我们就不用考虑了(与右上角的数比较时同理)。
那这样,我们就可以用position来作为target的坐标,通过不断的与左下角(或者右上角)比较,来不断接近target正确的位置。如果,我们求出的position超出了矩阵的范围,那就证明target并不在矩阵中。
解题的关键就在于左下角和右上角的数的特殊性,只要理解了这一点,那题目就迎刃而解了。
接下来我会将这个思想用3种不同的代码来进行实现。
3.代码实现
按照之前的思想,我们用position_x和position_y来代表target的虚拟位置,初始的虚拟位置可以放在左下角或者右下角。但是只能从一边逼近,双管齐下的方法接下来会介绍。在逼近的时候一定要弄清楚判断大小之后的逻辑关系,也就是位置应该怎么变化。
bool searchMatrix(vector<vector<int>>& matrix, int target) { int position_x = matrix.size() - 1; // the num of row int position_y = 0; // the num of column while (position_x >=0 && position_x < matrix.size() && position_y >= 0 && position_y < matrix[0].size()) { int num = matrix[position_x][position_y]; if (num > target) { // 理解这里的逻辑关系是很重要的一点 position_x--; } else if (num < target) { position_y++; } else { return true; } } return false; }
在理解了这两个特殊的点之后,我们是不是应该想想怎么同时利用这两个点呢?之前我们说过缩减问题的规模(和分治法有一定的区别,但思想是类似的),那我们怎样才能不断压缩matrix的大小呢?和第一种方法类似,我们还是要利用那个特殊点。对于左下角的数来说,如果target比它小,那我们就可以移除最下面的一行,如果target比它大,那我们就可以移除第一列;对于右下角的数来说也是相似的。就这样,我们可以在一次递归中消除最少两行/列(从两个顶点),这样不就达到了我们的目的了吗?
if (matrix.size() == 0 || matrix[0].size() == 0) { return false; } if (matrix.size() == 1 && matrix[0].size() == 1 && matrix[0][0] != target) { return false; } // 返回条件 int row = matrix.size(); int col = matrix[0].size(); int right_up = matrix[0][col - 1]; // 右上角 int left_down = matrix[row - 1][0]; // 左下角 if (target < left_down) { matrix.pop_back(); } else if (target > left_down) { for (int i = 0; i < matrix.size(); i++) { matrix[i].erase(matrix[i].begin()); } } else { return true; } if (target < right_up) { int erase_num = matrix[0].size() - 1; // 如果直接使用matrix[0].size()会出错 // 因为当matrix[0]中有元素已经被删除时 // matrix[1]中还没有被删除 // 这就会导致删除错误元素的情况发生 for (int i = 0; i < matrix.size(); i++) { matrix[i].erase(matrix[i].begin() + erase_num); } } else if (target > right_up) { matrix.erase(matrix.begin()); } else { return true; } return searchMatrix(matrix, target);
对于这种方法,我们同样必须搞清楚逻辑关系,不清楚的时候可以在纸上画一画。除了逻辑要清晰以外,还有一个必须要注意的点是数组边界和下标问题,也就是说我们一定要随时记住下标的问题。就本题而言,容易出现问题的几个地方如下:
1.对二维数组来说,matrix.size()=0,但是我们却访问了matrix[0].size()
2.比如说现在block外面定义了row或者col,然后每次都直接使用。因为我们每一次判断都会对数组进行删除,直接使用row或者col会导致数组越界,甚至会出现删除的是错误的数。
所以我们一定要随时关注数组size的问题,当程序出现bug的时候也可以从这方面入手。
既然我们可以使用递归完成,那同样的我们也能使用循环来完成。整个思想是完全一样的,只不过实现方法不同。
if (matrix.size() == 0 || matrix[0].size() == 0) { return false; } while (matrix.size() != 0 && matrix[0].size()) { if (target < matrix[matrix.size() - 1][0]) { matrix.pop_back(); } else if (target > matrix[matrix.size() - 1][0]) { for (int i = 0; i < matrix.size(); i++) { matrix[i].erase(matrix[i].begin()); } } else { return true; } if (matrix.size() == 0 || matrix[0].size() == 0) return false; if (matrix.size() == 1 && matrix[0].size() == 1 && matrix[0][0] != target) { return false; } if (target < matrix[0][matrix[0].size() - 1]) { int erase_num = matrix[0].size() - 1; for (int i = 0; i < matrix.size(); i++) { matrix[i].erase(matrix[i].begin() + erase_num); } } else if (target > matrix[0][matrix[0].size() - 1]) { matrix.erase(matrix.begin()); } else { return true; } if (matrix.size() == 1 && matrix[0].size() == 1 && matrix[0][0] != target) { return false; } } return false;
left_down 和 right_up在这里每一次循环中都在更新,相当于递归中每一次的更新。
4.总结
对于数组下标的问题不够重视,导致在写代码的时候出现了很多bug。同样,代码水平比较低,写不出简洁的代码,仍需要努力。
有任何问题欢迎在评论区留言。
阅读全文
0 0
- LeetCode : Search a 2D Matrix 解析
- [leetcode][Search] Search a 2D Matrix
- LeetCode: Search a 2D Matrix
- LeetCode Search a 2D Matrix
- [Leetcode] Search a 2D Matrix
- LeetCode : Search a 2D Matrix
- [LeetCode] Search a 2D Matrix
- Leetcode 74 Search a 2D Matrix
- leetcode 90: Search a 2D Matrix
- [LeetCode]Search a 2D Matrix
- [Leetcode] Search a 2-D matrix
- [Leetcode]Search a 2D Matrix
- [leetcode]Search a 2D Matrix
- LeetCode-Search a 2D Matrix
- [leetcode] Search a 2D Matrix
- LeetCode - Search a 2D Matrix
- LeetCode:Search a 2D Matrix
- LeetCode 74: Search A 2D Matrix
- python爬虫之快速构造标准格式headers
- 得到文件夹中的文件列表的方法
- Codeforces 346B
- Hadoop入门必须知道的简单知识
- 实验一:顺序表实验报告
- LeetCode : Search a 2D Matrix 解析
- 《C++ Concurrency in Action》笔记13 std::recursive_mutex
- 记我的第一次批量抓取网页图片的经历
- 实验一线性表的基本操作实现及其应用
- Predicting Human Eye Fixations via an LSTM-based Saliency Attentive Model
- 前端面试知识点集锦
- java nio buffer
- A a = new B();
- python3 [爬虫实战] selenium + requests 爬取安居客