这次的比赛简直了,直接从结论开始说吧,居然才做出两题,虽然排名还是差不多1500的样子,不算太难看,但让人火大的是最后一题事实上是能够做出来的,思路完全正确,最后居然是开始排列组合的统计计算上由于python自己的精度问题导致结果一直不对,真的是让人蛋疼。
然后赛后看了一下别人的实现,几乎和我一毛一样,唯一的区别就是我自己在写 C n m C_n^m Cnm函数的实现,然后对方直接调用了python中math库里的实现。。。
emmmm…
好吧,计算机里面精度的把控确实是一个问题,别人知道这个库函数我不知道本身也就是我自己的问题,但是只是因为这个奇葩的原因导致最后一题一直通不过终究还是异常的不甘心。
不爽啊!!!
给出题目一的试题链接如下:
这题没啥好说的,就是按照题目说的直接暴力枚举就可以了,唯一需要注意的就是稍微边界条件。
给出python的代码实现如下:
class Solution:
def containsPattern(self, arr: List[int], m: int, k: int) -> bool:
def is_match(idx, m, k):
for i in range(m, m*k):
if arr[idx + i % m] != arr[idx + i]:
return False
return True
n = len(arr)
for i in range(n+1 - m*k):
if is_match(i, m, k):
return True
return False
提交代码评测得到:耗时36ms,占用内存14MB。
给出题目二的试题链接如下:
这一题首先要注意的是,每当出现一次0时,列表就被分成了前后两部分,我们需要分别考察前后两部分中的最长序列长度。
另一方面,我们需要考察的,对一个非零的序列,我们要怎么找到最长的积为正数的序列。
这个可以参考求和的方式,我们求出每个连乘到某一个元素之后的正负值,只需要比对头尾均为正值的序列长度和头尾均为负值的最大序列长度即可。
给出python的代码实现如下:
class Solution:
def getMaxLen(self, nums: List[int]) -> int:
def get_max(sign):
n = len(sign)
ans = n-1 - sign[::-1].index(1)
if -1 in sign:
st = sign.index(-1)
ed = n-1 - sign[::-1].index(-1)
ans = max(ans, ed - st)
return ans
sign = [1]
ans = 0
for n in nums:
if n > 0:
sign.append(sign[-1])
elif n < 0:
sign.append(-sign[-1])
else:
ans = max(ans, get_max(sign))
sign = [1]
ans = max(ans, get_max(sign))
return ans
提交代码评测得到:耗时604ms,占用内存28MB。
给出题目三的试题链接如下:
这道题比赛的时候我没能做出来,甚至没啥靠谱的思路,唯一的想法就是暴力地枚举法求解。即每次将一个点从1变成0,然后考察能否出现隔离的情况。不过当时没能将代码写出来,赛后写了一下代码,果然遇到了超时问题,92个测试样例中仅通过了48个。真的是非常惨了。
下面,我们先给出枚举法的代码实现如下。
class Solution:
def minDays(self, grid: List[List[int]]) -> int:
n = len(grid)
m = len(grid[0])
def is_isolated():
have_visited = set()
counter = 0
for i in range(n):
for j in range(m):
if grid[i][j] == 0 or (i, j) in have_visited:
continue
stack = [(i, j)]
counter += 1
if counter >= 2:
return True
while stack != []:
x, y = stack.pop(0)
have_visited.add((x, y))
if x-1 >= 0 and grid[x-1][y] == 1 and (x-1, y) not in have_visited:
stack.append((x-1, y))
if x+1 < n and grid[x+1][y] == 1 and (x+1, y) not in have_visited:
stack.append((x+1, y))
if y-1 >= 0 and grid[x][y-1] == 1 and (x, y-1) not in have_visited:
stack.append((x, y-1))
if y+1 < m and grid[x][y+1] == 1 and (x, y+1) not in have_visited:
stack.append((x, y+1))
return counter == 0
ans = n * m
def dfs(row, col, counter):
nonlocal ans
if counter >= ans:
return
if is_isolated():
ans = min(ans, counter)
return
for i in range(row, n):
if i == row:
for j in range(col, m):
if grid[i][j] == 0:
continue
grid[i][j] = 0
dfs(i, j, counter+1)
grid[i][j] = 1
else:
for j in range(m):
if grid[i][j] == 0:
continue
grid[i][j] = 0
dfs(i, j, counter+1)
grid[i][j] = 1
return
dfs(0, 0, 0)
return ans
如前所述,上述代码运行超时,92个测试样例仅能通过48个。
后续看了一下头几名的大神们的解法,发现主要有两点区别:
因此,我们修改代码得到:
class Solution:
def minDays(self, grid: List[List[int]]) -> int:
n = len(grid)
m = len(grid[0])
def is_isolated():
have_visited = set()
counter = 0
for i in range(n):
for j in range(m):
if grid[i][j] == 0 or (i, j) in have_visited:
continue
stack = [(i, j)]
have_visited.add((i, j))
counter += 1
if counter >= 2:
return True
while stack != []:
x, y = stack.pop(0)
if x-1 >= 0 and grid[x-1][y] == 1 and (x-1, y) not in have_visited:
stack.append((x-1, y))
have_visited.add((x-1, y))
if x+1 < n and grid[x+1][y] == 1 and (x+1, y) not in have_visited:
stack.append((x+1, y))
have_visited.add((x+1, y))
if y-1 >= 0 and grid[x][y-1] == 1 and (x, y-1) not in have_visited:
stack.append((x, y-1))
have_visited.add((x, y-1))
if y+1 < m and grid[x][y+1] == 1 and (x, y+1) not in have_visited:
stack.append((x, y+1))
have_visited.add((x, y+1))
return counter == 0
if is_isolated():
return 0
for i in range(n):
for j in range(m):
if grid[i][j] == 0:
continue
grid[i][j] = 0
if is_isolated():
return 1
grid[i][j] = 1
return 2
此时,重新提交代码即可通过,评测得到:耗时1816ms,占用内存13.7MB,均属于当前最优值。
给出题目四的试题链接如下:
这一题事实上就是考察能够构成相同二叉查找树的序列总和。我们从中去除掉题中已给出的一个就是我们最终的答案。
考察二叉查找树的序列数目,它可以使用一个递归问题来解决:
因此,对一个二叉查找树,它的输入序列就由三部分组成:
其中,前二者可以通过递归的方式获得,对于最后一个问题,他事实上就是一个插入问题,假设左子树中有n个元素,右子树中有m个元素,则可能的排序方式就有 C n + m n = ( n + m ) ! n ! × m ! C_{n+m}^{n} = \frac{(n+m)!}{n! \times m!} Cn+mn=n!×m!(n+m)!中排序方式。
因此,我们就可以得到最终的答案。
给出代码实现如下:
from math import factorial
class Solution:
def numOfWays(self, nums: List[int]) -> int:
MOD = 10**9 + 7
@lru_cache(None)
def _c(n, m):
return factorial(n) // (factorial(n-m) * factorial(m))
def dp(nums):
if len(nums) <= 1:
return 1
left = [i for i in nums if i < nums[0]]
right = [i for i in nums if i > nums[0]]
ans = (_c(len(nums)-1, len(left)) * dp(left) * dp(right)) % MOD
return ans
return dp(nums) - 1
提交代码评测得到:耗时200ms,占用内存19.1MB。
然而,悲剧的是,实际比赛中我的代码并没能通过。原因在于 C n + m n C_{n+m}^{n} Cn+mn函数我是自己实现的,然后python在求解时出现了精度问题导致在处理高阶的数据当中答案出现了小数,与真实值不一致,然后就GG了。
真的是,算了,就当是吃个教训吧,与君共勉。