模板
70%题目是单调性的
25%是一段满足,一段不满足,存在一个两段性的性质


当我们将区间
[l, r]划分成[l, mid]和[mid + 1, r]时,其更新操作是r = mid或者l = mid + 1;,计算mid时不需要加1。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;//此时l=r;}
当我们将区间
[l, r]划分成[l, mid - 1]和[mid, r]时,其更新操作是r = mid - 1或者l = mid;,此时为了防止死循环,计算mid时需要加1。- 例如 
r=l+1,则mid=l,whlie之后l=mid陷入死循环
如果写完之后发现是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; //此时l=r;}
**l = mid**,那么在计算**mid**时需要加上**1**,否则如果写完之后发现是**r = mid**,那么在计算**mid**时不能加**1**。
**
二分的流程: 
- 例如 
 
- 确定二分边界
 - 编写二分代码框架
 - 设计一个check()
 - 判断一下区间如何更新
 - 如果更新方式
- l = mid,r = mid-1 
二分查找
class Solution {public int search(int[] nums, int target) {int left = 0;int right = nums.length-1;int mid = 0;while(left<=right) {mid = (left+right)>>1;if(target < nums[mid]) {right = mid-1;}else if(target > nums[mid]) {left = mid+1;}else {return mid;}}return -1;}}
以二分查找为模板的题目
35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 
 - l = mid,r = mid-1 
 
你可以假设数组中无重复元素。
示例 1:
输入: [1,3,5,6], 5
输出: 2
示例 2:
输入: [1,3,5,6], 2
输出: 1
示例 3:
输入: [1,3,5,6], 7
输出: 4
示例 4:
输入: [1,3,5,6], 0
输出: 0
class Solution {public int searchInsert(int[] nums, int target) {// 第一个>=target的位置if(nums.length==0)return 0;int left = 0,right = nums.length;int mid = 0;while(left < right) {mid = left+right>>1;if(nums[mid] >= target) {right = mid;} else {left = mid+1;}}return left;}}
153. 寻找旋转排序数组中的最小值

class Solution {public int findMin(int[] nums) {int l = 0 , r = nums.length-1;int length = nums.length-1;while(l < r) {int mid= l+r>>1;if(nums[mid] > nums[length]) {l = mid+1;} else {r = mid;}}return nums[l];}}
287. 寻找重复数
这个是无法套用模板的题目
使用抽屉原理,  n*logn
class Solution {public int findDuplicate(int[] nums) {int left = 1;int right = nums.length-1;while(left<right) {int mid = left+right>>1;int cnt = 0;for(int x:nums){if(x>=left && x<=mid) {cnt++;}}if(cnt>mid-left+1) {right = mid;} else {left = mid+1;}}return left;}}
没有模板时候自己做的题目
1. 旋转数组的最小数字
做了很久,很恶心
**
https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/

class Solution {public int minArray(int[] numbers) {int left = 0,right=numbers.length-1;int mid= 0;while(left<=right) {mid = (left+right)>>1;if(numbers[mid] < numbers[right]) {right = mid;} else if (numbers[mid] > numbers[right]) {left = mid+1;} else {right-=1;}}return numbers[left];}}
34. 在排序数组中查找元素的第一个和最后一个位置
这个题目的**binarySearch需要仔细看一下,一个函数实现两个功能,可以分别查找target与target+1的元素的起始位置**
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:
你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution {public int[] searchRange(int[] nums, int target) {int leftIdx = binarySearch(nums, target, true);int rightIdx = binarySearch(nums, target, false) - 1;if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) {return new int[]{leftIdx, rightIdx};}return new int[]{-1, -1};}public int binarySearch(int[] nums, int target, boolean lower) {int left = 0, right = nums.length - 1, ans = nums.length;while (left <= right) {int mid = (left + right) / 2;if (nums[mid] > target || (lower && nums[mid] >= target)) {right = mid - 1;ans = mid;} else {left = mid + 1;}}return ans;}}作者:LeetCode-Solution链接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/solution/zai-pai-xu-shu-zu-zhong-cha-zhao-yuan-su-de-di-3-4/来源:力扣(LeetCode)著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
4. 寻找两个正序数组的中位数.
寻找第k大的数字,每次比较num1[(k/2)-1] 和 num2[(k/2)-1];
- 两者中的小值,因为二者前面都有(k/2)-1个,所以较小值前面最多有k-2个数字,所以他不可能是第k大的数字
 - 所以较小值和它前面的所有值都可以舍去
 

class Solution {public double findMedianSortedArrays(int[] nums1, int[] nums2) {if (nums1.length > nums2.length) {return findMedianSortedArrays(nums2, nums1);}int m = nums1.length;int n = nums2.length;int left = 0, right = m;// median1:前一部分的最大值// median2:后一部分的最小值int median1 = 0, median2 = 0;while (left <= right) {// 前一部分包含 nums1[0 .. i-1] 和 nums2[0 .. j-1]// 后一部分包含 nums1[i .. m-1] 和 nums2[j .. n-1]int i = (left + right) / 2;int j = (m + n + 1) / 2 - i;// nums_im1, nums_i, nums_jm1, nums_j 分别表示 nums1[i-1], nums1[i], nums2[j-1], nums2[j]int nums_im1 = (i == 0 ? Integer.MIN_VALUE : nums1[i - 1]);int nums_i = (i == m ? Integer.MAX_VALUE : nums1[i]);int nums_jm1 = (j == 0 ? Integer.MIN_VALUE : nums2[j - 1]);int nums_j = (j == n ? Integer.MAX_VALUE : nums2[j]);if (nums_im1 <= nums_j) {median1 = Math.max(nums_im1, nums_jm1);median2 = Math.min(nums_i, nums_j);left = i + 1;} else {right = i - 1;}}return (m + n) % 2 == 0 ? (median1 + median2) / 2.0 : median1;}}
