• Java二分查找


    前提

    待查找数组必须为有序数组(可以是升序也可以是降序)

    本次谈论为升序初级二分查找

    基础版

    “>>>”用位移操作可避免出现负数和int显示有误的情况

    1. //这只能找到第一个等于target的值的下标,且数组中必须有target,数组要求为升序
    2. public static int binarySearch(int[] arr,int target){
    3. int left = 0;
    4. int right = arr.length - 1;
    5. while(left <= right){
    6. int mid = (left + right)>>>1;
    7. if(arr[mid] == target){
    8. return mid;
    9. }else if(arr[mid] < target){
    10. left = mid + 1;
    11. }else if(arr[mid] > target){
    12. right = mid - 1;
    13. }
    14. }
    15. return -1;
    16. }

    这里的右指针是数组最后一个元素,则while判断可以有等号,且判断移动后right = mid - 1 

    改进版

    1. public static int binarySearchNews(int[] arr,int target){
    2. int left = 0;
    3. int right = arr.length;
    4. while(left < right){
    5. int mid = (left + right)>>>1;
    6. if(arr[mid] == target){
    7. return mid;
    8. }else if(arr[mid] < target){
    9. left = mid + 1;
    10. }else if(arr[mid] > target){
    11. right = mid;
    12. }
    13. }
    14. return -1;
    15. }

    这里的右指针是数组最后一个元素再往后一个位置,相当于是边界,则while判断不能有等号,且判断移动后right = mid 。推荐使用这种方式,减少执行和判断次数

    平衡版

    类似“夹逼准则“,再while循环内,i和j依次循环逼近目标值,最后在循环外运用三目运算符比较。

    1. class Solution {
    2. public int search(int[] nums, int target) {
    3. int i = 0;
    4. int j = nums.length;
    5. while(i+1
    6. int m = (i+j)>>>1;
    7. if(nums[m]>target){
    8. j = m;
    9. }else {
    10. //target>=nums[m]的情况,且最后利用的是i下表所在值
    11. i = m;
    12. }
    13. }
    14. return (nums[i] == target) ? i : -1;
    15. }
    16. }

    (搜索插入位置)Java中Arrarys工具类提供的binarySearch实现的返回值

    1. // Like public version, but without range checks.
    2. private static int binarySearch0(long[] a, int fromIndex, int toIndex,
    3. long key) {
    4. int low = fromIndex;
    5. int high = toIndex - 1;
    6. while (low <= high) {
    7. int mid = (low + high) >>> 1;
    8. long midVal = a[mid];
    9. if (midVal < key)
    10. low = mid + 1;
    11. else if (midVal > key)
    12. high = mid - 1;
    13. else
    14. return mid; // key found
    15. }
    16. return -(low + 1); // key not found.
    17. }

    若找不到则返回一个负数,同时返回的应含有搜索目标插入点的位置信息,所以返回的-(low + 1) = -(插入点 + 1),因为插入点为数组下标是正数,所以要加个负号,又因为插入点可能在0处,所以要加个1才能保证找不到的时候返回负数。

    Leftmost/Rightmost实现(可有重复元素)

    1. public int leftMost(int[] arr , int target){
    2. int i = 0;int j = arr.length - 1;
    3. int candicate = -1;
    4. while(i<=j){
    5. int m = (i + j)>>>1;
    6. if(target
    7. j = m - 1;
    8. }else if(target>arr[m]){
    9. i = m + 1;
    10. }else{
    11. candicate = m;
    12. j = m - 1; //有可能是重复元素,j则继续往左边走一位,继续判断进不进入循环
    13. }
    14. }
    15. return candicate;
    16. }
    1. public int rightMost(int[] arr , int target){
    2. int i = 0;int j = arr.length-1;
    3. int candicate = -1;
    4. while(i<=j){
    5. int m = (i + j)>>>1;
    6. if(target
    7. j = m - 1;
    8. }else if(target>arr[m]){
    9. i = m + 1;
    10. }else{
    11. candicate = m;
    12. i = m + 1; //有可能是重复元素,i则继续往右边走一位,继续判断进不进入循环
    13. }
    14. }
    15. return candicate;
    16. }

    Leftmost/Rightmost应用

    Leftmost(返回目标元素最靠左的下标):返回值加一求排名,返回值减一求目标值小于目标值的范围,返回值求大于等于目标值的范围和目标值不存在时的插入位置。

    Rightmost(返回目标元素最靠右的下标):返回值加一求大于目标值的范围,返回值求小于等于目标值的范围。

    综合起来用即可求出一个区间的确定范围。

    -----笔记整理来自黑马程序员-----

  • 相关阅读:
    深入了解Elasticsearch的CRUD:ES Java API之增删改查
    Java随笔-volatile
    NodeJs实战-待办列表(7)-connect组件简化代码
    Python 生命游戏(tkinter版)
    C# 迭代器
    详解设计模式:原型模式
    外设驱动库开发笔记49:BY25Qxx存储器驱动
    IMU标定之---Allan方差
    【JavaEE】计算机是如何工作的
    面试中常见的的 web 安全问题
  • 原文地址:https://blog.csdn.net/m0_73065928/article/details/132797893