1.在一个有序数组中查找某数是否存在
public static boolean select(int [] arr,int num) {
int left = 0;
int right = arr.length-1;
while(left<=right) {
int middle = left + ((right - left) >> 1);
if(num>arr[middle]) {
left = middle+1;
}
else if(num==arr[middle]) {
return true;
}else if(num<arr[middle]){
right = middle-1;
}
}
return false;
}
public static void main(String[] args) {
int [] arr = {1,3,5,7,9,16};
boolean b = select(arr, 1);
System.out.println(b);
}
注:int middle = left + ((right - left) >> 1);这段代码和middle=(left+right)/2等效
为什么要这么写呢?1.位运算要比直接的乘除法运算要快 2.如果直接用(left+right)>>1可能会导致它的大小超过整形的大小
注:不要搞错了 num是要和arr[middle]比较,每次修改的是middle
2.在一个有序数组中查找 大于等于某个数最左面的位置
例如:{1,1,1,3,3,3,4,5,5,6}这个数组arr中大于等于3的最左面位置即为arr[4]
关于这道题的思路,本质上还是二分法问题(左边和右边的留存问题)如果middle大于等于3就把middle右边的排除掉(说明边界在左边),如果小于等于3就把左边排除掉(说明边界在右边)
关于大于等于:如果大于num说明 num还有很多在左面 如果等于num有两种情况1.左面还有num,不是要找的,无所谓,index的值还会改变2.这就是要找的,它左面不会再有进行大于等于num的情况了 index就不会更新了 这个index就是要找的.
顺带一提当时我脑子一抽自作聪明搞了个== 结果发现根本就二分不起来
public static int selectleft(int [] arr,int num) {
int left = 0;
int right = arr.length-1;
int index = -1;
while(left<=right) {
int middle = left + ((right - left) >> 1);
if(arr[middle]>=num) {
right = middle-1;
index = middle;
}
else if(arr[middle]<num){
left = middle+1;
}
}
return index;
}
public static void main(String[] args) {
int [] arr = {1,1,1,3,3,3,4,5,5,6};
int b = selectleft(arr, 3);
System.out.println(b);
}
本质上都是要查找的东西是在middle左面还是有面罢了
3.在一个有序数组中查找 小于等于某个数最右面的位置
逻辑同上
public static int selectleft(int [] arr,int num) {
int left = 0;
int right = arr.length-1;
int index = 0;
while(left<=right) {
int middle = left + ((right - left) >> 1);
if(arr[middle]>num) {
right = middle-1;
}
else if(arr[middle]<=num){
left = middle+1;
index = middle;
}
}
return index;
}
public static void main(String[] args) {
int [] arr = {1,1,1,3,3,3,4,5,5,6};
int b = selectleft(arr, 3);
System.out.println(b);
}
4.找出无序且相邻不等数组中一个局部最小值
局部最小值: 和相邻的数比最小 就叫局部最小值
分三种情况讨论
1.在arr[0]处(开头处) 只要后一个元素小就是局部最小
2.在arr[arr.length-1]处(结尾处),只要比前一个元素小就是局部最小
3.在其他位置 要比前一个和后一个小才是局部最小
在一个相邻不等的无序(注意是无序不是随机,如果是随机是包含有序的可能性的)数组中总有一个局部最小
public static int selectmin(int [] arr) {
if (arr == null || arr.length == 0) {
return -1; // 数组为空的情况
}
if (arr.length == 1 || arr[0] < arr[1]) {
return 0;
}
if (arr[arr.length - 1] < arr[arr.length - 2]) {
return arr.length - 1;
}
int left = 1;
int right = arr.length - 2;
int mid = 0;
while (left < right) {
mid = (left + right) / 2;
if (arr[mid] > arr[mid - 1]) {
right = mid - 1;
} else if (arr[mid] > arr[mid + 1]) {
left = mid + 1;
} else {
return mid;
}
}
return left;
}
public static void main(String[] args) {
int [] arr = {8,2,4,3,5,7};
int b = selectmin(arr);
System.out.println(b);
}
逻辑其实很简单 如果middle不是局部最小值那就去找它的左边/右边 左半个数组和右半个数组也满足无序且相邻不等的条件
你可能会问:那 1,2,3,4,3,4,3,2,1这种情况怎么办?它整体无序但它的左半/右半不是无序的啊?
答:在开始的边界元素就已经判断完毕了 甚至都不用走后面的二分流程.....