LeetCode笔记:Weekly Contest 247(补发)
Posted 墨客无言
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode笔记:Weekly Contest 247(补发)相关的知识,希望对你有一定的参考价值。
1. 题目一
给出题目一的试题链接如下:
1. 解题思路
这一题挺直接的,由于都是正数,所以直接对原数据进行排序,然后选取最大的两个元素相乘减去最小的两个元素的乘积即可得到最大值。
2. 代码实现
给出python代码实现如下:
class Solution:
def maxProductDifference(self, nums: List[int]) -> int:
nums = sorted(nums)
return nums[-1]*nums[-2] - nums[0]*nums[1]
提交代码评测得到:耗时164ms,占用内存15.4MB。
2. 题目二
给出题目二的试题链接如下:
1. 解题思路
这一题的思路还是比较清晰的,我的解法是先将每一圈的元素拿出来,然后进行旋转,最后重新填入到矩阵当中。
2. 代码实现
给出python代码实现如下:
class Solution:
def rotateGrid(self, grid: List[List[int]], k: int) -> List[List[int]]:
n, m = len(grid), len(grid[0])
l = min(n, m) // 2
res = [[0 for _ in range(m)] for _ in range(n)]
for i in range(l):
s = [grid[j][i] for j in range(i, n-i)] + [grid[n-1-i][j] for j in range(i+1, m-i)] + [grid[j][m-1-i] for j in range(n-i-2,i,-1)] + [grid[i][j] for j in range(m-i-1,i,-1)]
# print(s)
delta = k % len(s)
s = s[-delta:] + s[:-delta]
idx = 0
for j in range(i, n-i):
res[j][i] = s[idx]
idx += 1
for j in range(i+1, m-i):
res[n-1-i][j] = s[idx]
idx += 1
for j in range(n-i-2,i,-1):
res[j][m-1-i] = s[idx]
idx += 1
for j in range(m-i-1,i,-1):
res[i][j] = s[idx]
idx += 1
return res
提交代码评测得到:耗时140ms,占用内存14.7MB。
3. 题目三
给出题目三的试题链接如下:
1. 解题思路
这一题我自己是没有搞定,最后看了别人的解法才想到的解法。
不过解法确实巧妙。
由于我们一共只有10个字符,且每个字符只有奇数和偶数两种状态,因此,我们只需要使用 2 10 2^{10} 210,即1024个状态即可记录下所有可能的状态值。
其中,0的初始状态值就为1。
当我们每经过一个字符,我们可以更新当前的状态值,此时,我们遍历所有与当前状态位数相差为1的状态出现的次数,就可以得到所有到当前字符为止的所有可能的wonderful substring的个数。
累加其全部的结果我们即可得到最终的结果。
2. 代码实现
给出python代码实现如下:
class Solution:
def wonderfulSubstrings(self, word: str) -> int:
n = len(word)
loc = [0 for _ in range(1024)]
loc[0] = 1
status = 0
res = 0
for i, c in enumerate(word):
c = ord(c) - ord('a')
status = status ^ (1 << c)
res += loc[status]
for j in range(10):
pre = status ^ (1 << j)
res += loc[pre]
loc[status] += 1
return res
提交代码评测得到:耗时2688ms,占用内存15.4MB。
4. 题目四
给出题目四的试题链接如下:
1. 解题思路
这一题多少有点看答案的成分在里面吧,不过能把这题搞定还是很开心的。
这题的整体思路可以拆分为两个部分:
- 通过出度来获取整个树的拓扑排序序列;
- 通过拓扑排序序列来求解所有可能的排序数目。
其中,第一部分事实上还是比较好实现的,关键在于第二部分,数学的部分偏多一点。
我们假设某一棵树的根节点 r 0 r_0 r0包含 k k k个直接的子节点(记为 r 1 r_1 r1到 r k r_k rk),每个子节点展开的子树的大小(即所有的节点数目)分别为 s 1 s_1 s1到 s k s_k sk,那么,我们可以很快推导得到,所有关于这棵树的拓扑排序数目为:
f ( r 0 ) = ( ∑ i = 1 k s i ) ! Π i = 1 k ( s i ! ) ⋅ Π i = 1 k f ( r i ) f(r_0) = \\frac{(\\sum_{i=1}^{k}{s_i})!}{\\Pi_{i=1}^{k}(s_i!)} \\cdot\\Pi_{i=1}^{k}f(r_i) f(r0)=Πi=1k(si!)(∑i=1ksi)!⋅Πi=1kf(ri)
这个公式也很好解释,首先当成完全有序排列,此时共有 ( ∑ i = 1 k s i ) ! (\\sum_{i=1}^{k}{s_i})! (∑i=1ksi)!可能的排序方法,然后由于每一个子树事实上都是一个拓扑序列,他们内部的排序数目不能够使用全排列,而应该修改为其拓扑排序的数目,因此,我们要对结果乘上一个修正因子 f ( r i ) s i ! \\frac{f(r_i)}{s_i!} si!f(ri),遍历 r 0 r_0 r0所有的子节点即可得到上述推导公式。
可以看到,由此,最终的答案就可以通过一个递推函数快速地给出来。
但是,需要注意的是,由于这里我们需要对
1
0
9
+
7
10^9+7
109+7进行同余操作,因此,我们还需要对我们的求解公式进行一定的调整,将除法操作转换为乘法操作,这个可以通过乘法逆元进行实现,而python 3.9中的pow
函数可以快速地实现这个功能,只要计算pow(a, -1, mod)
就可以快速地得到a关于mod的乘法逆元。
综上,我们就可以最终得到上述问题的解答了。
2. 代码实现
给出python代码实现如下:
class Solution:
def waysToBuildRooms(self, prevRoom: List[int]) -> int:
MOD = 10**9+7
n = len(prevRoom)
def get_topological_seq(prevRoom):
deg = Counter(prevRoom)
nodes = [u for u in range(n) if u not in deg]
i, m = 0, len(nodes)
while i < m:
u = nodes[i]
v = prevRoom[u]
deg[v] -= 1
if v != -1 and deg[v] == 0:
nodes.append(v)
m += 1
i += 1
return nodes
def get_subtree_size(nodes, prevRoom):
sizes = [1 for _ in range(n)]
for u in nodes[:-1]:
sizes[prevRoom[u]] += sizes[u]
return sizes
def get_graph(prevRoom):
graph = defaultdict(list)
for u, v in enumerate(prevRoom):
graph[v].append(u)
return graph
def get_factorial(n):
f = [1 for _ in range(n+1)]
for i in range(2, n+1):
f[i] = (f[i-1] * i) % MOD
g = [pow(x, -1, MOD) for x in f]
return f, g
nodes = get_topological_seq(prevRoom)
sizes = get_subtree_size(nodes, prevRoom)
graph = get_graph(prevRoom)
f, g = get_factorial(n)
dp = [f[sizes[i]-1] for i in range(n)]
for u in nodes:
if graph[u] == []:
continue
for v in graph[u]:
dp[u] = (dp[u] * dp[v] * g[sizes[v]]) % MOD
return dp[0]
提交代码评测得到:耗时3928ms,占用内存55MB。
以上是关于LeetCode笔记:Weekly Contest 247(补发)的主要内容,如果未能解决你的问题,请参考以下文章