二元搜尋 - a920604a/leetcode GitHub Wiki
- Binary Search
categories:
- CS
- Algorithm
comments: false
title: Binary Search
tags:觀念
O(logN),想法簡單,細節是魔鬼。溢位、mid是加一減一、while()用<= 還是<。
注意搜尋區間和while終止條件
搜尋左右邊界,只要修改nums[mid] ==target
條件處
題目
- 34 Find First and Last Position of Element in Sorted Array (Medium)
- 35 Search Insert Position (Easy)
- 209 Minimum Size Subarray Sum
- *354 Russian Doll Envelopes (Hard)
- 392 Is Subsequence (Easy)
- 658 Find K Closest Elements
- 704 Binary Search (Easy)
- 793 Preimage Size of Factorial Zeroes Function (Hard)
- 875 Koko Eating Bananas (Medium)
- 2594 Minimum Time to Repair Cars (Medium)
- 1011 Capacity To Ship Packages Within D Days (Medium)
- 1870 Minimum Speed to Arrive on Time
- 1898 Maximum Number of Removable Characters
- 2226 Maximum Candies Allocated to K Children
- 410 Split Array Largest Sum (Hard)
補充
- *4 Median of Two Sorted Arrays
- 33 Search in Rotated Sorted Array
- 81 Search in Rotated Sorted Array II
- 69 Sqrt(x)
- 153 Find Minimum in Rotated Sorted Array
- 154 Find Minimum in Rotated Sorted Array II
- 167 Two Sum II - Input Array Is Sorted
- 274 H-Index
- 275 H-Index II
- 278 First Bad Version
- *300 Longest Increasing Subsequence
- *315 Count of Smaller Numbers After Self (Hard)
- 334 Increasing Triplet Subsequence
- 374 Guess Number Higher or Lower
- 475 Heaters
- 611 Valid Triangle Number
- 633 Sum of Square Numbers
- 1283 Find the Smallest Divisor Given a Threshold
- 1894 Find the Student that Will Replace the Chalk
- 2187 Minimum Time to Complete Trips (Medium)
Binary Search 框架與變形
int binarySearch(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 ...;
}
int binarySearch(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;
}
- 盡量不要出現else,所有情況都寫清楚。
- 終止條件left == right QA
- 為什麼 while 迴圈條件是
<=
而不是<
因為right = nums.leagth-1 ,而不是nums.length,區別相當於:前者是[left, right]
,後者是[left, right)
,因為索引大小為nums.length是越界的。
也可以這樣寫
//...
while(left < right) {
// ...
}
return nums[left] == target ? left : -1;
左側邊界的二元搜尋(較普及的寫法) [1,2,2,2,3] 尋找所有2的位置
// option 1
int left_bound(int[] nums, int target) {
if (nums.length == 0) return -1;
int left = 0;
int right = nums.length; // 注意
while (left < right) { // 注意
int mid = (left + right) / 2;
if (nums[mid] == target) {
right = mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid; // 注意
}
}
return left;
}
// option 2
int left_bound(int[] nums, int target) {
// 搜索区间为 [left, right]
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
// if else ...
if (nums[mid] < target) {
// 搜索区间变为 [mid+1, right]
left = mid + 1;
} else if (nums[mid] > target) {
// 搜索区间变为 [left, mid-1]
right = mid - 1;
} else if (nums[mid] == target) {
// 收缩右侧边界
right = mid - 1;
}
}
if (left >= nums.length || nums[left] != target) // 检查越界
return -1;
return left;
}
- 因為
while(left< right)
,終止條件left == right
,搜尋區間[left, right)
- 因為 搜尋區間
[left, right)
,會 分成兩區間[left, mid)
和[mid+1, right)
- 返回left 和 right 都一樣意思,因為終止條件是 left== right
右側邊界的二元搜尋
int right_bound(int[] nums, int target) {
if (nums.length == 0) return -1;
int left = 0, right = nums.length;
while (left < right) {
int mid = (left + right) / 2;
if (nums[mid] == target) {
left = mid + 1; // 注意
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid;
}
}
if(l==0) return -1; // 注意
return nums[l-1]==target?l-1:-1; // 注意
}
- 因為終止條件是 left== right , 所以return left-1 和 return right-1 都一樣。
- 因為left = mid + 1; while迴圈結束時,nums[left] 一定不等於target,而nums[left-1]可能是target
統一左右兩側邊界的二元搜尋
int right_bound(int[] nums, int target) {
int l = 0, r = nums.size()-1;
while(l<=r){
int mid = l + (r-l)/2;
if(nums[mid] == target){
// return mid;
r = mid-1; // left bound
// l = mid+1 ; // right bound
}
else if(nums[mid]<target) l = mid+1;
else r = mid -1 ;
}
// left bound
if(l>= nums.size() || nums[l]!=target) return -1;
return l;
//right bound
// if(r<0 || nums[r]!=target) return -1;
// return r;
}