本周题目不太难。

第一题 5315. 6 和 9 组成的最大数字

简单题。

直接遍历把第一个 6 改成 9 就行。

用 python 很方便,但是需要注意 python 的字符串是不可变的,需要转成 list 方便操作(当然我是从 int 转成 str 再转成了 list)

class Solution:
    def maximum69Number (self, num: int) -> int:
        x = list(str(num))
        for i in range(len(x)):
            if x[i] == '6':
                x[i] = '9'
                break
        return int(''.join(x))

在题目评论里看到别人的解法,太强了

class Solution:
    def maximum69Number (self, num: int) -> int:
        return int(str(num).replace('6','9',1))

第二题 5316. 竖直打印单词

这个远远没有题库里的第 6 题 Z 字形变换 难,这题很靠前,估计很多人都做过吧。

本题目尤其用 python 方便,连去结尾空格都有函数。

class Solution:
    def printVertically(self, s: str) -> List[str]:
        s = s.split(' ')
        max_l = 0
        for w in s:
            max_l = max(max_l, len(w))
        r = [[] for i in range(max_l)]
        for w in s:
            for i in range(max_l):
                if i < len(w):
                    r[i].append(w[i])
                else:
                    r[i].append(' ')
        rr = []
        for x in r:
            rr.append(''.join(x).rstrip())
        return rr

第三题 5317. 删除给定值的叶子节点

本题比赛中的示例 5 刚开始是有问题的:

示例 5:

输入:root = [1,2,3], target = 2
输出:[1,2,3]

让我犹豫了一会。

后来这个 target 改成 1 就对了。

也不难

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

class Solution:
    def removeLeafNodes(self, root: TreeNode, target: int) -> TreeNode:
        def del_t(t):
            if t.left:
                if del_t(t.left):
                    t.left = None
            if t.right:
                if del_t(t.right):
                    t.right = None
            if not t.left and not t.right:
                if t.val == target:
                    return True
            return False
        if del_t(root):
            return None
        return root

第四题 5318. 灌溉花园的最少水龙头数目

这题目 18 年初实习面试的时候被问过。线段覆盖问题。贪心算法。面试的时候我想的使用递归方法,这次写的是迭代。

思路是:
先把每个水龙头的范围转化成区间,弄成一个区间数组。
比如 示例 1

1685_example_1.png

转换成:

[[0, 3], [0, 5], [1, 3], [2, 4]]

这里做了两个优化:

  1. 长度为零的就忽略了
  2. 超出 0 到 n 范围的就截止到 [0, n] 区间内

然后我们可以在按照区间的左端点排序。(上面的数组已经是这个顺序了)

其实另外还有一个优化:如果一个区间被另一个区间完全覆盖了,那这个区间也是无效的,应该删掉,例如 [1, 3] 完全落在 [0, 3] 内。

结果这里就只剩下 [0, 5] 了:
[[0, 5]]

所以这个例子不好,可以看下示例 3

n = 7, ranges = [1,2,1,0,2,1,0,1]

经过上述操作后剩下的区间其实也只有刚好三个了:
[(0, 3), (2, 6), (6, 7)]
所以干脆去掉

之后的做法是:

如果这个区间数量是 0 或者第一个区间不能覆盖 0,直接返回 -1
然后就开始贪心:

  1. 第一个区间必选,ans 变量计已选的区间数
  2. 判断是否可以覆盖,如果可以,返回 ans
  3. 从下一个区间开始,所有可以选择的区间(如果这个区间的左端点小于等于上一个选中区间的右端点,就可以选)中找一个右端点最大的,选择,如果没有可选的,返回 -1

这个代码写的不够精炼

class Solution:
    def minTaps(self, n: int, ranges: List[int]) -> int:
        # ranges 转化为区间
        seg = []
        for i in range(n+1):
            if ranges[i] > 0:
                seg.append((max(0, i - ranges[i]), min(n, i + ranges[i])))
        # 去掉被其他区间覆盖的区间
        s2 = {}
        for s in seg:
            if s[0] not in s2:
                s2[s[0]] = []
            s2[s[0]].append(s)
        seg = []
        for k in s2:
            t = s2[k][0]
            for xx in s2[k]:
                if xx[1] > t[1]:
                    t = xx
            seg.append(t)
        s2 = {}
        for s in seg:
            if s[1] not in s2:
                s2[s[1]] = []
            s2[s[1]].append(s)
        seg = []
        for k in s2:
            t = s2[k][0]
            for xx in s2[k]:
                if xx[0] < t[0]:
                    t = xx
            seg.append(t)
            
            
        seg.sort(key=lambda x: x[0]) # 按区间左端点排序
 
        
        if not seg or seg[0][0] != 0: # 区间数量是 0 或者第一个区间不能覆盖 0,直接返回 -1
            return -1
        
        i = 0
        ans = 1
        while seg[i][1] != n:
            nx = i
            j = 1 + i
            while j < len(seg) and seg[j][0] <= seg[i][1]:
                if seg[nx][1] < seg[j][1]:
                    nx = j
                j += 1
            if nx == i:
                return -1
            ans += 1
            i = nx
        return ans

谢谢阅读

欢迎访问我的博客 https://codeplot.top/

我的博客的刷题分类


sxwxs
292 声望21 粉丝

计算机专业学生