这个周末其实没有打比赛,因为周一在上海这边有点事,就周日先过来找刘y师姐还有刘br师兄玩耍了,然后就顺理成章地翘掉了今天的周赛。
这里必须要感谢一下刘y师姐还有刘br师兄的盛情款待,不但cover了我这上海这边的住宿费用,还带我吃了一顿超超超豪华的日式烤肉,幸福之情无法言喻!
不过感觉最近自己一直在受别人照顾呢,很幸运自己遇到了这么多的好朋友,但是也不能一直把这些当成是理所当然的,还是要加油才行啊,自己!
给出题目一的试题链接如下:
这一题没啥好说的,就是直接按照题意给出的规则进行匹配然后计数就是了……
我们直接给出python代码实现如下:
class Solution:
def countMatches(self, items: List[List[str]], ruleKey: str, ruleValue: str) -> int:
if ruleKey == "type":
idx = 0
elif ruleKey == "color":
idx = 1
else:
idx = 2
return len([item for item in items if item[idx] == ruleValue])
提交代码评测得到:耗时264ms,占用内存20.8MB。
当前最优的代码实现耗时244ms,但是实现思路是一致的,因此这里就不多做展开了。
给出题目二的试题链接如下:
这一题我的实现思路是比较暴力的,因为基底和可用的配料总量均小于10,且每一种配料至多只能加两份,因此,考察配料的全分布也就是 3 1 0 3^10 310种,这个算法复杂度是完全可以接受的,因此,我的思路就是直接给出所有的配料成本集合,然后对每一个材料基底去看能取到的最接近目标值的配料使用方法是什么。
给出python代码实现如下:
class Solution:
def closestCost(self, baseCosts: List[int], toppingCosts: List[int], target: int) -> int:
n, m = len(baseCosts), len(toppingCosts)
baseCosts = sorted(baseCosts)
def dp(idx):
if idx >= m:
return [0]
else:
nxt = dp(idx+1)
return nxt + [x+toppingCosts[idx] for x in nxt] + [x+2*toppingCosts[idx] for x in nxt]
dosing = sorted(list(set(dp(0))))
m = len(dosing)
res = []
for i in range(n):
if baseCosts[i] > target:
res.append(baseCosts[i])
break
delta = target - baseCosts[i]
idx = bisect.bisect_left(dosing, delta)
if idx == m:
res.append(baseCosts[i] + dosing[-1])
else:
if dosing[idx] == delta:
return target
res.append(baseCosts[i] + dosing[idx])
if idx != 0:
res.append(baseCosts[i] + dosing[idx-1])
return sorted(res, key=lambda x: (abs(target-x), x))[0]
提交代码评测得到:耗时48ms,占用内存19.1MB。
给出题目三的试题链接如下:
这一题一开始做的时候思路上出了点岔子,后来是对着bad-case做出来的,放到比赛的时候不好说一定做不出来吧,但是估计免不了要吃点苦头了,唉,总感觉最近打比赛好像一直不太顺啊……
回过头来说说这题的思路吧,其实还算是蛮简单的。因为就是要让两个数组的值逼近,那么无非就是从当前和比较大的数组里面将一个较大的数变为1,或者从当前和较小的数组里面将它的值变为6。
只是,一开始我的思路是将两个数组独立考虑,但是后来对比bad-case看了一下之后发现自己脑残了,两个数组完全没有必要独立进行考虑,只要一起考虑就可以了。
事实上,我们只要在两个数组的和还没有相同的时候不断地选取当前变化后引起差值变化最大的数进行改变即可。
而针对这个情况,我们只要事先将数组进行排序就行了,后续的算法复杂度就只有 O ( N ) O(N) O(N)了,因此,整体的算法复杂度就是排序的算法复杂度,即 O ( N ⋅ l o g N ) O(N \cdot logN) O(N⋅logN)。
给出python代码实现如下:
class Solution:
def minOperations(self, nums1: List[int], nums2: List[int]) -> int:
n, m = len(nums1), len(nums2)
if 6*n < m or n > 6*m:
return -1
s1, s2 = sum(nums1), sum(nums2)
if s1 == s2:
return 0
elif s1 > s2:
return self.minOperations(nums2, nums1)
nums1 = sorted(nums1)
nums2 = sorted(nums2, reverse=True)
res = 0
i, j = 0, 0
delta = s2 - s1
while delta > 0:
if i >= n:
delta -= (nums2[j]-1)
j += 1
elif j >= m:
delta -= (6-nums1[i])
i += 1
elif nums2[j]-1 <= 6-nums1[i]:
delta -= (6-nums1[i])
i += 1
else:
delta -= (nums2[j]-1)
j += 1
res += 1
return res
提交代码评测得到:耗时1216ms,占用内存18.9MB。
给出题目四的试题链接如下:
这一题自己做的时候就完全没有思路,后来是看答案之后看了好久才终于想明白的,实在是惭愧……
说白了,这题其实也挺直接的,说白了只要搞清楚合并的本质就行了:
换句话说,我们只需要计算追及时间,然后使用一个堆排序对其进行维护,然后在每一次合并发生后,更新后一辆车在下一次合并可能的合并中起点为前一辆车的起点车辆。
给出python代码实现如下:
class Solution:
def getCollisionTimes(self, cars: List[List[int]]) -> List[float]:
n = len(cars)
starting_points = [i-1 for i in range(n)]
res = [-1 for _ in range(n)]
def cal_time(st, ed):
return (cars[ed][0] - cars[st][0]) / (cars[st][1] - cars[ed][1])
q = []
for i in range(n-1):
if cars[i][1] > cars[i+1][1]:
t = cal_time(i, i+1)
heapq.heappush(q, (t, i, i+1))
while q:
t, st, ed = heapq.heappop(q)
if res[st] != -1:
continue
res[st] = t
starting_points[ed] = starting_points[st]
st, ed = starting_points[st], ed
if st == -1:
continue
if cars[st][1] > cars[ed][1]:
t = cal_time(st, ed)
heapq.heappush(q, (t, st, ed))
return res
提交代码评测得到:耗时2372ms,占用内存59.8MB。
当前最优的代码实现耗时1208ms,但是没怎么看懂他的思路,有兴趣的读者可以自行研究一下,这里我就暂时不多涉及了……