Basic
需求:在有序数组A内,查找值target
如果找到返回索引
如果找不到返回-1
算法描述:
前提:给定一个内含n个元素的有序数组A(升序),一个待查找值
设置两个索引:i=0;j=n-1;
如果j>i,查找停止
设置m=floor(i+j/2),floor为向下取整的最小整数
如果target>m,设置i=m+1;
如果traget<m,设置j=m-1;
如果traget=m,找到待查找值。
实现:
package 二分查找;
public class BinarySearch {
public static void main(String[] args) {
// TODO Auto-generated method stub
}
public static int binarySearchBasic(int[] a,int target) {
int i=0,j=a.length-1; //设置指针初值
while(i<=j) { //范围有内容
int m=(i+j)/2;
if(target<a[m]) {
j=m-1;
}else if(target>a[m]) {
i=m+1;
}else {
return m;
}
}
return -1;
}
}
问题1:
为什么是i<=j,而不是i<j?
i,j区间内会有未比较的元素,i<=j它们共同指向的元素也可以遍历到。
问题2:
(i+j)/2有没有问题?
若数字较大,再次循环:
i=m+1;
m=(i+j)/2;会超出范围变成负数
同一个二进制数,第一位是否是符号位。会使数值展现不同。(Java中会考虑符号位)
可以通过无符号右移来达到除2效果。
解决方法:
无符号右移>>>
package 二分查找;
public class BinarySearch {
public static void main(String[] args) {
// TODO Auto-generated method stub
}
public static int binarySearchBasic(int[] a,int target) {
int i=0,j=a.length-1; //设置指针初值
while(i<=j) { //范围有内容
int m=(i+j)>>>2;
if(target<a[m]) {
j=m-1;
}else if(target>a[m]) {
i=m+1;
}else {
return m;
}
}
return -1;
}
}
额外应用:
(0+7)/2 3.5 //不需要设置float,可当成整数
(0+7)>>>1 3
练习优化过程
Pocess1超出时间限制
class Solution {
public int searchInsert(int[] nums, int target) {
int i=0,j=nums.length-1;
int m=(i+j)>>>1;
int index=0;
while(i<=j){
index++;
if(target<m){
j=m-1;
}else if(m<target){
i=m+1;
}else{
return index;
}
}
for(int k=0;k<nums.length;k++){
while(target>nums[k]){
index=k+1;
}
}
return index;
}
}
问题分析:
1. 二分查找逻辑错误:比较 target 和 m(中间索引)而不是 nums[m](中间值)。
2. 无限循环:在二分查找部分,没有更新 m的值,导致循环条件永远不变。
3. 错误的索引计算:在二分查找中返回的是 index(循环次数)而不是正确的位置。
4. 不必要的线性搜索:最后的线性搜索部分既不正确也不必要。i就是应该插入的位置。
Process2优化
class Solution {
public int searchInsert(int[] nums, int target) {
int i = 0, j = nums.length - 1;
while (i <= j) {
int m = (i + j) >>> 1;
if (nums[m] == target) {
return m;
} else if (nums[m] < target) {
i = m + 1;
} else {
j = m - 1;
}
}
return i;
}
}