LeetCode题解 week2(2)

来源:互联网 发布:犀牛软件版本分析 编辑:程序博客网 时间:2024/05/16 13:39

34 Search for a Range
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].

对应一个已经排好序的数组+寻找target+O(log n),最先想到的算法应该就是二分查找算法了。但是我们学过的最基础的二分查找算法主要是针对查找一个目标值而非一个范围,这个时候,便需要在范围比较判定赋值上面下功夫了。

一个普通的二分查找:

while(low <= high){    int mid = (low + high)/2;        if(nums[mid] == target) {            return mid;        }         else if(nums[mid] > target) {            high = mid - 1;        }         else {            low = mid + 1;        }    }

每次取中间值,如果恰好等于目标,即找到了目标值,直接返回,若是中间值比目标值大,则说明目标在数列的左半边,在数列的左半边进行下一次寻找,若是中间值比目标值小,则在数列的右半边进行寻找,如此重复知道找到目标值(或者不存在)为止。

而这题要求边界,即是在可能有复数个目标值的情况下,找到最左边的那个目标值(下界)和最右边的那个目标值(上界),所以需要在普通的二分查找中进行判断条件和边界赋值的修改。

下界二分查找:

while(low < high) {    int mid = (low + high) / 2;    if(nums[mid] < target)        low = mid + 1;    else        high = mid;}if(nums[low] != target)    return -1;else return low;

关键是每次判断nums[mid]与target的大小重新选定查找范围时,若取左半边时,将nums[mid]也包括进去,使得当target有复数个值的时候,最左边的那个(第一个)会一直在搜索范围之内,直到最后退出while循环的时候,只剩下一个元素(即第一个目标值)或者是找不到目标,完成了搜索。

上界二分查找:

while(low < high) {    int mid = (low + high + 1) / 2;    if(nums[mid] > target)        high = mid - 1;    else        low = mid;}if(nums[high] != target)    return -1;else return high;

思想与下界二分查找类似,但是此时mid = (low + high + 1) / 2,保证当搜索数列只剩两位的时候不会陷入死循环(取右)。

对于这道题便可以使用两次二分查找分别查找到值等于target的第一次出现的位置(最左边的target)和最后一次出现的位置(最右边的target),从而达成在O(log n)的时间复杂度下求出其范围。

当然还要注意越界问题,当nums为空的时候会出现越界,所以要拿出来单独考虑。

参考代码如下:

class Solution {public:    vector<int> searchRange(vector<int>& nums, int target) {        int i = 0;        int j = nums.size() -1;        int mid;        vector<int> result;        // set default        result.push_back(-1);        result.push_back(-1);        // find the lower bound        if(j == -1)            return result;        while(i < j) {            mid = (i + j) / 2;            if (nums[mid] < target)                i = mid + 1;            else                j = mid;        }        if(nums[i] != target)            return result;        else            result[0] = i;        // find the upper bound        j = nums.size() -1;        while(i < j) {            mid = (i + j + 1) / 2;            if(nums[mid] > target)                j = mid - 1;            else                i = mid;        }        result[1] = j;        return result;    }};