5489. 两球之间的磁力
在代号为 C-137 的地球上,Rick 发现如果他将两个球放在他新发明的篮子里,它们之间会形成特殊形式的磁力。Rick 有 n 个空的篮子,第 i 个篮子的位置在 position[i] ,Morty 想把 m 个球放到这些篮子里,使得任意两球间 最小磁力 最大。
已知两个球如果分别位于 x 和 y ,那么它们之间的磁力为 |x - y| 。
给你一个整数数组 position 和一个整数 m ,请你返回最大化的最小磁力。
1.202场周赛3AC,第三题这题一开始就想二分,没想出来,先做了第四题,可惜的AK机会。。二分一生的天敌
分析:
答案是求任意两点间的最小距离最大化,最小距离:1,最大距离:arr[-1]-arr[0],check函数用于检查当前的距离是否能满足题目的要求放m个球,然后二分搜索距离即可。
总结:或许可以抽象出一个思维框架,二分的思考流程是,首先确定你要二分东西的区间(上下限),然后去二分这个想要的东西,这里时间复杂度logn,然后再用n的时间去检查是否满足要求!
class Solution:
def maxDistance(self, position: List[int], m: int) -> int:
position.sort()
left=1
right=position[-1]-position[0]
def check(diff):
count,i,j = 1,0,0
while j=m
while left<=right:
mid=(left+right)//2
if check(mid):
left=mid+1
else:
right=mid-1
return left-1
面试题 08.03. 魔术索引
魔术索引。 在数组A[0...n-1]中,有所谓的魔术索引,满足条件A[i] = i。给定一个有序整数数组,编写一种方法找出魔术索引,若有的话,在数组A中找出一个魔术索引,如果没有,则返回-1。若有多个魔术索引,返回索引值最小的一个。
示例1:
输入:nums = [0, 2, 3, 4, 5]
输出:0
说明: 0下标的元素为01.不是真正的二分,因为数组不是严格的单调增加
class Solution:
def findMagicIndex(self, nums: List[int]) -> int:
if not nums: return -1
if nums[0]==0:return 0
p, n = 0, len(nums)
while p < n:
if nums[p] > p: p = nums[p]
elif nums[p] == p: return p
else: p += 1
return -1
面试题 10.05. 稀疏数组搜索
稀疏数组搜索。有个排好序的字符串数组,其中散布着一些空字符串,编写一种方法,找出给定字符串的位置。
示例1:
输入: words = ["at", "", "", "", "ball", "", "", "car", "", "","dad", "", ""], s = "ta"
输出:-1
说明: 不存在返回-1。
示例2:输入:words = ["at", "", "", "", "ball", "", "", "car", "", "","dad", "", ""], s = "ball"
输出:41.不是真正的递增序列,问题是当遇到arr[mid]==""时要知道left和right怎么变化,这里处理的方法是遇到空的时候线性扫描
class Solution:
def findString(self, words: List[str], s: str) -> int:
left=0
right=len(words)-1
while left<=right:
mid=(left+right)//2
if words[mid]=="":
if words[right]==s:return right #左扫 右扫都可以
right-=1
elif words[mid]==s:return mid
elif words[mid]>s:right=mid-1
else:left=mid+1
return -1
剑指 Offer 53 - I. 在排序数组中查找数字 I
统计一个数字在排序数组中出现的次数。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:输入: nums = [5,7,7,8,8,10], target = 6
输出: 01.二分中带线性扫描,极端情况会退化到o(n)
2.2个二分,一个确定上边界,一个确定下边界
class Solution:
def search(self, nums: List[int], target: int) -> int:
left=0
right=len(nums)-1
while left<=right:
mid=(left+right)//2
if nums[mid]==target:
tmp=1
mid_keep=mid
while mid-1>=0 and nums[mid-1]==target:
mid-=1
tmp+=1
while mid_keep+1target:right=mid-1
else:left=mid+1
return 0
class Solution:
def search(self, nums: [int], target: int) -> int:
i,j=0,len(nums)-1
while i<=j:
mid=(i+j)//2
if nums[mid]<=target:i=mid+1
else:j=mid-1
right=i-1
i=0
while i<=j:
mid=(i+j)//2
if nums[mid]>=target:j=mid-1
else:i=mid+1
left=j+1
return right-left+1
剑指 Offer 11. 旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
示例 1:
输入:[3,4,5,1,2]
输出:1
示例 2:输入:[2,2,2,0,1]
输出:01.二分很灵活,可以多写几组数据先观察清楚!
class Solution:
def minArray(self, numbers: List[int]) -> int:
left=0
right=len(numbers)-1
while left<=right:
mid=left+(right-left)//2
if numbers[mid]numbers[right]:
left=mid+1
else:right-=1
return numbers[left]
167. 两数之和 II - 输入有序数组
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:
返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。1.双指针o(n)
2.二分,对每一个数作为num,然后二分的去查找target-num,o(nlogn)
class Solution(object):
def twoSum(self, numbers, target):
"""
:type numbers: List[int]
:type target: int
:rtype: List[int]
"""
if not numbers:
return []
left = 0
right = len(numbers) - 1
while left < right:
if numbers[left]+numbers[right]==target:
return [left+1,right+1]
elif numbers[left]+numbers[right]>target:
right -= 1
else:
left += 1
return
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
n=len(numbers)
for i in range(n):
left=i+1
right=n-1
while left<=right:
mid=(right+left)//2
if numbers[mid]==target-numbers[i]:return [i+1,mid+1]
elif numbers[mid]>target-numbers[i]:right=mid-1
else:left=mid+1
return [-1,-1]
744. 寻找比目标字母大的最小字母
给你一个排序后的字符列表 letters ,列表中只包含小写英文字母。另给出一个目标字母 target,请你寻找在这一有序列表里比目标字母大的最小字母。
在比较时,字母是依序循环出现的。举个例子:
如果目标字母 target = 'z' 并且字符列表为 letters = ['a', 'b'],则答案返回 'a'
1.二分真的很灵活,很显然当arr[mid]<=target是left=mid+1,但arr[mid]>target时如果right=mid-1,假如mid正好是第一个大于target的数不就被跳过了么,虽然跳过了,但最后结束时left=mid+1又加回来了!
class Solution:
def nextGreatestLetter(self, letters: List[str], target: str) -> str:
left=0
right=len(letters)-1
while left<=right:
mid=(right+left)//2
if letters[mid]<=target:
left=mid+1
else:
right=mid-1
return letters[left] if left