文章目录
1. 查找某个元素
这是最常规的一种查找,给定一个元素key, 如果key存在于数组中,返回key对应的下标,不存在则返回-1
[0,1,2,3,4,5,6,]
: 如果key=1,查找结果返回1;key=7,查找结果返回-1
1.1 左闭右闭区间
left=0,right=n-1
n表示数组的长度
public static int binary_search(int nums[], int target) {
if (nums == null || nums.length == 0)
return -1;
int left = 0, right = nums.length-1;
while (left <= right) {//注意点1
int mid = left + (right - left) / 2;
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid-1;//注意点2
}
return -1;
}
1.2 左闭右开区间
left=0,right=n
n表示数组的长度
public static int binary_search(int nums[], int target) {
if (nums == null || nums.length == 0)
return -1;
int left = 0, right = nums.length;
while (left < right) {//注意点1
int mid = left + (right - left) / 2;
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid;//注意点2
}
return -1;
}
两种情况对比:
左闭右闭:
注意点1: 因为right的取值是nums.length-1
,因此while循环处需要使用<=号,此时当left==right==nums.length-1
时,循环体中下标并不会越界;
注意点2:因为时左闭右闭区间,因此当mid被访问之后,当访问mid左边的元素时应该是[left.mid-1], 由于是左闭右闭区间,所以直接right=mid-1
左闭右开:
注意点1:因为right的取值是nums.length
,因此while循环处需要使用<号,而不是<=, 因为当left==right==nums.length
;时,循环体中的下标就有可能越界;
注意点2: 因为时左闭右开区间,因此当mid被访问之后,当访问mid左边的元素时应该是[left.mid-1]
, 由于是左闭右开区间,因此当right=mid时,即[left,mid), [left.mid-1]等价于[left,mid)
2. 查找某个元素的最左出现位置
[1,2,2,2,2,3,4,5] key=2
返回最左边的2,下标为1
形式1
//左闭右闭形式
public static int binary_search(int nums[], int target) {
if (nums == null || nums.length == 0)
return -1;
int left = 0, 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 if (nums[mid] > target)
right = mid-1;
}
// target比nums数组中的所有数字都大--->left>=nums.length
//先进行left范围的判断,防止后面数组访问越界
//target不存在于数组中---->nums[left]!=target
if(left>=nums.length||nums[left]!=target)
return -1;
return left;
}
形式2
//左闭右开形式
public static int binary_search(int nums[], int target) {
if (nums == null || nums.length == 0)
return -1;
int left = 0, right = nums.length;
while (left < right) {//注意点1
int mid = left + (right - left) / 2;
if (nums[mid] == target)
right=mid;//注意点2
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid;//注意点3
}
// target比nums数组中的所有数字都大或都小(target不存在)
//先进行left范围的判断,防止后面数组访问越界
if(left>=nums.length||nums[left]!=target)//注意点4
return -1;
return left;
}
形式3
public int binary_search_left(int arr[],int target)
{
int left=0,right=arr.length-1;
while(left<=right)
{
int mid=left+(right-left)/2;
if(arr[mid]>target)
right=mid-1;
else if(arr[mid]<target)
left=mid+1;
else if(arr[mid]==target)
{
//当前如果arr[mid]==target再进行判断
//mid==0: 已经是最左边了 返回结果
//mid!=0 但是arr[mid-1]不等于key 说明arr[mid]是最左边的
//arr[mid-1]<arr[mid]=key....
if(mid==0||arr[mid-1]!=target)
return mid;
else
right=mid-1;
}
}
return -1;
}
3. 查找某个元素的最右出现位置
[1,2,2,2,2,3,4,5] key=2
返回最右边的2,下标为4
形式1
//左闭右闭
public static int binary_search(int nums[], int target) {
if (nums == null || nums.length == 0)
return -1;
int left = 0, right = nums.length-1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target)//找到不立即返回 压缩左边界
left=mid+1;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid-1;
}
// target比nums数组中的所有数字都小/大(target不存在)
//先进行right范围的判断,防止后面数组访问越界
//因为right可以取到,因此right<0时,[left,right]即为空
if(right<0||nums[right]!=target)
return -1;
return right;//right可以取到 返回right
}
形式2
//左闭右开
public static int binary_search(int nums[], int target) {
if (nums == null || nums.length == 0)
return -1;
int left = 0, right = nums.length;
while (left < right) {//注意点1
int mid = left + (right - left) / 2;
if (nums[mid] == target)
left=mid+1;//注意点2
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid;//注意点3
}
// target比nums数组中的所有数字都小/大(target不存在)
//先进行right范围的判断,防止后面数组访问越界
//因为right取不到,因此right<=0时,[left,right)即为空
if(right<=0||nums[right-1]!=target)
return -1;
return right-1;//因为right取不到 所以返回right-1
}
形式3
//升序
public int binary_search_right(int arr[],int target)
{
int left=0,right=arr.length-1;
while(left<=right)
{
int mid=left+(right-left)/2;
if(arr[mid]<target)
left=mid+1;
else if(arr[mid]>target)
right=mid-1;
else if(arr[mid]==target)
{
//mid==arr.length-1: mid是最后一个位置了 直接返回
//mid不是最后一个位置 但是处于这种情况: arr[mid]=key<arr[mid+1] 因此mid是最右位置
if(mid==arr.length-1||arr[mid+1]!=target)
return mid;
else
left=mid+1;
}
}
return -1;
}
4. 查找某个元素的左边界
4.1 非严格左边界
从key开始往左寻找第一个a[i]<=key
[1,3,4,5,7,9] 4的非严格左边界是4; 6的非严格左边界是5
public static int binary_search(int nums[], int target) {
if (nums == null || nums.length == 0)
return -1;
int left = 0, right = nums.length-1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target)
return mid;//如果key存在 非严格左边界就是自己
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid-1;
}
//left表示小于target的元素的数量 所以最后一个小于的元素的下标就是left-1
//如果target小于数组中的所有元素 left=0 结果返回-1 表示target没有左边界
return left-1;
}
4.2 严格左边界
从key开始往左寻找第一个a[i]<key
[1,3,4,5,7,9] 4的严格左边界是3; 6的严格左边界是5
public static int binary_search(int nums[], int target) {
if (nums == null || nums.length == 0)
return -1;
int left = 0, 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 if (nums[mid] > target)
right = mid-1;
}
//left表示小于target的元素的数量 所以最后一个小于的元素的下标就是left-1
//如果target小于数组中的所有元素 left=0 结果返回-1 表示target没有左边界
return left-1;
}
5. 查找某个元素的右边界
5.1 非严格右边界
从key开始往右寻找第一个a[i]>=key
[1,3,4,5,7,9] 4的非严格右边界是4; 6的非严格右边界是7
public static int binary_search(int nums[], int target) {
if (nums == null || nums.length == 0)
return -1;
int left = 0, right = nums.length-1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target)//相等时直接返回 key存在的话 右边界即自己
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid-1;
}
//left表示小于target的元素的数量 所以最后一个小于的元素的下标就是left-1
//这里直接返回left 小于target的元素是[0...left-1] 则nums[left]>=target
//如果left==nums.lebgth 说明targt大于数组中的所有元素
return left;
}
5.2 严格右边界
从key开始往右寻找第一个a[i]>key
[1,3,4,5,7,9] 4的严格右边界是5; 6的严格左边界是7
public static int binary_search(int nums[], int target) {
if (nums == null || nums.length == 0)
return -1;
int left = 0, right = nums.length-1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target)//相等时不直接返回 而是继续往左寻找
left=mid+1;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid-1;
}
//left表示小于等于target的元素的数量 所以最后一个小于等于的元素的下标就是left-1
//这里直接返回left 小于等于target的元素是[0...left-1] 则nums[left]>target
//如果left==nums.lebgth 说明targt大于数组中的所有元素
return left;
}