1、题目介绍
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]
2、思路总结
虽然之前说用二分法的要求是没有重复元素,但是这道题居然可以用二分法做出来,我也是通过代码随想录了解到这道题,借鉴了大佬的做法之后做了出来。
连续使用两次二分查找法,第一次查找重复元素的第一个位置,第二次查找重复元素的第二个元素。其中的要点是查找到元素之后 right = middle-1 和 left = middle+1
现在先贴上大佬的代码:
// 两次二分查找,分开查找第一个和最后一个
// 时间复杂度 O(log n), 空间复杂度 O(1)
// [1,2,3,3,3,3,4,5,9]
public int[] searchRange2(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
int first = -1;
int last = -1;
// 找第一个等于target的位置
while (left <= right) {
int middle = (left + right) / 2;
if (nums[middle] == target) {
first = middle;
right = middle - 1; //重点
} else if (nums[middle] > target) {
right = middle - 1;
} else {
left = middle + 1;
}
}
// 最后一个等于target的位置
left = 0;
right = nums.length - 1;
while (left <= right) {
int middle = (left + right) / 2;
if (nums[middle] == target) {
last = middle;
left = middle + 1; //重点
} else if (nums[middle] > target) {
right = middle - 1;
} else {
left = middle + 1;
}
}
return new int[]{first, last};
}
然后是我的代码
3、代码
class Solution(object):
def searchRange(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
left=0
right=len(nums)-1
flag=0
while left<=right:
middle = left+(right-left)//2
if target<nums[middle]:
right=middle-1
elif target>nums[middle]:
left=middle+1
if nums[middle]==target:
first=middle#先找到最前面的重复元素
right=middle-1#将right变小,查找是否有更小的重复元素
flag=1
if flag==0:
return -1,-1
left=0
right=len(nums)-1
flag=0
while left<=right:
middle = left+(right-left)//2
if target<nums[middle]:
right=middle-1
elif target>nums[middle]:
left=middle+1
if nums[middle]==target:
last=middle#先找到最后面的重复元素
left=middle+1#将left变大,查找是否有更大的重复元素
flag=1
if flag==0:
return -1,-1
elif flag==1 :
return first,last