序:二分法使用场景中,数位未必一定有序;只要能够构建排他性,就可使用二分法(可以砍掉左侧或者右侧)
适用场景:
1.在一个有序数组中,找到某个数是否存在
2.在一个有序数组中,找>=某个数的最左位置(例:【1,2,4,4,4,7,8,9】找4的最左位置。答案:2位置)
3.在一个有序数组中,找<=某个数的最右位置
4.局部最小问题
有序数组中,找某个数是否存在
public class SearchNum {
public boolean exist(int[] target, int num) {
boolean result = false;
if (target == null || target.length < 1) {
return result;
}
int left = 0, right = target.length - 1, mid = 0;
while (left < right) {
//(left + right) / 2 可能溢出 left = 19亿 right = 20亿,相加后溢出
mid = left + ((right - left) >> 1);
if (target[mid] == num) {
result = true;
return result;
} else if (target[mid] > num) {
right = mid - 1;
} else {
left = mid + 1;
}
}
result = target[left] == num;
return result;
}
}
有序数组中,找>=某个数的最左位置
public class SearchLeftmost {
public Integer search(int[] target, int num) {
Integer result = null;
if (target == null || target.length < 1) {
return result;
}
int left = 0, right = target.length - 1, mid = 0;
while (left <= right) {
//(left + right) / 2 可能溢出 left = 19亿 right = 20亿,相加后溢出
mid = left + ((right - left) >> 1);
if (target[mid] >= num) {
right = mid - 1;
result = mid;
} else {
left = mid + 1;
}
}
return result;
}
}
局部最小问题:
题目:
无序数组,任意相邻的俩个数不等,数组中的数可以是负数,正数,0。求局部最小(找到一个局部最小位置即可) 备注-局部最小的口径如下 a.0位置的数比1位置的数小,那么0是局部最小 b.n-1位置的数比n-2位置的数小,那么n-1是局部最小 c.中间的数(非0位置,非n-1),比它左面的数小且比它右面的数小,那么次数的位置是局部最小
思想:二分法
证明二分法的可行性:
a.校验数组0位置的数是否小于1位置,如果小于,返回0
b.校验数组n-1位置的数是否小于n-2位置的,如果小于,返回n-1
c.如果a和b都不成立,说明0位置与1位置组成的局部是递减的且n-2位置和n-1位置组成的局部是递增的。综上证明“中间一定有局部最小的存在”
d.找到中间位置mid,判断中间位置的值是否比mid-1且比mid+1小,如果以上成立,那么返回mid位置;但如果不成立,出现如下情况
要么mid比mid-1大(砍掉右侧,左侧必存才局部最小)
要么mid比m+1大(砍掉左侧,右侧必存才局部最小)
要么mid大于mid-1且大于mid+1(左侧,右侧均可)
代码:
public class LocalMin {
public int searchLocalMin(int[] target) {
int result = -1;
if (target == null || target.length <= 1) {
return result;
}
int left = 0, right = length, mid = 0;
if (target[left] < target[left + 1]) {
result = 0;
return result;
}
if (target[right] < target[right - 1]) {
result = right;
return result;
}
left ++;
right --;
while (left < right) {
mid = left + ((right - left) >> 1);
if (target[mid] > target[mid - 1]) {
right = mid - 1;
} else if (target[mid] > target[mid + 1]) {
left = mid + 1;
} else {
result = mid;
return result;
}
}
result = left;
return result;
}
}