This article is based on Datewhale Phase 31 Team Learning
Binary Lookup Code:
class Solution: def search(self, nums: List[int], target: int) -> int: left = 0 right = len(nums) - 1 # Find target within interval [left, right] while left <= right: # Take Interval Middle Node mid = (left + right) // 2 # If the target value is found, return directly to the center location if nums[mid] == target: return mid # If nums[mid] is less than the target value, continue searching in [mid + 1, right] elif nums[mid] < target: left = mid + 1 # If nums[mid] is larger than the target value, continue searching in [left, mid-1] else: right = mid - 1 # No elements were searched, returning -1 return -1
1. About left <= right and left < right:
- If the statement is Left <= right, and the element found does not exist, then while The condition for judging a statement to be out of bounds is left == right + 1, written as an interval is [right + 1, right], the interval to be searched is empty, there are no elements in the interval to be searched, so terminating the loop can return directly - 1 Yes.
- If the judgement statement is left < right and the element found does not exist, while The condition for judging a statement to be out of bounds is left == right, written as an interval is [right, right]. In this case, the interval is not empty, there is still an element in the interval to be searched, and it is not certain that the element to be searched is not in this interval, then the loop terminates and returns - 1 Is wrong.
For example, intervals [2, 2], element 2 It belongs to this interval, terminates the cycle, returns - 1 That element is missing.
In the face of this situation, you can add a layer of judgment and judgment when returning. left Does the pointed position equal the target element, and if so returns left, return if not - 1
In addition, use left < right The other benefit of this is when you exit the loop left == right If so, you don't have to decide that you should go back left still Right Yes.
2. Two Ideas for Binary Search
-
Find directly
class Solution: def search(self, nums: List[int], target: int) -> int: left = 0 right = len(nums) - 1 # Find target within interval [left, right] while left <= right: # Take Interval Middle Node mid = left + (right - left) // 2 # If the target value is found, the direct range center location if nums[mid] == target: return mid # If nums[mid] is less than the target value, continue searching in [mid + 1, right] elif nums[mid] < target: left = mid + 1 # If nums[mid] is larger than the target value, continue searching in [left, mid-1] else: right = mid - 1 # No elements were searched, returning -1 return -1
-
Exclusion Method
Code 1:
class Solution: def search(self, nums: List[int], target: int) -> int: left = 0 right = len(nums) - 1 # Find target within interval [left, right] while left < right: # Take Interval Middle Node mid = left + (right - left) // 2 # nums[mid] is smaller than the target value, excluding the impossible interval [left, mid], and continue searching in [mid + 1, right] if nums[mid] < target: left = mid + 1 # nums[mid] is greater than or equal to the target value, the target element may continue searching in [left, mid] else: right = mid # Determines whether the remaining elements of an interval are the target elements, not returns -1 return left if nums[left] == target else -1
Code 2:
class Solution: def search(self, nums: List[int], target: int) -> int: left = 0 right = len(nums) - 1 # Find target within interval [left, right] while left < right: # Take Interval Middle Node mid = left + (right - left + 1) // 2 # nums[mid] is larger than the target value, excluding the impossible interval [mid, right], and continue searching in [left, mid-1] if nums[mid] > target: right = mid - 1 # nums[mid] is less than or equal to the target value, the target element may continue searching in [mid, right] else: left = mid # Determines whether the remaining elements of an interval are the target elements, not returns -1 return left if nums[left] == target else -1
- You can remember about boundary settings as follows:As long as you see left = mid Round up. That is:
- left = mid + 1 and right = mid and mid = left + (right - left) // 2 Must be paired.
- Right = mid-1 and left = mid and mid = left + (right - left + 1) // 2 Must be paired.
Title:
0704. Find
Given a n Ordered (ascending) integer array of elements nums and a target value Target , Write a function search nums If the target value has a return subscript, otherwise it returns -1.
Input: nums = [-1,0,3,5,9,12], target = 9
Output: 4
Interpretation: 9 appears in nums with subscript 4
class Solution: def search(self, nums: List[int], target: int) -> int: length = len(nums) l = 0 r = length - 1 while l <= r : mid = (l + r)//2 if nums[mid] == target: return mid elif nums[mid] < target: l = mid + 1 else : r = mid - 1 return -1
0035. Search insert location
Given a sorted 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, return the position where it will be inserted sequentially.
You must use an algorithm with O(log n) time complexity.
Input: nums = [1,3,5,6], target = 5
Output: 2
class Solution: def searchInsert(self, nums: List[int], target: int) -> int: length = len(nums) l = 0 r = length - 1 while l <= r: mind = (l + r)//2 if nums[mind] == target: return mind elif nums[mind] < target: l = mind + 1 else : r = mind - 1 return l
0374. Guess the number
The rules for guessing a number game are as follows:
For every game, I play from 1 reach n Randomly select a number. Please guess which number was selected.
If you make a mistake, I'll tell you if your guess is larger or smaller than the one I selected.
You can get a guess by calling a predefined interface, int guess(int num), and the return value has three possible scenarios (-1,1) Or 0:
-1: I chose a number smaller than what you guessed < num
1: I chose a number larger than your guess pick > num
0: I chose the same number as you guessed. Congratulations! Bingo! pick == num
Return the number I selected.
Input: n = 10, pick = 6
Output: 6
# The guess API is already defined for you. # @param num, your guess # @return -1 if my number is lower, 1 if my number is higher, otherwise return 0 # def guess(num: int) -> int: class Solution: def guessNumber(self, n: int) -> int: left, right = 1, n while left <= right: mid = (left + right) // 2 if not guess(mid): return mid elif guess(mid) == -1: right = mid - 1 else: left = mid + 1
0069. Sqrt(x)
Give you a non-negative integer x, calculate and return X The arithmetic square root of.
Since the return type is an integer, only the integer part of the result is retained, and the decimal part is discarded.
Note: No built-in exponential functions and operators, such as pow(x, 0.5) or x ** 0.5, are allowed.
Input: x = 4 Output: 2
class Solution: def mySqrt(self, x: int) -> int: l = 0 r = x while l <= r: mid = (l + r)//2 m = mid * mid n = (mid + 1) * (mid + 1) if m <= x: if n == x: return mid + 1 elif n > x: return mid else: l = mid + 1 else : r = mid - 1
0167.Sum of Two Numbers II - Transfer Ordered Array
Given a sorted in non-decreasing order Array of integers Number, please find out from the array that the sum of two numbers is equal to the target number Target.
The function should return the subscript values of these two numbers as an array of integers of length 2. Numbers'subscripts count from 1, so the answer array should satisfy 1 <= answer[0] < answer[1] <= numbers.length.
You can assume that each input corresponds to a unique answer, and that you cannot reuse the same elements.
Input: numbers = [2,7,11,15], target = 9
Output: [1,2]
Explanation: The sum of 2 and 7 equals the target number 9. So index1 = 1, index2 = 2.
class Solution: def twoSum(self, numbers: List[int], target: int) -> List[int]: l, r = 0, len(numbers) - 1 while l <= r: if numbers[l] + numbers[r] == target: return [l + 1, r + 1 ] elif numbers[l] + numbers[r] < target: l += 1 else: r -= 1
1011. Delivery of packages within D days
Parcels on conveyor belts must be transported from one port to another within D days.
I on conveyor belt The weight of each package is weights[i]. Every day, we load packages onto conveyor belts in the order of weight given. We will not carry more weight than the maximum carrying weight of the ship.
Returns the minimum carrying capacity of a ship capable of delivering all packages on a conveyor belt within D days.
Input: weights = [1,2,3,4,5,6,7,8,9,10], D = 5
Output: 15
Explanation:
Ships with a minimum load of 15 will be able to deliver all packages within five days, as follows:
Day 1: 1, 2, 3, 4, 5
Day 2: 6, 7
Day 3: 8
Day 4: 9
Day 5:10
Please note that the goods must be shipped in the given order, so it is not allowed to use a ship with a capacity of 14 and divide the package into (2, 3, 4, 5), (1, 6, 7), (8), (9), (10).
Author's Note: If this question was not written about my first reaction DP during the practice of binary search, it was later found that DP would time out,,,
class Solution: def shipWithinDays(self, weights: List[int], days: int) -> int: # If it weren't for the dichotomy search,,,,,,,, left = max(weights) right = sum(weights) # Transportation must be between max(weights) and sum(weights) while left <= right: mid = (left + right)//2 day, num = 1, 0 for i in weights: num += i if num > mid: num = i day += 1 if day > days: # Notice the boundary left = mid + 1 elif day <= days: # Can't guarantee equality is where minimum capacity is, so change to right right = mid - 1 return left
0278.The wrong version
You are the 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 was developed based on a previous version, all versions after the wrong version are incorrect.
Suppose you have n versions [1, 2,..., n], and you want to find the first version that caused all subsequent versions to fail.
You can call bool isBadVersion(version) The interface determines if the version number version is in error in the unit test. Implement a function to find the first wrong version. You should minimize the number of calls to the API.
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.
# The isBadVersion API is already defined for you. # @param version, an integer # @return an integer # def isBadVersion(version): class Solution: def firstBadVersion(self, n): """ :type n: int :rtype: int """ l, r = 1, n while l <= r: mid = (l + r)//2 if isBadVersion(mid): r = mid - 1 else: l = mid + 1 return l
0033. Search for Rotated Sort Array
The integer array nums is arranged in ascending order, and the values in the array are different from each other.
Nums rotates an array to [nums[k], nums[k+1],..., nums[n-1], nums[0], nums[1],..., nums[1],..., nums[k-1] (subscripts count from 0) before passing it to the function. For example, [0,1,2,4,5,6,7] may become rotated at subscript 3 [4,5,6,7,0,1,2].
Give you a rotated array of nums and an integer target, if the target value exists in nums, return its subscript, otherwise return - 1 .
Input:nums = [4,5,6,7,0,1,2], target = 0 Output:4
class Solution: def search(self, nums: List[int], target: int) -> int: l, r = 0, len(nums) - 1 while l <= r: mid = (l + r)//2 if nums[mid] == target: return mid # Divided into ordered and disordered elif nums[mid] < nums[r]: # mid Right Ordered if nums[mid] < target and nums[r] >= target: # Goals in order l = mid + 1 else: r = mid - 1 else: # mid Left Ordered if nums[mid] > target and nums[l] <= target: # Goals in order r = mid - 1 else: l = mid + 1 return -1
0153. Find the most value in a rotated sort array
An array with a known length of n is pre-sorted in ascending order and rotated 1 to N times to obtain an input array. For example, the original array nums = [0,1,2,4,5,6,7] may get after changing:
If you rotate it four times, you get [4,5,6,7,0,1,2]
If you rotate it seven times, you get [0,1,2,4,5,6,7]
Notice that the result of one rotation of the array [a[0], a[1], a[2],..., a[n-1]] is the array [a[n-1], a[0], a[1], a[2],..., a[n-2].
You are given an array of nums elements with different values, which was originally an ascending array and rotated several times as described above. Please find and return the smallest element in the array.
Input: nums = [3,4,5,1,2] Output: 1 Explanation: The original array is [1,2,3,4,5], rotate three times to get the input array.
class Solution: def findMin(self, nums: List[int]) -> int: l, r = 0, len(nums) - 1 while l < r: mid = (l + r)//2 if nums[mid] <= nums[r]: r = mid # Minimum on the left side of mid or mid itself else: l = mid + 1 # Minimum must be on the right side of mid return nums[l]
Reference Links LeetCode for Algorithms | LeetCode for Algorithms