Leetcode weekly 198

换酒问题

原题链接
在这里插入图片描述
没啥好说的,直接模拟就行,停止循环的条件就是没有酒了

class Solution:
    def numWaterBottles(self, numBottles: int, numExchange: int) -> int:
        remain=0 #换酒之后还有多少空瓶
        ans=0 #答案
        while numBottles:
            ans+=numBottles
            numBottles,remain=(numBottles+remain)//numExchange,(numBottles+remain)%numExchange
        return ans

子树中标签相同的节点数

在这里插入图片描述
本质是dfs,通过dfs建立子树中各个标签的计数,进而更新ans数组
本题中存在一个测试用例

4,[[0,2],[0,3],[2,1]],'aeed'

即如图所示,使得不能建立parent-children关系而是建立graph关系,利用visited来确定是否访问过该节点
在这里插入图片描述

class Solution:
    def countSubTrees(self, n: int, edges: List[List[int]], labels: str) -> List[int]:
        ans=[0 for _ in range(n)]
        graph=collections.defaultdict(list)
        for a,b in edges:
            graph[a].append(b)
            graph[b].append(a)
        #建立graph,储存关系
        visited=set()
        def helper(node,labels):
            visited.add(node)#标记访问
            child=[ 0 for _ in range(26)]#初始化结果
            child[ord(labels[node])-ord('a')]+=1
            '''
           	在没有发现上述测试用例之前写的,类似于if not children的递归结束语句
           	由于有visited集合之后可以删去
            if not graph[node]:
                ans[node]+=1 
                return child
            '''
            for nxt in graph[node]:
                if nxt not in visited:
                    for i,val in enumerate(helper(nxt,labels)):
                    #递归求子数组中各标签计数
                        child[i]+=val
                
            ans[node]+=child[ord(labels[node])-ord('a')]
            return child
        #递归调用
        helper(0,labels)
        return ans

最多的不重叠子字符串

在这里插入图片描述
第一步:求满足第二个条件的子串
第二步:以贪心的方法,由短到长选取符合字符串
在这里插入图片描述
结合上图讲解第一步

class Solution:
    def maxNumOfSubstrings(self, s: str) -> List[str]:
        show=collections.defaultdict(list)
        #step 1 求满足第二个条件的子串
        for i,ch in enumerate(s):
            show[ch].append(i)
        # 记录各个字母及其出现位置
        interval=[]
		# 对每个字母进行遍历
        for ch in show:
            flag=True
            l,r=show[ch][0],show[ch][-1]
            #试图确定以l为起点的区间是否满足第二个条件
            #对[l,r]区间进行遍历
            k=l+1
            while k<r+1:
                ch2=s[k]
                if show[ch2][0]<l:
                #说明该区间已经被使用,即上图中字符‘b’的情形
                    flag=False
                    break
                r=max(r,show[ch2][-1])#是否需要拓展右端点
                k+=1
            if flag:
                interval.append([l,r])
        #step 2 贪心选取子串
        interval.sort(key=lambda x:x[1]-x[0])
        ans=[]
        for inter1 in interval:
            flag=True
            for inter2 in ans:
                if inter1[0]<inter2[0] and inter1[1]>inter2[1]:
                    flag=False
                    break
            if flag:
                ans.append(inter1)
        
        return [s[a:b+1] for a,b in ans]

找到最接近目标值的函数值

在这里插入图片描述
比赛的时候以为是选取l,r两个数,然后想到trie于是没想出来orz
结果比完了看到是区间…星际玩家不要刷leetcode
出来看了别人的题解发现了一个特别巧妙的解法,使用了前缀+集合去重的方法

class Solution:
    def closestToTarget(self, arr: List[int], target: int) -> int:
        ans=abs(arr[0]-target)
        prev=set()
        prev.add(arr[0])
        for ni in arr:
            prev={ni & num for num in prev} 
            prev.add(ni)
            ans=min(ans, min( abs(num-target) for num in prev))
        return ans

试着在本地跑了一下代码,arr给的是打乱的range(10**5),发现前缀集合最大长度也只有9,很难上10,就算是顺序的也只有17.
想了一下原因是:
假如arr[i]中第k位为0,那么之后的前缀和中所有的数第k位都为0,这就限制了前缀的长度不超过 l o g 2 N + 1 log_{2}N+1 log2N+1
使用的数据为打乱的range(10**5)
使用的数据为不打乱的range(10**5)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值