1. Topic
Given an integer array nums arranged in ascending order, and a target value target. Find the start and end positions of the given target value in the array.
If the target value target does not exist in the array, return [-1, -1].
Advanced:
- Can you design and implement an O(log n) algorithm to solve this problem?
Example 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
Example 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
Example 3:
输入:nums = [], target = 0
输出:[-1,-1]
prompt:
- 0 <= nums.length <= 105
- -109 <= nums[i] <= 109
- nums is a non-decreasing array
- -109 <= target <= 109
Two, solve
1. Binary search method
Idea:
Sort nums
all the numbers in the array to target
form a window, remember that the left/right boundary indexes of the window are respectively left
and right
, respectively corresponding to the first element on the left/right of the window.
The number of target
occurrences of a number can be transformed into: the dichotomy method finds the left boundary left
and the boundary respectively right
, and the number target
of easy-to-obtain numbers is right-left-1
.
Algorithm analysis:
- Initialization : left boundary
i = 0
, with boundaryj = len(nums)-1
. - Cycle dichotomy :
[i, j]
Jump out when there is no element in the closed interval :
2.1. Calculate the midpointm = (i+j)/2
(rounded down)
2.2. Ifnums[m]<target
, then the target is in the closed interval[m+1, j]
, so executei = m+1
;
2.3. Ifnums[m]>target
, then the target is in the closed interval[i, m-1]
, so executej = m-1
;
2.4. Ifnums[m]=target
, then the right boundary is in the interval[m+1, j]
; the left boundary is in the closed interval[i, m-1]
. Therefore, it is divided into the following two cases:
[1]. If you find the right boundary right, then executei = m+1
; (when jumping out, i points to the right boundary)
[2]. If you find the left boundary left, then executej = m-1
; (when jumping out j points to the left boundary) - Return value . Apply the dichotomy twice, find the
right
sum respectivelyleft
, and return it finallyright-left-1
.
Code-Version 1:
class Solution {
public int search(int[] nums, int target) {
// 搜索右边界 right
int i = 0, j = nums.length - 1;
while(i <= j) {
int m = (i + j) / 2;
if(nums[m] <= target) i = m + 1;
else j = m - 1;
}
int right = i;
// 若数组中无 target ,则提前返回
if(j >= 0 && nums[j] != target) return 0;
// 搜索左边界 right
i = 0; j = nums.length - 1;
while(i <= j) {
int m = (i + j) / 2;
if(nums[m] < target) i = m + 1;
else j = m - 1;
}
int left = j;
return right - left - 1;
}
}
Time complexity: O (logn) O(logn)O ( l o g n )
space complexity: O (1) O(1)O ( 1 )
The above code is less readable and can be optimized to the following version:
Code-Version 2:
class Solution {
public int search(int[] nums, int target) {
return helper1(nums, target) - helper2(nums, target) - 1;
}
public int helper1(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] <= target) left = mid + 1;
else right = mid - 1;
}
return left;
}
public int helper2(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] < target) left = mid + 1;
else right = mid - 1;
}
return right;
}
}
The above code is quite redundant and can be further optimized:
Code-Version 3:
class Solution {
public int search(int[] nums, int target) {
return helper(nums, target) - helper(nums, target - 1);
}
int helper(int[] nums, int tar) {
int i = 0, j = nums.length - 1;
while(i <= j) {
int m = (i + j) / 2;
if(nums[m] <= tar) i = m + 1;
else j = m - 1;
}
return i;
}
}
Time complexity: O (n) O(n)O ( n )
space complexity: O (n) O(n)O ( n )
Three, reference
1. Interview Question 53-I. Find the number I in a sorted array (Dichotomy, clear illustration)