• 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].

    分析


    思路1:

    首先想到的思路是用二分法查找到target,然后从target开始,同时向左右两边扩展窗口,但是最坏的时间复杂度是O(n);

    思路2:

    采用递归,recursive。
    终止条件:
    1. 当 nums[l] == target == nums[r]
        返回{l,r}
    2. 当 target 落在 [nums[l],nums[r]]之外,返回{-1,-1}

    递归部分:
    当 nums[l] <= target <= nums[r],分别对左半边和后半边进行search。同时将两个结果进行合并。

    假设有一数组nums[],我们把它分为两部分
    A...B  C...D
    当出现终止条件中的一条时,都会立即返回;
    如果俩个部分都进入了递归部分,说明 
    A <= target <= B
    C <= target <= D
    所以可以得知,
    target = B = C 
    那么A..B的左边界就是nums的左边界,C..D的右边界就是nums的右边界,否则返回其中一个不是{-1,-1}的结果,就是这样合并两个结果的。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    class Solution {
    public:
        vector<int> searchRange(vector<int>& nums, int target) {
            return helper(nums, 0, nums.size() - 1, target);
        }
        vector<int> helper(vector<int> & nums,int l, int r, int target){
            if(nums.empty())return vector<int>{-1,-1};
            if(nums[l] == target && target == nums[r]){
                return vector<int>{l,r};
            }
            else if(nums[l] <= target && target <= nums[r]){
                int mid = (l + r) >> 1;
                vector<int> L = helper(nums, l, mid, target);
                vector<int> R = helper(nums, mid+1, r, target);
                if(L[0] != -1 && R[0] != -1){
                    return vector<int> {L[0],R[1]};
                }
                else if(L[0] != -1){
                    return L;
                }
                else{// 剩下的 R 不为{-1, -1} 和 R 是{-1, -1}的情况可以合并
                    return R;
                }
            }
            return vector<int>{-1, -1};
        }
    };

    思路3:

    使用一般的二分查找,找到target的首个元素
    然后再找 target+1 可以插入的首个位置,
    这两者之间即为所求
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    class Solution {
    public:
        vector<int> searchRange(vector<int>& nums, int target) {
            if(nums.empty()) return vector<int> {-1, -1};
            int l = bs(nums, target);
            if(nums[l] == target){
                int r = bs(nums, target + 1);
                /**
                 * 当nums的最后一个元素是target的时候,需要将边界r自增才是可以插入target+1的位置
                 * 比如[2,2,2]则r的值是2,和[2,2,4]的返回值同是2,
                 */
                 
                if(nums[r] == target) 
                    r++;
                return vector<int> {l, r - 1};
            }
            else{
                return vector<int> {-1, -1};
            }
        }
        // using binary search to find the first element in nums or the position that could be used to insert the element
        int bs(vector<int> & nums, int target){
            int l = 0, r = nums.size() - 1, mid;
            while(l < r){
                mid = (l + r) >> 1;
                if(nums[mid] < target){
                    l = mid + 1;
                }
                else{
                    r = mid;
                }
            }
            return r;
        }
    };

    思路4

    写两个找边界的函数,一个找上边界,一个找下边界;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    class Solution {
    public:
        vector<int> searchRange(vector<int>& nums, int target) {
            if(nums.empty()) return vector<int> {-1, -1};
            int l = lob(nums, target);
            if(nums[l] == target){
                int r = upb(nums, target);
                return vector<int> {l, r};
            }
            return vector<int> {-1, -1};
        }
         
        int lob(vector<int> & nums, int target){
            int l = 0, r = nums.size() - 1, mid;
            while(l < r){
                mid = (l + r) >> 1; // insure the mid always be at the lower position
                if(nums[mid] < target){
                    l = mid + 1;
                }
                else{
                    r = mid;
                }
            }
            return r;
        }
         
        int upb(vector<int> & nums, int target){
            int l = 0, r = nums.size() - 1, mid;
            while(l < r){
                mid = (l + r + 1) >> 1;// insure the mid always be at the upper position
                if(nums[mid] > target){
                    r = mid - 1;
                }
                else{
                    l = mid;
                }
            }
            return l;
        }
    };




  • 相关阅读:
    循环调用spring的dao,数个过后无响应
    WebEx如何录制电脑内的声音
    java对象转换String类型的三种方法
    使用Hibernate+MySql+native SQL的BUG,以及解决办法
    mysql之触发器trigger
    mysql 触发器学习
    Java对比两个数据库中的表和字段,写个冷门的东西
    PHP几个快速读取大文件例子
    Java安全中的“大坑”,跨平台真“浮云”
    国内一些大公司的开源项目
  • 原文地址:https://www.cnblogs.com/zhxshseu/p/c8ae187c169beb07f9646be57ee2ec22.html
Copyright © 2020-2023  润新知