二分探索の一般的なシナリオ: 数値を検索し、左側の境界を検索し、右側の境界を検索します。つまり、順序付けされた配列 arr が与えられた場合、最初に a が出現する位置を左から、右から初めて a が出現する位置に番号 a があるかどうかを調べます。
注:合計left + (right - left) / 2
の 結果は同じですが、合計が 大きくなり すぎて直接加算してオーバーフローが発生する(left + right) / 2
のを防ぐため 、プログラミングでは一般に前者が使用されます。left
right
Pythonの実装
def binary_search(nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1
while left <= right:
mid = left + (right - left) // 2
if nums[mid] < target:
left = mid + 1
elif nums[mid] > target:
right = mid - 1
elif nums[mid] == target:
# 直接返回
return mid
# 直接返回
return -1
def left_bound(nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1
while left <= right:
mid = left + (right - left) // 2
if nums[mid] < target:
left = mid + 1
elif nums[mid] > target:
right = mid - 1
elif nums[mid] == target:
# 别返回,锁定左侧边界
right = mid - 1
# 判断 target 是否存在于 nums 中
# 此时 target 比所有数都大,返回 -1
if left == len(nums):
return -1
# 判断一下 nums[left] 是不是 target
return left if nums[left] == target else -1
def right_bound(nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1
while left <= right:
mid = left + (right - left) // 2
if nums[mid] < target:
left = mid + 1
elif nums[mid] > target:
right = mid - 1
elif nums[mid] == target:
# 别返回,锁定右侧边界
left = mid + 1
# 此时 left - 1 索引越界
if left - 1 < 0:
return -1
# 判断一下 nums[left] 是不是 target
return left - 1 if nums[left - 1] == target else -1
C++の実装
int binary_search(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while(left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if(nums[mid] == target) {
// 直接返回
return mid;
}
}
// 直接返回
return -1;
}
int left_bound(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 别返回,锁定左侧边界
right = mid - 1;
}
}
// 判断 target 是否存在于 nums 中
// 此时 target 比所有数都大,返回 -1
if (left == nums.size()) return -1;
// 判断一下 nums[left] 是不是 target
return nums[left] == target ? left : -1;
}
int right_bound(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 别返回,锁定右侧边界
left = mid + 1;
}
}
// 此时 left - 1 索引越界
if (left - 1 < 0) return -1;
// 判断一下 nums[left] 是不是 target
return nums[left - 1] == target ? (left - 1) : -1;
}