Binary Method 二分法
- 2021.12.24
- Algorithm Binary Method / Divide and Conquer
分治法 Divide and Conquer
總是能夠將「問題 X 」拆分為「問題 A 」和「問題 B 」
滿足「問題 A 」+「問題 B 」=「問題 X 」
且能確定「問題 X 」的解只存在於「問題 A 」或「問題 B 」兩者其中之一
如果「問題 X 」的 brute force 解法之 time complexity 為 O(n)
則使用 binary method 的時間複雜度將減少為 O(log(n))
注意要小心演算法是否每個範圍內的數都會被遍歷!
Template
Strictly Increasing
Pattern: while left <= right
left, right = bound_left, bound_right while left <= right: mid = (left + right) // 2 num = array[mid] if is_satisfied(num, target) == "not enough" / you need to adjust left: left = mid + 1 elif is_satisfied(num, target) == "too many" / you need to adjust right: right = mid - 1 else: return mid return None
Pattern: while left < right ≡ Duplicate Elements, Left-Most Insertion Point
left, right = bound_left, bound_right while left < right: # Leave when left == right mid = (left + right) // 2 num = array[mid] if is_satisfied(num, target) == "not enough" / you need to adjust left: left = mid + 1 elif is_satisfied(num, target) == "too many" / you need to adjust right: right = mid return left # left == middle == right
Duplicate Elements
The point is the position where or is_satisfied(mid, target) == "satisfied"
is.
Left-Most Insertion Point
回傳的i
s.t. is_satisfied(i - 1, target) == "not enough"
and (is_satisfied(i, target) == "too many"
or is_satisfied(i - 1, target) == "satisfied")
left, right = bound_left, bound_right + 1 while left < right: mid = (left + right) // 2 num = array[mid] if is_satisfied(num, target) == "not enough": left = mid + 1 elif is_satisfied(num, target) == "too many" or is_satisfied(mid, target) == "satisfied": right = mid return left
Right-Most Insertion Point
回傳的i
s.t. (is_satisfied(i - 1, target) == "not enough"
or is_satisfied(i - 1, target) == "satisfied")
and is_satisfied(i, target) == "too many"
left, right = bound_left, bound_right + 1 while left < right: mid = (left + right) // 2 num = array[mid] if is_satisfied(num, target) == "not enough" or is_satisfied(mid, target) == "satisfied": left = mid + 1 elif is_satisfied(num, target) == "too many": right = mid return left
Binary Search
Python 可以使用 bisect
def find_i(nums, num, left=0, right=-1): right = (right + len(nums)) % len(nums) while left < right: mid = (left + right) // 2 if nums[mid] < num: left = mid + 1 else: right = mid return left
非整數形式的二分法
範例
Solution
def root(x,n): l, r = 0, x while r - l > 0.001: rt = float(l + r) / 2 rt_to_the_nth_power = rt ** n if rt_to_the_nth_power > x: r = rt elif rt_to_the_nth_power < x: l = rt else: return rt return round(rt, 3)
經典例題
Leetcode # 704. Binary Search 
- 注意迴圈停止的條件
當 nums 內只有一元素時
若 while 的條件為 while left < right:
會導致不進入迴圈直接回傳 -1 結束 - 注意更新左右邊界的方式
如上所述,當 left 為 right – 1 時,cur 會等於 left
此時若 target 大於 nums[cur] 且左邊界的更新條件為 left = cur
會造成 left 永遠等於 cur 無法更新,導致無窮迴圈
class Solution: def search(self, nums: List[int], target: int) -> int: left, right = 0, len(nums) - 1 while left <= right: cur = (left + right) // 2 if nums[cur] == target: return cur if target > nums[cur] : left = cur + 1 else: right = cur - 1 return -1
Mountain Array
Leetcode # 852. Peak Index in a Mountain Array
Leetcode # 1095. Find in Mountain Array
相關例題
- Leetcode # 35. Search Insert Position
- Leetcode # 74. Search a 2D Matrix
- Leetcode # 81. Search in Rotated Sorted Array II
- Leetcode # 209. Minimum Size Subarray Sum
- Leetcode # 215. Kth Largest Element in an Array
- Leetcode # 278. First Bad Version
- Leetcode # 852. Peak Index in a Mountain Array
- Leetcode # 1095. Find in Mountain Array
- Leetcode # 1940. Longest Common Subsequence Between Sorted Arrays
- Leetcode # 2616. Minimize the Maximum Difference of Pairs
- Leetcode # 2861. Maximum Number of Alloys
Last Updated on 2024/06/09 by A1go