灵神的二分视频:二分查找 红蓝染色法_哔哩哔哩_bilibili
34
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
right = len(nums) - 1
left = 0
res = [-1,-1]
mid = int((right + left)/2)
while right >= left:
if nums[mid] < target:
left = mid + 1
mid = int((right + left)/2)
continue
if nums[mid] > target:
right = mid - 1
mid = int((right + left)/2)
continue
if nums[mid] == target:
res[0] = mid
res[1] = mid
break
if res[0] != -1:
right = mid + 1
left = mid - 1
while right >= 0 and right < len(nums):
if nums[right] != target:
break
res[1] = right
right += 1
while left >= 0:
if nums[left] != target:
break
res[0] = left
left -= 1
return res
35
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
left = -1
right = len(nums)
while left + 1 < right:
mid = (left + right) // 2
if nums[mid] < target:
left = mid
else:
right = mid
return right
704
class Solution:
def search(self, nums: List[int], target: int) -> int:
left = -1
right = len(nums)
while left + 1 < right:
mid = (left + right) // 2
if nums[mid] < target:
left = mid
else:
right = mid
if right >= 0 and right < len(nums) and nums[right] == target:
return right
else:
return -1
744
class Solution:
def nextGreatestLetter(self, letters: List[str], target: str) -> str:
left = -1
right = len(letters)
while left + 1 < right:
mid = (left + right) // 2
if letters[mid] < chr(ord(target) + 1):
left = mid
else:
right = mid
if right >= 0 and right < len(letters):
return letters[right]
else:
return letters[0]
2529
class Solution:
def maximumCount(self, nums: List[int]) -> int:
left = -1
right = len(nums)
pos = 0
neg = 0
while left + 1 < right:
mid = (left + right) // 2
if nums[mid] < 1:
left = mid
else:
right = mid
pos = len(nums) - right
left = -1
right = len(nums)
while left + 1 < right:
mid = (left + right) // 2
if nums[mid] < 0:
left = mid
else:
right = mid
neg = right
return max(pos,neg)
1385
class Solution:
def findTheDistanceValue(self, arr1: List[int], arr2: List[int], d: int) -> int:
arr2.sort()
res = 0
for taget in arr1:
left = -1
right = len(arr2)
while left + 1 < right:
mid = (left + right) // 2
if arr2[mid] + d < taget:
left = mid
else:
right = mid
if right == len(arr2) or arr2[right] > taget + d:
res += 1
return res
1385
先将potions列表排序,保证它是一个单调列表。然后遍历每一个咒语,找到刚好满足success条件的位置,即求出当前咒语和药水的成功对数。
class Solution:
def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]:
potions.sort()
res = []
for i in spells:
left = -1
right = len(potions)
while left + 1 < right:
mid = (left + right) // 2
if i * potions[mid] < success:
left = mid
else:
right = mid
res.append(len(potions)-right)
return res
2389
class Solution:
def answerQueries(self, nums: List[int], queries: List[int]) -> List[int]:
ans = []
nums.sort()
for j in range(1,len(nums)):
nums[j] += nums[j-1]
print(nums)
for i in queries:
left = -1
right = len(nums)
while left + 1 < right:
mid = (left + right) // 2
if nums[mid] < i + 1:
left = mid
else:
right = mid
ans.append(right)
return ans
1170
使用二分查找找到刚好比queries中统计值大1的位置,再用words的长度减去即为答案。
class Solution:
def numSmallerByFrequency(self, queries: List[str], words: List[str]) -> List[int]:
q = []
w = []
for i in words:
a = min(i)
w.append(i.count(a,0,len(i)))
for j in queries:
b = min(j)
q.append(j.count(b,0,len(j)))
w.sort()
res = []
for k in q:
left = -1
right = len(w)
while left + 1 < right:
mid = (left + right) // 2
if w[mid] < k + 1:
left = mid
else:
right = mid
res.append(len(w) - right)
return res
2080
先记录每个数字出现的位置,再用二分查找找出满足的位置,先找左端,再找右端。
class RangeFreqQuery:
def __init__(self, arr: List[int]):
pos = defaultdict(list)
for i, x in enumerate(arr):
pos[x].append(i)
self.pos = pos
def query(self, left: int, right: int, value: int) -> int:
a = self.pos[value]
# a.sort()
lf = -1
lr = len(a)
while lf + 1 < lr:
mid = (lf + lr) // 2
if a[mid] < left:
lf = mid
else:
lr = mid
res = 0
res += lr
lf = -1
lr = len(a)
while lf + 1 < lr:
mid = (lf + lr) // 2
if a[mid] < right + 1:
lf = mid
else:
lr = mid
res = lr - res
return res
# Your RangeFreqQuery object will be instantiated and called as such:
# obj = RangeFreqQuery(arr)
# param_1 = obj.query(left,right,value)
2563
排序,然后进行二分查找。排序后顺序可能会混乱,题目要求的是下标 i < j。但是经过分析,我们可以发现,如果使用暴力做法,那么nums[j] 再整个过程中,和除了他自己本身的数都进行了一次数对判断(即nums[j] + 任意非自己的数)。 假设数对(i,j),i < j 满足nums[i] + nums[j] >= lower && nums[i] + nums[j] <= upper,那么数对(j,i)也满足,所以在结果上这两个数组是等价的,但由于题目要求只要(i,j),所以取其中一半即可,也就是我们可以忽略对原数组排序后下标的改变,保证只计入(i,j)或者(j,i)其中一种到答案中即可。所以我们可以设置每一次二分查找的区间为[ 0 , j - 1] (我这里采用的是开区间写法,所以是 [ 0 , j ]),这样就可以保证只计入(i,j)或者(j,i)。
class Solution:
def countFairPairs(self, nums: List[int], lower: int, upper: int) -> int:
res = 0
n = nums
n.sort()
for i in range(len(n)):
x = n[i]
left = -1
right = i
while left + 1 < right:
mid = (left + right) // 2
if n[mid] + x < lower:
left = mid
else:
right = mid
p1 = right
left = -1
right = i
while left + 1 < right:
mid = (left + right) // 2
if n[mid] + x < upper + 1:
left = mid
else:
right = mid
res += (right - p1)
return res
2856
class Solution:
def minLengthAfterRemovals(self, nums: List[int]) -> int:
x = nums[len(nums) // 2]
left = -1
right = len(nums)
while left + 1 < right:
mid = (left + right) // 2
if nums[mid] < x:
left = mid
else:
right = mid
p1 = right
left = -1
right = len(nums)
while left + 1 < right:
mid = (left + right) // 2
if nums[mid] < x + 1:
left = mid
else:
right = mid
res = right - p1
return max(res * 2 - len(nums), len(nums) % 2)