关键词:查找算法 二分法 映射 位运算
题目一:统计目标成绩的出现次数
方法一:我自己写的。[ 用时: 13 m 3 s ] 二分法+线性扫描
方法二:看了题解
方法一:
二分法+线性查找
思路:
先二分查找找到和target一样的数的位置,假设为i。
然后以i位置出发点,左右两边查找数据是否等于target。
复杂度计算:
时间复杂度O(logn+n)
空间复杂度O(1)
代码:
class Solution {
public:
int countTarget(vector<int>& scores, int target) {
int l=0;
int r=scores.size()-1;
while(l<=r)//二分查找
{
int mid=(l+r)/2;
if(scores[mid]==target)
break;
else if(scores[mid]>target)
{
r=mid-1;
}
else//scores[mid]<target
{
l=mid+1;
}
}
if(l>r)//找不到
{
return 0;
}
int tar_l=(l+r)/2;//左右线性查找
while(tar_l>=0&&scores[tar_l]==target)
{
tar_l--;
}
int tar_r=(l+r)/2;
while(tar_r<scores.size()&&scores[tar_r]==target)
{
tar_r++;
}
return tar_r-tar_l-1;
}
};
方法二:
双二分法。
思路:
先用二分法找符合target这一堆数字的最左边。
然后再 二分法找符合target这一堆数字的最右边。
右-左+1就是结果。
复杂度计算:
时间复杂度O(logn)
空间复杂度O(1)
代码:
class Solution {
public:
int countTarget(vector<int>& scores, int target) {
if(scores.empty()) return 0;
int tar_l=0;
int tar_r=scores.size()-1;
int l=0;
int r=scores.size()-1;
while(l<=r)//左
{
int mid=(l+r)/2;
if(scores[mid]==target)
{
tar_l=mid;
r=mid-1;
}
else if(scores[mid]>target)
{
r=mid-1;
}
else//scores[mid]<target
{
l=mid+1;
}
}
if(scores[tar_l]!=target)
{
return 0;
}
l=0;
r=scores.size()-1;
while(l<=r)//右
{
int mid=(l+r)/2;
if(scores[mid]==target)
{
tar_r=mid;
l=mid+1;
}
else if(scores[mid]>target)
{
r=mid-1;
}
else//scores[mid]<target
{
l=mid+1;
}
}
return tar_r-tar_l+1;
}
};
题目二:点名
方法一:
[ 用时: 6 m 6 s ] 二分法 映射
思路:
映射法做。
映射:只要数字和下标不同,就说明这个数或者这个数之前的数缺了。
利用二分查找来找到我们想要的那个数。
复杂度计算:
时间复杂度O(logn)
空间复杂度O(1)
代码:
class Solution {
public:
int takeAttendance(vector<int>& records) {
int l=0,r=records.size()-1;
while(l<=r)
{
int mid=(l+r)/2;
if(records[mid]==mid)
{
l=mid+1;
}
else
{
r=mid-1;
}
}
return l;
}
};
方法二:
位运算 异或
只是炫技。时间上还不如二分。
思路:
如果两个数相同,异或为0,剩下的那个就是被单着的。
0,1,2,3,5和0,1,2,3,4,5异或,就会得到4了。
复杂度计算:
时间复杂度O(n)
空间复杂度O(1)
代码:
class Solution {
public:
int takeAttendance(vector<int>& records) {
if(records[0]!=0) return 0;
int res=0;
int i=0;
for(const int&x:records)//0,1,2,3,5和0,1,2,3,4异或
{
res=res^i^x;
i++;
}
return res^i;//别忘了最后一位5
}
};