周赛 334 题解

plus2047 于 2023-02-26 发布

最近一段时间非常繁忙,周赛已经鸽了好几周了,再鸽下去这事怕是没了。本周周赛中规中矩。

1.

image

按照题目要求操作即可。生成一个前缀和,一个后缀和,然后做减法。

class Solution:
    def leftRigthDifference(self, nums: List[int]) -> List[int]:
        n = len(nums)
        left, right = [0] * n, [0] * n
        for i in range(n - 1):
            left[i + 1] = nums[i] + left[i]
            right[-i - 2] = nums[-i - 1] + right[-i - 1]
        return [abs(x - y) for x, y in zip(left, right)]

2.

image

这个题目需要利用一个恒等式:x * 10 % m = x % m * 10 % m. 证明不难,注意等式右边 x % m = x - k * m 然后 x % m * 10 % m = x * 10 % m - k * m * 10 % m 第二项显然等于 0.

当然并不是之前学习过这个恒等式,而是这个题目与前缀和高度相似,所以怀疑可以使用前缀和相似的方法求解。

class Solution:
    def divisibilityArray(self, word: str, m: int) -> List[int]:
        pre = 0
        res = []
        for c in word:
            pre = pre * 10 + int(c)
            pre %= m
            res.append(int(pre == 0))
        return res

3.

image

这个题目主要是要想到是使用二分法(二分答案)求解。如果不使用二分法,很难找到一个配对策略。

借助二分法,我们只需要验证能否标记 n 对即可。不难想到,最佳标记策略就是尝试用最小的 n 个数和最大的 n 个数去配对,并且是按顺序配对。

温习一下,使用二分法的前提是,

class Solution:
    def maxNumOfMarkedIndices(self, nums: List[int]) -> int:
        nums.sort()
        n = len(nums)
        left, right = 0, n // 2
        while left < right:
            mid = (left + right + 1) // 2
            if all(2 * nums[i] <= nums[-mid+i] for i in range(mid)):
                left = mid
            else:
                right = mid - 1
        return left * 2

4.

image image

这个问题是一个典型的图算法,与最段路问题高度相似。不同的是每个节点需要一定时间之后才能访问。

首先,不难发现一些事实:

考虑类似于 dijstra 算法的过程,如果在 d 时刻尝试访问某个节点,节点的访问时间限制是 x,则有以下三种情况:

由此,当我们知道访问某个节点的最优时刻之后,可以求解由该节点访问任何相邻节点的最优时刻。这样就相当于可以求解图上节点之间的距离了,于是这个问题就跟一般的图最段路问题没有区别了,可以使用 Dijkstra 算法求解了。注意以上论证是严格的,这里的算法是严格的 Dijkstra 算法,能保证时间复杂度是 O(n log n).

class Solution:
    def minimumTime(self, grid: List[List[int]]) -> int:
        
        if grid[1][0] > 1 and grid[0][1] > 1:
            return -1

        # shortest path, like dijstra
        m, n = len(grid), len(grid[0])
        dist = [[-1] * n for _ in range(m)]
        q = [(0, 0, 0)]
        
        while q:
            d, i, j = heappop(q)
            if dist[i][j] != -1 and dist[i][j] <= d:
                continue
            dist[i][j] = d
            
            t = d + 1
            for _i, _j in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]:
                if _i >= m or _j >= n or _i < 0 or _j < 0:
                    continue
                x = grid[_i][_j]
                _d = t if t >= x else x if t % 2 == x % 2 else x + 1
                heappush(q, (_d, _i, _j))
        
        return dist[m - 1][n - 1]