二分法
数学中的二分法我们都学过,但是运用到这我就忘了,程序中的二分法是起源于数学中的函数找零点,假设待查找序列和题目的要求之间的关系是单调递增的,先取区间的中心,判断该处函数值和题目标准值的大小关系,如果函数值偏小,那么应该在中心右侧的区间继续查找;如果函数值偏大 ,那么应该在中心左侧区间继续查找,直到找到对应的值或者区间缩小到左右端点之间不再包含其他数据结束。
这样一段代码:我们都能看懂什么意思,但是里面的每一个临界点(4个推敲点)才是我们需要去推敲的
public static int rank(int key,int nums[])//nums必须有序
{
//查找范围的上下界
int low=0;
int high=nums.length-1;
//未查找到的返回值
int notFind=-1;
while(low<=high)
{
//二分中点=数组左边界+(右边界-左边界)/2
//整数类型默认取下整
int mid=low+(high-low)/2;
if(nums[mid==key])
{
//查找成功
return mid;
}
//中间值是如果大于key
else if(nums[mid]>key)//推敲点1
{
//证明key在[low,mid-1]这个区间
//因为num[mid]已经判断过了所以下界要减一
high=mid-1;//推敲点2
}
else if(nums[mid]<key)//推敲点3
{
//证明key在[mid+1,high]这个区间
//同样判断过mid对应的值要从mid+1往后判断
low=mid+1;//推敲点4
}
}
//while循环完了都没返回,肯定没找到咯
return notFind;
}
力扣34
题目:给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]
**分析:**这道题的要求有复杂度限制,显然是需要用二分法去求解的,二分法找一个数想必我们都陌生了,需要注意的是关于边界值的取舍。只找到一个数的话,找到我们就可以返回了,但是这道题不是,当我们找到一个数时,我们得确定他的左边和右边都没有相同的数才能最后返回。因此我们得进行左边搜索最小索引和右边搜索最大索引。
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] ans={-1,-1};
ans[0]=findFirst(nums,target);
ans[1]=findLast(nums,target);
return ans;
}
static int findFirst(int[] nums, int target) {
if (nums.length == 0) return -1;
int first = 0;
int last = nums.length; // 注意
while (first < last) { // 注意
int mid = (first + last) / 2;
if (nums[mid] == target) {
last = mid;
} else if (nums[mid] < target) {
first = mid + 1;
} else if (nums[mid] > target) {
last = mid; // 注意
}
}
// target 比所有数都大
if (first == nums.length) return -1;
// 如果最后找到了最小的目标返回目标的位置,没有返回-1
return nums[first] == target ? first : -1;
}
static int findLast(int[] nums, int target) {
if (nums.length == 0) return -1;
int first = 0, last = nums.length;
while (first < last) {
int mid = (first + last) / 2;
if (nums[mid] == target) {
first = mid + 1; // 注意
} else if (nums[mid] < target) {
first = mid + 1;
} else if (nums[mid] > target) {
last = mid;
}
}
//target比所有数都小
if (first == 0) return -1;
// 如果最后找到了最大的目标返回目标的位置,没有返回-1
return nums[first -1] == target ? (first -1) : -1;
}
}