力扣打卡题(二分法)
力扣34题
解题思路:
1、使用二分法模板直接套用
二分法标准模板
public static int BinSearch(int[] nums, int target){
if(nums.length< 0)
return -1;
int right = nums.length;
int left = 0;
while(left <= right){
int mid = (right - left)/2 + left;//防止越界
if(nums[mid] < target)
left = mid+1;
else if(nums[mid] > target)
rigth = mid-1;
else return mid
}
return -1;
}
二分法变体1:查找第一个等于目标值的下标
public int bsearch(int[] a, int n, int value) {
int low = 0;
int high = n - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (a[mid] > value) {
high = mid - 1;
} else if (a[mid] < value) {
low = mid + 1;
} else {
if ((mid == 0) || (a[mid - 1] != value)) return mid;
else high = mid - 1;
//如果不满足条件,就说明数组前面还有满足(a[mid-1] == value)的下标
}
}
return -1;
}
二分法变体2:查找最后一个等于目标值的下标
public int bsearch(int[] a, int n, int value) {
int low = 0;
int high = n - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (a[mid] > value) {
high = mid - 1;
} else if (a[mid] < value) {
low = mid + 1;
} else {
if ((mid == n - 1) || (a[mid + 1] != value)) return mid;
else low = mid + 1;
}
}
return -1;
}
二分法变体3:查找第一个大于等于给定值的元素
public int bsearch(int[] a, int n, int value) {
int low = 0;
int high = n - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (a[mid] >= value) {
if ((mid == 0) || (a[mid - 1] < value)) return mid;
else high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
二分法变体4:查找最后一个大于等于给定的元素
public int bsearch7(int[] a, int n, int value) {
int low = 0;
int high = n - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (a[mid] > value) {
high = mid - 1;
} else {
if ((mid == n - 1) || (a[mid + 1] > value)) return mid;
else low = mid + 1;
}
}
return -1;
}
最后回到本题使用上述1,2两种变体就可以了
public int[] searchRange(int[] nums, int target) {
if(nums.length == 0) return new int[]{-1,-1};
return new int[]{searchLeft(nums,target),searchRight(nums,target)};
}
//左边第一个
public int searchLeft(int[] nums,int target){
int right = nums.length-1;
int left = 0;
while(left <= right){
int mid = (right-left)/2 + left;
if(nums[mid] < target){
left = mid+1;
}else if(nums[mid] > target){
right = mid-1;
}
else {
if(mid == 0 || nums[mid-1] != target){
return mid;
}
else right = mid-1;
}
}
return -1;
}
//右边第一个
public int searchRight(int[] nums,int target){
int right = nums.length-1;
int left = 0;
while(left <= right){
int mid = (right-left)/2 + left;
if(nums[mid] < target){
left = mid+1;
}else if(nums[mid] > target){
right = mid-1;
}
else {
if(mid == right || nums[mid+1] != target){
return mid;
}
else left = mid+1;
}
}
return -1;
}
最后附上截图
第二种方法也是二分法的变体
先找其左边界,再找其右边界即可,注意找左边界的时候,由右侧逼近;找右边界的时候,由左侧逼近
public int[] searchRange(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return new int[]{-1, -1};
}
return binSearch(nums, 0, nums.length - 1, target);
}
private int[] binSearch(int[] nums, int low, int high, int target) {
if (low >= high) {
return nums[low] == target ? new int[]{low,low} : new int[]{-1, -1};
} else {
int mid = low + (high - low)/2;
if (nums[mid] == target) {
// 左右分开查找
int[] left = binSearch(nums, low, mid-1, target);
int[] right = binSearch(nums, mid+1, high, target);
int l = left[0] == -1 ? mid : Math.min(left[0], mid);
int r = right[1] == -1 ? mid : Math.max(right[1], mid);
return new int[]{l, r};
} else if (nums[mid] < target){
return binSearch(nums, mid+1, high, target);
} else {
return binSearch(nums, low, mid-1, target);
}
}
}