Binary search
Binary search is usually applied to an ordered array. It is an algorithm that divides the search space into two after each comparison.
Terms used in binary search:
Target: target. The value you want to find
Index: index. The current location you want to find
Left, Right: left and Right indicators (which can be understood as the subscripts corresponding to the left and Right endpoints of a closed interval). We use them to maintain the index of search space
Mid: middle indicator (the index of the middle position calculated according to the index of the left and right endpoints). We use conditions to determine whether we should look left or right.
Question 1: basic questions (template)
Given an n-element ordered (ascending) integer array nums and a target value target, write a function to search the target in nums. If the target value exists, return the subscript, otherwise return - 1.
Example:
Input: num = [- 1,0,3,5,9,12], target = 9
Output: 4
Explanation: 9 appears in nums and the subscript is 4
Tips:
You can assume that all elements in nums are not repeated.
n will be between [1, 10000].
Each element of num will be between [- 9999, 9999].
Source: LeetCode
Link: https://leetcode-cn.com/problems/binary-search
(the following code has detailed comments)
java
public class BinarySearch704 { //Define nums array, and target value public int search(int[] nums, int target) { int left = 0;//Leftmost subscript int right = nums.length-1;//Subscript of rightmost number //Remember to bring an equal sign when judging the while condition while(left<=right) { //Find the middle position and judge whether the value corresponding to this position is equal to target int mid = left +(right - left)/2; if(nums[mid] == target) { return mid; } //If the target value is less than the middle position value, use this part to dichotomy again //It's easy to get confused about adding 1 minus 1. Remember that the subscript of the array starts from 0. If you can't, draw a picture else if(nums[mid] > target) { right = mid-1; } else { left = mid+1; } } return -1; } }
python
# Method one dichotomy, which is basically the same as java) class Solution: def search(self, nums: List[int], target: int): left, right = 0, len(nums) - 1 #left is 0 and right is len (nums) - 1 while left <= right: mid = left + (right - left) // 2 if nums[mid] == target: return mid if target < nums[mid]: right = mid - 1 else: left = midt + 1 return -1 # Method 2 (not dichotomy, less code, but slow operation) from typing import List class Solution: def search(self, nums: List[int], target: int): #Traversal, compare the number in target and num one by one if target in nums : return nums.index(target) # The Python index() method detects whether the string contains a substring str. if beg (start) and # End (end) range, check whether it is included in the specified range. This method is the same as python find() method, # But if str is not in the string, an exception will be reported. else: return -1
C
#include <stdio.h> int search(int* nums, int numsSize, int target){ { int first = 0,last = numsSize-1,mid; while(first <= last) { mid = first + (last - first) / 2;//Identify intermediate elements if(nums[mid] > target) { last = mid-1; //mid has been swapped. last moves forward one bit } else if(nums[mid] < target) { first = mid+1;//mid has been exchanged. first moves back one bit } else //Judge whether they are equal { return mid; } } return -1; }
The above code is basically the most basic template for binary search.
Difficulties of dichotomy
At present, dichotomy is not difficult at all, but its details are extremely error prone.
Does the while loop have an equal sign
right and left are plus one and minus one
These details vary with the meaning of the topic
Question 2 (the question is a little windy)
You are a product manager and are currently leading a team to develop new products. Unfortunately, the latest version of your product has not passed the quality test. Since each version is developed based on the previous version, all versions after the wrong version are wrong.
Suppose you have n versions [1, 2,..., n], you want to find the first wrong version that causes errors in all subsequent versions.
You can call the bool isBadVersion(version) interface to determine whether the version number is wrong in the unit test. Implement a function to find the first wrong version. You should minimize the number of calls to the API.
Example:
Input: n = 5, bad = 4
Output: 4
Explanation:
Call isbadversion (3) - > false
Call isbadversion (5) - > true
Call isbadversion (4) - > true
So, 4 is the first wrong version.
Tips:
1 <= bad <= n <= 231 - 1
Source: LeetCode
Link: https://leetcode-cn.com/problems/first-bad-version
Analyze the meaning of the topic
In fact, it is also a search problem in an ordered array. And we need to "minimize the number of calls to the API", so we still use the dichotomy.
Then look at the example. isBadVersion is used to judge whether the version is a bad version. Therefore, if the result is false, the version is a good version.
java
public class FirstWrongVersion278 { public int firstBadVersion(int n) { // If you want to understand the questions, you should still take the dichotomy test // It is not an array. You can use subscripts from the beginning, which is more in line with language habits int left = 1; int right = n; // Stop the loop when the two are equal, so the while condition does not add an equal sign this time while(left < right) { int mid = left + (right-left)/2; if(isBadVersion(mid)) { // Because this mid is likely to be the first wrong, don't subtract one and let it be included in the interval again right = mid;// The answer is in the interval [left, mid] }else { //At this time, this version is correct and needs to be looked for later //This version does not need to be included in the interval left = mid + 1; } } return right; } }
python
class Solution: def firstBadVersion(self, n): """ :type n: int :rtype: int """ left = 0 right = n while(left<right): mid = left + (right - left)//2 if isBadVersion(mid): right = mid else: left = mid+1 return right
C
int firstBadVersion(int n) { int left = 1, right = n; while (left < right) { // Cycle until the left and right end points of the interval are the same int mid = left + (right - left) / 2; // Prevent overflow during calculation if (isBadVersion(mid)) { right = mid; // The answer is in the interval [left, mid] } else { left = mid + 1; // The answer is in the interval [mid+1, right] } } // At this time, there is left == right, and the interval is reduced to a point, which is the answer return left; }
Question 3 (still very simple)
Given a sort array and a target value, find the target value in the array and return its index. If the target value does not exist in the array, returns the position where it will be inserted in order.
You must use an algorithm with a time complexity of O(log n).
Example:
Input: num = [1,3,5,6], target = 7
Output: 4
Input: num = [1,3,5,6], target = 0
Output: 0
Input: num = [1], target = 0
Output: 0
Tips:
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums is an ascending array without repeating elements
-104 <= target <= 104
Source: LeetCode
Link: https://leetcode-cn.com/problems/search-insert-position
java
public class SearchInsertionLocation35 { public int searchInsert(int[] nums, int target) { //You can still use dichotomy 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 { right = mid - 1; } } return left; } }
python
class Solution: def searchInsert(self, nums: List[int], target: int) -> int: left = 0 right =len(nums)-1 while(left <= right): mid = left + (right - left)//2 if(nums[mid] == target ): return mid elif(nums[mid] < target): left = mid + 1 else: right = mid - 1 return left
C
int searchInsert(int* nums, int numsSize, int target){ int left = 0, right = numsSize - 1, ans = numsSize; while (left <= right) { int mid = ((right - left) >> 1) + left; //Mid = (left + right) > > 1 //Shift right operator > >, the operation result can exactly correspond to the half value of an integer, which can just replace the mathematical Division 2 operation, //But it's faster than dividing by two. //Mid = (left + right) > > 1 is equivalent to mid=(left+right)/2 if (target <= nums[mid]) { ans = mid; right = mid - 1; } else { left = mid + 1; } } return ans; }