复习二——二分搜索

一、二分搜索

Given a sorted integer array- nums, and anteger - target.

Find the any/first/last position of target in nums

Return -1 if target does not exist.

算法复杂度: O(logn)

关键点:

start + 1 < end

start + (end - start)/2

A[mid] = 

class Solution{
    /**
     * @param nums: The integer array
     * @param target: target to find.
     * @return: The first position of target. Position start from 0
     */
    public int binarySearch(int[] nums, int target) {
        if(nums == null || nums.length = 0 ){
            return -1;
        }
        int start = 0, end = nums.length -1;
        while(start + 1 < end) {
            int mid = start + (end - start)/2;
            if(nums[mid] == target) {
                end = mid;
            } else if(nums[mid] < target) {
                start = mid;
            }else {
                end = mid;
            }
        }
        if(nums[start] == target){
            return start;
        }
        if(nums[end] == target){
            return end;
        }
        return -1;
    }
}

变种题

二分位置之OOXX

一般会给你一个数组,让你找数组中第一个/最后一个满足某个条件的位置

OOOOO.... OOXX.... XXXXXX

题目:

描述

代码库的版本号是从 1 到 n 的整数。某一天,有人提交了错误版本的代码,因此造成自身及之后版本的代码在单元测试中均出错。请找出第一个错误的版本号。

你可以通过 isBadVersion 的接口来判断版本号 version 是否在单元测试中出错,具体接口详情和调用方法请见代码的注释部分。

调用 isBadVersion 的方法,比如java的调用方式是SVNRepo.isBadVersion(v)

class Solution {
    /**
     * @param n : An integers
     * @return: An integer which is the first bad version
     */
    public it findFirstBadVersion(int n ) {
        int start = 1, end = n;
        while(start + 1 < end){
            int mid = start + (end -start) /2;
            if(SVNRepo.isBadVersion(mid)) {
                end = mid;
            } else {
                start  = end;
            }
        }
        if(SVNRepo.isBadVersion(satrt)) {
            return start;
        }
        return end;
    }
}

 题目:

描述

假设一个按升序排好序的数组在其某一未知点发生了旋转(比如0 1 2 4 5 6 7 可能变成4 5 6 7 0 1 2)。你需要找到其中最小的元素。

第一步先看最后一个数是否大雨第一个数,如果大于说明这个数组并没有翻转。直接返回第一个数
第二步做二分,通过和第一个数比较来决定向左或者移动:
    如果大于或者等于第一个数说明在翻转的左边,那么向右移动
    同理,如果小于则在右边,向左移动
public class Solution {
    /**
     * @param nums: a rotated sorted array
     * @return: the minimum number in the array
     */
    public int findMin(int[] nums) {
        if(numd == null || nums.length == 0) {
            return -1;
        }
        //如果最后一个数>=第一个数,说明没有翻转,直接返回第一个数
        if(nums[nums.length-1] >= nums[0])
            return nums[0]
        //通过判断属于rotation的左边哪或者右边来决定 往左或者往右搜索
        int start = 0, end = nums.lenghth -1;
        while(start + 1< end) {
            int mid = start + (end - start) /2;
            if(nums[mid] >= nums[0]){
                start = mid;
            }else{
                end = mid;
            }
        }
        return Math.min(nums[start], nums[end]);
    
    }

二、

二分位置 之Half half

并无法找到一个条件,形成OOXX的密性,但可以根据判断,保留下有解的那一半或者去掉无解的一半

方法:二分
二分查找第一个不小于target的元素很简单,但是需要确定二分区间的范围。
此时还是需要成倍地找到右边界。
初始右边界为1,如果右边界的数小于target,就将其倍增, 直到右边界不小于target。
这是可以二分查找了。
public class Solution {
    public int searchBigSortedArray(ArrayReader reader, int target) {
        int firstElement = reader.get(0);
        if(firstElement == target) 
            return 0;
        else if(firstElement > target)
            return -1;
        int idx = 0, jump =1;
        while(jump != 0 ){
            while(jump!=0 && reader.get(idx+jump) >= target) {
                jump >> 1;
            }
            idx += jump;
            jump <<= 1;
        }
        if(reader.get(idx + 1) == target)
            return idx + 1;
        else 
            return -1;
    }
}

public class Solution {
    public int searchBigSortedArray( ArrayReader reader, int target) {
        int l = 0, r = 1, mid;
        while(reader.get(r) < target) {
            r <<= 1
        }
        while(l < r) {
            mid = (l+r) >> 1;
            if(reader.get(mid) >= target) {
                r = mid;
            }else {
                l = mid + 1;
            }
        }
        if(reader.get(l) == target) {
            return l;
        }else {
            return -1;
        }
    }
}

159 · 寻找旋转排序数组中的最小值

描述

假设一个按升序排好序的数组在其某一未知点发生了旋转(比如0 1 2 4 5 6 7 可能变成4 5 6 7 0 1 2)。你需要找到其中最小的元素。

样例

样例 1:

 
输入:[4, 5, 6, 7, 0, 1, 2]
输出:0
解释:
数组中的最小值为0

样例 2:

输入:[2,1]
输出:1
解释:
数组中的最小值为1
第一步先看最后一个数是否大雨第一个数,如果大于说明这个数组并没有翻转。直接返回第一个数
第二步做二分,通过和第一个数比较来决定向左或者移动:
    如果大于或者等于第一个数说明在翻转的左边,那么向右移动
    同理,如果小于则在右边,向左移动
public class Solution {
    /**
     * @param nums: a rotated sorted array
     * @return: the minimum number in the array
     */
    public int findMin(int[] nums) {
        if(numd == null || nums.length == 0) {
            return -1;
        }
        //如果最后一个数>=第一个数,说明没有翻转,直接返回第一个数
        if(nums[nums.length-1] >= nums[0])
            return nums[0]
        //通过判断属于rotation的左边哪或者右边来决定 往左或者往右搜索
        int start = 0, end = nums.lenghth -1;
        while(start + 1< end) {
            int mid = start + (end - start) /2;
            if(nums[mid] >= nums[0]){
                start = mid;
            }else{
                end = mid;
            }
        }
        return Math.min(nums[start], nums[end]);
    
    }
}

1)通过判断mid和target是否处于翻转的同一边,来决定搜索的方向
 如果在同一边,按照正常的二分搜索方向
 如果在翻转的不同边,反转二分搜索的方向
2)如果>最后一个数:在左边, 否则在右边
public class Solution {
    /**
     * @param A: an integer rotated sorted array
     * @param target: an integer to be searched
     * @return: an integer
     */
    public int search(int[] A, int target) {
        if(A == null || A.length == 0) {
            returnœ -1;
        }
        //通过判断mid和target是否处于翻转的同一边,来决定搜索的方向
        //如果 > 最后一个数: 在左边,otherwise 在右边
        int start = 0, end = A.length -1, div = A[A.length -1];
        while(start + 1 < end) {
            int mid = start + (end - start)/2;
            if(A[mid] == target) {
                return mid;
            }
            //如果在同一边,按照正常的二分搜索方向
            if((A[mid] > div && target > div) 
            || A[mid] <= div && target <= div){
                if(A[mid] > target) {
                    end = mid;
                }else{
                    start = mid;
                }
            }else {
                //如果在翻转的不同边,反转二分搜索的方向
                if(A[mid]>target) {
                    start = mid
                }else {
                    end = mid;
                }
            }
            
        }
        if(A[start] == target)
                return start;
            if(A[end] == target) {
                return end;
            }
        return -1;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值