二分查找算法
二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。
首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
704. 二分查找 - 力扣(LeetCode)
取值方法不同, 1.1能取到数组所有数, 1.2最后一个数取不到,且while(l < r) 最后一个数不会判断,+1后就会退出,需要特判。 方法2 ,条件是 = 会判断再退出(少一重循环)
//方法1.1[l,r), int 除法下取整, 不会取到 r,这里的r是数组长度+1
class Solution {
public int search(int[] nums, int target) {
int r = nums.length;
int l = 0;
while (l < r) {
int mid = l + r >> 1;
if (nums[mid] < target) l = mid + 1;
else if(nums[mid] > target) r = mid;
else return mid;
}
return -1;
}
}
//方法1.2 取值不同 [left,rigth)
class Solution {
public int search(int[] nums, int target) {
int r = nums.length - 1;
int l = 0;
while (l < r) {
int mid = l + r >> 1;
if (nums[mid] < target) l = mid + 1;
else r = mid;
}
if(nums[l] == target) return l;
else return -1;
}
}
//方法二:
class Solution {
public int search(int[] nums, int target) {
int r = nums.length - 1;
int l = 0;
int mid = 0;
while (l <= r) {
mid = l + r >> 1;
if (nums[mid] < target) l = mid + 1;
else if(nums[mid] > target) r = mid - 1;
else return mid;
}
return -1;
}
}
35. 搜索插入位置 - 力扣(LeetCode)
//方法一: [left,rigth)
class Solution {
public int searchInsert(int[] nums, int target) {
// 插入位置个数 len + 1
int r = nums.length;
int l = 0;
while (l < r) {
int mid = l + r >> 1 ; //下取整,不会取到 r 数组
if (nums[mid] < target) l = mid + 1;
else r = mid;
}
//返回 l, r相同,循环退出条件是 l == r;
return r;
}
}
//方法二
class Solution {
public int searchInsert(int[] nums, int target) {
int r = nums.length - 1;
int l = 0;
while (l <= r) {
int mid = l + r >> 1 ;
if (nums[mid] == target) return mid;
else if (nums[mid] < target) l = mid + 1;
else {
r = mid - 1;
}
}
//返回 l 与 r + 1一样, 当nums[mid] < target时,插入位置不能是当前位 l = mid+1是当前可能位置 ,
// > 时会 r = mid - 1, 但可能比 - 1 的位置的数小, 不能插入。
return l;
//return r + 1;
}
}
34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
#include<iostream>
using namespace std;
int n,q;
const int N=100010;
int a[N];
int main(){
cin>>n>>q;
for (int i = 0 ; i < n ; i++ ) scanf("%d" ,&a[i]);
while(q--){
int x;
int l=0,r=n-1;
int lb = 0;
scanf("%d",&x);
while(l <= r){ //首次出现的位置
int mid=l+r>>1;
if(a[mid] < x) l = mid + 1; //!=,最终l指向第一次出现的位置
else {
r = mid - 1;
lb = mid;
}
}
int rb = 0;
if(a[lb]!=x){
cout<<"-1 -1"<<endl;
}else{
cout<<lb<<" ";
int l=0,r=n-1; //最后一次出现的位置,l指向最后出现的位置
while(l <= r){ //左闭右开
int mid=(l+r)>>1; //防止l=mid 死循环(下取整)
if(a[mid]<=x) {
l=mid + 1;
rb = mid;
} //等于还往后找最后的位置
else r=mid-1;
}
cout<<rb<<endl;
}
}
return 0;
}
#include<iostream>
using namespace std;
int n,q;
const int N=100010;
int a[N];
int main(){
cin>>n>>q;
for (int i = 0 ; i < n ; i++ ) scanf("%d" ,&a[i]);
while(q--){
int x;
int l=0,r=n-1;
scanf("%d",&x);
while(l<r){ //首次出现的位置
int mid=l+r>>1;
if(a[mid]<x) l=mid+1; //!=,最终l指向第一次出现的位置
else r=mid;
}
if(a[l]!=x){
cout<<"-1 -1"<<endl;
}else{
cout<<l<<" ";
int l=0,r=n-1; //最后一次出现的位置,l指向最后出现的位置
while(l<r){
int mid=(l+r+1)>>1; //防止l=mid 死循环(下取整)
if(a[mid]<=x) l=mid; //等于还往后找最后的位置
else r=mid-1;
}
cout<<l<<endl;
}
}
return 0;
}