剑指 Offer 04. 二维数组中的查找
题意
在一个二维数组中,每一行都按照从左至右非递减的顺序排序,每一列都按照从上到下非递减的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是由含有该整数。
思路
就是在一个有序的二维数组中,让你快速的找到一个数,如果有就输出true,没有就输出false。
有序!!!!!------->想到了二分
遍历每一行,每一行进行二分,找是否存在这样的数,没有就遍历到下一行。
class Solution
{
public:
bool findNumberIn2DArray(vector<vector<int>>& vec, int target)
{
for (int i = 0; i < vec.size(); i ++)
{
int len = vec[i].size();
for (int j = 0; j < len; j ++)
{
int l = 0, r = len - 1;
while (l < r)
{
int mid = l + r >> 1;
if (vec[i][mid] == target) return true;
else if (vec[i][mid] < target) l = mid + 1;
else r = mid;
}
if (vec[i][l] == target) return true;
}
}
return false;
}
};
面试题 10.03. 搜索旋转数组
题意
搜索旋转数组,给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次,次数不不详。请编写代码找出数组中的某个元素,假设数组元素原先是按升序排列的。若有多个相同的元素,返回索引值最小的一个。
思路
最开始的时候我没有理解到旋转数组的意思,也没有搞清楚它的规则,试了一下,发现有重复的数,并且有复数,于是我想到了离散化+二分(毕竟实在一个序列中找一个数,优先想到二分,排序嘛),也做出来了 ,但是耗时72ms,太慢了,这里把代码贴出来:
#include <iostream>
class Solution {
public:
map<int, int> mp;
int a[100010];
int search(vector<int>& vec, int target) {
int cnt = 0;
for (int i = 0; i < vec.size(); i ++)
{
if (!mp.count(vec[i]))
{
mp[vec[i]] = i;
a[cnt ++] = vec[i];
}
}
sort(a, a + cnt);
for (int i = 0; i < cnt; i ++)
int l = 0, r = cnt;
while (l < r)
{
int mid = (l + r) >> 1;
if (a[mid] == target) return mp[a[mid]];
else if (a[mid] < target) l = mid + 1;
else r = mid;
}
return a[l] == target ? mp[a[l]] : -1;
}
};
后面重新看了一下样例,发现了规律,每一个排完序后的数组都分为两截,一半是升序,一般是降序,那么,这样就简单了, 首先我们可以找到它的一个分界点,也就是从某个点开始,这个点前面是按照降序,这个点后面是按照升序(当然也有可能是反过来的),然后我们在确定target这个值是在前面这个区间还是后面这个区间,确定了之后我们便可以使用二分了,因为序列是有序的。那么第一步我们就是要确定分解点在哪了,通过后面的样例(有几个没有通过的样例发现的),开头位置和结尾位置可能会有重复,所以我们开始把重复的去掉,然后在用二分,找到第一个比arr[0]大的数,从这个位置是分界点,后面我们再次二分找到答案,所以就是二分+二分:
class Solution {
public:
int search(vector<int>& vec, int target) {
int l = 0, r = vec.size() - 1;
while (r > 1 && vec[0] == vec[r]) r --;
while (l < r)
{
int mid = (l + r + 1) >> 1;
if (vec[mid] >= vec[0]) l = mid;
else r = mid - 1;
}
if (target >= vec[0]) l = 0;
else l = r + 1, r = vec.size() - 1;
// 以上是找到分界点
while (l < r)
{
int mid = (l + r) >> 1;
if (vec[mid] >= target) r = mid;
else l = mid + 1;
}
return vec[r] == target ? r : -1;
}
};
952. 按公因数计算最大组件大小
题意
一个数组,当两个数的因数大于1的时候,这两个数之间连接一条边,返回其中的最大的连通数。