给出题目一的试题链接如下:
这题的解题思路还是比较清晰的,无非就是将原先的string按照给定的indices进行排序即可。
因此,一种比较直观的实现方法就是:
下面,我们给出python的代码实现如下:
class Solution:
def restoreString(self, s: str, indices: List[int]) -> str:
ans = [c for c in s]
for i, idx in enumerate(indices):
ans[idx] = s[i]
return "".join(ans)
提交代码之后得到评测结果如下:耗时52ms,占用内存13.8MB,属于当前最优效果。
给出第二题的试题链接如下:
这道题我们实际来考察一下解法,就可以很快速地得到代码地实现思路。
在做这个问题时,我们只需要从末尾开始,每一次遇到一个不连续的字符,就做一次翻转,这样,做完全部的翻转之后,我们就能得到同样前后变化顺序的字符串,即他与原始字符串要么相同,要么相反。
然后,我们考虑第一个字符,如果是0,则我们无需再做额外的操作,反之,我们多做一次反转即可。
例:
src: 00000 -> tgt: 10111
step 01: 00000 -> 00111
step 02: 00111 -> 01000
step 03: 01000 -> 10111
基于上述思路,我们即可快速地给出代码实现如下:
class Solution:
def minFlips(self, target: str) -> int:
count = 1 if target[0] == "1" else 0
flag = target[0]
for c in target:
if c != flag:
count += 1
flag = c
return count
提交代码得到评测结果如下:耗时60ms,占用内存14.3MB,属于当前最优效果。
给出题目三的试题链接如下:
这一题的解题思路可以基于后续遍历进行改写。
对任意两个叶子节点,他们必定分立于某一个根节点的左右两子树,因此,他们的距离就是他们针对这一个根节点的深度之和。
故,整体的解题思路就可以写作如下:
由于本人语文不太好,上述思路解释多少会有点晦涩。因此,下面我们直接给出代码实现,希望令上面的解释可以更好理解一点。。。
给出代码实现如下:
class Solution:
def countPairs(self, root: TreeNode, distance: int) -> int:
count = 0
def dfs(root):
nonlocal count
if root is None:
return []
elif root.left is None and root.right is None:
return [0]
left_leaves = dfs(root.left)
right_leaves = dfs(root.right)
for lleaf in left_leaves:
for rleaf in right_leaves:
if lleaf + rleaf + 2 <= distance:
count += 1
return [dep + 1 for dep in left_leaves + right_leaves]
dfs(root)
return count
提交代码得到评测结果如下:耗时296ms,占用内存15.1MB。
当前的最优结果耗时240ms,但是思路为同样的思路,只是在实现细节上有所不同。
给出题目四的试题链接如下:
这道题比赛的时候留了将近一个小时来做,最终做了半个多小时之后放弃了,因为实在想不到什么非常好的解题思路,甚至说连一个比较合理的暴力求解思路都没能想到。
其主要难点在于以下几点:
a3 -> a2
a3b2a4 -> a7
(删除了bb
)a10 -> a9
a5a6 -> a11
因此,直接按照字符串的子串簇的方式考虑每次最优先删除次序的方式就会很难考虑清楚每次操作究竟应该删除哪个子串,要删除多少长度。
比赛之后,研读了一下大佬的解法,发现大佬并没有考虑一次删除一个子串,而是每次删除一个字符,并基于此通过动态规划的方式对这个问题进行了解答。
下面,我们给出大佬的解题思路:
另外需要注意的是,在求解最优压缩子串长度的算法问题上,我们不能每次都暴力的将整个子串都传入进行求解,一来字符串的复制会消耗大量的时间,二来每次计算整个序列的压缩子串长度的时间复杂度是O(N),其两两之间会存在大量的重复计算内容。
参考大佬的解题方法,他是采用了增量地计算每一段连续子串的压缩字符长度的方式进行求解的。
下面,我们基于大佬的解答思路来进行自己的代码实现。
依照上述解题思路,我们仿写得到代码实现如下:
import math
class Solution:
def getLengthOfOptimalCompression(self, s: str, k: int) -> int:
def cal_compressed_consecutive_string_len(strlen):
if strlen <= 1:
return strlen
else:
return 1 + len(str(strlen))
n = len(s)
@lru_cache(None)
def dp(idx, consecutive_len, pre_char, delete_num):
if delete_num > k:
return math.inf
if idx == n:
return cal_compressed_consecutive_string_len(consecutive_len)
# delete s[idx]
l1 = dp(idx+1, consecutive_len, pre_char, delete_num + 1)
# keep s[idx]
if s[idx] == pre_char:
l2 = dp(idx+1, consecutive_len+1, pre_char, delete_num)
else:
l2 = dp(idx+1, 1, s[idx], delete_num) + cal_compressed_consecutive_string_len(consecutive_len)
return min(l1, l2)
return dp(0, 0, '', 0)
提交代码评测得到:耗时2764ms,占用内存372.8MB。
这个耗时在昨天的查看结果中属于第一梯队的,但是今天再次查看的时候最优耗时已经被刷到了500ms,2764ms这个成绩已经被甩到50%之后了。。。
看了一下大佬们的优化代码,发现对其中做了很多细节的优化。
但是,处于代码可读性的考虑(qi shi jiu shi lan),这里就不做过多的展开了,如果有兴趣的话可以自行查看大佬们的优化算法。