二分查找向上还是向下取整_搜索旋转排序数组和查找旋转排序数组的最小值

f2625fe8ad838d141cbe9f511bcba935.png
 /**
     * create by: 睚雪
     * description: 用二分查找
     * 会出现几种情况
     * 如果数组只有一个数 那么 left==fight 循环不走 直接输出left
     * 1. 左值 < 中值, 中值 < 右值 :没有旋转,最小值在最左边,可以收缩右边界
     * 2. 左值 > 中值, 中值 < 右值 :有旋转,最小值在左半边,可以收缩右边界
     * 3. 左值 < 中值, 中值 > 右值 :有旋转,最小值在右半边,可以收缩左边界
     * create time: 2020-4-27 20:43
     * @params [nums]
     * @return int
     */
    public static int findMin(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] > nums[right]) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return nums[left];
    }

9b25ad6c62b2a13b82203026f2237380.png

解法一:

偷懒式解法 靠着上一题的算法找出最小值 以这个值进行分割将这个旋转数组分割成两个排序数组 进行二分搜索

public static int searchFindMin(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] > nums[right]) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }
public static int search(int[] nums, int target) {

        if(nums.length==0){
            return -1;
        }
        int right = nums.length-1;
        int left = 0;
        int min = searchFindMin(nums);//最小的位置的边界
        if(target<=nums[right]){ //这个数字在最小值到最右边这个区间 不管数组怎么旋转从最小值到最右边一定是升序数组
            left = findTarget2(nums,min,right,target);
        }else{
            if(min!=0&&nums[min-1]>=target){ //这个数字在另一个区间
                left= findTarget2(nums,0,min-1,target);
            }else{
                return -1; //比所有值都大那么就只能是-1了
            }
        }
        if(nums[left]==target){
            return left;
        }else {
            return -1;
        }
    }

解法二:

直接在这个旋转数组里进行查找

大体上有两个状态

  1. left-mid之间还是一个排序数组没有干扰
    1. 正常的二分搜索
  2. left-mid之间有被破坏 要进一步分析target在哪边
    1. 就算是被破坏了但是mid到right一定是完整的
    2. 判断target是否在 mid-right之间 如果是缩小左半区
    3. 不在mid-right之间 砍掉右半区
public static int search2(int[] nums, int target) {
        int right = nums.length-1;
        int left = 0;
        int mid = 0;
        while(left<=right){ //这里的=于是考虑到数组只有一个元素省的多写一个判断
            mid = left+(right-left)/2;
            if(nums[mid]==target){ //当遍历到最后一个的时候因为计算公式是向下取整所以会是left
                return mid;
            }
            if(nums[left]<=nums[mid]){ //先判断从left到mid这段数组是否是升序的 =是考虑到数组可能会有重复的选项
                //正常的升序 再次判断 target在mid的左边还是右边
                if (target >= nums[left] && target < nums[mid]) { //确认在左半边 缩小右半区
                    right = mid;
                } else {
                    left = mid + 1;
                }
            }else{ //乱序了
                if(target>nums[mid]&&target<=nums[right]){
                    //虽然乱了但是target的值是在乱了的那边也就是右边 缩小左半区
                    left = mid+1;
                }else{
                    //不管怎么样从最小值到右半区肯定是没有他了 将右半区砍掉
                    right = mid;
                }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值