leetcode第144场周赛总结

leetcode第144场周赛总结

第一题:5117. IP 地址无效化

给你一个有效的 IPv4 地址 address,返回这个 IP 地址的无效化版本。
所谓无效化 IP 地址,其实就是用 “[.]” 代替了每个 “.”。

示例1:

输入:address = “1.1.1.1”
输出:“1[.]1[.]1[.]1”

示例2:

输入:address = “255.100.50.0”
输出:“255[.]100[.]50[.]0”

提示:

给出的 address 是一个有效的 IPv4 地址

分析:这是个非常简单的题,直接遍历替换就好了。

class Solution(object):
    def defangIPaddr(self, address):
        """
        :type address: str
        :rtype: str
        """
        ans = ""
        for c in address:
            if c == ".":
                ans += "[.]"
            else:
                ans += c
        return ans
第二题:5118. 航班预订统计

这里有 n 个航班,它们分别从 1 到 n 进行编号。
我们这儿有一份航班预订表,表中第 i 条预订记录 bookings[i] = [i, j, k] 意味着我们在从 i 到 j 的每个航班上预订了 k 个座位。
请你返回一个长度为 n 的数组 answer,按航班编号顺序返回每个航班上预订的座位数。

示例:

输入:bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5
输出:[10,55,45,25,25]

提示:

1 <= bookings.length <= 20000
1 <= bookings[i][0] <= bookings[i][1] <= n <= 20000
1 <= bookings[i][2] <= 10000

