34. Search for a Range

本文介绍了一种在有序数组中查找特定目标值起始和结束位置的方法,通过递归和二分查找实现,确保了O(log n)的时间复杂度。

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;
     }
};




转载于:https://www.cnblogs.com/zhxshseu/p/c8ae187c169beb07f9646be57ee2ec22.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值