日渐头秃的代码日记 -- 第316场周赛继续划水

112 阅读3分钟

这是我参与『掘金日新计划·10月更文挑战』的第4天。 划水一天

今天仅有两道比较简单的题目,两道6分的难题,震惊了。

一、判断两个事件是否存在冲突

给你两个字符串数组 event1 和 event2 ,表示发生在同一天的两个闭区间时间段事件,其中:

  • event1 = [startTime1, endTime1] 且
  • event2 = [startTime2, endTime2]

事件的时间为有效的 24 小时制且按 HH:MM 格式给出。

当两个事件存在某个非空的交集时(即,某些时刻是两个事件都包含的),则认为出现 冲突 。

如果两个事件之间存在冲突,返回 true **;否则,返回 **false 。

 

示例 1:

输入: event1 = ["01:15","02:00"], event2 = ["02:00","03:00"]
输出: true
解释: 两个事件在 2:00 出现交集。

示例 2:

输入: event1 = ["01:00","02:00"], event2 = ["01:20","03:00"]
输出: true
解释: 两个事件的交集从 01:20 开始,到 02:00 结束。

示例 3:

输入: event1 = ["10:00","11:00"], event2 = ["14:00","15:00"]
输出: false
解释: 两个事件不存在交集。

 

提示:

  • evnet1.length == event2.length == 2.
  • event1[i].length == event2[i].length == 5
  • startTime1 <= endTime1
  • startTime2 <= endTime2
  • 所有事件的时间都按照 HH:MM 格式给出

解析

比较简单,按照题目意思模拟一下就行了

代码

class Solution:
    def haveConflict(self, event1: List[str], event2: List[str]) -> bool:
        event1_start = int(event1[0].split(":")[0]) * 60 + int(event1[0].split(":")[1])
        event1_end  = int(event1[1].split(":")[0]) * 60 + int(event1[1].split(":")[1])
        event2_start = int(event2[0].split(":")[0]) * 60 + int(event2[0].split(":")[1])
        event2_end  = int(event2[1].split(":")[0]) * 60 + int(event2[1].split(":")[1])
        if event1_start > event2_end or event1_end < event2_start:
            return False
        else:
            return True

甚至可以更简单一点,利用Python的字符串大小比较特点来完成。

class Solution:
    def haveConflict(self, event1: List[str], event2: List[str]) -> bool:
        if event2[0] > event1[1] or event1[0] > event2[1]:
            return False
        else:
            return True

二、最大公因数等于 K 的子数组数目

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 nums 的子数组中元素的最大公因数等于 k 的子数组数目。

子数组 是数组中一个连续的非空序列。

数组的最大公因数 是能整除数组中所有元素的最大整数。

 

示例 1:

输入: nums = [9,3,1,2,6,3], k = 3
输出: 4
解释: nums 的子数组中,以 3 作为最大公因数的子数组如下:
  • [9,3,1,2,6,3]
  • [9,3,1,2,6,3]
  • [9,3,1,2,6,3]
  • [9,3,1,2,6,3]

**示例 2:**

输入: nums = [4], k = 7 输出: 0 解释: 不存在以 7 作为最大公因数的子数组。


 

**提示:**

-   `1 <= nums.length <= 1000`
-   `1 <= nums[i], k <= 10^9`

## 解析
因为数组长度较小,可以直接考虑复杂度N方的办法

