算法之二分法查找及其变种

二分查找就是将查找的键和子数组的中间键作比较,如果被查找的键小于中间键,就在左子数组继续查找;如果大于中间键,就在右子数组中查找,否则中间键就是要找的元素。

一、二分法查找

/**
 * 二分法查找,前提:数组必须先排好序
 * 
 * @param arrs
 * @param target
 * @return
 */
public static int binarySearch(int[] arrs, int target) {
    int low = 0;
    int high = arrs.length - 1;
    int m = 0;

    while(low <= high) {
        m = (low + high) / 2;
        if(arrs[m] == target) {
            return m;
        }
        if(target < arrs[m]) {
            high = m - 1;
        }
        if(target > arrs[m]) {
            low = m + 1;
        }
    }
    return -1;
}

二、二分法查找变种

关于二分查找,如果条件稍微变换一下,比如:数组之中的数据可能可以重复,要求返回匹配的数据的最小(或最大)的下标;更近一步, 需要找出数组中第一个大于key的元素(也就是最小的大于key的元素的)下标,等等。 这些,虽然只有一点点的变化,实现的时候确实要更加的细心。

二分查找的变种和二分查找原理一样,主要就是变换判断条件(也就是边界条件),还有就是注意判断返回值,是 low还是 high。

二分查找变种较多,不过它们的“套路”是一样的,基本步骤如下:
1. 根据要求判断出比较条件。
2. 判断出是返回low, 还是返回high。
题目中有“第一个/最左边“关键词就返回 low, 题目中有“最后一个/最右边”关键词就返回high。

1、查找第一个与target相等的元素

/**
 * 查找第一个与target相等的元素
 * 
 * @param arrs
 * @param target
 * @return
 */
public static int findFirstEqual(int[] arrs, int target) {
    int low = 0;
    int high = arrs.length - 1;
    int m = 0;

    while(low <= high) {
        m = low + (high - low) / 2;
        //只要target小于等于就往左移
        if(arrs[m] >= target) {
            high = m - 1;
        } else {
            low = m +1;
        }
    }
    if(low < arrs.length && arrs[low] == target) {
        return low;
    }
    return -1;
}

2、查找最后一个与target相等的元素

/**
 * 查找最后一个与target相等的元素
 * 
 * @param arrs
 * @param target
 * @return
 */
public static int findLastEqual(int[] arrs, int target) {
    int low = 0;
    int high = arrs.length - 1;
    int m = 0;

    while(low <= high) {
        m = low + (high - low) / 2;
        //只要target小于等于就往右移
        if(arrs[m] <= target) {
            low = m +1;
        } else {
            high = m - 1;
        }
    }
    if(high >= 0 && arrs[high] == target) {
        return high;
    }
    return -1;
}

3、查找最后一个小于target的元素

/**
* 查找最后一个小于target的元素.也就是说返回小于target的最右边元素下标。
 * 
 * @param arrs
 * @param target
 * @return
 */
public static int findLastSmaller(int[] arrs, int target) {
    int low = 0;
    int high = arrs.length - 1;
    int m = 0;

    while(low <= high) {
        m = low + (high - low) / 2;
        //条件就是题目中的小于target
        if(arrs[m] < target) {
            low = m +1;
        } else {
            high = m - 1;
        }
    }
    //返回最右边
    return high;
}

4、查找第一个等于或者大于target的元素

/**
 * 查找第一个等于或者大于target的元素
 * 
 * @param arrs
 * @param target
 * @return
 */
public static int findFirstEqualLarger(int[] arrs, int target) {
    int low = 0;
    int high = arrs.length - 1;
    int m = 0;

    while(low <= high) {
        m = low + (high - low) / 2;
        //条件就是题目中的等于或者大于target
        if(arrs[m] >= target) {
            high = m - 1;
        } else {
            low = m +1;
        }
    }
    //返回最左边
    return low;
}

猜你喜欢

转载自blog.csdn.net/iluojie/article/details/81273631