0%

LeetCode 第 204 场周赛

5499. 重复至少 K 次且长度为 M 的模式

垃圾题解 略

垃圾代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution:
def containsPattern(self, arr: List[int], m: int, k: int) -> bool:
print('ohhh')
n = len(arr)
if m * k > n: return False
for i in range(n - m + 1):
a = arr[i : i + m]
c = 1
j = i + m
while j <= n - m:
kk = 0
while kk < m and a[kk] == arr[j + kk]: kk += 1
if kk == m: c += 1
else: break
j += kk
# print(str(i) + " " + str(c) + "-----")
if c >= k: return True
return False

5500. 乘积为正数的最长子数组长度

垃圾题解 略

垃圾代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution:
def getMaxLen(self, nums: List[int]) -> int:
l0, l1, l_1 = -1, 0, -1
flag = False
res = 0
for i in range(len(nums)):
n = nums[i]
if n == 0:
l0 = i
l1 = i + 1
l_1 = -1
flag = False
else:
if n < 0:
flag = not flag
if l_1 == -1: l_1 = i
if flag and l_1 != -1: res = max(res, i - l_1)
elif not flag: res = max(res, i - l1 + 1)
# print(res, end=' ')
# print('----')
return res

5501. 使陆地分离的最少天数

垃圾题解

求把一个连通分量拆成俩的最小切割次数. 这题撑死最多切两次 (即当图有三个及以上的点时, 图的边缘必存在只有两条边的点).

先遍历一遍全图, 如果本来就有不止一个分量, 直接返回 0.

然后判断一个特例: 连通分量就一个, 但该分量就两个点. 这样的话删除一个后依然是一个连通分量. 所以要删两次, 返回 2.

然后遍历所有点, 如果找到一个点只有一条边, 返回 1; 如果找到有点有两条边, 则临时删除该点, DFS 遍历全图判断是不是变成了两个分量, 是则返回 1 (不要问我什么割点、什么 Tarjan, 爷忘光啦. 反正我赌 LeetCode 会让我过).

剩下的情况直接返回 2.

垃圾代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Solution:
def minDays(self, grid: List[List[int]]) -> int:
n, m = len(grid), len(grid[0])
cnt1 = 0
vis = [[False] * m for _ in range(n)]
def dfs(g, v, x, y):
if v[x][y]: return True
v[x][y] = True
if x > 0 and g[x - 1][y] == 1 and not v[x - 1][y]: dfs(g, v, x - 1, y)
if y > 0 and g[x][y - 1] == 1 and not v[x][y - 1]: dfs(g, v, x, y - 1)
if x < len(g) - 1 and g[x + 1][y] == 1 and not v[x + 1][y]: dfs(g, v, x + 1, y)
if y < len(g[0]) - 1 and g[x][y + 1] == 1 and not v[x][y + 1]: dfs(g, v, x, y + 1)
flag = False
for i in range(n):
for j in range(m):
if grid[i][j] == 1: cnt1 += 1
if grid[i][j] == 1 and not vis[i][j]:
if flag: return 0
flag = True
dfs(grid, vis, i, j)
if cnt1 == 2: return 2
for i in range(n):
for j in range(m):
if grid[i][j] == 0: continue
c = []
if i > 0 and grid[i - 1][j] == 1: c.append((i - 1, j))
if j > 0 and grid[i][j - 1] == 1: c.append((i, j - 1))
if i < n - 1 and grid[i + 1][j] == 1: c.append((i + 1, j))
if j < m - 1 and grid[i][j + 1] == 1: c.append((i, j + 1))
if len(c) == 1: return 1
if len(c) != 2: continue
grid[i][j] = 0
for ii in range(n):
for jj in range(m):
vis[ii][jj] = False
dfs(grid, vis, c[0][0], c[0][1])
if not vis[c[1][0]][c[1][1]]: return 1
grid[i][j] = 1
return 2

5502. 将子数组重新排序得到同一个二叉查找树的方案数

垃圾题解

给一棵二叉查找树, 问有多少种方法产生此树 (即求可行的输入顺序的个数 - 1).

根节点必为输入的第一个. 剩下的, 左右子树互不影响, 可以随意穿插 (只要左子树的顺序之间、右子树的顺序之间的顺序不变即可).

所以 输入顺序个数 = 左子树输入顺序个数 * 右子树输入顺序个数 * 左右子树所有穿插的可能数, 其中 左右子树所有穿插的可能数 = C(总结点数 - 1, 左或右子树节点个数).

垃圾代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import math
class Solution:
def numOfWays(self, nums: List[int]) -> int:
def comb(n, m):
return math.factorial(n)//(math.factorial(n-m)*math.factorial(m))
MOD = int(10 ** 9 + 7)
def dfs(arr):
n = len(arr)
if n <= 2: return 1
left, right = [], []
for i in range(1, n):
if arr[i] < arr[0]: left.append(arr[i])
else: right.append(arr[i])
l, r = len(left), len(right)
return dfs(left) * dfs(right) * comb(n - 1, l) % MOD
return dfs(nums) - 1