LeetCode Contest 188
快半年没有参加 LeetCode 的每周比赛了,感觉已经跟不上节奏了哈。四题用了1个小时,错了一次罚时5分钟,然后就排到350左右了。
第一题Build an Array With Stack Operations
class Solution:
def buildArray(self, target: List[int], n: int) -> List[str]:
ret = []
cur = 0
for t in target:
ret.extend(["Push", "Pop"] * (t - cur - 1))
ret.append("Push")
cur = t
return ret
第二题Count Triplets That Can Form Two Arrays of Equal XOR
看了一下数据范围,数组的长度最大只有300。这明显可以暴力搜。因为怕超时,我就直接用 C 写了。
int countTriplets(int* arr, int arrSize){
int s[301];
s[0] = 0;
for (int i = 0; i < arrSize; i ++)
s[i + 1] = s[i] ^ arr[i];
int ret = 0;
for (int i = 0; i < arrSize; i ++) {
for (int k = i + 1; k < arrSize; k ++) {
for (int j = i + 1; j <= k; j ++) {
int a = s[j] ^ s[i];
int b = s[k+1] ^ s[j];
ret += a == b;
}
}
}
return ret;
}
第三题Minimum Time to Collect All Apples in a Tree
一开始没有察觉到这是一个多叉树,所以没有想到好的办法。我是做了最后一题回来再提交一次后错了才发现这是多叉树。题解的想法是这样的:对于一个节点,我们递归地算出子树收集所有苹果的时间,如果子树有苹果,结果要加2,这是从节点到子树根节点一个来回的时间。
class Solution:
def minTime(self, n: int, edges: List[List[int]], hasApple: List[bool]) -> int:
children = [[] for _ in range(n)]
for p, c in edges:
children[p].append(c)
def collect(root):
ans = 0
for child in children[root]:
t = collect(child)
ans += t
if t or hasApple[child]:
ans += 2
return ans
return collect(0)
第四题Number of Ways of Cutting a Pizza
动态规划的题目。我们用 dp(i, j, k) 表示从 i 行,从 j 列开始切,需要切成 k 块的切法。
边界条件 如果 i 或者 j 超出边界,那么就直接返回0。如果 k 是1,我们只需检查剩下的 pizza 里有没有苹果即可。
转移方程 因为可以横着切或者竖着切,我们需要分别考虑这两种情况。竖着切的时候我们枚举切完之后上面那块 pizza 的最后一行序号 ic。若从第 i 到 ic 行有苹果,则
dp(i, j, k) += dp(ic+1, j, k-1)
横着切的想法也是一样的。
为了快速检测某个区域是否有苹果,我预先计算所有左上角区域的和 s
。这样我们可以在 O(1) 的时间内算出一个区域的所有数字之和来判断是否有苹果。
class Solution:
def ways(self, pizza: List[str], k: int) -> int:
MOD = 10 ** 9 + 7
n, m = len(pizza), len(pizza[0])
s = [[0] * (m + 1) for _ in range(n + 1)]
for i, row in enumerate(pizza):
for j, c in enumerate(row):
s[i][j] = s[i - 1][j] + s[i][j - 1] + (c == 'A') - s[i-1][j-1]
def get(i, j, x, y):
return s[x][y] - s[x][j-1] - s[i-1][y] + s[i-1][j-1]
memo = {}
def dp(i, j, k):
if i >= n or j >= m:
return 0
if k == 1:
return 1 if get(i, j, n-1, m-1) > 0 else 0
if (i, j, k) in memo:
return memo[i, j, k]
ans = 0
for ic in range(i, n):
if get(i, j, ic, m-1) > 0:
ans = (ans + dp(ic+1, j, k-1)) % MOD
for jc in range(j, m):
if get(i, j, n-1, jc) > 0:
ans = (ans + dp(i, jc+1, k-1)) % MOD
memo[i, j, k] = ans
return ans
return dp(0, 0, k)