leetcode 34. Search for a Range (binary search std::lower_bound)

来源:互联网 发布:回收站数据恢复免费版 编辑:程序博客网 时间:2024/06/08 00:01

写在前面

一个简单的二分查找的题目,惯常的二分查找然后循环查找边界虽然可以AC,但是是肯定不符合要求的,所以必须从二分查找上找答案。

题目描述

Given an array of integers sorted in ascending order, find the starting and ending position of a given target value.

Your algorithm’s runtime complexity must be in the order of O(log n).

If the target is not found in the array, return [-1, -1].

For example,
Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].

思路分析

我们通常使用二分查找的方式就是简单地在指定范围内去查找一个数,而我们知道,C++ lower_bound和upper_bound是C++语言中的二分查找泛型算法(当然也有binary_search,这里不讨论)。前者返回区间内大于等于目标值的第一个位置的迭代器,不存在则返回end()迭代器,后者返回区间内大于目标值的第一个位置的迭代器,不存在同样返回end()迭代器(这里是upper_bound的直观解释,正式的解释可以查阅文档)。对于本题,我们使用这两个函数,就可以轻易解出满足要求的题解。当然,这部分的关键代码是lower_bound的实现,lower_bound本身是二分查找的变形,很简单,这种写法可以作为二分查找的模板写法。

lower_bound(非模板的实现)

// 这里返回下标位置

int lower_bound(vector<int>& nums, int target) {    int left = 0;    int right = nums.size();    while(left<right) {        auto mid = left + (right-left)/2; // 这种写法可以防止left+right 过大导致的溢出        if(target>nums[mid])left = mid+1;        else right = mid;    }    return left;}

// AC 解

class Solution {public:    vector<int> searchRange(vector<int>& nums, int target) {        auto iter = std::lower_bound(nums.begin(),nums.end(),target);        if(iter==nums.end()||*iter!=target) return {-1,-1};        auto left = iter-nums.begin();        auto siter = std::upper_bound(iter,nums.end(),target);        auto right = siter-nums.begin()-1;        return {left,right};        // 排好序的数组 一般是二分查找        // binary search        // lower_bound        if(nums.size()==0) return {-1,-1};        int left = 0,right = nums.size();        // lower_bound        while(left<right) {            auto mid = left + (right-left)/2;            if(target<=nums[mid]) right = mid;            else left = mid+1;        }        if(left == nums.size()||nums[left]!=target) return {-1,-1};        int retLeft = left;        right = nums.size();            while(left<right) {            auto mid = left + (right-left)/2;            if(target+1<=nums[mid]) right = mid;            else left = mid+1;        }        if(left == retLeft) return {retLeft,retLeft};        int retRight = left-1;        return {retLeft,retRight};    }};
原创粉丝点击