• 二分查找的变体问题


    之前一篇随笔介绍了二分查找的最最基本的实现,该实现要求待查找的数据是有序且不存在重复元素的数组。

    而今天我们就要介绍二分查找的变体问题,待查找数据是有序但是存在重复元素的数组,主要有以下几个问题:

    1. 查找第一个等于指定值的元素的位置。
    2. 查找最后一个等于指定值的元素的位置。
    3. 查找第一个大于指定值的元素的位置。
    4. 查找最后一个小于指定值的元素的位置。

    这个呢,就要比不存在重复元素的数组稍微复杂一些,但也不难,只要我们能够找好临界条件就事半功倍了。

    原理呢,没有啥要讲的,可以直接看代码,很容易看懂,并且我同时写了通过递归实现和循环实现。

     

    查找第一个等于指定值的元素的位置(第一种实现方式,该方式是找到了一个值之后,从该位置往前数看还有没有等于指定值的元素)

     1 package com.structure.search;
     2 
     3 /**
     4  * 二分查找法
     5  *
     6  * @author zhangxingrui
     7  * @create 2019-02-15 21:29
     8  **/
     9 public class BinarySearch_FirstValue {
    10 
    11     public static void main(String[] args) {
    12         int[] nums = new int[]{4, 6, 9, 9, 19, 19, 30, 30, 40, 500, 500, 500004, 500004};
    13         System.out.println(binarySearch(nums, 0, nums.length - 1, 30));
    14         System.out.println(binarySearch(nums, 30));
    15     }
    16 
    17     /**
    18      * @Author: xingrui
    19      * @Description: 二分查找法(针对有序数组且存在重复元素(找到第一个指定值的位置)-递归方式实现)
    20      * @Date: 21:37 2019/2/15
    21      */
    22     private static int binarySearch(int[] nums, int p, int r, int k){
    23         if(p > r)
    24             return -1;
    25 
    26         int mid = (p + r) / 2;
    27         if(nums[mid] == k)
    28             return getMinIndex(nums, mid, k);
    29 
    30         if(k > nums[mid])
    31             return binarySearch(nums, mid + 1, r, k);
    32         else
    33             return binarySearch(nums, p,  mid - 1, k);
    34     }
    35 
    36     /**
    37      * @Author: xingrui
    38      * @Description: 二分查找法(针对有序数组且不存在重复元素(找到第一个指定值的位置)-循环实现)
    39      * @Date: 21:37 2019/2/15
    40      */
    41     private static int binarySearch(int[] nums, int k){
    42         int p = 0;
    43         int r = nums.length - 1;
    44         while (p <= r){
    45             int mid = (p + r) / 2;
    46 
    47             if(nums[mid] == k)
    48                 return getMinIndex(nums, mid, k);
    49 
    50             if(k > nums[mid])
    51                 p = mid + 1;
    52             else
    53                 r = mid - 1;
    54         }
    55         return -1;
    56     }
    57 
    58     private static int getMinIndex(int[] numbers, int mid, int k){
    59         while (mid > 0 && numbers[mid - 1] == k){
    60             mid--;
    61         }
    62         return mid;
    63     }
    64 
    65 }

     

    查找第一个等于指定值的元素的位置(第二种实现方式,该方式是找到了一个值之后,判断当前位置是否是临界元素,如果不是则继续执行)

     1 package com.structure.search;
     2 
     3 /**
     4  * 二分查找法
     5  *
     6  * @author zhangxingrui
     7  * @create 2019-02-15 21:29
     8  **/
     9 public class BinarySearch_FirstValue2 {
    10 
    11     public static void main(String[] args) {
    12         int[] nums = new int[]{4, 6, 9, 9, 19, 19, 30, 30, 30, 30, 40};
    13         System.out.println(binarySearch(nums, 0, nums.length - 1, 30));
    14         System.out.println(binarySearch(nums, 30));
    15     }
    16 
    17     /**
    18      * @Author: xingrui
    19      * @Description: 二分查找法(针对有序数组且存在重复元素(找到第一个指定值的位置)-递归方式实现)
    20      * @Date: 21:37 2019/2/15
    21      */
    22     private static int binarySearch(int[] nums, int p, int r, int k){
    23         if(p > r)
    24             return -1;
    25         int mid = (p + r) / 2;
    26 
    27         if(k > nums[mid])
    28             return binarySearch(nums, mid + 1, r, k);
    29         else if(k < nums[mid])
    30             return binarySearch(nums, p,  mid - 1, k);
    31         if(mid == 0 || nums[mid - 1] != k)
    32             return mid;
    33         else
    34             return binarySearch(nums, p,  mid - 1, k);
    35     }
    36 
    37     /**
    38      * @Author: xingrui
    39      * @Description: 二分查找法(针对有序数组且不存在重复元素(找到第一个指定值的位置)-循环实现)
    40      * @Date: 21:37 2019/2/15
    41      */
    42     private static int binarySearch(int[] nums, int k){
    43         int p = 0;
    44         int r = nums.length - 1;
    45 
    46         while (p <= r){
    47             int mid = (p + r) / 2;
    48 
    49             if(k > nums[mid])
    50                 p = mid + 1;
    51             else if(k < nums[mid])
    52                 r = mid - 1;
    53             else if(mid == 0 || nums[mid - 1] != k)
    54                 return mid;
    55             else
    56                 r = mid - 1;
    57         }
    58         return -1;
    59     }
    60 
    61 }

    查找最后一个等于指定值的元素的位置(第一种实现方式,该方式是找到了一个值之后,从该位置往后数看还有没有等于指定值的元素

     1 package com.structure.search;
     2 
     3 /**
     4  * 二分查找法
     5  *
     6  * @author zhangxingrui
     7  * @create 2019-02-15 21:29
     8  **/
     9 public class BinarySearch_LastValue {
    10 
    11     public static void main(String[] args) {
    12         int[] nums = new int[]{4, 6, 9, 9, 19, 19, 30, 30, 40, 500, 500, 500004, 500004};
    13         System.out.println(binarySearch(nums, 0, nums.length - 1, 30));
    14         System.out.println(binarySearch(nums, 30));
    15     }
    16 
    17     /**
    18      * @Author: xingrui
    19      * @Description: 二分查找法(针对有序数组且存在重复元素(找到第一个指定值的位置)-递归方式实现)
    20      * @Date: 21:37 2019/2/15
    21      */
    22     private static int binarySearch(int[] nums, int p, int r, int k){
    23         if(p > r)
    24             return -1;
    25 
    26         int mid = (p + r) / 2;
    27         if(nums[mid] == k)
    28             return getMaxIndex(nums, mid, k);
    29 
    30         if(k > nums[mid])
    31             return binarySearch(nums, mid + 1, r, k);
    32         else
    33             return binarySearch(nums, p,  mid - 1, k);
    34     }
    35 
    36     /**
    37      * @Author: xingrui
    38      * @Description: 二分查找法(针对有序数组且不存在重复元素(找到第一个指定值的位置)-循环实现)
    39      * @Date: 21:37 2019/2/15
    40      */
    41     private static int binarySearch(int[] nums, int k){
    42         int p = 0;
    43         int r = nums.length - 1;
    44         while (p <= r){
    45             int mid = (p + r) / 2;
    46 
    47             if(nums[mid] == k)
    48                 return getMaxIndex(nums, mid, k);
    49 
    50             if(k > nums[mid])
    51                 p = mid + 1;
    52             else
    53                 r = mid - 1;
    54         }
    55         return -1;
    56     }
    57 
    58     private static int getMaxIndex(int[] numbers, int mid, int k){
    59         int length = numbers.length;
    60         while (mid < length && numbers[mid + 1] == k){
    61             mid++;
    62         }
    63         return mid;
    64     }
    65 
    66 }

    查找最后一个等于指定值的元素的位置(第二种实现方式,该方式是找到了一个值之后,判断当前位置是否是临界元素,如果不是则继续执行)

     1 package com.structure.search;
     2 
     3 /**
     4  * 二分查找法
     5  *
     6  * @author zhangxingrui
     7  * @create 2019-02-15 21:29
     8  **/
     9 public class BinarySearch_LastValue2 {
    10 
    11     public static void main(String[] args) {
    12         int[] nums = new int[]{4, 6, 9, 9, 19, 19, 30, 30, 30, 30, 40};
    13         System.out.println(binarySearch(nums, 0, nums.length - 1, 30));
    14         System.out.println(binarySearch(nums, 30));
    15     }
    16 
    17     /**
    18      * @Author: xingrui
    19      * @Description: 二分查找法(针对有序数组且存在重复元素(找到第一个指定值的位置)-递归方式实现)
    20      * @Date: 21:37 2019/2/15
    21      */
    22     private static int binarySearch(int[] nums, int p, int r, int k){
    23         if(p > r)
    24             return -1;
    25         int mid = (p + r) / 2;
    26 
    27         if(k > nums[mid])
    28             return binarySearch(nums, mid + 1, r, k);
    29         else if(k < nums[mid])
    30             return binarySearch(nums, p,  mid - 1, k);
    31         if(mid == nums.length - 1 || nums[mid + 1] != k)
    32             return mid;
    33         else
    34             return binarySearch(nums, mid + 1, r, k);
    35     }
    36 
    37     /**
    38      * @Author: xingrui
    39      * @Description: 二分查找法(针对有序数组且不存在重复元素(找到第一个指定值的位置)-循环实现)
    40      * @Date: 21:37 2019/2/15
    41      */
    42     private static int binarySearch(int[] nums, int k){
    43         int p = 0;
    44         int r = nums.length - 1;
    45 
    46         while (p <= r){
    47             int mid = (p + r) / 2;
    48 
    49             if(k > nums[mid])
    50                 p = mid + 1;
    51             else if(k < nums[mid])
    52                 r = mid - 1;
    53             else if(mid == nums.length - 1 || nums[mid + 1] != k)
    54                 return mid;
    55             else
    56                 p = mid + 1;
    57         }
    58         return -1;
    59     }
    60 
    61 }

    查找第一个大于指定值的元素的位置

     1 package com.structure.search;
     2 
     3 /**
     4  * 二分查找法
     5  *
     6  * @author zhangxingrui
     7  * @create 2019-02-15 21:29
     8  **/
     9 public class BinarySearch_FirstGreaterValue {
    10 
    11     public static void main(String[] args) {
    12         int[] nums = new int[]{4, 6, 9, 9, 19, 19, 30, 30, 30, 30, 40};
    13         System.out.println(binarySearch(nums, 0, nums.length - 1, 9));
    14         System.out.println(binarySearch(nums, 9));
    15     }
    16 
    17     /**
    18      * @Author: xingrui
    19      * @Description: 二分查找法(针对有序数组且存在重复元素(找到第一个大于指定值的位置)-递归方式实现)
    20      * @Date: 21:37 2019/2/15
    21      */
    22     private static int binarySearch(int[] nums, int p, int r, int k){
    23         if(p > r)
    24             return -1;
    25         int mid = (p + r) / 2;
    26 
    27         if(k >= nums[mid])
    28             return binarySearch(nums, mid + 1, r, k);
    29         else{
    30             if(mid == nums.length - 1 || nums[mid - 1] <= k)
    31                 return mid;
    32             else return binarySearch(nums, p, mid - 1, k);
    33         }
    34     }
    35 
    36     /**
    37      * @Author: xingrui
    38      * @Description: 二分查找法(针对有序数组且不存在重复元素(找到第一个大于指定值的位置)-循环实现)
    39      * @Date: 21:37 2019/2/15
    40      */
    41     private static int binarySearch(int[] nums, int k){
    42         int p = 0;
    43         int r = nums.length - 1;
    44 
    45         while (p <= r){
    46             int mid = (p + r) / 2;
    47 
    48             if(k >= nums[mid])
    49                 p = mid + 1;
    50             else if(k < nums[mid]){
    51                 if(mid == nums.length - 1 || nums[mid - 1] == k)
    52                     return mid;
    53                 else
    54                     r = mid - 1;
    55             }
    56         }
    57         return -1;
    58     }
    59 
    60 }

    查找最后一个小于指定值的元素的位置

     1 package com.structure.search;
     2 
     3 /**
     4  * 二分查找法
     5  *
     6  * @author zhangxingrui
     7  * @create 2019-02-15 21:29
     8  **/
     9 public class BinarySearch_LastLessValue {
    10 
    11     public static void main(String[] args) {
    12         int[] nums = new int[]{4, 6, 9, 9, 19, 19, 30, 30, 30, 30, 40};
    13         System.out.println(binarySearch(nums, 0, nums.length - 1, 30));
    14         System.out.println(binarySearch(nums, 30));
    15     }
    16 
    17     /**
    18      * @Author: xingrui
    19      * @Description: 二分查找法(针对有序数组且存在重复元素(找到第一个大于指定值的位置)-递归方式实现)
    20      * @Date: 21:37 2019/2/15
    21      */
    22     private static int binarySearch(int[] nums, int p, int r, int k){
    23         if(p > r)
    24             return -1;
    25         int mid = (p + r) / 2;
    26 
    27         if(k <= nums[mid]){
    28             return binarySearch(nums, p, mid - 1, k);
    29         }
    30         else{
    31             if(mid == 0 || nums[mid + 1] == k)
    32                 return mid;
    33             else
    34                 return binarySearch(nums, mid + 1, r, k);
    35         }
    36     }
    37 
    38     /**
    39      * @Author: xingrui
    40      * @Description: 二分查找法(针对有序数组且不存在重复元素(找到第一个大于指定值的位置)-循环实现)
    41      * @Date: 21:37 2019/2/15
    42      */
    43     private static int binarySearch(int[] nums, int k){
    44         int p = 0;
    45         int r = nums.length - 1;
    46 
    47         while (p <= r){
    48             int mid = (p + r) / 2;
    49 
    50             if(k <= nums[mid])
    51                 r = mid - 1;
    52             else if(k > nums[mid]){
    53                 if(mid == 0 || nums[mid + 1] == k)
    54                     return mid;
    55                 else
    56                     p = mid + 1;
    57             }
    58         }
    59         return -1;
    60     }
    61 
    62 }

      以上就是关于二分查找的几个变体问题了,代码还是比较详细的。

     

    书上说,天下没有不散的宴席。不要怕,书上还说了,人生何处不相逢。

  • 相关阅读:
    linux如何查看所有的用户和组信息(转载)
    linux下快速查找文件(转载)
    openLDAP学习笔记
    IDEA无法新建GUI Form文件
    Java开发环境配置时的dt.jar与tools.jar是什么(转载)
    windows bat批处理基础命令学习教程(转载)
    23. Merge k Sorted Lists
    一些词
    docker
    指定gpu
  • 原文地址:https://www.cnblogs.com/alinainai/p/10405229.html
Copyright © 2020-2023  润新知