## 代码
```python
class Solution:
    @cache
    def _gcd(self, x, y):
        return math.gcd(x, y)
    
    def list_gcd(self, s):
        g = 0
        for i in range(len(s)):
            if i == 0:
                g = s[i]
            else:
                g = self._gcd(g, s[i])
        return g
    def subarrayGCD(self, nums: List[int], k: int) -> int:
        if len(set(nums)) == 1 and nums[0] == k:
            return int((1 + len(nums)) * len(nums) / 2)
        cnt = 0
        for start in range(len(nums)):
            if nums[start] < k:
                continue
            for end in range(start+1, len(nums)+1):
                if nums[end-1] < k:
                    break
                if self.list_gcd(nums[start:end]) == k:
                    cnt += 1

        return cnt

从第三题开始秀了起来。。。

三、使数组相等最小的开销

给你两个下标从 0 开始的数组 nums 和 cost ,分别包含 n 个  整数。

你可以执行下面操作 任意 次:

  • 将 nums 中 任意 元素增加或者减小 1 。

对第 i 个元素执行一次操作的开销是 cost[i] 。

请你返回使 nums 中所有元素 相等 的 最少 总开销。

 

示例 1:

输入: nums = [1,3,5,2], cost = [2,3,1,14]
输出: 8
解释: 我们可以执行以下操作使所有元素变为 2 :
- 增加第 0 个元素 1 次,开销为 2 。
- 减小第 1 个元素 1 次,开销为 3 。
- 减小第 2 个元素 3 次,开销为 1 + 1 + 1 = 3 。
总开销为 2 + 3 + 3 = 8 。
这是最小开销。

示例 2:

输入: nums = [2,2,2,2,2], cost = [4,2,8,1,3]
输出: 0
解释: 数组中所有元素已经全部相等,不需要执行额外的操作。

 

提示:

  • n == nums.length == cost.length
  • 1 <= n <= 10^5
  • 1 <= nums[i], cost[i] <= 10^6

解析

这是一道数学题,相关的知识点是加权中位数。

暴力解法的代码,第四个case就超时了

class Solution:
    @cache
    def f(self, x):
        s = 0
        for i in range(len(self.nums)):
            s += abs(self.nums[i] - x) * self.cost[i]
        return s
    
    def minCost(self, nums: List[int], cost: List[int]) -> int:
        if len(nums) == 1:
            return 0
        self.nums = nums
        self.cost = cost
        m = 1000000000000000000000000
        for x in range(1, 1000001):
            s = self.f(x)
            m = min(s, m)
        print(m)
        return(m)

加权中位数的解法

class Solution:
    def minCost(self, nums: List[int], cost: List[int]) -> int:
        s = sorted(zip(nums, cost))
        total = sum(cost)
        tmp = 0
        target = 0
        for n, c in s:
            tmp += c
            if tmp >= total / 2:
                target = n
                break
        res = 0
        for n, c in s:
            res += abs(target-n) * c
        print(res)
        return res

四、使数组相似的最少的操作次数

给你两个正整数数组 nums 和 target ,两个数组长度相等。

在一次操作中,你可以选择两个 不同 的下标 i 和 j ,其中 0 <= i, j < nums.length ,并且:

  • 令 nums[i] = nums[i] + 2 且
  • 令 nums[j] = nums[j] - 2 。

如果两个数组中每个元素出现的频率相等,我们称两个数组是 相似 的。

请你返回将 nums 变得与 target 相似的最少操作次数。测试数据保证 nums 一定能变得与 target 相似。

 

示例 1:

输入: nums = [8,12,6], target = [2,14,10]
输出: 2
解释: 可以用两步操作将 nums 变得与 target 相似:
- 选择 i = 0 和 j = 2 ,nums = [10,12,4] 。
- 选择 i = 1 和 j = 2 ,nums = [10,14,2]2 次操作是最少需要的操作次数。

示例 2:

输入: nums = [1,2,5], target = [4,1,3]
输出: 1
解释: 一步操作可以使 nums 变得与 target 相似:
- 选择 i = 1 和 j = 2 ,nums = [1,4,3]

示例 3:

输入: nums = [1,1,1,1,1], target = [1,1,1,1,1]
输出: 0
解释: 数组 nums 已经与 target 相似。

 

提示:

  • n == nums.length == target.length
  • 1 <= n <= 10^5
  • 1 <= nums[i], target[i] <= 10^6
  • nums 一定可以变得与 target 相似。

解析

高端的题目往往以最简单的方式解答。这道题被秀的头皮发麻。

因为是加2或者减2,所以数字的奇偶性是不会发生变化的。又因为给的数组nums一定会变为target的相似数组,因此每一步都是在向目标靠近。把nums分成奇数数组和偶数数组,再排序一下,把target也同样操作,看看起始的时候差距是多少,肯定是4的倍数,除以4就可以了。

代码

class Solution:
    def makeSimilar(self, nums: List[int], target: List[int]) -> int:
        a = sorted([x for x in nums if x % 2 == 0])
        b = sorted([x for x in nums if x % 2 == 1])
        c = sorted([x for x in target if x % 2 == 0])
        d = sorted([x for x in target if x % 2 == 1])
        
        diff_ac = 0
        diff_bd = 0
        for i in range(len(a)):
            diff_ac += abs(a[i] - c[i])
        for i in range(len(b)):
            diff_bd += abs(b[i] - d[i])
        return int((diff_ac + diff_bd) / 4)

简化后的代码可以参考大佬们的

class Solution:
    def makeSimilar(self, nums: List[int], target: List[int]) -> int:
        nums.sort(key=lambda x: (x % 2, x))
        target.sort(key=lambda x: (x % 2, x))
        # 前面的排序相当于对于奇数偶数进行了分类,前面为奇数,后面为偶数
        return sum(abs(x - y) for x, y in zip(nums, target)) // 4

作者:小羊肖恩
链接:https://leetcode.cn/circle/discuss/uO4WuN/view/CUy95z/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

如果按照题目要求来模拟,还真不容易处理。

又是划水的一天。

预祝周一快乐。