文章目录
045 Car Fleet 车队
一条单车道高速公路上有n辆汽车前往同一目的地。、
给你两个整数数组position和speed ,长度都是n 。
- position[i]是ith car的位置(以英里为单位)
- speed[i]是ith辆车的速度(以英里每小时为单位)
目的地位于target英里位置。
一辆车不能超过它前面的另一辆车。它只能追上另一辆车,然后以与前面的车相同的速度行驶。
车队是一组非空的以相同位置和相同速度行驶的汽车。单辆车也被视为车队。
如果一辆汽车在车队到达目的地时追上车队,则该汽车被视为车队的一部分。
返回将到达目的地的不同车队的数量。
示例1:
Input: target = 10, position = [1,4], speed = [3,2]
Output: 1
解释:从 1(速度 3)和 4(速度 2)出发的汽车组成一个车队,在目的地 10 处相遇。
示例2:
Input: target = 10, position = [4,1,0,7], speed = [2,2,1,1]
Output: 3
解释:从 4 和 7 开始的汽车在位置 10 处形成车队。从 1 和 0 开始的汽车永远追不上它们前面的汽车。这样,就有3个车队将到达目的地。
解题1: 栈
这里我们通过计算每辆汽车到达目的地需要多少时间,但是根据题目,如上图所示,蓝色汽车最开始以速度2行驶,当它追上绿色车的时候就以速度1行驶了,所以这里我们从距离目的地最近的那辆车开始遍历计算,以相反的顺序迭代这个道路上的车辆
class Solution:
def carFleet(self, target: int, position: List[int], speed: List[int]) -> int:
pair = [[p, s] for p,s in zip(position, speed)]
stack = []
for p, s in sorted(pair)[::-1]: # list[start:end:step],这样就可以实现列表的反转了\
stack.append((target - p)/s)
if len(stack) >= 2 and stack[-1] <= stack[-2]:
stack.pop()
return len(stack)
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
空间复杂度:
O
(
n
)
O(n)
O(n)
046 Search a 2D Matrix 搜索二维矩阵
给定一个mxn二维整数数组matrix和一个整数target 。
- matrix中的每一行均按非降序排序。
- 每行的第一个整数都大于前一行的最后一个整数。
如果target存在于matrix中,则返回true ,否则返回false 。
你能写一个在
O
(
l
o
g
(
m
∗
n
)
)
O(log(m * n))
O(log(m∗n))时间内运行的解决方案吗?
解题1:双重二分查找
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
ROWS, COLS = len(matrix), len(matrix[0])
top, bot = 0, ROWS - 1
while top <= bot:
row = (top + bot) // 2
if target > matrix[row][-1]:
top = row + 1
elif target < matrix[row][0]:
bot = row - 1
else:
break
if not (top <= bot):
return False
row = (bot + top) // 2
l, r = 0, COLS-1
while l <= r:
m = (l + r) //2
if target > matrix[row][m]:
l = m +1
elif target < matrix[row][m]:
r = m - 1
else:
return True
return False
时间复杂度:
O
(
m
l
o
g
n
)
O(mlogn)
O(mlogn),这里先找到哪一行,再在这行中使用二分查找。当然还有更低的时间复杂度
O
(
l
o
g
m
+
l
o
g
n
)
O(logm+logn)
O(logm+logn),这就是对行和列都使用二分查找的方法,双重二分查找
空间复杂度:
O
(
1
)
O(1)
O(1)
047 Koko Eating Bananas 科科吃香蕉
给定一个整数数组piles ,其中piles[i]是ith堆中香蕉的数量。您还会获得一个整数h ,它表示您必须吃完所有香蕉的小时数。
您可以决定每小时吃香蕉的速度k/每个小时,你可以选择一堆香蕉并从这堆香蕉中吃掉k香蕉。如果这堆香蕉少于k ,你可以吃完这堆香蕉,但不能在同一小时内吃掉另一堆香蕉。
返回最小整数k以便您可以在h小时内吃掉所有香蕉。
示例1:
Input: piles = [1,4,3,2], h = 9
Output: 2
解释:如果进食率为 2,您可以在 6 小时内吃完香蕉。如果进食率为 1,则需要 10 小时才能吃完所有香蕉(超过 h=9),因此最小进食率为 2。
示例2:
Input: piles = [25,10,23,4], h = 4
Output: 25
解题1:二分查找
对于给定了列表,吃香蕉的速度最小可以是1,最大应该是这个列表中的最大值。所以我们需要遍历的k的范围就是在这个之间。
class Solution:
def minEatingSpeed(self, piles: List[int], h: int) -> int:
l, r = 1, max(piles)
res = r
while l <= r:
k = (l+r) // 2
hours = 0
for p in piles:
hours += math.ceil(p / k)
if hours <= h:
res = min(res, k)
r = k -1
else:
l = k + 1
return res
时间复杂度:
O
(
n
l
o
g
m
)
O(nlogm)
O(nlogm)
空间复杂度:
O
(
1
)
O(1)
O(1)
048 Find Minimum in Rotated Sorted Array 查找旋转排序数组中的最小值
给定一个长度为n的数组,该数组最初按升序排序。现在它已经旋转了1到n次。例如,数组nums = [1,2,3,4,5,6]可能会变为:
- [ 3 , 4 , 5 , 6 , 1 , 2 ]如果旋转4次。
- [ 1 , 2 , 3 , 4 , 5 , 6 ]如果旋转6次。
请注意,旋转数组4次会将数组的最后四个元素移动到开头。将数组旋转6次生成原始数组。
假设旋转排序数组nums中的所有元素都是唯一的,则返回该数组的最小元素。
在O(n)时间内运行的解决方案很简单,您能编写在O(log n) time内运行的算法吗?
示例1:
Input: nums = [3,4,5,6,1,2]
Output: 1
示例2:
Input: nums = [4,5,0,1,2,3]
Output: 0
解题1:二分查找
这里我们首先需要比较最左侧的值是否小于中间的值,如果是的话,则表示该部分是未旋转数组的右侧部分,在这种情况下我们需要向右搜索,这里我们清楚左侧的内容,左指针放到mid+1的位置上来。可以看到在剩下的部分中,最左侧的值要小于最右侧的值,所以剩下部分的数组是已经排序好的并且没有旋转的。
class Solution:
def findMin(self, nums: List[int]) -> int:
res = nums[0]
l, r = 0, len(nums)-1
while l <= r:
# 如果左侧小于右侧,说明是已经按照升序排序的
if nums[l] < nums[r]:
res = min(nums[l], res)
break
m = (l + r) // 2
res = min(res, nums[m])
if nums[m] >= nums[l]:
l = m + 1
else:
r = m - 1
return res
时间复杂度:
O
(
l
o
g
n
)
O(logn)
O(logn)
空间复杂度:
O
(
1
)
O(1)
O(1)
049 Search in Rotated Sorted Array 在旋转排序数组中搜索
给定一个长度为n的数组,该数组最初按升序排序。现在它已经旋转了1到n次。例如,数组nums = [1,2,3,4,5,6]可能会变为:
- [ 3 , 4 , 5 , 6 , 1 , 2 ]如果旋转4次。
- [ 1 , 2 , 3 , 4 , 5 , 6 ]如果旋转6次。
给定旋转排序数组nums和整数target ,返回nums中target的索引,如果不存在则返回-1 。
您可以假设排序旋转数组nums中的所有元素都是唯一的,在O(n)时间内运行的解决方案很简单,您能编写在O(log n) time内运行的算法吗?
示例1:
Input: nums = [3,4,5,6,1,2], target = 1
Output: 4
示例2:
Input: nums = [3,5,6,0,1,2], target = 4
Output: -1
解题1:二分查找
class Solution:
def search(self, nums: List[int], target: int) -> int:
l, r = 0, len(nums) - 1
while l <= r:
mid = (l + r) // 2
if target == nums[mid]:
return mid
# 左侧部分,如果左侧小于中间,说明是递增部分
if nums[l] <= nums[mid]:
# 如果目标值大于该部分最大值,或者目标值小于该部分最小值
if target > nums[mid] or target < nums[l]:
l = mid + 1
else:
r = mid - 1
# 右侧部分
else:
if target < nums[mid] or target > nums[r]:
r = mid - 1
else:
l = mid + 1
return -1
时间复杂度:
O
(
l
o
g
n
)
O(logn)
O(logn)
空间复杂度:
O
(
1
)
O(1)
O(1)