算法练习(2)—— 简单分治
前言
分治不仅仅是分而治之这么一个简单的道理思想,其中蕴含的各种各样的优化方法才是其最大的魅力及难点…很明显大部分这类题目都在复杂度上有一定的要求。
这次做的题目虽然是medium难度,而且跟分治没有很大关系,做起来还是相当轻松的~
习题
这次的题目在leetcode算法题中的Divide and Conquer
栏目中的第240题:
Search a 2D Matrix II
老规矩,上题:
Description
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.
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
, returntrue
.
Given target =20
, returnfalse
.
思路与代码
1.首先理解一下题意,就是给你一个按已知顺序排好序的矩阵(具体顺序是右边一定比左边大,下边一定比上边大)。目的是给你一个target,看它是否在矩阵中。
2.接下来讨论可行的方法:
从头到尾扫描一遍,有即有,无即无。这是最蠢的办法,既然矩阵给你排好序了,肯定有更好更简单的搜索方法。因此这个方法肯定要弃用
上面那个想法就涉及到起点选择在哪里的问题。一开始想到的是左上角,但是因为这个矩阵的特点,我们知道左上角和右下角分别是数的最小值和最大值。遇到最差的情况,比如说从左上角开始扫描,但是那个数值偏大,可能要扫描很多次。因此有两个选择可能比较好,一个是选择矩阵的中心点,另一个是选择左下角或者右上角。
选择矩阵的中心点可能会遇到一些问题。比如说当行数和列数不是奇数的时候不好选取。以及从中间向两边出发的结束条件其实是出边界与否。因此不如直接选取左下角或者右上角。在题目所给的例子中,也可以看出18和15比较接近于30的一半,可以说是比较理想的数字…所以最后决定用左下角或右上角作为搜索的起点,搜索判断终止的条件是出矩阵边界与否。
3.最后写出来的代码相当简单:
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if (matrix.empty())
return false;
int row = matrix.size();
int col = matrix[0].size();
// 选取左下角作为搜索的起点
int x = row - 1, y = 0;
while (x >= 0 && y < col) {
if (matrix[x][y] == target)
return true;
if (matrix[x][y] < target)
y++;
else
x--;
}
return false;
}
};