题目
来源:LeetCode.
给定一个按照升序排列的整数数组 nums,和一个目标值 target。
找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
时间复杂度为 O(log n)
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
示例 3:
输入:nums = [], target = 0
输出:[-1,-1]
提示:
- 0 < = n u m s . l e n g t h < = 105 0 <= nums.length <= 105 0<=nums.length<=105
- − 109 < = n u m s [ i ] < = 109 -109 <= nums[i] <= 109 −109<=nums[i]<=109
- n u m s 是 一 个 非 递 减 数 组 nums 是一个非递减数组 nums是一个非递减数组
- − 109 < = t a r g e t < = 109 -109 <= target <= 109 −109<=target<=109
接下来看一下解题思路:
思路:二分法:
最直观的想法是通过 循环遍历
来查找,记录第一个 target
和 最后一个 target
的下标, 但是时间复杂度是 O(n)
。
看到题目,在升序的数组里,要求时间复杂度为 O(log n) 找目标值,首先想到的是二分查找。
二分查找适用场景:有序或者部分有序,基本使用二分搜索及其变种;
因为每次搜索数据的一半,时间复杂度
O
(
l
o
g
n
)
O(logn)
O(logn)
考虑要寻找
t
a
r
g
e
t
target
target 的开始和结束位置,需要找数组中 【第一个 等于
t
a
r
g
e
t
target
target 的位置】和 【最后一个 等于
t
a
r
g
e
t
target
target 的位置】
由于两者的判断条件不同,为了代码复用,可以定义一个 bool
类型,来区分 第一个和最后一个,然后在查找的过程中 使用 二分法
查找
java实现
int[] searchRange(int[] nums, int target) {
if (nums.length < 1) {
return new int[]{-1, -1};
}
return new int[]{findIndex(nums, target, true), findIndex(nums, target, false)};
}
int findIndex(int[] nums, int target, boolean pre) {
int left = 0;
int right = nums.length - 1;
int ans = -1;
while (left <= right) {
int mid = (left + right) >> 1;
if (nums[mid] == target) {
ans = mid;
if (pre) {
right = mid - 1;
} else {
left = mid + 1;
}
} else if (nums[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return ans;
}
C++实现
public:
vector<int> searchRange(vector<int>& nums, int target) {
if ((int)nums.size() < 1) {
return vector<int>{-1, -1};
}
return vector<int>{findIndex(nums, target, true), findIndex(nums, target, false)};
}
public:
int findIndex(vector<int>& nums, int target, bool pre) {
int left = 0;
int right = (int)nums.size() - 1;
int ans = -1;
while (left <= right) {
int mid = (left + right) >> 1;
if (nums[mid] == target) {
ans = mid;
if (pre) {
right = mid - 1;
}
else {
left = mid + 1;
}
}
else if (nums[mid] > target) {
right = mid - 1;
}
else {
left = mid + 1;
}
}
return ans;
}
}
python实现
class Solution(object):
def searchRange(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
if len(nums) < 1:
return [-1, -1]
return [self.findIndex(nums, target, True), self.findIndex(nums, target, False)]
def findIndex(self, nums, target, pre):
left = 0
right = len(nums) - 1
ans = -1
while left <= right:
mid = (left + right) >> 1
if nums[mid] == target:
ans = mid
if pre:
right = mid - 1
else:
left = mid + 1
elif nums[mid] > target:
right = mid - 1
else:
left = mid + 1
return ans
复杂度分析
时间复杂度:
O
(
log
n
)
O(\log n)
O(logn),其中
n
n
n 为
nums
\textit{nums}
nums 数组的大小。整个算法时间复杂度即为二分查找的时间复杂度
O
(
log
n
)
O(\log n)
O(logn)。
空间复杂度:
O
(
1
)
O(1)
O(1)。只需要常数级别的空间存放变量。