算法学习--二分查找的学习

1、二分查找使用场景

  在有序数组中,快速查找某个数字或者某个范围,最终都是对某个 target的查找,隶属于search算法的一种

2、二分使用要求

  1) 必须能够随机存储,O(1)常数时间访问,比如数组或者vector等或者底层依靠顺序存储结构实现的数据结构

  2) 必须有序,或者在局部范围内有序,可以进行左右范围的判定

3、时间复杂度

  二分的时间复杂为O(logN),递推公式为O(N) = O(N/2) + O(1),通过常熟时间内将原有的问题规模减少到原来的一半;

4、二分的分析步骤

  1) 明确对谁使用二分,

  2) 二分后如何选择下一个要处理的范围

5、二分经典模版

  二分边界采用相邻即退出,然后再去根据题目要求判断先返回end还是先返回start 

int binarySearch(vector<int>& nums, int tartget, int start, int end){

    int size = nums.size();
    if(size == 0 || start > end){
        return -1;
    }
     while(start + 1 < end){
        int mid = start + (end - start) / 2;
        if(nums[mid] == target){
            return mid;
        }
        else if(nums[mid] > target){
            end = mid;
        }
        else {
            start = mid;
        }
    }
    if(nums[start] == target){
        return start;
    }
    if(nums[end] == target){
        return end;
    }
    return -1;
}

  二分模版的变形,返回第一个target出现的位置或者返回最后一个target的位置等,就是在内部判断向左向右时,等于的情况怎么办,下面采用例题说明。

6、 二分经典题目

  1) 经典二分查找问题

  直接使用模版,不解释;

  2) 查找目标最后一个位置

  给一个升序数组,找到target最后一次出现的位置,如果没出现过返回-1;当中间的数组值等于target的时候,应该将此时的start值更新成mid;

  

class Solution {
public:
    /**
     * @param A an integer array sorted in ascending order
     * @param target an integer
     * @return an integer
     */
    int lastPosition(vector<int>& A, int target) {
        // Write your code here
        int vectorLen = A.size();
        if (vectorLen == 0) {
            return -1;
        }
        
        int start = 0;
        int end = vectorLen - 1;
        while(start + 1 < end) {
            int mid = start + (end - start) / 2;
            if(A[mid] == target){
                start = mid;
            }
            else if(A[mid] < target) {
                start = mid;
            }
            else {
                end = mid;
            }
        }
        
        if(A[end] == target) {
            return end;
        }
        if(A[start] == target) {
            return start;
        }
        return -1;
    }
};

  3) 查找target出现的第一个位置

  给定一个排序的整数数组(升序)和一个要查找的整数target,用O(logn)的时间查找到target第一次出现的下标(从0开始),如果target不存在于数组中,返回-1。此时和题目2中的分析类似,当nums[mid] == target时,此时应该更新end的值,因为前面还可能存在target;

  

class Solution {
public:
    /**
     * @param nums: The integer array.
     * @param target: Target number to find.
     * @return: The first position of target. Position starts from 0. 
     */
    int binarySearch(vector<int> &array, int target) {
        // write your code here
        int arrayLen = array.size();
        if( arrayLen == 0){
            return -1;
        }
        
        int start = 0;
        int end = arrayLen - 1;
        while(start + 1 < end){
            int mid = start + (end - start) / 2;
            if(array[mid] >= target){
                end = mid;
            }
            if(array[mid] < target){
                start = mid;
            }
        }
        if(array[start] == target){
            return start;
        }
        if(array[end] == target){
            return end;
        }
        return -1;
    }
};

  4) 找到排序数组中最接近的元素

  在一个排好序的数组 A 中找到 i 使得 A[i] 最接近 target

  

//还是标准的二分程序,就是在返回值时的判断不一样了,比较谁距离target近
class Solution {
public:
    /**
     * @param A an integer array sorted in ascending order
     * @param target an integer
     * @return an integer
     */
    int closestNumber(vector<int>& A, int target) {
        // Write your code here
        int size = A.size();
        if(size == 0){
            return -1;
        }
        
        //标准二分模版定义开始和结束变量
        int begin = 0;
        int end = size - 1;
        while(begin + 1 < end){
            int mid = begin + (end - begin) / 2;
            if(A[mid] >= target){
                end = mid;
            }
            else {
                begin = mid;
            }
        }
        
        return abs(A[begin] - target) < abs(A[end] - target) ? begin : end;
    }
};

  5) 最大连续数组的最大平均值

  给定一个有正有负的数组,返回长度大于K的子数组的最大的平均值;

  对于使用二分的两个条件来说,满足随机存储,但是这个数组不是排序的数组,那么对与这道题来说就不是对数组本身进行二分;一个数组的的子数组的平均值必然大于数组元素的最小值,小于数组的最大值,其他的必然存在这个范围内,那么可以对答案进行二分进行查找;

posted @ 2017-01-20 11:34  罐装可乐  阅读(308)  评论(0编辑  收藏  举报