二分查找的坑点与总结
2016-12-09 17:09
309 查看
二分查找足够简单,但是坑点也有不少,下面来总结一下
以下是二分查找的标准写法
以下这个函数是二分查找nums中[left,right)部分,right值取不到,如果查到的话,返回所在地,如果查不到则返回最后一个小于target值得后一个位置。
一般来说写的二分查找的标准程序应该是右边right值取不到的情况,所以while循环中要加一步判断i是否小于等于nums.size();
对于坑点2,如果是右值点可以取到情况下,必须是i<=j否则会出现查找偏差,比如数组中就一个元素[3],让查找5的位置,理应返回1,但是此时会输出成0,
对于坑点3,主要应用在如果数组中有重复元素,需要判断其具体要返回什么位置。
对于坑点,5,如果i不加1的,比如i = 0,j= 1 的情况,会出现mid = 0然后一直死循环下去
对于坑点4,依据right能不能取到而定,如果right可以取到则,right必须要-1,不减1的话,还是会出现i = j时的死循环。
另外一种二分查找,今天面试头条的时候,被要求写一个二分查找,原本以为足够的简单,但是发现坑点还是有很多的,比如面试官问,如果数组中出现了重复元素该怎么办?怎么返回重复元素的第一个位置,如果查不到则返回-1,后来想了想写了个这个方法
这个有一个简化的写法,减少比较次数【注意以下写法只适合返回最开始出现的位置,如果题目改成出现的最后的一个位置,则还是得用上面的方法】
就是一个排好序的数组,然后将其平移之后,找最小的元素。
诸如[3 4 5 6 7 1 2]
154. Find Minimum in Rotated Sorted Array II
它的进阶形式,如果有重复元素的话,该如何呢
要考虑到这种情况[3 3 3 3 3 3 3 3 1 3 ] [1 1 1 1 1 1 1 1 1 1 2 1 1]
33. Search in Rotated Sorted Array
就是在平移数组中找到一个目标数target,找不到则返回-1,找到返回下标
进阶形式,就是数组中有重复元素了怎么办
81. Search in Rotated Sorted Array II
或者采用我一开始的直接二分判断的方法
以下是二分查找的标准写法
以下这个函数是二分查找nums中[left,right)部分,right值取不到,如果查到的话,返回所在地,如果查不到则返回最后一个小于target值得后一个位置。
//右值点不能取到的情况 int binary_search(vector<int>& nums,int left,int right, int target) { //坑点(1)right究竟能不能取到的问题,这里是不能取到的情况 int i = left; int j= right; while(i<j){ int mid = i+(j-i)/2; //坑点(2)这里尽量这么写,因为如果写成(i+j)/2则有溢出的风险 if(nums[mid]>=target) //坑点(3)这个地方大于还是大于等于要依据情况而定 j = mid; //坑点(4)因为右值点反正不能取到,所以j就可以等于mid else i = mid+1; //坑点(5) } return i; } //右值点能取到的情况 int searchInsert(vector<int>& nums,int left,int right, int target) { int i = left; int j= right; while(i<=j ){ int mid = i+(j-i)/2; if(nums[mid]>=target) j = mid-1; else i = mid+1; } return i; }
一般来说写的二分查找的标准程序应该是右边right值取不到的情况,所以while循环中要加一步判断i是否小于等于nums.size();
对于坑点2,如果是右值点可以取到情况下,必须是i<=j否则会出现查找偏差,比如数组中就一个元素[3],让查找5的位置,理应返回1,但是此时会输出成0,
对于坑点3,主要应用在如果数组中有重复元素,需要判断其具体要返回什么位置。
对于坑点,5,如果i不加1的,比如i = 0,j= 1 的情况,会出现mid = 0然后一直死循环下去
对于坑点4,依据right能不能取到而定,如果right可以取到则,right必须要-1,不减1的话,还是会出现i = j时的死循环。
另外一种二分查找,今天面试头条的时候,被要求写一个二分查找,原本以为足够的简单,但是发现坑点还是有很多的,比如面试官问,如果数组中出现了重复元素该怎么办?怎么返回重复元素的第一个位置,如果查不到则返回-1,后来想了想写了个这个方法
int searchInsert(vector<int>& nums, int target) { int i = 0; int j = nums.size() - 1; while (i < j) { int mid = i + (j - i) / 2; if (nums[mid] > target) j = mid - 1; else if (nums[mid] == target) //即继续二分查找查找相等元素的左边界即可 j = mid; else i = mid + 1; } if (nums[i] == target) return i; else return -1; }
这个有一个简化的写法,减少比较次数【注意以下写法只适合返回最开始出现的位置,如果题目改成出现的最后的一个位置,则还是得用上面的方法】
int binarySearch(vector<int> &array, int target) { // write your code here int i = 0; int j = array.size() - 1; while (i < j) { int mid = i + (j - i) / 2; if (array[mid] >= target) j = mid ; else i = mid + 1; } if (array[i] == target) return i; else return -1; }
二分查找的变种
leetcode 153.Find Minimum in Rotated Sorted Array就是一个排好序的数组,然后将其平移之后,找最小的元素。
诸如[3 4 5 6 7 1 2]
int findMin(vector<int> &num) { int start=0,end=num.size()-1; while (start<end) { if (num[start]<num[end]) return num[start]; int mid = (start+end)/2; if (num[mid]>=num[start]) { //这一步为什么要≥是因为如果mid = start的情况 start = mid+1; } else { end = mid; } } return num[start]; } //更简洁的做法,比右边,因为最右边的必然严格小于最左边,所以等于上面的方法比了一个次小的 int findMin(vector<int>& nums) { int i = 0, j = nums.size()-1; while(i<j){ int mid = (i+j)/2; if(nums[mid]>nums[j]) i =mid+1; else j = mid; } return nums[i]; }
154. Find Minimum in Rotated Sorted Array II
它的进阶形式,如果有重复元素的话,该如何呢
要考虑到这种情况[3 3 3 3 3 3 3 3 1 3 ] [1 1 1 1 1 1 1 1 1 1 2 1 1]
int findMin(vector<int>& nums) { int i = 0, j = nums.size()-1; while(i<j){ int mid = (i+j)/2; if(nums[mid]>nums[j]) i =mid+1; else if(nums[mid]<nums[j]) j = mid; else j--; } return nums[i]; } //但实际上这种方法是有一点小问题的,虽然在这个问题中体现不出来,比如就是如果最小值是重复的,且最小值横跨数组左右两个端点的时候,诸如[1 1 1 1 1 1 1 1 1 1 2 1 1]这种情况,它找出的最小值的位置其实严格意义上不算最小值的位置。 [*]
33. Search in Rotated Sorted Array
就是在平移数组中找到一个目标数target,找不到则返回-1,找到返回下标
//这道题一开始的思路是直接二分,然后,后来看了解答,就是用上面的方法找出最小值,然后最小值的位置也就意味着其右平移的距离,所以先假设数组没有平移,二分查找,mid的位置给换成现在数组的位置 rot_mid = (mid+rotate)%n int search(vector<int>& nums, int target) { int i=0,j= nums.size()-1; while(i<j){ int mid = (i+j)/2; if( nums[mid]>nums[j]) i = mid+1; else j = mid; } int rot = i; i = 0; j = nums.size()-1; while(i<=j){ //注意这个地方必须是<=,因为[1] 找1,如果是<的话就不行了。 int mid = (i+j)/2; int rot_mid = (mid+rot)%nums.size(); if(nums[rot_mid] == target) return rot_mid; if(nums[rot_mid]>target) j = mid-1; else i = mid+1; } return -1; }
进阶形式,就是数组中有重复元素了怎么办
81. Search in Rotated Sorted Array II
bool search(vector<int>& nums, int target) { int i = 0,j = nums.size()-1; while(i<j){ int mid = (i+j)/2; if(nums[mid]>nums[j]) i = mid+1; else if(nums[mid]<nums[j]) j = mid; else j--; } //鉴于[*]处的分析,所以这种最小值是重复的,且横跨首尾的情况,需要额外处理 if(i == 0 && nums[i] == nums[nums.size()-1]){ i = nums.size()-1; while(i>0 &&nums[i-1] == nums[i]) i--; } int rot = i; i = 0; j = nums.size()-1; while(i<=j){ int mid = (i+j)/2; int rot_mid = (mid+rot)%nums.size(); if(nums[rot_mid] == target) return true; if(nums[rot_mid]>target) j = mid-1; else i = mid+1; } return false; }
或者采用我一开始的直接二分判断的方法
bool search(vector<int>& nums, int target) { int i = 0,j = nums.size()-1; while(i<=j){ int mid = (i+j)/2; if(nums[mid] == target) return true; if(nums[mid]>nums[j]) if(target>nums[mid] ||target<=nums[j]) i = mid+1; else j = mid-1; else if(nums[mid]<nums[j]) if(target>nums[mid] && target<=nums[j]) i = mid+1; else j = mid-1; else j--; } return false; }
相关文章推荐
- 二分查找递归与非递归总结
- 查找(二):二分查找----<学习总结>
- [LeetCode] Serch Insert Position (总结二分查找) Java version
- binarySearch二分查找总结
- 二分查找总结
- 二分查找总结
- 由九度1502引出的对二分查找的一点总结v1.0
- 对排序的总结&&二分查找
- [leetcode]二分查找总结
- 各种二分查找算法总结
- 【二分查找】学习总结
- 二分查找总结
- 二分查找总结
- 二分查找总结
- java中二分查找的总结
- 查找算法总结之顺序查找、二分查找、静态树查找
- 二分查找小小总结
- 二分查找分类总结
- 查找一,基于ST的顺序与二分 总结关键字
- 二分查找总结