比赛感想
做出了三题,掉分应该不会掉,最后一题没做出来,这次难度还行。第一题又把题目理解错了,挂了一次。。还得加油呀=,=
第一题 等价多米诺骨牌对的数量
题目大意
给你一个由一些多米诺骨牌组成的列表 dominoes,dominoes[i] = [a, b]
和 dominoes[j] = [c, d]
等价的前提是 a==c
且 b==d
,或是 a==d
且 b==c
。现求等价的骨牌对 (i, j)
的数量。
解题思路
每个多米诺骨牌的a,b,若a>b,将其换位,按第一列排序,在第一列相等的情况下排序第二列。相等的多米诺骨牌x块,则骨牌对数为x*(x - 1) / 2。
代码如下
class Solution:
def numEquivDominoPairs(self, dominoes: List[List[int]]) -> int:
for i in range(0, len(dominoes)):
if dominoes[i][1] < dominoes[i][0]:
(dominoes[i][0], dominoes[i][1]) = (dominoes[i][1], dominoes[i][0])
dominoes = sorted(dominoes, key = lambda a:a[1])
dominoes = sorted(dominoes, key= lambda a:a[0])
i = 0
sum = 0
while i + 1 < len(dominoes):
ls_sum = 1
while i + 1 < len(dominoes) and dominoes[i] == dominoes[i + 1]:
ls_sum += 1
i += 1
sum += ls_sum * (ls_sum - 1) // 2
i += 1
return sum
第二题 颜色交替的最短路径
题目大意
在一个有向图中,节点分别标记为 0, 1, ..., n-1
。这个图中的每条边不是红色就是蓝色,且存在自环或平行边。
red_edges
中的每一个 [i, j]
对表示从节点 i
到节点 j
的红色有向边。类似地,blue_edges
中的每一个 [i, j]
对表示从节点 i
到节点 j
的蓝色有向边。
返回长度为 n
的数组 answer
,其中 answer[X]
是从节点 0
到节点 X
的最短路径的长度,且路径上红色边和蓝色边交替出现。如果不存在这样的路径,那么 answer[x] = -1
。
解题思路
我们可以用f[i][0]表示通过red道路到 i 这个点的最短路径,f[i][1]表示通过blue道路到 i 这个点的最短路径,用广度优先搜索即可。
代码如下
class Solution:
def shortestAlternatingPaths(self, n: int, red_edges: List[List[int]], blue_edges: List[List[int]]) -> List[int]:
red_edge = [set() for i in range(n)]
blue_edge = [set() for i in range(n)]
f = [[None, None] for i in range(n)]
f[0] = [0, 0]
for each in red_edges:
red_edge[each[0]].add(each[1])
for each in blue_edges:
blue_edge[each[0]].add(each[1])
#从0开始
now_arrived_red = [0]
now_arrived_blue = [0]
step = 0
#广搜
while len(now_arrived_red) > 0 or len(now_arrived_blue) > 0:
new_arrived_blue = []
new_arrived_red = []
step += 1
for point in now_arrived_red:
for path in blue_edge[point]:
if f[path][1] == None:
f[path][1] = step
new_arrived_blue.append(path)
for point in now_arrived_blue:
for path in red_edge[point]:
if f[path][0] == None:
f[path][0] = step
new_arrived_red.append(path)
now_arrived_blue = new_arrived_blue
now_arrived_red = new_arrived_red
#获得答案
ans = []
for i in range(n):
point_ans = -1
if f[i][0] != None:
point_ans = f[i][0]
if f[i][1] != None:
if point_ans == -1:
point_ans = f[i][1]
else:
point_ans = min(point_ans, f[i][1])
ans.append(point_ans)
return ans
第三题 叶值的最小代价生成树
题目大意
给你一个正整数数组 arr
,考虑所有满足以下条件的二叉树:
- 每个节点都有 0 个或是 2 个子节点。
- 数组
arr
中的值与树的中序遍历中每个叶节点的值一一对应。(知识回顾:如果一个节点有 0 个子节点,那么该节点为叶节点。) - 每个非叶节点的值等于其左子树和右子树中叶节点的最大值的乘积。
在所有这样的二叉树中,返回每个非叶节点的值的最小可能总和。
解题思路
这题的关键是数组arr中的值与树的中序遍历中的值一一对应,这表示数组arr的顺序不能换。我们可以用f[i][j]表示从i到j的叶子构成的树中所有非叶节点的值的和的最小值。转移方程式:f[i][j] = min(f[i][j],f[i][k] + f[i][k+1][j] + max_leaf[i][k] * max_leaf[k+1][j]),时间效率为O(n^3)。
代码如下
class Solution:
def mctFromLeafValues(self, arr: List[int]) -> int:
f = [[None for i in range(len(arr))] for j in range(len(arr))]
max_leaf = [[0 for i in range(len(arr))] for j in range(len(arr))]
for i in range(len(arr)):
for j in range(i, len(arr)):
max_leaf[i][j] = max(max_leaf[i][j - 1], arr[j])
for i in range(len(arr)):
f[i][i] = 0
for length in range(2, len(arr) + 1):
for i in range(0, len(arr) - length + 1):
j = i + length - 1
for k in range(i, j):
if f[i][j] == None:
f[i][j] = f[i][k] + f[k + 1][j] + max_leaf[i][k] * max_leaf[k + 1][j]
else:
f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + max_leaf[i][k] * max_leaf[k + 1][j])
return f[0][len(arr) - 1]
第四题 绝对值表达式的最大值
题目大意
给你两个长度相等的整数数组,返回下面表达式的最大值:
|arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + |i - j|
解题思路
|arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + |i - j|
默认i > j则 原式 = |arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + i - j
|arr1[i] - arr1[j]| = max(arr1[i] - arr1[j], arr1[j] - arr1[i])
|arr2[i] - arr2[j]| = max(arr2[i] - arr2[j], arr2[j] - arr2[i])
原式 = max(arr1[i] - arr1[j], arr1[j] - arr1[i]) + max(arr2[i] - arr2[j], arr2[j] - arr2[i]) + i - j
原式 = max(arr1[i] - arr1[j] + arr2[i] - arr2[j] + i - j,
arr1[i] - arr1[j] + arr2[j] - arr2[i] + i - j,
arr1[j] - arr1[i] + arr2[i] - arr2[j] + i - j,
arr1[j] - arr1[i] + arr2[j] - arr2[i] + i - j)
原式 = max((arr1[i] + arr2[i] + i) - (arr1[j] + arr2[j] + j),
(arr1[i] - arr2[i] + i) - (arr1[j] - arr2[j] + j),
(-arr1[i] + arr2[i] + i) - (-arr1[j] + arr2[j] + j),
(-arr1[i] - arr2[i] + i) - (-arr1[j] - arr2[j] + j))
故用四种情况算最大值即可。
代码如下
class Solution:
def maxAbsValExpr(self, arr1: List[int], arr2: List[int]) -> int:
'''
原式 = max(arr1[i] - arr1[j], arr1[j] - arr1[i]) + max(arr2[i] - arr2[j], arr2[j] - arr2[i]) + i - j
= max(arr1[i] - arr1[j] + arr2[i] - arr2[j] + i - j,
arr1[i] - arr1[j] + arr2[j] - arr2[i] + i - j,
arr1[j] - arr1[i] + arr2[i] - arr2[j] + i - j,
arr1[j] - arr1[i] + arr2[j] - arr2[i] + i - j)
= max((arr1[i] + arr2[i] + i) - (arr1[j] + arr2[j] + j),
(arr1[i] - arr2[i] + i) - (arr1[j] - arr2[j] + j),
(-arr1[i] + arr2[i] + i) - (-arr1[j] + arr2[j] + j),
(-arr1[i] - arr2[i] + i) - (-arr1[j] - arr2[j] + j))
:param arr1:数组1
:param arr2:数组2
:return: |arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + |i - j| 最大值
'''
ans = -99999999999
for operator1 in [-1, 1]:
for operator2 in [-1, 1]:
minn = None
for i in range(len(arr1)):
value = arr1[i] * operator1 + arr2[i] * operator2 + i
if i == 0:
minn = value
else:
minn = min(minn, value)
ans = max(ans, value - minn)
return ans