数据结构与算法Day12----二分查找(下)

常见的二分查找变形问题(以数据是从小到大排列为前提且集合中存在重复的数据为例):

1、查找第一个值等于给定值的元素。

(1)、思路:

a[mid]跟要查找的value的大小关系有三种情况:大于、小于、等于。
对于a[mid]>value的情况,需要更新high= mid-1;
对于a[mid]<value的情况,需要更新low=mid+1。
当a[mid]=value的时候, 如果查找的是任意一个值等于给定值的元素,当a[mid]等于要查找的值时, a[mid]就是我们要找的元素。如果求解的是第一个值等于给定值的元素,当a[mid]等于要查找的值时,我们就需要确认一下这个a[mid]是不是第一个等于给定值的元素。如果mid等于0,那这个元素已经是数组的第一个元素,那它肯定是我们要找的;如果mid不等于0,但a[mid]的前一个元素a[mid-1]不等于value,那也说明a[mid]就是我们要找的第一个等于给定值的元素。如果经过检查之后发现a[mid]前面的一个元素a[mid-1]也等于value,那说明此时的a[mid]肯定不是要查找的第一个等于给定值的元素。那就更新high=mid-1,因为要找的元素肯定出现在[low, mid-1]之间。

(2)、源码:
public int bsearch(int[] a, int value) {
    int low = 0;
    int high = a.length - 1;
    while (low <= high) {
        int mid = low + ((high - low) >> 1);
        if (a[mid] > value) {
            high = mid - 1;
        } else if (a[mid] < value) {
            low = mid + 1;
        } else {
            if ((mid == 0) || (a[mid - 1] != value))  return mid;
            else  high = mid - 1;
        }
    }
    return -1;
}

2、查找最后一个值等于给定值的元素。

(1)、思路:

a[mid]跟要查找的value的大小关系有三种情况:大于、小于、等于。
对于a[mid]>value的情况,需要更新high= mid-1;
对于a[mid]<value的情况,需要更新low=mid+1。
当a[mid]=value的时候, 如果查找的是任意一个值等于给定值的元素,当a[mid]等于要查找的值时, a[mid]就是我们要找的元素。如果求解的是最后一个值等于给定值的元素,当a[mid]等于要查找的值时,我们就需要确认一下这个a[mid]是不是最后一个等于给定值的元素。如果mid等于a.length - 1,那这个元素已经是数组的最后一个元素,那它肯定是我们要找的;如果mid不等于0,但a[mid]的后一个元素a[mid+1]不等于value,那也说明a[mid]就是我们要找的最后一个等于给定值的元素。如果经过检查之后发现a[mid]后面的一个元素a[mid+1]也等于value,那说明此时的a[mid]肯定不是要查找的最后一个值等于给定值的元素。那就更新low=mid+1,因为要找的元素肯定出现在[mid+1, high]之间。

(2)、源码:
public int bsearch(int[] a, int value) {
    int low = 0;
    int high = a.length - 1;
    while (low <= high) {
        int mid = low + ((high - low) >> 1);
        if (a[mid] > value) {
            high = mid - 1;
        } else if (a[mid] < value) {
            low = mid + 1;
        } else {
            if ((mid == n - 1) || (a[mid + 1] != value)) return mid;
            else low = mid + 1;
        }
    }
    return -1;
}

3、查找第一个大于等于给定值的元素。

(1)、思路:

如果a[mid]小于要查找的值value,那要查找的值肯定在[mid+1, high]之间,所以,我们更新low=mid+1。
对于a[mid]大于等于给定值value的情况,我们要先看下这个a[mid]是不是我们要找的第一个值大于等于给定值的元素。如果a[mid]前面已经没有元素,或者前面一个元素小于要查找的值value,那a[mid]就是我们要找的元素。如果a[mid-1]也大于等于要查找的值value,那说明要查找的元素在[low, mid-1]之间,所以,我们将high更新为mid-1。

(2)、源码:
public int bsearch(int[] a, int value) {
    int low = 0;
    int high = a.length - 1;
    while (low <= high) {
        int mid = low + ((high - low) >> 1);
        if (a[mid] >= value) {
            if ((mid == 0) || (a[mid - 1] < value)) return mid;
            else high = mid - 1;
        } else {
            low = mid + 1;
        }
    }
    return -1;
}

4、查找最后一个小于等于给定值的元素。

(1)、思路:

如果a[mid]大于要查找的值value,那要查找的值肯定在[mid+1, high]之间,所以,我们更新low=mid+1。
对于a[mid]小于等于给定值value的情况,我们要先看下这个a[mid]是不是我们要找的最后一个值小于等于给定值的元素。如果a[mid]后面已经没有元素,或者后面一个元素大于要查找的值value,那a[mid]就是我们要找的元素。如果a[mid-1]也小于等于要查找的值value,那说明要查找的元素在[mid + 1, high]之间,所以,我们将low更新为mid+1。

(2)、源码:
public int bsearch7(int[] a, int value) {
    int low = 0;
    int high = a.length - 1;
    while (low <= high) {
        int mid = low + ((high - low) >> 1);
        if (a[mid] > value) {
            high = mid - 1;
        } else {
            if ((mid == n - 1) || (a[mid + 1] > value)) return mid;
            else low = mid + 1;
        }
    }
    return -1;
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容