昨天的双周赛刚刚受过一次打击,结果今天的周赛就直接崩盘了,4道题居然只做出了一题,全球排名4000多,滑铁卢都滑倒马里亚纳大海沟底下去了,整个人都傻了,浑浑噩噩看着结果发呆,简直不敢相信这结果。
再看看其他人的成绩,头几名也就花了20分钟,20分钟的题目,然后我搞了一个半小时就这德行。。。
简直不想说什么了,第一题看错题目,第二题思路混乱,第三第四题又是超时问题,横竖搞不定,心中只有一句***不知当讲不当讲。。。
心累。。。
给出题目一的试题链接如下:
5543. 两个相同字符之间的最长子字符串这一题没啥难度,虽然现在真心没啥脸说这句话,不过基本都是看过就会的,无非就是找到找到第一个和最后一个出现的相同字符,然后计算其间的字符串长度而已。
给出python代码实现如下:
class Solution: def maxLengthBetweenEqualCharacters(self, s: str) -> int: cache = defaultdict(list) ans = -1 for idx, c in enumerate(s): if c in cache: ans = max(ans, idx - cache[c][0] - 1) cache[c].append(idx) return ans提交代码评测得到:耗时32ms,占用内存14MB。属于当前最优方案。
给出题目二的试题链接如下:
5544. 执行操作后字典序最小的字符串这一题比赛的时候横竖没做出来,赛后想了好久也没个好的思路。看了头上几位大佬们的解法,也感觉都挺复杂的,一时半会也没看懂他们的思路,知道后面偶然间发现一个解法,真的是崩掉了我的三观。。。
他的思路异常的简单,不管三七二十一,将所有可能的变换结果全部遍历生成,然后直接取其中的最小字符串。。。
我表示。。。
唉,心累。。。
给出python代码实现如下:
class Solution: def findLexSmallestString(self, s: str, a: int, b: int) -> str: def add(s): return "".join([c if idx % 2 == 0 else str((int(c) + a) % 10) for idx, c in enumerate(s)]) def rotate(s): return s[b:] + s[:b] seen = set([s]) queue = [s] while queue: s = queue.pop(0) s1 = add(s) if s1 not in seen: seen.add(s1) queue.append(s1) s2 = rotate(s) if s2 not in seen: seen.add(s2) queue.append(s2) return min(seen)提交代码评测得到:耗时1424ms,占用内存15.8MB。
不过,这个算法显然太过暴力了,看了一下,当前的最优解法耗时仅44ms,有近两个量级的性能提升,不过,这里实在是不想去看他们的解法了,有兴趣的读者可以自行研究一下,如果可以的话请务必在评论区讲解一下,真心不想再看代码了。。。
(≧﹏ ≦)
给出题目三的试题链接如下:
5545. 无矛盾的最佳球队这一题拿到题目的第一反应又是一道动态规划的题目,那么我们可以使用缓存方式将其转换为一道递归算法的题目进行实现。
思路就是:
首先对年龄和得分进行pair之后排序;对每一个球员,有选择和不选择两种情况,分别考察选用和不选用情况下的最大可选球员数目,取最大值。给出python代码实现:
class Solution: def bestTeamScore(self, scores: List[int], ages: List[int]) -> int: player = [(age, score) for age, score in zip(ages, scores)] player = sorted(player) n = len(player) @lru_cache(None) def dp(idx, last_score): if idx >= n: return 0 ans = dp(idx+1, last_score) while idx < n and player[idx][1] < last_score: idx += 1 if idx < n: age, score = player[idx] ans = max(ans, score + dp(idx+1, score)) return ans return dp(0, 0)然而遇到代码超时问题,147个测试样例仅能通过131个。
考察了一下排名前两名的两位大佬的code,发现本质上来说他们也是用的动态规划,但是他们的算法实现方式比我却优雅了许多,他们并不是讨论每个人被选择与不选择情况下的总分数,而是讨论的是当每个人被选择的情况下所能获得的最大分数。
我们直接给出python代码如下:
class Solution: def bestTeamScore(self, scores: List[int], ages: List[int]) -> int: player = sorted([(a, s) for a, s in zip(ages, scores)]) n = len(player) dp = [s for a, s in player] ans = 0 for i in range(n): for j in range(i): if player[i][1] >= player[j][1]: dp[i] = max(dp[i], dp[j] + player[i][1]) ans = max(ans, dp[i]) return ans其中,dp[i]表示在选用了第i个球员的情况下前i个球员能够获得的最大分数。
提交代码评测得到:耗时2236ms,占用内存14.3MB。
而当前最优代码耗时仅240ms,还有近一个量级的性能提升,不过实在是不想看他的code了,有兴趣的读者可以自行去研究一下。
给出题目四的试题链接如下:
5128. 带阈值的图连通性这一题其实不难,可惜我比赛的时候没有时间去看这题,可惜了。
这一题是典型的DSU的题目,我们只需要构建一个DSU图然后寻找联通关系就行了。
不过,需要注意的是,我们一开始的想法是针对每两个点看他们的最大公约数是否满足大于threshold条件然判断是否要进行连接,这种方式会导致超时。
正确的思路应该是考察每一个大于threshold的因子,然后将他们的倍数进行连接。
给出python代码实现如下:
class DSU: def __init__(self, n): self.dsu = [i for i in range(n+1)] def union(self, x, y): xr = self.find(x) yr = self.find(y) self.dsu[yr] = xr def find(self, x): if x == self.dsu[x]: return x self.dsu[x] = self.find(self.dsu[x]) return self.dsu[x] class Solution: def areConnected(self, n: int, threshold: int, queries: List[List[int]]) -> List[bool]: dsu = DSU(n) for i in range(threshold+1, n+1): for j in range(2, n // i + 1): dsu.union(i, i * j) return [dsu.find(x) == dsu.find(y) for x, y in queries]提交代码评测得到:耗时996ms,占用内存49.2MB。