比赛感想
这次比赛血崩。。。第一题一直没通过心态爆炸,然后到最后就通过第四题,分数又降了不少。。赛后回顾了一下,第一题是因为没有初始化,提交解答后的测试应该是创建了一个实例,然后测试多个样例。第二题是个树的题目,不是很难,刚开始时没看懂题目,看了函数的返回值才知道要做什么,第三题想了很久都没想出来,看了别人的代码,别人是真的厉害,写的代码真的很巧妙,第四题是比较基础的状压dp。
第一题 数组的相对排序
题目大意
给了两个数组arr1和arr2,对 arr1
中的元素进行排序,使 arr1
中项的相对顺序和 arr2
中的相对顺序相同。未在 arr2
中出现过的元素需要按照升序放在 arr1
的末尾。
解题思路
因为0 <= arr1[i], arr2[i] <= 1000,对arr1进行排序,重载compare函数即可。
代码如下
class Solution:
dic_ys = {}
maxx = 0
#自定义key
def customKey(self, x):
if x in self.dic_ys:
return self.dic_ys[x]
else:
return x + self.maxx
#初始化
def init(self):
self.dic_ys = {}
self.maxx = 0
def relativeSortArray(self, arr1, arr2):
self.init()
for i in range(0, len(arr2)):
self.dic_ys[arr2[i]] = i
for each in arr1:
self.maxx = max(self.maxx, each)
return sorted(arr1, key=self.customKey)
第二题 最深叶节点的最近公共祖先
题目大意
给你一个有根节点的二叉树,找到它最深的叶节点的最近公共祖先。
解题思路
先确定树的最大深度是多少,然后再从根节点遍历这棵树,返回左子树中达到最大深度的叶子数量+右子树中达到最大深度的叶子数量,第一个到达树的最大深度的叶子数量总量的节点即为最近公共祖先,详细见代码。
代码如下
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.depth = 0
self.ans = None
self.max_sum = 0
#确定最大深度
def findDepth(self, root: TreeNode) -> int:
if root == None:
return 0
return max(self.findDepth(root.left), self.findDepth(root.right)) + 1
#遍历树
def travelTree(self, root: TreeNode, now_depth: int) -> int:
if root == None:
return 0
now_sum = 0
if now_depth == self.depth:
now_sum = 1
else:
now_sum = self.travelTree(root.left, now_depth + 1) + self.travelTree(root.right, now_depth + 1)
#如果数量比记录的最深叶节点数量大则更新,遍历完树后的self.max_sum即为总最深叶节点数量
if now_sum > self.max_sum:
self.max_sum = now_sum
self.ans = root
return now_sum
#初始化
def initValue(self):
self.depth = 0
self.ans = None
self.max_sum = 0
def lcaDeepestLeaves(self, root: TreeNode) -> TreeNode:
self.initValue()
self.depth = self.findDepth(root)
self.travelTree(root, 1)
return self.ans
第三题 表现良好的最长时间段
题目大意
给你一份工作时间表 hours
,上面记录着某一位员工每天的工作小时数。
工作小时数大于 8
小时的时候是「劳累的一天」。
所谓「表现良好的时间段」,意味在这段时间内,「劳累的天数」是严格 大于「不劳累的天数」。
返回「表现良好时间段」的最大长度。
解题思路
劳累的一天为1,不劳累的天数为-1,sum_day[i]即为1~i的劳累天数减去不劳累天数,要求i~j天的劳累天数减去不劳累天数即为sum_day[j]-sum_day[i-1]。现要求「劳累的天数」是严格 大于「不劳累的天数」,即sum_day[j]-sum_day[i-1]>0,即sum_day[j]>sum_day[i-1].确定左端节点为i,现需确定右端节点j,如果遍历,则时间复杂度仍为O(n^2);现在我们是需要越多越好,故生成一个max_day数组表示在1~i天之后的最大值。
用一张图表示一下
在确定左端节点为i后,然后就可以对j使用二分了,j从i+1到length,如果max_day[j]>sum_day[i-1],则在j至length中找,否则在i+1至j-1中找,具体实现看代码,时间复杂度O(nlogn)。
代码如下
class Solution:
def longestWPI(self, hours) -> int:
#sum_day[i]表示劳累的天数大于不劳累天数的数量
sum_day = [0]
for i in range(0, len(hours)):
if hours[i] > 8:
sum_day.append(1)
else:
sum_day.append(-1)
sum_day[i + 1] += sum_day[i]
sum_day.append(-99999)
#max_day[i]表示在1~(i天后(包括第i天))的最大值
max_day = [-99999 for i in range(0, len(hours) + 2)]
for i in range(len(hours), -1, -1):
max_day[i] = max(sum_day[i], max_day[i + 1])
ans = 0
for i in range(0, len(hours) + 1):
#用二分处理满足条件的最大值
l, r = i + 1, len(hours) + 1
while l < r:
mid = (l + r) // 2 + 1
#天数为mid-i,表示在从第i+1天到mid天的劳累天数大于不劳累天数的数量
if max_day[mid] > sum_day[i]:
l = mid
else:
r = mid - 1
if max_day[l] > sum_day[i]:
ans = max(ans, l - i)
return ans
第四题 最小的必要团队
题目大意
每个人都有一些技能,团队需要某部分技能,现挑选一些人满足团队的技能需求,要求人数最少。
解题思路
因为req_skills.length <= 16,所以这个敏感的数字就想到了状态压缩dp,2^16 = 65536。把对应的技能转换成二进制位上的数字。状态转移方程f[j | people_skill[i]] = min(f[j] + 1,f[j | people_skill[i]])表示j的状态上加上第i个人的技能可以从j状态转化过来。
代码如下
class Solution:
def smallestSufficientTeam(self, req_skills: List[str], people: List[List[str]]) -> List[int]:
people_skill = [0 for i in range(len(people))]
#计算每个人技能对应的二进制值
for i in range(len(people)):
for each_skill in people[i]:
for j in range(len(req_skills)):
if each_skill == req_skills[j]:
people_skill[i] += 1 << j
f = [999 for i in range(2**len(req_skills))]
last = [-1 for i in range(2**len(req_skills))]
getpeople = [-1 for i in range(2**len(req_skills))]
f[0] = 0
for i in range(len(people)):
for j in range(2**len(req_skills)):
#状态转移
if f[j] + 1 < f[j | people_skill[i]]:
f[j | people_skill[i]] = f[j] + 1
last[j | people_skill[i]] = j
getpeople[j | people_skill[i]] = i
#求序列
now = 2**len(req_skills) - 1
ans = []
while last[now] != -1:
ans.append(getpeople[now])
now = last[now]
return ans