说明:以下的所有内容都是来自个人对于二分查找使用情况的浅薄理解,仅供个人参考!不喜勿喷,欢迎大家来纠错!
1.明显的条件:
数组为有序的,并且明确告诉你数组的元素不会重复。
这种情况是一定能用二分查找的。
2.隐含的条件:
题目说明数组为:
非升序(意思是数组为整体降序,允许数组元素重复);
例如: int[] array={9,8,8,6,5,4,3,2,1}
非降序(意思是数组整体为升序,允许数组元素重复);
例如:int[] array={0,1,1,2,3,4,5,6,6,6,7}
在这种情况下,我目前遇到得一个情况是下面的“例题2” 就可以用二分查找。
1,左闭右闭区间型:
right为数组的长度-1,即数组下标可能访问到right;
left为0下标;
在这种情况下,查找的target可能为边界情况,所以while()的循环条件就是 left<=right.
并且,当你的 array[mid]>target时,target以及target的右边是不存在target的,区间的边界情况是不变的,即仍是左闭右闭区间,
即 right=mid-1;
当你的array[mid]<target时,target以及target的左边是不存在target的,区间的边界情况也是不变的,仍是左闭右闭区间,
即 left=mid+1;
当满足array[mid]=target时,mid是target的下标,即返回mid;
2,左闭右开区间型:
right为数组的长度,即数组下标不可能访问到right;
left为0下标;
在这种情况下,查找的target不可能为边界情况,所以while()的循环条件就是 left<right.
并且,当你的 array[mid]>target时,target以及target的右边是不存在target的,区间的边界情况是不变的,即仍是左闭右开区间,
即 right=mid;
当你的array[mid]<target时,target以及target的左边是不存在target的,区间的边界情况也是不变的,仍是左闭右开区间,
即 left=mid+1;
当满足array[mid]=target时,mid是target的下标,即返回mid;
连接:
https://leetcode-cn.com/problems/binary-search/
力扣上的题:二分查找
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
输入: nums = [-1,0,3,5,9,12], target = 9 输出: 4 解释: 9 出现在 nums 中并且下标为 4
左闭右闭型解法:
class Solution { public static int search(int[] nums, int target) { int left=0; int right=nums.length-1; while(left<=right){ int mid=left+(right-left)/2; if(nums[mid]>target){ right=mid-1; }else if(nums[mid]<target){ left=mid+1; }else{ return mid; } } return -1; } }
左闭右开型解法:
class Solution { public static int search(int[] nums, int target) { int left=0; int right=nums.length; // 注意这里变了没有-1. while(left<right){ // 这里的循环条件没有等号 int mid=left+(right-left)/2; if(nums[mid]>target){ right=mid;//这里本来就是取不到的数组长度值 不用-1; }else if(nums[mid]<target){ left=mid+1; }else{ return mid; } } return -1; } }
1.对应一中的 1的情况:
连接:
https://leetcode-cn.com/problems/search-insert-position/
题目:
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
用例:
输入: nums = [1,3,5,6], target = 5 输出: 2
输入: nums = [1,3,5,6], target = 2 输出: 1
输入: nums = [1,3,5,6], target = 0 输出: 0
左闭右闭型解法:
class Solution { public static int searchInsert(int[] nums, int target) { int l=0; int r=nums.length-1; //左闭右闭区间。 while(l<=r){ int mid=l+(r-l)/2; if(nums[mid]>target){ r=mid-1; }else if(nums[mid]<target){ l=mid+1; }else{ return mid; // 处理了target 存在于数组里的情况 } } return r+1; // 处理了1.target在数组之前,2.target插入了数组中。3.target在数组最后边。 } }
左闭右开型解法:
class Solution { public static int searchInsert(int[] nums, int target) { //二分法第二种方法; int left=0; int right=nums.length; //左闭又开区间; while(left<right){ int mid=left+(right-left)/2; if(nums[mid]>target){ right=mid; }else if(nums[mid]<target){ left=mid+1; }else{ return mid; } } return right; } }
2.对应一种的 2 的题:
连接:
https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/
题目:
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:
你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?
用例:
输入:nums = [5,7,7,8,8,10], target = 8 输出:[3,4]
输入:nums = [5,7,7,8,8,10], target = 6 输出:[-1,-1]
左闭又闭型解法:
class Solution { //先找>=target的第一个 //再找>target的第一个 //第一种解法 public int[] searchRange(int[] nums, int target) { int l=searchFirst(nums,target); int r=searchFirst(nums,target+1); if(l==nums.length||nums[l]!=target){ return new int[]{-1,-1}; } return new int[]{l,r-1}; } public int searchFirst(int[] nums,int target){ int l=0; int r=nums.length; while(l<r){ int mid=l+(r-l)/2; if(nums[mid]>=target){ r=mid; }else{ l=mid+1; } } return l; } }
左闭右开型解法:
class Solution { //先找>=target的第一个 //再找>target的第一个 //第二种解法 public int[] searchRange(int[] nums, int target) { int l=searchFirst(nums,target); int r=searchFirst(nums,target+1); if(l==nums.length||nums[l]!=target){ return new int[]{-1,-1}; } return new int[]{l,r-1}; } public int searchFirst(int[] nums,int target){ int l=0; int r=nums.length-1;// 这里变了 while(l<=r){ int mid=l+(r-l)/2; if(nums[mid]>=target){ r=mid-1;//这里变了 }else{ l=mid+1; } } return l; } }
关于个人对于数组二分查找的总结就完了,欢迎大家指出错误。再次声明,这个博客只是个人粗浅的理解和总结,不喜勿喷!不喜勿喷!不喜勿喷! 重要事情说三遍!!!
如果觉得此博客能帮到你,请关注支持一下,万分感谢》