在排序数组中查找数字
题目
统计一个数字在排序数组中出现的次数。 0 < = 数 组 长 度 < = 50000 0 <= 数组长度 <= 50000 0<=数组长度<=50000
**思路 **
排序数组 nums中的所有数字 target形成一个窗口,记窗口的 左 / 右边界索引分别为 left和 right,分别对应窗口左边 / 右边的首个元素。
本题要求统计数字 target的出现次数,可转化为:使用二分法分别找到左边界 left和右边界 right ,易得数字target的数量为
r
i
g
h
t
−
l
e
f
t
−
1
right - left - 1
right−left−1
(1)初始化: 左边界 i = 0,右边界 j = len(nums) - 1代表闭区间 [i, j] 。
(2)循环二分: 当i≤j 时循环 (即当闭区间 [i, j]为空时跳出)
- 计算中点 m = (i + j) // 2m=(i+j)//2 ,其中 “” 为向下取整除法;
- 若nums[m] < target,则数字 target一定在闭区间 [m + 1, j]中,因此执行 i = m + 1;
- 若 nums[m] > target ,则数字 target一定在闭区间 [i, m - 1] 中,因此执行 j = m - 1;
- 若 nums[m] = target ,则右边界 right在闭区间 [m+1, j]中;左边界 left 在闭区间 [i, m-1] 中。
分为以下两种情况:
– 若查找右边界 right,则执行 i = m + 1;(跳出时 i 指向右边界)
– 若查找左边界 left,则执行 j = m - 1;(跳出时 j指向左边界)
(3)返回值: 应用两次二分,得到左右边界
(或者python的代码中,right=j left=i,则left和right分别指向第一个和最后一个target,返回right-left+1)
时间复杂度 O ( l o g n ) O(logn) O(logn)
C++
class Solution {
public:
int search(vector<int>& nums, int target) {
if(nums.empty())
return 0;
int n=nums.size();
int left = 0, right = n-1, mid;
int x, y;
while(left<right) //找到第一个target
{
mid = (left+right)/2;
if(nums[mid]>=target)
right = mid;
else
left = mid+1;
}
if (nums[left]!=target) //数组中不含target
return 0;
x = left; //x指向第一个left
right = n;
while(left<right) //找到最后一个target
{
mid = (left+right)/2;
if(nums[mid]<=target)
left = mid+1;
else
right = mid;
}
y = left; //y指向最后一个target
return y-x;
}
};
python
class Solution:
def search(self, nums: List[int], target: int) -> int:
i, j = 0, len(nums)-1
while i<=j: #找右边界,最后一个target之后
m = (i+j)//2
if nums[m]<=target:
i = m+1
else:
j = m-1
right = i
i, j = 0, len(nums)-1
while i<=j: #找左边界,第一个target之前
m = (i+j)//2
if nums[m]<target:
i = m+1
else:
j = m-1
left = j
return right-left-1