zoukankan      html  css  js  c++  java
  • 有关于二分搜索的常见问题(java实现)

    前言:

    二分搜索是一个非常常见的面试题目,它具有非常广泛的用途。熟练的掌握二分搜索的基本形式和他的变式是非常重要的。接下来我们将使用java实现一些常见的有关二分搜索的问题。

    具体内容:

    1.二分搜索的基本形式:在一个有序的数组中查找k,如果k存在的话就返回k的下标,否则就返回-1

    基本的二分搜索要注意以下几个问题:

    (1)边界条件:如果k比array[0]小,或者k比array[length-1]大的话,那就说明k是不存在的;如果数组的长度为0那么也说明k是不存在的

    (2)middle的求法:middle = low+(high-low)/2

    以下是具体代码:

    //在一个有序无重复数组中找到和k相等的数的位置,找不到就返回-1
        public static  int binarySearchUnique(int[] array, int k){
            int length = array.length;
            int low = 0, high = length-1;
            if(low>high || k<array[low]||k>array[high]){
                return -1;
            }
            while(low<=high){
                int middle = low+(high-low)/2;
                if(array[middle] == k){
                    return middle;
                }else{
                    if(array[middle]>k){
                        low = middle +1;
                    }else{
                        high = middle -1;
                    }
                    
                }
            }
            return -1;
        }
        

    2.二分搜索进阶版:在一个有序有重复的数组中找到大于等于k的最小下标,如果不存在就返回-1

    思想:(1)将k和array[middle]的值进行对比,如何前者更大的话,那么说明low=middle+1;否则说明high=middle;这里为什么不是high=middle-1,因为有可能array[middle-1]比k要小,那么这个时候high就不是大于等于k的元素的最小下标所在的上限。

    (2)外层循环条件由low<=high;改成了low<high;因为如果是low等于high的话,由于high=middle,那么有可能会陷入死循环

    (3)跳出循环的条件是low等于high。此时返回的low就是所求的值。

    注意的点:(1)边界情况的判断:数组的长度要大于0

    (2)循环的跳出条件是low<high

    (3)最后的low就是所求的值

        //在一个有序有重复的数组中找到和k相等的数的最小下标,找不到就返回-1
        //search the position for the number which is the first number of <=k
        public static int binarySearchMany(int[] array, int k){
            int high = array.length -1;
            int low = 0;
            if(low>high||k>array[high]){
                return -1;
            }
            while(low<high){
                int middle = low+(high-low)/2;
                if(array[middle]<k){
                    low = middle + 1;
                }else{
                    high = middle;
                }
            }
            return low;
        }
        

    3.二分搜索进阶版:在一个有序的无重复的前后轮转的数组中找到k的位置,如果k不存在的话返回-1
    思想:将k值和array[middle],array[high]以及array[low]分别比较:

    当 k==array[middle]时,说明找到了

    当array[middle]<k<=array[high],说明low=middle+1;

    当array[middle]<k&&array[high]<k,我们只能知道high = high -1;

    当array[low]<=k<array[middle], 说明high = middle -1;

    当array[low]>k&&array[middle]>k,我们只能知道low = low+1;

    //给定一个有序递增数组,不含有重复元素,但是这个有序数组发生了rotate,用二分查找找到k的位置,k不存在的话返回1
        public static int binarySearchRotate(int[] array, int k){
            int length = array.length -1;
            int low = 0, high = length;
            if(low>high){
                return -1;
            }
            while(low<=high){
                int middle = low+(high - low)/2;
                if(array[middle]==k){
                    return middle;
                }else{
                    if(array[low]<=k&&array[middle]>k){
                        high = middle -1;
                    }else if(array[low]>k&&array[middle]>k){
                        low += 1;
                    }else if(array[high]>=k&&array[middle]<k){
                        low = middle+1;
                    }else{
                        high = high-1;
                    }
                    
                }
            }    
            return -1;
            
        }

    4.二分搜索进阶版:在一个有序的无重复的数组中找到满足array[i]=i的最小下标

    思想:

    (1)array[middle]>=middle,那么说明下标大于middle的那部分数据都是不可能的

    (2)array[middle]<=middle, 那么说明下标小于middle的那部分数据都输不可能的

    边界:如果array[0]>0的话,那么是不可能找到的,同理array[length-1]也不能小于length;数组的长度要大于0

        //给定一个有序递增数组arr,其中不含有重复元素,请找到满足arr[i]==i条件的最左的位置。如果所有位置上的数都不满足条件,返回-1
        public static int binarySearchIndex(int[] array){
            int low = 0, high = array.length-1;
            if(low>high||array[low]>0||array[high]<high){
                return -1;
            }
            while(low<high){
                int middle = low +(high-low)/2;
                if(array[middle]>=middle){
                    high = middle - 1;
                }else if(array[middle]<middle){
                    low = middle + 1;
                }
            }
            if(array[low]==low){
                return low;
            }
            return -1;
        }

    测试:
    对以上的代码进行测试:

    1.先写出朴素的搜索函数:

        
        // the common method to find the k
        public static int findk(int[] array, int k){
            for(int i = 0; i<array.length; i++){
                if(array[i]==k){
                    return i;
                }
            }
            return -1;
        }
        // the common method to find the first value which is >=k
        public static int findFirstValue(int[] array, int k){
            for(int i = 0; i<array.length; i++){
                if(array[i]>=k){
                    return i;
                }
            }
            return -1;
        }
        //the common method to find first number which satisfy array[i] = i
        public static int findFirstIndex(int[] array){
            for(int i=0; i<array.length; i++){
                if(array[i]==i){
                    return i;
                }
            }
            return -1;
        }
        

    2.进行测试

        public static void main(String args[]){
            int N = 1000000;
            Random rand = new Random();
            double same = 0.0;
            while(N>0){
                int n = rand.nextInt(50)+1;
                int k = rand.nextInt();
                int[] array = new int[n];
                for(int i = 0; i<n; i++){
                    array[i] = rand.nextInt();
                }
                Arrays.sort(array);
                int position;
                position = binarySearchMany(array, k);
                int position2 = findFirstValue(array, k);
                if(position == position2){
                    same++;
                }else{
                    System.out.println(k);
                    for(int i=0; i<n; i++){
                        System.out.print(array[i]+" ");
                    }
                    System.out.println();
                    System.out.println(position);
                    System.out.println(position2);
                }
                N--;
            }
            double ratio = same/1000000;
            System.out.println(ratio);
        }

    3.经过测试以上代码皆为正确代码

  • 相关阅读:
    python,生产环境安装
    neo4j 图数据库
    RNN系列
    机器学习关于AUC的理解整理
    fensorflow 安装报错 DEPENDENCY ERROR
    dubbo Failed to check the status of the service com.user.service.UserService. No provider available for the service
    使用hbase遇到的问题
    MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk
    gradle 安装
    jenkins 安装遇到的坑
  • 原文地址:https://www.cnblogs.com/whatyouknow123/p/9016665.html
Copyright © 2011-2022 走看看