十一、二分查找
1.知识梳理
模板
public int searchInsert(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
//满足条件
if (nums[mid] == target) {
return mid;
}
//继续二分
if (nums[mid] > target) {
right = mid - 1;
}else {
left = mid + 1;
}
}
//未找到
return -1;
}
2.题型总结
(1)在排序数组中二分查找
class Solution {
public int searchInsert(int[] nums, int target) {
if (nums.length == 0) return -1;
int left = 0;
int right = nums.length;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] >= target) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
}
public static int peakIndexInMountainArray(int[] arr) {
//注意,要留出头和尾
int i = 1;//i=0 X!
int j = arr.length - 2;//j=arr.length-1 X!
while (i <= j) {
int m = i + (j - i) / 2;
if (arr[m] > arr[m - 1] && arr[m] < arr[m + 1]) {
i = m + 1;
} else if (arr[m] < arr[m - 1] && arr[m] > arr[m + 1]) {
j = m - 1;
}else {
return m;
}
}
return -1;//找不到就随意返回}
剑指 Offer II 070. 排序数组中只出现一次的数字
class Solution {
public int singleNonDuplicate(int[] nums) {
int i = 0;
int j = nums.length - 1;
while(i < j){
int m = i + (j - i)/2;
if(nums[m] == nums[m^1]){
i = m + 1;
}else{
j = m;
}
}
return nums[i];
}
}
class Solution {
public int singleNonDuplicate(int[] nums) {
int i = 0;
int j = nums.length - 1;
while(i < j){
int m = i + (j - i)/2;
m -= m & 1;
if(nums[m] == nums[m+1]){
i = m + 2;
}else{
j = m;
}
}
return nums[i];
}
}
0 1 2 3
1 2 3 4
1 3 6 10
生成数的范围:[0,9]
[0]
[1 2]
[3 5]
[6 9]
要查找的数要求:>=前一个,<后一个
返回值:返回后一个下标
能取到,i和j就<=,取不到,就<
class Solution {
int sum;
int[] temp;
public Solution(int[] w) {
temp = new int[w.length];
for (int i = 0; i < w.length; i++) {
sum += w[i];
temp[i] = sum;
}
}
public int pickIndex() {
Random rand = new Random();
int p = rand.nextInt(sum);
int l = 0;
int r = temp.length;
while (l < r) {
int m = l + (r - l) / 2;
if (temp[m] <= p) {
l = m + 1;
} else {
r = m;
}
}
return l;
}
}
(2)在数值范围内二分查找
class Solution {
public int mySqrt(int x) {
int l = 1, r = x;
int ans = 0;
while (l <= r) {
int m = l + (r - l) / 2;
if (m <= x / m) {
ans = m;
l = m + 1;
} else {
r = m - 1;
}
}
return ans;
}
//方法一:袖珍计算器算法
public int mySqrt2(int x) {
if (x == 0) {
return 0;
}
int ans = (int) Math.exp(0.5 * Math.log(x));
return (long) (ans + 1) * (ans + 1) <= x ? ans + 1 : ans;
}
//方法三:牛顿迭代
public int mySqrt3(int a) {
long x = a;
while (x * x > a) x = (x + a / x) / 2;
return (int)x;
}
//https://leetcode-cn.com/problems/sqrtx/solution/x-de-ping-fang-gen-by-leetcode-solution/
}
Hours(K) <= H && Hours(K-1)>H
7 / 4 = 2
5 / 4 = 2
4 / 4 = 1
class Solution {
public int minEatingSpeed(int[] piles, int h) {
//获取右边界
int maxPile = Integer.MIN_VALUE;
for (int pile : piles) {
maxPile = Math.max(maxPile, pile);
}
//二分查找
int l = 1;
int r = maxPile;
while (l <= r) {
int m = l + (r - l) / 2;
if (getHours(piles, m) <= h) {
if (m == 1 || getHours(piles, m - 1) > h) {
return m;
}
r = m -1;
}else {
l = m + 1;
}
}
return -1;
}
private int getHours(int[] piles, int speed) {
int hours = 0;
for (int pile : piles) {
hours += ((pile - 1) / speed + 1);
}
return hours;
}
}