本来打算在LeetCode上刷题的,结果发现LeetCode的题有些多,还是先在牛客上刷剑指offer针对性强些。
时间限制:1秒 空间限制:32768K 热度指数:1416236
题目描述
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
这题最不动脑子的就是暴力查找。再仔细看下题,单独一个维度的数是有序的。所以,可以想到按每一横行二分查找,算法复杂度O(nlogn)。这里我也是醉了,写个二分还越界,果然已退役就回到解放前了。这里顺便总结下二分的写法吧!
题目链接:题目链接
二分法:
class Solution {
public:
bool Find(int target, vector<vector<int> > array) {
int n = array.size();
for(int i = 0; i < n; i++)
{
int l = 0, r = array[i].size();//上边界和下边界
while(l < r)//这里注意
{
int mid = (l + r) >> 1;
if (array[i][mid] > target)
{
r = mid;
}
else if (array[i][mid] < target)
{
l = mid + 1;//mid+1是防止l和r相差1时陷入死循环
}
else
{
return true;
}
}
}
return false;
}
};
二分的几种写法:
//1.把边界[l,r]分为[l,mid]和[mid+1,r]更新时r=mid或者l=mid+1
int bsearch(int l, int r,int num)
{
while (l < r)
{
int mid = l + r >> 1;
if (mid > num) r = mid;
else l = mid + 1;
}
return l;
}
//2.把边界[l,r]分为[l,mid-1],[mid,r]更新时r=mid-1或者l=mid
int bsearch(int l, int r,int num)
{
while (l < r)
{
int mid = l + r >> 1;
if (mid > num) r = mid-1;
else l = mid;
}
return l;
}
//3.把边界[l,r]分为[l,mid-1],mid,[mid+1,r]更新时r=mid-1或者l=mid+1
int bsearch(int l, int r,int num)
{
while (l <= r)//这里细节
{
int mid = l + r >> 1;
if (mid > num) r = mid-1;
else if(mid < num) l = mid+1;
else return mid;
}
}
写完后看看评论区,发现评论区果然多大佬。上面二分只用到了“每一行都按照从左到右递增的顺序排序”这个条件,但从上到下递增没用到。更优的思路是先把数和左下角的数比较,如果更大则往右比较,如果更小则往上走。这个算法复杂度O(n)。
class Solution {
public:
bool Find(int target, vector<vector<int> > array) {
int r = array.size()-1, v = 0;
while (r >= 0 && v < array[r].size())
{
if (array[r][v] < target)
{
v++;
}
else if (array[r][v] > target)
{
r--;
}
else
{
return true;
}
}
return false;
}
};