2020/07/19 rank:492/5779 AC: 2/4
这次的题目比较难,只A了两道。
第二题,子树中标签相同的节点数
方法是采用DFS的方法处理树有关的问题,这道题目的难点在于如何保存子树的信息。同时需要注意是一个无向图。
首先我们要记录一个集合visit
这个集合表示了已经访问的节点,可以防止子节点重新回到父节点从而进入死循环。同时我们每次查找一个节点的子函数要返回这个子树保存的全部字典信息。因此要注意字典的更新。
class Solution:
def countSubTrees(self, n: int, edges: List[List[int]], labels: str) -> List[int]:
tree = collections.defaultdict(list)
for a, b in edges:
tree[a].append(b)
tree[b].append(a)
visit = set()
ans = [0]*n
def dfs(x):
# 每次进入一个新的递归函数时候,都需要重新初始化字典,最终返回的字典是这个包含这个节点子树的信息。
dic = collections.defaultdict(int)
visit.add(x)
for next in tree[x]:
if next in visit:
continue
cur = dfs(next)
for item in cur:
dic[item] += cur[item]
dic[labels[x]] += 1
ans[x] = dic[labels[x]]
return dic
dfs(0)
return ans
第三题,最多不重复子字符串
这个题目在比赛时候没有做出来,但是思路是正确的,考虑的贪心的思路。这个题目由三个限制,第一个是保证某全部字符都被囊括,第二是除了这个字符其余的字符也都被囊括其中,三是在满足最优解之后要求总长度最大。
解决第一个问题需要维护一个字典,保存每个字符的起始位置和终止位置。第二个问题比较麻烦,需要进行枚举,对于不同的字符就要进行囊括,第三个问题可以采用贪心的方法,依次选择长度最小且不重叠的。
class Solution:
def maxNumOfSubstrings(self, s: str) -> List[str]:
# 第一个问题,存储每个节点的起始和终止位置
dic = {}
for i in range(len(s)):
word = s[i]
if word not in dic:
dic[word] = [i, i]
else:
dic[word][1] = i
# 依次考虑是否囊括了新的字符,要加入合并区间
has = {}# 避免重复计算
for word in dic.keys():
has.clear()
has = {word}
be = i = dic[word][0]
end = dic[word][1]
# 这里采用了while循环,因为我们会时刻变化end和i的数值
while i<end:
newword = s[i]
if newword not in has:
has.add(newword)
if be>dic[newword][0]:
be = i = dic[newword][0]
end = max(end, dic[newword][1])
i += 1
dic[word] = [be, end]
# 第三步按照贪心的思路,依次选择长度小的子串
lis = list(dic.values())
lis.sort(key = lambda x:(x[1]-x[0]))
ans = []
visit = [0]*len(s) # 用于维护这个位置是否已经被使用,不能只维护区间头,因为可能有[2,3],[6,7]
for i in range(len(lis)):
be, end= lis[i]
cur = visit[:]
flag = 0
for j in range(be, end+1):
if cur[j] == 1:
flag = 1
break
cur[j] = 1 # 进行尝试性修改
if flag == 0:
ans.append(s[be:end+1])
visit = cur[:]
return ans
第四题,找到最接近目标值的函数值
题目的本质是计算了一个区间内数字与和,得到与target
的最小差。
需要注意两个特点,一个是不停的与是单调的,越与越小,另外一个是,[l, r+1]区间的与是[l, r]区间的与在与上s[r+1]。
class Solution:
def closestToTarget(self, arr: List[int], target: int) -> int:
ans = abs(arr[0]-target)
arr = list(set(arr))
for l in range(len(arr)):
nums = arr[l]
for r in range(l, len(arr)):
nums &= arr[r]
ans = min(ans, abs(target-nums))
if nums <=target:
break
return ans