【剑指offer2】 chap11 二分查找

十一、二分查找

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)在排序数组中二分查找

剑指 Offer II 068. 查找插入位置

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;
    }
}

剑指 Offer II 069. 山峰数组的顶部

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];
    }
  }

剑指 Offer II 071. 按权重生成随机数

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)在数值范围内二分查找

剑指 Offer II 072. 求平方根

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/
}

剑指 Offer II 073. 狒狒吃香蕉

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;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值