Given an ordered (ascending) integer array nums
of n
elements and a target value target
, write a function to search for nums
in target
and return the subscript if the target value exists, and -1
otherwise.
Example 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
Example 2:
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
Problem solving ideas
The basic framework of binary search is as follows:
int binarySolution(int[] nums, int target) {
int left = 0, right = ...;
while (...) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
...
} else if (nums[mid] < target) {
left = ...;
} else if (nums[mid] > target) {
right = ...;
}
}
return ...;
}
A technique for analyzing binary search is: do not appear else, but write all cases with else if, so that all details can be clearly displayed.
The part marked by ...
is the place where details may occur. When you see a binary search code, pay attention to these places first.
In addition, it is necessary to prevent overflow when calculating mid
. The result of left + (right - left) / 2
in the code is the same as that of 0622438daf1ef6, but it effectively prevents left
and (left + right) / 2
from right
too large to directly add to cause overflow.
The solution to this question is as follows:
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1; // 注意
// 注意
while (left <= right) {
int mid = left + (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;
}
}
Here are a few of those details.
1. Why is the condition of the while loop <= instead of <?
Answer: Because the assignment to initialize right
is nums.length - 1
, the index of the last element, not nums.length
.
Because we need to search for all elements, using <=
to search is the interval [left, right]
that is closed at both ends. If we use <
, it is equivalent to the interval [left, right)
, which is closed on the left and open on the right.
If<
is used, and then the initial assignment ofright
is changed tonums.length
, the search in the range of[left, right]
can also be realized, but the last element will be missed.
Also note the conditions for ending the search. Can terminate when the target value is found: nums[mid] == target
. If it is not found, it needs while
to terminate the loop and then return to -1
. When should the while loop terminate? should terminate when the search range is empty.
The termination condition of while(left <= right)
is left == right + 1
, and the form written as an interval is [right + 1, right]
, or a specific number into [3, 2]
.
The termination condition of while(left < right)
is left == right
, and the form written as an interval is [right, right]
, or a specific number is entered into [2, 2]
. At this time, the interval is not empty, and there is a number 2
, but at this time, the loop of while
is terminated. That is to say, the interval [2, 2]
was missed, and the index 2
was not searched. It would be wrong to return -1
directly at this time.
It is also possible to use while(left < right)
. We already know the cause of the error, so we can patch it:
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length;
while (left < right) {
int mid = left + (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 nums[left] == target ? left : -1;
}
}
2. Why left = mid + 1
, right = mid - 1
? I see some codes are right = mid
or left = mid
The concept of "search interval" has just been clarified, and the search interval of this algorithm is closed at both ends, that is, [left, right]
. So when we find that the index mid
is not the target
we are looking for, where should we search next?
Of course, it is to search for [left, mid-1]
or [mid+1, right]
, right? should be removed from the search range because mid
has already been searched.
3. What's wrong with this algorithm?
For example, if you are given an ordered array nums = [1,2,2,2,3]
and target
is 2
, the index returned by this algorithm is 2
, that's right. But if I want to get the left edge of target
, which is index 1
, or I want to get the right edge of target
, which is index 3
, then this algorithm can't handle it.
Such requirements are very common, You might say, find a target
, and then linearly search left or right? Yes, but not good, because it is difficult to guarantee the logarithmic complexity of binary search.
Summarize
- Don't use
else
, write all cases clearly withelse if
- When calculating
mid
, it is necessary to prevent overflow. Useleft + (right - left) / 2
to subtract first and then add it. while
loop condition<=
corresponds toright
, the initial value isnums.length - 1
, and the termination condition isleft == right + 1
, such as[3, 2]
- If the condition of the
while
loop is<
, the initial value ofright
needs to be changed tonums.length
, and the termination condition isleft == right
, such as[2, 2]
, which will miss the elements of the last interval, which needs to be judged separately. - When
mid
is not thetarget
you are looking for, the next step should be to search for[left, mid-1]
or[mid+1, right]
, corresponding toleft = mid + 1
orright = mid - 1
- Binary search time complexity
O(logn)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。