Leetcode34. Find First and Last Position of Element in Sorted Array
Given an array of integers nums sorted in ascending order, find thestarting 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].
Example 1:
Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
Example 2:
Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]
解法一 线性扫描
对 target
检查每一个下标,一定能得到正确答案。时间复杂度
O
(
N
)
O(N)
O(N),不符合题意。
解法二 两次二分查找
普通二分查找
int binarySearch(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while(left <= right) {
int mid = (right + left) / 2;
if(nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid - 1;
}
return -1;
}
- 注意①:
right = nums.length - 1
和left <= right
:搜索区间为[left,right]
,循环终止条件为left == right + 1
,写成区间的形式就是[right + 1, right]
,而while(left < right)
的循环终止条件为left == right
。 - 注意②:
left = mid + 1
和right = mid - 1
:因为mid
已经搜索过,应该从搜索区间中去除。
找左侧边界的二分
int left_bound(int[] nums, int target) {
if (nums.length == 0) return -1;
int left = 0;
int right = nums.length;
while (left < right) {
int mid = (left + right) / 2;
if (nums[mid] == target) {
right = mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid;
}
}
// target 比所有数都大
if (left == nums.length) return -1;
return nums[left] == target ? left : -1;
}
- 注意①:
right = nums.length;
和while (left < right)
:搜索区间为[left,right)
,循环终止条件为left == right
。 - 注意②:
left = mid + 1;
和right = mid
:因为是左闭右开,所以当nums[mid] < target
时,遍历区间为[mid+1,right)
,同理当nums[mid] > target
时,遍历区间为[left,mid)
(因为nums[mid] != target
,所以舍弃)。 - 注意③:返回
left
的含义:nums[]
中小于target
的值有left
个,即target
的下标正好为nums[left]
。 - 注意④:
nums[mid] == target
后令right = mid
:首先因为循环终止条件为left == right
,故即使此mid
为唯一一个target
,程序也可以返回正确的结果;找到target
时,在区间[left, mid)
中继续搜索,不断向左收缩,达到锁定左侧边界的目的。 - 注意⑤:返回
left
和right
是一样的因为循环终止条件为left == right
。
找右侧边界的二分
int right_bound(int[] nums, int target) {
if (nums.length == 0) return -1;
int left = 0, right = nums.length;
while (left < right) {
int mid = (left + right) / 2;
if (nums[mid] == target) {
left = mid + 1;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid;
}
}
if (left == 0) return -1;
return nums[left-1] == target ? (left-1) : -1;
}
- 注意①:
nums[mid] == target
后令left = mid + 1
,找到target
时,在区间[mid+1, right)
中继续搜索,不断向右收缩,达到锁定右侧边界的目的。循环的结束条件是left == right
。 - 注意②:返回
left - 1
。
Java
public class Solution {
public int[] searchRange(int[] nums, int target) {
int len = nums.length;
if (len == 0) {
return new int[]{-1, -1};
}
int firstPosition = findFirstPosition(nums, target);
if (firstPosition == -1) {
return new int[]{-1, -1};
}
int lastPosition = findLastPosition(nums, target);
return new int[]{firstPosition, lastPosition};
}
private int findFirstPosition(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = (left + right) >>> 1;
// 小于一定不是解
if (nums[mid] < target) {
// 下一轮搜索区间是 [mid + 1, right]
left = mid + 1;
} else {
right = mid;
}
}
if (nums[left] == target) {
return left;
}
return -1;
}
private int findLastPosition(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = (left + right + 1) >>> 1;
// 大于一定不是解
if (nums[mid] > target) {
// 下一轮搜索区间是 [left, mid - 1]
right = mid - 1;
} else {
left = mid;
}
}
return left;
}
}
C++
#include <iostream>
#include <vector>
using namespace std;
class Solution {
private:
int findFitstPosition(vector<int> &nums, int target) {
int size = nums.size();
int left = 0;
int right = size - 1;
while (left < right) {
int mid = (left + right) >> 1;
if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
if (nums[left] != target) {
return -1;
}
return left;
}
int findLastPosition(vector<int> &nums, int target) {
int size = nums.size();
int left = 0;
int right = size - 1;
while (left < right) {
int mid = (left + right + 1) >> 1;
if (nums[mid] > target) {
right = mid - 1;
} else {
left = mid;
}
}
if (nums[left] != target) {
return -1;
}
return left;
}
public:
vector<int> searchRange(vector<int> &nums, int target) {
int size = nums.size();
if (size == 0) {
return {-1, -1};
}
int fitstPosition = findFitstPosition(nums, target);
if (fitstPosition == -1) {
return {-1, -1};
}
int lastPosition = findLastPosition(nums, target);
return {fitstPosition, lastPosition};
}
};
Python
from typing import List
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
size = len(nums)
if size == 0:
return [-1, -1]
first_position = self.__find_first_position(nums, size, target)
if first_position == -1:
return [-1, -1]
last_position = self.__find_last_position(nums, size, target)
return [first_position, last_position]
def __find_first_position(self, nums, size, target):
left = 0
right = size - 1
while left < right:
mid = (left + right) >> 1
if nums[mid] < target:
left = mid + 1
else:
right = mid
if nums[left] == target:
return left
else:
return -1
def __find_last_position(self, nums, size, target):
left = 0
right = size - 1
while left < right:
mid = (left + right + 1) >> 1
if nums[mid] > target:
right = mid - 1
else:
left = mid
# 由于能走到这里,说明在数组中一定找得到目标元素
# 因此这里不用再做一次判断
return left