二分查找:在有序数组中查找一个值
通过不断 缩小查找区间 达到查找的目的 调节指针位置
如果arr[mid]<x,min = mid+1;
如果arr[mid]>x,max = mid-1;
如果arr[mid] == x, 找到结果;
时间效率为O(logn)
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
using namespace std;
int binary_search(int *arr,int n,int x){//数组,总大小,待查值
int head=0,tail=n-1,mid;
while(head <=tail){
mid = head +((tail-head)>>1);//mid = (head+tail)>>1; head和tail同时很大时会越界
if(arr[mid] == x) return mid;
if(arr[mid]<x)head =mid+1;
else tail = mid-1;
}
return -1;
}
int *getRandData(int n){
int *arr = (int *)malloc(sizeof(int)*n);
arr[0] = rand()%10;
for(int i=1;i<n;i++){
arr[i] = arr[i-1]+rand()%5+1;
}
return arr;
}
void output(int *arr,int n){
int len = 0;
for(int i =0;i<n;i++){
len +=printf("%5d",i);
}
printf("\n");
for(int i=0;i<len;i++) printf("-");
printf("\n");
for(int i=0;i<n;i++){
printf("%5d\t",arr[i]);
}
return ;
}
int main(){
srand(time(0));
int x,n;
scanf("%d",&n);
int *arr = getRandData(n);
output(arr,n);
while(~scanf("%f",&x)){
printf("arr[%d] = %d\n",binary_search(arr,10,x),x);
}
return 0;
}
二分查找的两种泛型情况
第一种情况:00001111111(查找第一个1)
binary_search_01模型:
i
nt binary_search_01(int *arr,int n,int x){
int head=0,tail=n-1,mid;
while(head<tail){
mid = head + ((tail-head)>>1);
output_binary_process(arr,n,head,tail,mid);
if(arr[mid]<x)head = mid+1;
else tail = mid;
}
return head;
}
第二种情况:11110000000
代码同理
大的区间使用二分查找,小区间使用顺序查找:(可防止死循环;不需要考虑边界条件)
while(tail-head>3){
mid = head+((tail-head)>>1);
if(arr[mid]==x) return mid;
if(arr[mid]<x) head = mid+1;
else head = mid -1;
}
for(int i =head;i<=tail;i++){
if(arr[i] == x) return i;
}
- 函数是压缩的数组,数组是展开的函数 *
- x 的平方根
class Solution {
public:
//10模型(找最后一个1)
/* 如果x是10
y 1 2 3 4 5
y^2 1 4 9 16 25
*/
int mySqrt(int x) {
double head = 0,tail = x,mid;
tail +=1;
for(int i=0;i<100;i++){
mid = head+((tail-head)/2.0);
if(mid*mid <= x) head = mid;
else tail = mid ;
}
return floor(head) ;
}
};
- 搜索插入位置
class Solution {
public:
//01模型 (找到第一个大于等于1的位置)
int searchInsert(vector<int>& nums, int target) {
int head=0,tail = nums.size()-1,mid;
while(tail -head>3){
mid = head +((tail -head)>>1);
if(nums[mid]>=target) tail = mid;
else head = mid+1;
}
for(int i=head;i<=tail;i++){
if(nums[i] >= target)
return i;
}
return nums.size();//重点!! 因为当 tail为nums.size()-1时 如果某个值不在搜索区间范围内时,应该插入到数组末尾
}
};
- 两数之和
class Solution {
public:
//先排序,再扫描数组中的每一位,寻找在扫描当前数组后面的元素,找到等于target-x的值。(target-x的任务可使用二分)
int binary_search(vector<int>&nums,vector<int>&ind,int head,int x){
int tail = ind.size()-1,mid;
while(head<=tail){
mid = head + ((tail-head)>>1);
if(nums[ind[mid]] == x) return mid;
if(nums[ind[mid]]<x) head = mid+1;
else tail = mid-1;
}
return -1;
}
vector<int> twoSum(vector<int>& nums, int target) {
//首先对下标进行排序
vector<int> ind(nums.size());//下标数组
for(int i=0;i<ind.size();i++) ind[i]=i;//初始化下标数组
sort(ind.begin(),ind.end(),[&](int i,int j){return nums[i]<nums[j];});//对下标数组进行排序
vector<int> ret(2);
//对下标数组进行二分
for(int i=0;i<ind.size();i++){
int val = nums[ind[i]];
//j在ind[i+1] -- ind[-1] 进行查找
int j=binary_search(nums,ind,i+1,target-val);//第三位传入的是二分查找的起始位置
if(j == -1) continue;
int a = ind[i];
int b = ind[j];
if(a>b) swap(a,b);
ret[0] = a;
ret[1] =b;
}
return ret;
}
};
- 在排序数组中查找元素的第一个和最后一个位置
class Solution {
public:
//在nums数组中查找第一个>=x的位置 01模型
int binary_search01(vector<int>&nums,int x){
int head=0,tail=nums.size()-1,mid;
while(tail-head>3){
mid = head+((tail-head)>>1);
if(nums[mid]>=x) tail = mid;//条件成立,尾指针向前移动
else head = mid+1;
}
for(int i = head;i<=tail;i++){
if(nums[i]>=x) return i;
}
return nums.size();
}
vector<int> searchRange(vector<int>& nums, int target) {
vector<int>ret(2);
ret[0] = binary_search01(nums,target);
if(ret[0]==nums.size()||nums[ret[0]]!=target){
ret[0]=ret[1] = -1;
return ret;
}
ret[1] = binary_search01(nums,target+1)-1;//ret[1]的求法: 寻找第一个大于目标值加1的数 ,然后在该位置减1就是目标值的为后一个数。
return ret;
}
};
- 将 x 减到 0 的最小操作数
class Solution {
public:
int binary_search(vector<int>&nums,int x){
int head=0,tail=nums.size()-1,mid;
while(head <=tail){
mid = head+((tail-head)>>1);
if(nums[mid] == x) return mid;
if(nums[mid]<x) head = mid+1;
else tail=mid-1;
}
return nums.size();
}
int minOperations(vector<int>& nums, int x) {
//前缀和数组(前缀和数组第一个位置固定为前0个元素的累加之和所以值一定为0,数组大小为nums.size()+1);
vector<int>suml(nums.size()+1);
vector<int>sumr(nums.size()+1);
suml[0] = sumr[0] = 0;
for(int i=0;i<nums.size();i++) suml[i+1] = suml[i]+nums[i];//数组前半部分的前缀和
for(int i=nums.size()-1;i>=0;i--) sumr[nums.size()-i] = sumr[nums.size()-i-1] +nums[i];//数组后半部分的前缀和
int ans =-1;
for(int i=0;i<suml.size();i++){
int j= binary_search(sumr,x-suml[i]);
if(j==-1) continue;
//选择元素合法性判断:
if(i+j>nums.size()) continue;//使用的元素数量大于总的元素数量
if(ans ==-1|| ans >i+j) ans = i+j;
}
return ans;
}
};
- 供暖器
class Solution {
public:
int binary_search_01(vector<int>&nums,int x){
int head = 0,tail =nums.size()-1,mid;
while(head<tail){
mid = head+((tail-head)>>1);
if(nums[mid]>=x)tail = mid;
else head = mid+1;
}
return head;
}
int findRadius(vector<int>& houses, vector<int>& heaters) {
sort(heaters.begin(),heaters.end());
int ans=0;
for(auto &x:houses){
int j=binary_search_01(heaters,x);
int a = abs(heaters[j]-x);
int b = (j? x-heaters[j-1]:a+1);
ans = max(ans,min(a,b));
}
return ans;
}
};
- 搜索旋转排序数组 II
class Solution {
public:
bool search(vector<int>& nums, int target) {
if(nums[0] == target || nums[nums.size()-1]==target)
return true;
int l=0,r=nums.size()-1,mid,head,tail;
while(l<nums.size() && nums[l] == nums[0]) ++l;
while(r>=0&& nums[r] == nums[0]) --r;
head = l,tail = r;
while(l<=r){
mid = (l+r)>>1;
if(nums[mid] == target) return true;
if(nums[mid]<=nums[tail]){
if(target<= nums[tail] && target >nums[mid]) l=mid+1;
else r= mid-1;
}else{
if(target<nums[mid] && target>=nums[head])r =mid -1;
else l =mid +1;
}
}
return false;
}
};
- 寻找两个正序数组的中位数
class Solution {
public:
double findk(vector<int> &nums1,vector<int>&nums2,int i,int j,int k){
if(i==nums1.size())return nums2[j+k-1];
if(j == nums2.size()) return nums1[i+k-1];
if(k == 1) return nums1[i]<nums2[j] ?nums1[i]:nums2[j];
int a= min(k/2,(int)nums1.size()-i);
int b=min(k-a,(int)nums2.size()-j);
a=k-b;
if(nums1[i+a-1]<=nums2[j+b-1]){
return findk(nums1,nums2,i+a,j,k-a);
}
return findk(nums1,nums2,i,j+b,k-b);
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int n=nums1.size(),m=nums2.size(),mid = (n+m+1)/2;
double a = findk(nums1,nums2,0,0,(n+m+1)/2);
if((n+m)%2==1) return a;
double b=findk(nums1,nums2,0,0,mid+1);
return (a+b)/2.0;
}
};