二分查找很简单,就是细节很抓狂
# !/usr/bin/env python3.7
# -*- coding: utf-8 -*-
# @Time : 2023/7/4 15:57
# @Author : Aulicz
# @File : 34searchRange.py
# @Software: PyCharm
# @Version:0.01
# 给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。
# 请你找出给定目标值在数组中的开始位置和结束位置。
# 如果数组中不存在目标值 target,返回 [-1, -1]。
# 你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
# 输入:nums = [5,7,7,8,8,10], target = 8
# 输出:[3,4]
# 提示:
# 0 <= nums.length <= 10^5
# -10^9 <= nums[i] <= 10^9
# nums 是一个非递减数组
# -10^9 <= target <= 10^9
from typing import List
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
# 经典二分查找写法见704,实际上左边就是第一个位置,右边减一是第二个位置
# 返回给定的位置
def binarySearch(nums: List[int], target: int, lower: bool) -> int:
n = len(nums)
i, j = 0, n - 1
res = 0
while i <= j:
mid = (i + j) // 2
# 此写法较为巧妙,一般写法每次都比较左右位置上的数即可(瞎想的,未证明)
if nums[mid] > target or (lower and nums[mid] >= target):
# 左侧为第一个大于等于target的下标
# 右侧为第一个大于target的下标
# 证明:当找左侧,第一次找到target后,会前移j
# 最后一次移动i,j在同一位置,如果nums[i]==target,会更新res
# 如果nums[i]<target res保持最后一次找到nums[mid]==target的位置,
# 因此是第一个大于等于target的下标
# 当找右侧,第一次找到target后,会后移i
# 最后一次移动i,j在同一位置,如果nums[i]>target,会更新res
# 如果nums[i]<target res保持最后一次找到nums[mid]>target的位置
# 又二分查找最后结果必定在target或者离target最近的两个数上
# 因此是第一个大于target的下标
# 但是如果不存在第一个比target大的数,查找会失败
# 所以需要加一个足够大的哨兵节点
j = mid - 1
res = mid
else:
i = mid + 1
return res
MAX_NUM = 10 ** 9 + 1
nums.append(MAX_NUM)
left_index = binarySearch(nums, target, True)
right_index = binarySearch(nums, target, False) - 1
n = len(nums)
# print([left_index, right_index])
if left_index <= right_index and right_index < n and nums[left_index] == target and nums[right_index] == target:
return [left_index, right_index]
else:
return [-1, -1]
# nums = [5,7,7,8,8,10]
nums = [1]
solution = Solution()
print(solution.searchRange(nums, 1))