力扣周赛343题解

52 阅读4分钟

计算列车到站时间

这道题目比较简单,只需要将正点到站时间和延误时间相加,然后对24取模,就可以得到实际到站时间。注意,如果结果是0,表示到站时间是00:00。

代码如下:

class Solution:
    def findDelayedArrivalTime(self, arrivalTime: int, delayedTime: int) -> int:
        # 将正点到站时间和延误时间相加,对24取模
        return (arrivalTime + delayedTime) % 24

时间复杂度:O(1) 空间复杂度:O(1)

倍数求和

这道题目可以利用容斥原理和等差数列求和公式来优化。容斥原理是一种计算集合并的方法,它可以避免重复计算或漏算。等差数列求和公式是一种快速计算等差数列前n项和的方法,它只需要知道首项、末项和项数。

具体来说,我们可以先计算[1,n]范围内能被3、5、7整除的数的和,然后减去能被15、21、35整除的数的和(因为这些数同时被两个因子整除了),最后加上能被105整除的数的和(因为这些数同时被三个因子整除了)。这样就可以避免重复或漏算。

代码如下:

class Solution:
    def sumOfMultiples(self, n: int) -> int:
        # 定义一个辅助函数,计算能被k整除的数的和
        def sum(n, k):
            # 等差数列求和公式:(首项 + 末项) * 项数 / 2
            return (k + (n // k * k)) * (n // k) // 2
        
        # 利用容斥原理计算结果
        return sum(n, 3) + sum(n, 5) + sum(n, 7) - sum(n, 15) - sum(n, 21) - sum(n, 35) + sum(n, 105)

时间复杂度:O(1) 空间复杂度:O(1)

滑动子数组的美丽值

这道题目可以用滑动窗口的思想来解决。我们维护一个长度为k的窗口,每次移动一位,并更新窗口内元素的最小值、最大值和美丽值。美丽值定义为最大值减去最小值。

为了快速找到窗口内元素的最小值和最大值,我们可以使用两个数据结构:一个是有序集合(如TreeSet),它可以在O(logk)的时间内插入、删除和查找元素;另一个是双端队列(如Deque),它可以在O(1)的时间内维护窗口内元素的单调性。

代码如下:

import collections
import bisect

class Solution:
    def slidingBeautyValue(self, nums: List[int], k: int) -> int:
        # 初始化有序集合和双端队列
        sorted_set = []
        min_queue = collections.deque()
        max_queue = collections.deque()
        
        # 定义一个辅助函数,计算窗口内元素的美丽值
        def beauty():
            return sorted_set[-1] - sorted_set[0]
        
        # 初始化结果为0
        ans = 0
        
        # 遍历数组
        for i in range(len(nums)):
            # 如果窗口已满,移除左边界元素
            if i >= k:
                sorted_set.pop(bisect.bisect_left(sorted_set, nums[i - k]))
                if min_queue[0] == nums[i - k]:
                    min_queue.popleft()
                if max_queue[0] == nums[i - k]:
                    max_queue.popleft()
            
            # 插入右边界元素到有序集合中
            bisect.insort(sorted_set, nums[i])
            
            # 维护最小值队列
            while min_queue and min_queue[-1] > nums[i]:
                min_queue.pop()
            min_queue.append(nums[i])
            
            # 维护最大值队列
            while max_queue and max_queue[-1] < nums[i]:
                max_queue.pop()
            max_queue.append(nums[i])
            
            # 如果窗口已满,更新结果
            if i >= k - 1:
                ans += beauty()
        
        # 返回结果
        return ans

时间复杂度:O(nlogk) 空间复杂度:O(k)

使数组所有元素变成1的最少操作次数

这道题目可以转化为寻找数组中GCD(最大公约数)为1的最短子数组。我们可以用前缀和+哈希表来快速求出任意区间内元素的GCD,并用双指针来维护一个滑动窗口。

具体来说,我们先遍历一遍数组,计算每个位置之前所有元素的GCD,并存储在哈希表中。然后我们用两个指针left和right表示窗口的左右边界,并维护一个变量cur表示当前窗口内元素的GCD。每次我们右移right指针,并更新cur为cur和nums[right]的GCD。如果cur为1,说明当前窗口满足条件,我们就尝试缩小窗口,即左移left指针,并更新cur为left之前所有元素的GCD与nums[left]之后所有元素的GCD之间的GCD。如果cur仍然为1,说明缩小后仍然满足条件,我们就更新结果为当前窗口长度;否则说明缩小后不满足条件,我们就恢复原来的窗口,并继续右移right指针。

代码如下:

import math

class Solution:
    def minOperationsToOne(self, nums: List[int]) -> int:
        # 定义一个辅助函数,计算两个数的GCD
        def gcd(a, b):
            return math.gcd(a, b)
        
        # 初始化哈希表存储前缀GCD
        prefix_gcd = {0:0}
        
        # 遍历数组计算前缀GCD
        for i in range(len(nums)):
            prefix_gcd[i + 1] = gcd(prefix_gcd[i], nums[i])
        
        # 如果整个数组的GCD不为1,直接返回-1
        if prefix_gcd[len(nums)] != 1:
            return -1
        
        # 初始化左右指针、当前GCD、结果
        left = 0
        right = 0
        cur = nums[0]
        ans = len(nums)
        
        # 遍历数组
        while right < len(nums):
            # 如果当前GCD为1,尝试缩小窗口
            if cur == 1:
                ans = min(ans, right - left + 1)
                cur = gcd(prefix
        # 返回结果
        return ans

时间复杂度:O(nlogn) 空间复杂度:O(n)