二分搜索法

下面给出二分搜索的四个经典例题,快速学习二分搜索

1、在有序数组中确定num是否存在

给定一个升序数组arr,判断一个数num是否在这个升序数组中,要求时间复杂度为O(logn)。

需要使用二分搜索,若直接遍历时间复杂度为O(n),不符合要求,下面给出java代码。

public class FindNum {

    public static void main(String[] args) {
        int[] arr = {1, 3, 5, 7, 9};    
        System.out.println(exist(5, arr));    //输出true 
    }

    public static boolean exist(int num, int[] arr) {
        if (arr == null || arr.length == 0) {
            return false;
        }
        int l = 0, r = arr.length - 1, m = 0;
        while (l <= r) {
            m = (l + r) / 2;
            if (arr[m] == num) {
                return true;    //中点位置的数就是所查找的num,直接返回true
            } else if (arr[m] > num) {    //中点位置的数大于num,因此要往中点左边的位置查找
                r = m - 1;        
            } else {
                l = m + 1;    //中点位置的数小于num,因此要往中点右边的位置查找
            }
        }
        return false;
    }
}

2、在有序数组中找>=num的最左位置

给定一个升序数组arr,并给出一个数num,求出这个数组中大于等于num的最左索引。要求时间复杂度为O(logn)。

public class FindLeft {
    public static void main(String[] args) {
        int[] arr = {1, 3, 3, 3, 9};  
        System.out.println(findLeft(3, arr));    //输出1
    }
    public static int findLeft(int num, int[] arr) {
        int l = 0, r = arr.length - 1, m = 0, ans = -1;
        while (l <= r) {
            m = (l + r) / 2;
            if (arr[m] >= num) {
                ans = m;
                r = m - 1;    //中点的数大于等于num,记下中点的位置,再去中点左边找
            } else {
                l = m + 1;
            }
        }
        return ans;
    }
}

3、在有序数组中找<=num的最右位置

给定一个升序数组arr,并给出一个数num,求出这个数组中小于等于num的最右索引。要求时间复杂度为O(logn)。

public class FindRight {
    public static void main(String[] args) {
        int[] arr = {1, 3, 3, 3, 9};
        System.out.println(findRight(3, arr));    //输出3
    }

    public static findRight(int num, int[] arr) {
        int l = 0, r = arr.length - 1, m = 0, ans = 0;
        while (l <= r) {
            m = (l + r) / 2;
            if (arr[m] <= num) {
                ans = m;
                l = m + 1;    //中点的数小于等于num,记下中点的位置,去中点的右边找
            } else {
                r = m - 1;   
            }
            return ansl
        }
    }
}

4、寻找峰值(leetcode原题)

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。

要求时间复杂度为O(logn),因此需要用二分查找法。

public class FindPeak {
    public static int findPeak(int[] nums) {
        int n = nums.length;
        if (n == 1) {
            return 0;  //若长度为1,峰值就是这个数组中唯一的这个数,因为默认-1和n位置都是无穷小
        }
        if (nums[0] > nums[1]) {
            return 0;  //若0位置大于1位置,返回0位置,因为-1位置无穷小
        }
        if (nums[n - 1] > nums[n - 2]) {
            return n-1; //若n-1位置大于n-2位置,返回n-1位置,因为n位置无穷小
        }
        
        int l = 1, r = n-2, m = 0, ans = -1;
        while(l <= r) {
            m = (l + r) / 2;
            if (nums[m - 1] > nums[m]) {
                r = m - 1;
            } else if (nums[m + 1] > nums[m]) {
                l = m + 1;
            } else {
                ans = m;
                break;
            }
        }
        return ans;
    }
}

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值