二分查找算法
对于很多简单的算法,一学就会,一做就废,所以还是得多实践,多动手,实践出真知,practice does make perfect!
without further ado,直接切入正题:
题目描述:
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
对于二分法的思路:
二分查找又叫折半查找,它要求数组有序,如其名字的含义一样在每一次查找的过程中折半查找可以排除一半的元素,其查找过程可以用一颗折半查找判定树来描述。
存在的主要问题:
二分查找的思路很简单,但是在编码的时候很容易在区间的边界上犯迷糊,在条件的判断上产生错误。
对于区间的概念,有开区间和闭区间之分,不同的区间有不同的代码实现细节。在思考的过程中要始终秉持着区间自始至终一致的原则,开始时选用左闭右闭的区间,则在需要用到这个区间的时候同样要考虑到左闭右闭。
代码实现一:
public static int search(int[] nums, int target) {
//在区间[left,right] 中查找目标元素target
int left = 0;
int right = nums.length - 1; //attention!!!
int mid;
while (left <= right){
//防止溢出,等价于(left + right)/2,但两个值的初始值都超过int限定大小的一半,那么left+right就会发生溢出,所以应该用left+(right-left)/2来防止求中值时候的溢出
//对于小范围的区间我们可能遇不到,但可以把它当做别人传授的一种技巧或者经验。
mid = left + (right - left)/2;
if(nums[mid] == target){
//当目标元素等于区间中间的那个元素时,直接返回该值。
return mid;
}else if(target < nums[mid]){
//当目标元素小于区间中间的那个元素时,考虑到mid肯定不是目标元素,选择在区间[left,mid -1]中继续查找。
right = mid -1;
}else {
//当目标元素大于区间中间的那个元素时,考虑到mid肯定不是目标元素在区间为[mid + 1,right]中继续查找。
left = mid + 1;
}
}
return -1; //未找到目标元素
}
代码实现二:
public static int search2(int[] nums, int target) {
//在区间[left,right) 中查找目标元素target
int left = 0;
int right = nums.length; //attention!!!
int mid;
while (left < right){
mid = left + (right - left)/2; //防止溢出
if(nums[mid] == target){
//当目标元素等于区间中间的那个元素时,直接返回该值。
return mid;
}else if(target < nums[mid]){
//当目标元素小于区间中间的那个元素时,由于区间是左闭右开,选择在区间[left,mid)中继续查找。
right = mid;
}else {
//当目标元素大于区间中间的那个元素时,选择在区间[mid + 1,right)中继续查找。
left = mid + 1;
}
}
return -1; //未找到目标元素
}