分析:我个人认为这题的题意表述不是很清晰,所以我自己重述一下题意:有编号为1~n的n个航班,航班记录表中的 bookings[i] = [i, j, k]表示编号为i~j的每个航班上都预定了k个位置。现在要我们按航班编号顺序返回每个航班上预订的座位数。
从提示可以看出测试集有可能非常大,所以用暴力法遍历肯定会超时(因为时间复杂度是O(n2),如下:

class Solution:
    def corpFlightBookings(self, bookings: List[List[int]], n: int) -> List[int]:
        ans = [0] * n
        for item in bookings:
            start = item[0]
            end = item[1]
            for j in range(start-1, end):
                ans[j] += item[2]
        return ans

所以我们得尝试找到时间复杂度为O(n)的解法。可以这样考虑:对于相邻的两个航班,假设编号为a和a+1,假设现在已知最终航班a的预定座位数,考虑一个包含了航班a在内的预定记录,那么对于航班a+1这个预定记录有两种可能,一是包含了航班a+1,二是不包含航班a+1。此外,还需考虑得就是以航班a+1为起始编号的航班记录,这就将航班a与航班a+1在预定记录中的三种可能都考虑到了,即在同一个记录中和分别在两个记录中。那么我们现在在已知了航班a的预定座位数的情况下想求航班a+1的预定座位数,根据上述三种情况,航班a+1的预定座位数=航班a的预定座位数-预定记录中以a为结束编号的记录的预定座位总和+预定记录中以a+1为起始编号的航班记录的预定座位总和。所以我们可以遍历bookings,对于起始航班编号我们将它加上预定座位数,对于结束航班编号,我们将它的后一个航班编号减去预定座位数。这个遍历结束后,我们再将除第一个航班编号外的每一个航班编号加上它前一个航班编号的预定座位数,即得最终答案。时间复杂度是O(n)。

class Solution:
    def corpFlightBookings(self, bookings: List[List[int]], n: int) -> List[int]:
        ans=[0]*n
        for x in bookings:
            ans[x[0]-1]+=x[2]
            if x[1]<n:
                ans[x[1]]-=x[2]
        for i in range(1,n):
            ans[i]+=ans[i-1]
        return ans
第三题:5119. 删点成林

给出二叉树的根节点 root,树上每个节点都有一个不同的值。
如果节点值在 to_delete 中出现,我们就把该节点从树上删去,最后得到一个森林(一些不相交的树构成的集合)。
返回森林中的每棵树。你可以按任意顺序组织答案。

示例:
在这里插入图片描述

输入:root = [1,2,3,4,5,6,7], to_delete = [3,5]
输出:[[1,2,null,4],[6],[7]]

提示:

树中的节点数最大为 1000。
每个节点都有一个介于 1 到 1000 之间的值,且各不相同。
to_delete.length <= 1000
to_delete 包含一些从 1 到 1000、各不相同的值。

分析:看提示中节点数最大为1000,看样子是要用O(n)解法了。此题我的想法是直接层序遍历这个树,对于当前遍历到的节点,判断一下此节点是不是要删除的节点,若是,则再判断它的左右子节点是不是要删除的节点,若不是,则将此子节点作为新树的根节点加入返回结果中;反之,若当前遍历到的节点不是要删除的子节点,则判断一下它的左右子节点是不是要删除的节点,若是,则断开当前节点与此子节点的连接。代码如下,对于初始根节点做特殊考虑,并且为了降低时间复杂度,可先将要删除的节点存于字典中,后续查找起来更高效:

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def delNodes(self, root, to_delete):
        """
        :type root: TreeNode
        :type to_delete: List[int]
        :rtype: List[TreeNode]
        """
        stack = []
        ans = []
        dic = collections.defaultdict(int)
        for num in to_delete:
            dic[num] = 1
        if dic[root.val]:
            if root.left:
                stack.append(root.left)
                if dic[root.left.val] == 0:
                    ans.append(root.left)
            if root.right:
                stack.append(root.right)
                if dic[root.right.val] == 0:
                    ans.append(root.right)
        else:
            stack.append(root)
            ans.append(root)
        while stack:
            cur = stack.pop(0)
            if dic[cur.val]:
                if cur.left:
                    stack.append(cur.left)
                    if dic[cur.left.val] == 0:
                        ans.append(cur.left)
                if cur.right:
                    stack.append(cur.right)
                    if dic[cur.right.val] == 0:
                        ans.append(cur.right)
            else:
                if cur.left:
                    stack.append(cur.left)
                    if dic[cur.left.val]:
                        cur.left = None
                if cur.right:
                    stack.append(cur.right)
                    if dic[cur.right.val]:
                        cur.right = None
        return ans
第四题:5120. 有效括号的嵌套深度

有效括号字符串 仅由 “(” 和 “)” 构成,并符合下述几个条件之一:
(1)空字符串
(2)连接,可以记作 AB(A 与 B 连接),其中 A 和 B 都是有效括号字符串
(3)嵌套,可以记作 (A),其中 A 是有效括号字符串
类似地,我们可以定义任意有效括号字符串 s 的 嵌套深度 depth(S):
(1)s 为空时,depth("") = 0
(2)s 为 A 与 B 连接时,depth(A + B) = max(depth(A), depth(B)),其中 A 和 B 都是有效括号字符串
(3)s 为嵌套情况,depth("(" + A + “)”) = 1 + depth(A),其中 A 是有效括号字符串
例如:"","()()",和 “()(()())” 都是有效括号字符串,嵌套深度分别为 0,1,2,而 “)(” 和 “(()” 都不是有效括号字符串。
给你一个有效括号字符串 seq,将其分成两个不相交的子序列 A 和 B,且 A 和 B 满足有效括号字符串的定义(注意:A.length + B.length = seq.length)。
现在,你需要从中选出任意一组有效括号字符串 A 和 B,使 max(depth(A), depth(B)) 的可能取值最小。
返回长度为 seq.length 答案数组 answer ,选择 A 还是 B 的编码规则是:如果 seq[i] 是 A 的一部分,那么 answer[i] = 0。否则,answer[i] = 1。即便有多个满足要求的答案存在,你也只需返回 一个。

示例1:

输入:seq = “(()())”
输出:[0,1,1,1,1,0]

示例2:

输入:seq = “()(())()”
输出:[0,0,0,1,1,0,1,1]

分析:这题题意有点难懂…它的意思是要我们找出两个子序列,注意不是字串,即可以不连续,让最后的深度最小。我们可以先求出不分组的情况下的最大深度d,在我们将整个字符串分成A,B两组后,最好的情况下我们可以将最大深度缩小一倍。所以我们可以以深度d/2为界,来将这个字符串给划分成两组,当目前深度小于d/2时,划为A组,即对应位置标记为0,反之则将对应位置标记为1。代码如下:

class Solution:
    def maxDepthAfterSplit(self, seq: str) -> List[int]:
        # compute the max depth
        d = h = 0
        for c in seq:
            if c == ')':
                h -= 1
            else:
                h += 1
            d = max(d, h)
        # cut depth in half
        d >>= 1
        r = [0 for _ in range(len(seq))]
        if d == 0:
            return r
        for i, c in enumerate(seq):
            if c == ')': h -= 1
            if h >= d: r[i] = 1
            if c == '(': h += 1
        return r
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值