二分搜素算法

二分搜索算法的三种情况

推荐博客,真的写的非常好!!!

1、当数组中没有重复元素时:

public int binarySearchImplement(int[] array, int target) {
        if (array == null || array.length == 0) return -1;

        int start = 0, end = array.length -1;
        int index = -1;
        boolean flag = false;

        while (start <= end) {  // <= 表示左闭右闭的区间
            //int mid = (start + end) >> 1;
            int mid = start + (end - start) /2; //这样写是为了防止加法溢出

            if (array[mid] == target) {
                index = mid;
                flag = true;
                break;
            } else if (array[mid] > target) {
                end = mid-1;
            } else {
                start = mid + 1;
            }
        }

        if (flag) return index;
        else return -1;
    }

 

2、当数组中有重复元素,寻找左边界

public int binarySearch_leftBound(int[] array, int target) {
        if (array == null || array.length == 0) return -1;

        int start = 0, end = array.length;  //左闭右开 => [0, length)

        while (start < end) {   //终止条件为: (start = end) => [start, start)
            int mid = start + ((end - start) >>> 1);    //移位运算的优先级小于加法,所以别忘了加括号

            if (array[mid] == target) {
                end = mid;
            } else if (array[mid] < target) {
                start = mid + 1;    //搜索区间变为[mid+1, end)
            } else if (array[mid] > target) {
                end = mid;  //搜索区间变为[start, mid)
            }
        }

        if (start == array.length) return -1;

        return array[start] == target? start: -1;   //start = end,也可以写成return end
    }

 

3、当数组中有重复元素,寻找右边界

public int binarySearch_rightBound(int[] array, int target) {
        if (array == null || array.length == 0) return -1;

        int start = 0, end = array.length;  //左闭右开 => [0, length)

        while (start < end) {   //终止条件为: (start = end) => [start, start)
            int mid = start + ((end - start) >>> 1);    //移位运算的优先级小于加法,所以别忘了加括号

            if (array[mid] == target) {
                start = mid + 1;    //向右边搜索
            } else if (array[mid] < target) {
                start = mid+1;    //搜索区间变为[mid+1, end)
            } else if (array[mid] > target) {
                end = mid;  //搜索区间变为[start, mid)
            }
        }

        if (start == 0) return -1;

        return array[start-1] == target? (start-1): -1;
    }

 

import org.junit.Test;
public class NC105 {
    @Test
    public void test() {
        int[] nums = {2,2};
        int target = 2;
        System.out.println(search_3(nums, target));
    }

    // 当数组中无重复元素
    public int search(int[] nums, int target) {
        if (nums == null || nums.length == 0) return -1;

        int left = 0, right = nums.length - 1;  // 搜索区间是左闭右闭[0, len-1]

        while (left < right) {  // 停止条件[left, left],left没有判断,最后要特判(while必须能停下来)
            int mid = left + ((right - left) >> 1);

            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else if (nums[mid] > target) {
                right = mid - 1;
            }
        }

        return nums[left] == target? left: -1;  // 这里加一下对left的判断
    }

    // 当数组中无重复元素
    public int search_1(int[] nums, int target) {
        if (nums == null || nums.length == 0) return -1;

        int left = 0, right = nums.length - 1;  // 搜索区间是左闭右闭[0, len-1]

        while (left <= right) {  // 停止条件[right+1, right],搜索区间就都为空了,这里就不用特判
            int mid = left + ((right - left) >> 1);

            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else if (nums[mid] > target) {
                right = mid - 1;
            }
        }

        return -1;
    }

    // 当数组中有重复元素,寻找左边界
    public int search_2(int[] nums, int target) {
        if (nums == null || nums.length == 0) return -1;

        int left = 0, right = nums.length;  // 左闭右开[left, right)

        while (left < right) {  //[left, left)  [2,2)
            int mid = left + ((right - left) >> 1);

            if (nums[mid] < target) {
                left = mid + 1;
            } else if (nums[mid] > target) {
                right = mid;
            } else if (nums[mid] == target) {
                right = mid;    //[2,2)
            }
        }

        if (left == nums.length) return -1; // 没有找到

        return nums[left] == target? right: -1; // 这两个语句的顺序不能乱 否则数组越界
    }

    // 当数组中有重复元素,寻找右边界
    public int search_3(int[] nums, int target) {
        if (nums == null || nums.length == 0) return -1;

        int left = 0, right = nums.length;  // 左闭右开[left, right)

        while(left < right) {   // [left, left) [2,3)
            int mid = left + ((right - left) >> 1); // 向下取整

            if (nums[mid] < target) {
                left = mid + 1;
            } else if (nums[mid] > target) {
                right = mid;
            } else if (nums[mid] == target) {
                left = mid + 1; // [2,3)
            }
        }
        if (right == 0)  return -1;

        return nums[right-1] == target? left-1: -1;
    }
}

  

posted @ 2021-03-15 21:48  Peterxiazhen  阅读(52)  评论(0编辑  收藏  举报