Writing in the front
- The article is summarized on the basis of predecessors plus their own understanding, only as their own learning record, not for any commercial use!
- If you find any mistakes or infringement problems in this article, please point them out. Thank you!
The basic framework
public int binarySearch(int[] array, int target) {
int left = 0;
intright = ... ;while(...). {int mid = left + (right - left) / 2;
if(nums[mid] == target) ... ;else if(nums[mid] < target) ... ;else if(nums[mid] > target) ... ; }return. ; }Copy the code
- instructions
- When you’re doing binary search, you don’t want an else, but you want to write everything out as an else if, so you can see all the details clearly
- In the code above
.
And the labeled part, that’s where the details might be different, that’s where the dichotomous type of problem might be different
Find a number
- Searches an array for a number, returning the index if it exists, or -1 if it does not
public int binarySearch(int[] array, int target) {
int left = 0;
int right = array.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (array[mid] == target) {
return mid;
} else if (array[mid] < target) {
left = mid + 1;
} else if (array[mid] > target) {
right = mid - 1; }}return - 1;
}
Copy the code
-
Q1: Why
while
The conditions for the cycle are< =
Rather than<
?- First point: it can be seen that right = array. length-1, then it indicates that the value of right can be selected, that is, the interval of binary search is [left, right], so left can be equal to right
- The second point is to know when to exit the loop
- Find the target value, which is passed
array[mid] == target
Conditions directlyreturn mid
- If no target value is found, it must pass
left > right
To exit the loop, i.eleft = right + 1
There is no such interval as [right + 1, right]return -1
- Find the target value, which is passed
- Finally, third point: in
right = array.length - 1
If no change is required, change towhile (left < right)
How do I get the right answer?- At this time
while
The conditions for exiting the loop are: one is to find target, directlyreturn mid
, the other is not found target, passleft = right
Exit the loop - [left, left] [left] [left] [left] [left, so put a patch on the return:
return array[left] == target ? left : -1
- The complete code is morphing code 1
- At this time
-
Q2: Why?
left = mid + 1
.right = mid - 1
?- You can see that
while
There are three if judgments in the loop, which obviously divide the array into three intervals: less than, equal to, and greater than, so when we find the indexmid
Not to findtarget
Where should you search next? - Search, of course
[left, mid - 1]
or[mid + 1, right]
Because themid
It’s been searched. We need to rule it out - Like the
right = mid
orleft = mid
Is the way to divide an array into two intervals
- You can see that
-
Q3: How do I change the code if right = array.length and while (left < right)?
- How can we get the right result when the conditions of the right and while loops are modified, with the emphasis on exiting the loop analysis
- Under this condition, there are two cases of derivation cycle:
- Find the target value, which is passed
array[mid] == target
Conditions directlyreturn mid
- If no target value is found, it must pass
left = right
To exit the loop, note the case of exit loop analysis:- At this time
left = right
The “search interval” when exiting the loop is[left, left)
Is not to judgearray[left]
Is equal to Target, so you need to add a judgment - At this time
left = right
It is possible to equal array.length, so we need to determine if the array is out of bounds
- At this time
- Find the target value, which is passed
- The complete code is in transformation of Code 2
-
Q3: What are the flaws of this algorithm?
- Let’s say I give you an ordered array
,2,2,2,3 nums = [1]
, target is 2, the index returned by this algorithm is 2, yes - But if I want the left edge of target, which is index 1, or I want the right edge of target, which is index 3, then this algorithm can’t handle it
- This is very common in real development, so how to modify the above algorithm to get the left or right edge? See below
- Let’s say I give you an ordered array
-
Deformation code 1
public int binarySearch(int[] array, 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; // Notice that something has changed here, too}}return nums[left] == target ? left : -1;
}
Copy the code
- Deformation Code 2
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; // 后面会讲为什么是 mid 而不是 mid - 1}}if(left == nums.length || nums[left] ! = target)return -1;
return left;
}
Copy the code
Find the left boundary
- Search for a number in an array with duplicate numbers, returning the leftmost subscript if it exists, and -1 if it does not
public int leftBound(int[] nums, int target) {
int left = 0;
int right = nums.length; // Note the comparison with the next version
while(left < right) { // Note the comparison with the next version
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
right = mid; // Note the comparison with the next version
}
else if (nums[mid] < target) {
left = mid + 1;
}
else if (nums[mid] > target) {
right = mid; // Note the comparison with the next version}}if(left == nums.length || nums[left] ! = target)return -1;
return left;
}
Copy the code
-
Q1: Why is it written here
right = nums.length
So that the search interval becomes left closed and right open?- This is common for binary searches that search the left and right edges
- It’s also provided later
right = nums.length - 1
, and use this way, need to pay attention to the changes
-
Q2: Why is it in while
<
Rather than< =
?- because
right = nums.length
Rather thannums.length - 1
. So the search interval for each cycle is[left, right)
Left closed right open form - In this case, it is through
left = right
To exit the loop, note the case of exit loop analysis:- At this time
left = right
There is no judgment when exiting the looparray[left]
Is equal to Target, so you need to determine - At this time
left = right
It is possible to equal array.length, so we need to determine if the array is out of bounds
- At this time
- because
-
Q4: Why
left = mid + 1
.right = mid
? It’s different from the previous algorithm, right?- Because our search interval is
[left, right)
Left closed right open, so whennums[mid]
After being detected, the next search interval should be divided into two intervals without mid, namely[left, mid)
或[mid + 1, right)
- Because our search interval is
-
Q3: Why can this algorithm search the left edge?
- The point is that
nums[mid] == target
Handling of this situation:if (nums[mid] == target) right = mid;
- Instead of immediately returning to target, narrow the upper bound of the “search range” right, in the range
[left, mid)
Continue to search, that is, constantly left shrinkage, to achieve the purpose of locking the left boundary
- The point is that
-
Q5: Can you make it
right = nums.length - 1
That is, to continue to use the “search interval” with both sides closed?- If you want to make
right = nums.length - 1
, then we need to change the while statement to:while (left <= right)
- The logic for updating left and right needs to be modified
if (nums[mid] == target) { right = mid - 1; // Shrink the right edge } else if (nums[mid] < target) { left = mid + 1; // Search interval changed to [mid+1, right] } else if (nums[mid] > target) { right = mid - 1; // Search interval changed to [left, mid-1] } Copy the code
- In this case, it is through
left = right + 1
To exit the loop, note the case of exit loop analysis:- At this time
left = right + 1
Exit the loop without judgingarray[left]
Is equal to Target, so you need to determine - when
target
比nums
Will exist if all elements inleft = right + 1 = nums.length
Makes the index out of bounds, so you need to add a judgment at the end
- At this time
- The complete code is morphing code 1
- If you want to make
-
Deformation code 1
public int leftBound(int[] nums, int target) {
int left = 0;
int right = nums.length - 1; // Note the comparison with the previous version
while(left <= right) { // Note the comparison with the previous version
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
right = mid - 1; // Note the comparison with the previous version
}
else if (nums[mid] < target) {
left = mid + 1;
}
else if (nums[mid] > target) {
right = mid - 1; // Note the comparison with the previous version}}if(left == nums.length || nums[left] ! = target)return -1;
return left;
}
Copy the code
Look for the right boundary
- Search for a number in an array with duplicate numbers, returning the right-most subscript if it exists, or -1 if it does not
public int rightBound(int[] nums, int target) {
int left = 0;
int right = nums.length; // Note the comparison with the next version
while(left < right) { // Note the comparison with the next version
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return left = mid + 1; // Note the comparison with the next version
}
else if (nums[mid] < target) {
left = mid + 1; // Note the comparison with the next version
}
else if (nums[mid] > target) {
right = mid // Note the comparison with the next version}}if (left == 0 || nums[left - 1] != target ) return -1;
return left - 1; // The return value is -1
}
Copy the code
-
Q1: Why is it written here
right = nums.length
So that the search interval becomes left closed and right open?- I’ve solved it up here
-
Q2: Why is it in while
<
Rather than< =
?- I’ve solved it up here
-
Q3: Why can this algorithm search the right edge?
- The point is that
nums[mid] == target
Processing:if (nums[mid] == target) left = mid + 1;
- when
nums[mid] == target
Do not return immediately, but increase the lower bound left of the “search interval”, so that the interval continuously shrinks to the right, to achieve the purpose of locking the right boundary
- The point is that
-
Q4: Why is it finally returned
left - 1
Unlike the function on the left margin, returnsleft
? And I think since we’re searching the right-hand side, we should go backright
to- First of all, one of the conditions for exiting the loop is
left == right
, then returnright - 1
And returnleft - 1
Is the same - Again, why return
left - 1
Rather thanleft
?- Again, the key point is
if (nums[mid] == target) return left = mid + 1;
Because when it’s equalleft
I added 1 first, so when I returnmid
When I subscript theta,left
Of course, we need to subtract 1 and return:mid = left - 1
- Again, the key point is
- First of all, one of the conditions for exiting the loop is
-
Q5: Can you make it
right = nums.length - 1
That is, to continue to use the “search interval” with both sides closed?- If you want to make
right = nums.length - 1
, then we need to change the while statement to:while (left <= right)
- The logic for updating left and right needs to be modified
if (nums[mid] == target) { left = mid + 1; // Shrink the left edge } else if (nums[mid] < target) { left = mid + 1; // Search interval changed to [mid + 1, right] } else if (nums[mid] > target) { right = mid - 1; // Search interval changed to [left, mid-1] } Copy the code
- In this case, it is through
left = right + 1
To exit the loop, note the case of exit loop analysis:- At this time
left = right + 1
Exit the loop without judgingarray[right]
Is equal to Target, so you need to determine - when
target
比nums
When all the elements are small, it will existright = left - 1 = -1
Makes the index out of bounds, so you need to add a judgment at the end
- At this time
- The complete code is morphing code 1
- If you want to make
-
Deformation code 1
public int rightBound2(int[] nums, int target) {
int left = 0;
int right = nums.length - 1; // Note the comparison with the previous version
while(left <= right) { // Note the comparison with the previous version
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
left = mid + 1;
}
else if (nums[mid] < target) {
left = mid + 1;
}
else if (nums[mid] > target) {
right = mid - 1; // Note the comparison with the previous version}}if (right < 0|| nums[right] ! = target )return -1;
return right; // Note the comparison with the previous version
}
Copy the code
Summary (Logical unity)
Find a number I
If initialize: right = nums.length thenwhileThe conditions of the cycle are:while(left < right) then left and right update logic is:if (nums[mid] == target) return mid;
else if (nums[mid] < target) left = mid + 1;
else if(nums[mid] > target) right = mid; Finally, you need to judge before returning:if(left == nums.length || nums[left] ! = target)return -1;
return left;
Copy the code
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; // 后面会讲为什么是 mid 而不是 mid - 1}}if(left == nums.length || nums[left] ! = target)return -1;
return left;
}
Copy the code
Find the left boundary ⅰ
If initialize: right = nums.length thenwhileThe conditions of the cycle are:while(left < right) then left and right update logic is:if (nums[mid] == target) right = mid;
else if (nums[mid] < target) left = mid + 1;
else if(nums[mid] > target) right = mid; Finally, we need to judge and return:if(left == nums.length || nums[left] ! = target)return -1;
return left;
Copy the code
public int leftBound(int[] nums, int target) {
int left = 0;
int right = nums.length; // Note the comparison with the next version
while(left < right) { // Note the comparison with the next version
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
right = mid; // Note the comparison with the next version
}
else if (nums[mid] < target) {
left = mid + 1;
}
else if (nums[mid] > target) {
right = mid; // Note the comparison with the next version}}if(left == nums.length || nums[left] ! = target)return -1;
return left;
}
Copy the code
Finding the right boundary ⅰ
If initialize: right = nums.length thenwhileThe conditions of the cycle are:while(left < right) then left and right update logic is:if (nums[mid] == target) left = mid + 1;
else if (nums[mid] < target) left = mid + 1;
else if(nums[mid] > target) right = mid; Finally, we need to judge and return:if (left == 0 || nums[left - 1] != target) return -1;
return left - 1;
Copy the code
public int rightBound(int[] nums, int target) {
int left = 0;
int right = nums.length; // Note the comparison with the next version
while(left < right) { // Note the comparison with the next version
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return left = mid + 1; // Note the comparison with the next version
}
else if (nums[mid] < target) {
left = mid + 1; // Note the comparison with the next version
}
else if (nums[mid] > target) {
right = mid // Note the comparison with the next version}}if (left == 0 || nums[left - 1] != target ) return -1;
return left - 1; // The return value is -1
}
Copy the code
Find a number ⅱ
If initialized: right = nums.length -1thenwhileThe conditions of the cycle are:while(left <= right)if (nums[mid] == target) return mid;
else if (nums[mid] < target) left = mid + 1;
else if (nums[mid] > target) right = mid - 1; Finally, we can return directly:return -1;
Copy the code
public int binarySearch(int[] array, int target) {
int left = 0;
int right = array.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (array[mid] == target) {
return mid;
} else if (array[mid] < target) {
left = mid + 1;
} else if (array[mid] > target) {
right = mid - 1; }}return - 1;
}
Copy the code
Find the left boundary ⅱ
If initialized: right = nums.length -1thenwhileThe conditions of the cycle are:while(left <= right)if (nums[mid] == target) right = mid - 1;
else if (nums[mid] < target) left = mid + 1;
else if (nums[mid] > target) right = mid - 1; Finally, we need to judge and return:if(left == nums.length || nums[left] ! = target)return -1;
return left;
Copy the code
public int leftBound(int[] nums, int target) {
int left = 0;
int right = nums.length - 1; // Note the comparison with the previous version
while(left <= right) { // Note the comparison with the previous version
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
right = mid - 1; // Note the comparison with the previous version
}
else if (nums[mid] < target) {
left = mid + 1;
}
else if (nums[mid] > target) {
right = mid - 1; // Note the comparison with the previous version}}if(left == nums.length || nums[left] ! = target)return -1;
return left;
}
Copy the code
Find the right boundary ⅱ
If initialized: right = nums.length -1thenwhileThe conditions of the cycle are:while(left <= right)if (nums[mid] == target) left = mid + 1;
else if (nums[mid] < target) left = mid + 1;
else if (nums[mid] > target) right = mid - 1; Finally, we need to judge and return:if (right < 0|| nums[right] ! = target)return -1;
return right;
Copy the code
public int rightBound2(int[] nums, int target) {
int left = 0;
int right = nums.length - 1; // Note the comparison with the previous version
while(left <= right) { // Note the comparison with the previous version
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
left = mid + 1;
}
else if (nums[mid] < target) {
left = mid + 1;
}
else if (nums[mid] > target) {
right = mid - 1; // Note the comparison with the previous version}}if (right < 0|| nums[right] ! = target )return -1;
return right; // Note the comparison with the previous version
}
Copy the code
LeetCode related questions
- Binary search
- 35. Search for insertion locations
- 34. Find the first and last positions of elements in a sorted array
Reference and thanks
- Dichotomous search details, incidentally compose a poem