每日一题
题目说明
34.在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 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]
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/solution/zai-pai-xu-shu-zu-zhong-cha-zhao-yuan-su-de-di-3-4/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
算法思路
其实这题目很简单,从头到尾遍历一遍就找到第一个和最后一个目标值就可以了。
但是这个方法的时间复杂度是O(n)。
而这题比较进阶的解法时间复杂度是 O(log n) 。
二分查找法:
利用题目所给特性,数组是按照升序排列的,所以我们可以使用二分查找法,且二分查找的时间复杂度就是O(log n)。
再我们遇到升序排列的时候,应该首先想到二分查找可不可以用,形成一种条件反射。
代码实现就很简单了。
代码实现
class Solution
{
public:
//二分查找
int bsearch(vector<int>& nums, int target, bool lower)
{
int left = 0;
int right = nums.size() - 1;
int ans = (int)nums.size();
while (left <= right)
{
int mid = (left + right) / 2;
if (nums[mid] > target || lower && nums[mid] >= target)
{
right = mid - 1;
ans = mid;
}
else
{
left = mid + 1;
}
}
return ans;
}
vector<int> searchRange(vector<int>& nums, int target)
{
int left1 = bsearch(nums, target, true);
int right1 = bsearch(nums, target, false) - 1;
if (left1 <= right1 && right1 < nums.size() && nums[left1] == target && nums[right1] == target)
{
return vector<int>{left1, right1};
}
return vector<int>{-1, -1};
}
};
复杂度分析
-
时间复杂度: O(log n) ,其中 n 为数组的长度。二分查找的时间复杂度为 O(logn),一共会执行两次,因此总时间复杂度为 O(logn)。
-
空间复杂度:O(1)。只需要常数空间存放若干变量。