【周赛总结】子树中标签相同的节点数,最多不重复子字符串,找到最接近目标值的函数值

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值