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


    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的子数组的最大的平均值;

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

  • 相关阅读:
    毕业设计-角色用户管理
    质因数分解
    高次同余方程
    线性同余方程
    乘法逆元
    约数,整除
    扩展欧几里得算法
    同余
    P2303 [SDOI2012] Longge 的问题
    最大公约数(gcd)与最小公倍数(lcm)
  • 原文地址:https://www.cnblogs.com/daguankele/p/6322354.html
Copyright © 2020-2023  润新知