二分模板
二分模板一共有两个,分别适用于不同情况。 算法思路:假设目标值在闭区间[l, r]中, 每次将区间长度缩小一半,当l = r时,我们就找到了目标值。 版本1 当我们将区间[l, r]划分成[l, mid]和[mid + 1, r]时,其更新操作是r = mid或者l = mid + 1;,计算mid时不需要加1。 C++ 代码模板: int bsearch_1(int l, int r) { while (l < r) { int mid = l + r >> 1; if (check(mid)) r = mid; else l = mid + 1; } return l; } 版本2 当我们将区间[l, r]划分成[l, mid - 1]和[mid, r]时,其更新操作是r = mid - 1或者l = mid;,此时为了防止死循环,计算mid时需要加1。 C++ 代码模板: int bsearch_2(int l, int r) { while (l < r) { int mid = l + r + 1 >> 1; if (check(mid)) l = mid; else r = mid - 1; } return l; }
数的范围
https://www.acwing.com/problem/content/791/
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner scan = new Scanner(System.in); int n = scan.nextInt(); int q = scan.nextInt(); int a[] = new int [n]; for(int i=0;i<n;i++){ a[i] = scan.nextInt(); } while(q-- > 0){ int x = scan.nextInt(); int l = 0, r = n-1; while(l<r){ int mid = l + r >> 1; if(a[mid]>=x) r = mid;//找左边点--当mid大于等于x时,说明左边点肯定在左边的区间--r=mid else l = mid +1; } if(a[l] != x) System.out.println("-1 -1"); else{ System.out.print(l+" "); l = 0; r = n - 1; while(l<r){ int mid = l + r + 1>> 1; if(a[mid]<=x) l = mid;//找右边点--当mid小于等于x时,说明右边点肯定在右边的区间--l=mid; else r = mid -1; } System.out.println(r); } } } }
搜索旋转排序数组
https://leetcode-cn.com/problems/search-in-rotated-sorted-array/
//先二分找到旋转点(两边的性质不同) //再判断target在左边还是在右边 //最后二分找target下标 class Solution { public int search(int[] nums, int target) { if(nums.length == 0) return -1; int l = 0, r = nums.length-1; while(l<r){ int mid = l + r + 1 >> 1; if(nums[mid]>=nums[0]) l = mid; else r = mid - 1; } if(target>=nums[0]) l =0; else{ l = r + 1; r = nums.length-1; } while(l<r){ int mid = l + r >> 1; if(nums[mid]>=target) r = mid; else l = mid + 1; } if(nums[r] == target) return r; else return -1; } }