Leetcode Weekly Contest 188

今天的周赛题目挺有意思的。

5404. 用栈操作构建数组

思路:
如果一个数在最后的数组里,只push;不在最后的数组里面,先push再pop

class Solution:
    def buildArray(self, target: List[int], n: int) -> List[str]:
        res = []
        cur = 1
        for x in target:
            while cur != x:
                res.append('Push')
                res.append('Pop')
                cur += 1
            res.append('Push')
            cur += 1
        return res

5405. 形成两个异或相等数组的三元组数目

思路:
类似前缀和的想法,将前n个数的异或和存储下来,例如 s u m [ i ] = a r r [ 0 ] ∧ a r r [ 1 ] ∧ . . . ∧ a r r [ i ] sum[i]= arr[0] \land arr[1] \land ... \land arr[i] sum[i]=arr[0]arr[1]...arr[i],那么从ij的异或和为 s u m [ i − 1 ] ∧ s u m [ j ] sum[i-1] \land sum[j] sum[i1]sum[j],另外0和任何数x异或和为x

class Solution:
    def countTriplets(self, arr: List[int]) -> int:
        pre_sum = [0]
        tmp = 0
        for x in arr:
            tmp ^= x
            pre_sum.append(tmp)
        res = 0
        for i in range(1,len(arr)):
            for k in range(i+1, len(arr)+1):
                for j in range(i+1,k+1):
                    a = pre_sum[i-1] ^ pre_sum[j-1]
                    b = pre_sum[k] ^ pre_sum[j-1]
                    if a==b:
                        res += 1
        return res

5406. 收集树上所有苹果的最少时间

思路:
类似层次遍历,对于每一个需要遍历的节点,从下向根节点回溯;如果该节点没有走过,结果加2,将该节点的父节点加入待遍历的节点;如果之前走过则,则忽略。
对于样例1
在这里插入图片描述

初始时 需要遍历(2,4,5);依次遍历,每次路径长度结果+2,然后将对应的父节点(1,0)加入待遍历节点;此时结果为6;
现在需要遍历(1,0),对于0已经是根节点,可以跳过;对于1,结果+2,将对应的父节点(0)加入待遍历节点;此时结果为8;
最后只剩下(0),跳过。最终结果为8。

class Solution:
    def minTime(self, n: int, edges: List[List[int]], hasApple: List[bool]) -> int:
        res = 0
        # 记录每个节点对应的子节点和父节点关系
        children = collections.defaultdict(list)
        father = [-1]*len(hasApple)
        for x in edges:
            children[x[0]].append(x[1])
            father[x[1]] = x[0]
        has_check = set()
        apple_id = []
        for i,x in enumerate(hasApple):
            if x:
                apple_id.append(i)
        t = apple_id
        # 宽搜来进行从下向上依次遍历
        while len(t) > 0:
            # 记录每个节点的父节点
            tt = set()
            for x in t:
                # 当前节点为根节点,跳过
                if x==0:
                    continue
                # 当前节点没有以前没有遇到。将其父节点加入待遍历节点,当前节点置为已遍历到。
                elif x not in has_check:
                    tt.add(father[x])
                    has_check.add(x)
                    res += 2
            # print(t,tt,res)
            t = list(tt)
        return res

5407. 切披萨的方案数

思路:
比较容易想到的方法是直接搜索,递归实现深度优先搜索进行寻找。直接暴力搜索会超时,加入简单的剪枝操作和记忆化搜索可以过。之后想了会用动态规划应该是比较直观的方法,但是动态规划和记忆化的搜索本质上没有太大的区别,都是记录了中间过程的最优方案。
因为每次切完都是拿掉左边和上边的部分,剩余右下的部分,因此可以用剩余pizza的左上角的点的位置,来形象的表示切pizza的操作。
横向切pizza即改变左上角的横坐标,纵向切pizza即改变左上角的纵坐标。
搜索剪枝:对于剩余的pizza,如果横切和纵切所有的可能方案数比k-1小,那么不可能将当前剩余的pizza切成k份。
记忆化:对于同一个pizza,(i,j,k) 可以唯一标识 剩余的pizza需要被切成k份的方案数量。

class Solution:
    def __init__(self):
        self.counter = {}
    
    def cut(self,pizza,i,j,k):
        # 记忆化搜索
        if (i,j,k) in self.counter:
            return self.counter[(i,j,k)]
        # 递归终止条件
        if k==1:
            # 当前pizza只需要分成1份,只需要判断是否包含苹果('A')
            for r in range(i,len(pizza)):
                for c in range(j,len(pizza[0])):
                    if pizza[r][c] == 'A':
                        # print(i,j,r,c)
                        self.res += 1
                        return 1
            return 0
        # 剪枝
        if len(pizza)-i-1 + len(pizza[0])-j-1 < k-1:
            return 0
        num = 0
        # 切的话需要满足上面或者左边的部分包含苹果('A')
        # 从上向下遍历,如果前面的行已经出现苹果,之后的行可以省略判断。因此用flag标志是否出现苹果。
        flag = False
        for m in range(i,len(pizza)-1):
            if flag:
                num += self.cut(pizza,m+1,j,k-1)
            else:
                for c in range(j,len(pizza[0])):
                    if pizza[m][c] == 'A':
                        flag = True
                        break
                if flag:
                    num += self.cut(pizza,m+1,j,k-1)
        flag = False
        for m in range(j,len(pizza[0])-1):
            if flag:
                num += self.cut(pizza,i,m+1,k-1)
            else:
                for r in range(i,len(pizza)):
                    if pizza[r][m] == 'A':
                        flag = True
                        break
                if flag:
                    num += self.cut(pizza,i,m+1,k-1)
        self.counter[(i,j,k)] = num
        return num

    def ways(self, pizza: List[str], k: int) -> int:
        return (self.cut(pizza,0,0,k) % int(1e9 + 7))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值