LeetCode笔记:Biweekly Contest 110

  • LeetCode笔记:Biweekly Contest 110
    • 1. 题目一
      • 1. 解题思路
      • 2. 代码实现
    • 2. 题目二
      • 1. 解题思路
      • 2. 代码实现
    • 3. 题目三
      • 1. 解题思路
      • 2. 代码实现
    • 4. 题目四
      • 1. 解题思路
      • 2. 代码实现
  • 比赛链接:https://leetcode.com/contest/biweekly-contest-110

1. 题目一

给出题目一的试题链接如下:

  • 2806. Account Balance After Rounded Purchase

1. 解题思路

这一题思路上还是很直接的,就是首先找到给出的数的上下两个10的整倍数,然后找到其中满足题意得那一个,然后求一下和100的差即可。

2. 代码实现

给出python代码实现如下:

class Solution:
    def accountBalanceAfterPurchase(self, purchaseAmount: int) -> int:
        a = (purchaseAmount // 10) * 10
        b = a + 10
        roundedAmount = a if abs(a-purchaseAmount) < abs(b-purchaseAmount) else b
        return 100 - roundedAmount

提交代码评测得到:耗时44ms,占用内存16.2MB。

2. 题目二

给出题目二的试题链接如下:

  • 2807. Insert Greatest Common Divisors in Linked List

1. 解题思路

这道题原意肯定是考链表,不过这里我偷了个机,直接先转成了array然后进行在恢复成链表,就省去了很多麻烦。

而剩下的就是求一下最大公约数,就不是啥大事了,用python自带的函数即可,当然自己实现也不复杂,就不赘述了。

2. 代码实现

给出python代码实现如下:

class Solution:
    def insertGreatestCommonDivisors(self, head: Optional[ListNode]) -> Optional[ListNode]:
        nodes = []
        while head:
            nodes.append(head.val)
            head = head.next
        
        n = len(nodes)
        for i in range(n-1):
            a = nodes[2*i]
            b = nodes[2*i+1]
            nodes.insert(2*i+1, gcd(a,b))
        
        nodes = [ListNode(val) for val in nodes]
        n = len(nodes)
        for i in range(n-1):
            nodes[i].next = nodes[i+1]
        return nodes[0]

提交代码评测得到:耗时123ms,占用内存21.5MB。

3. 题目三

给出题目三的试题链接如下:

  • 2808. Minimum Seconds to Equalize a Circular Array

1. 解题思路

这一题其实想清楚之后还是挺简单的,因为其实最终肯定是要全部变成某一个具体的元素,因此,而要变成某一个元素,其所需的时间事实上就是其他元素到其最近的距离的最大值。

而要求这个值,事实上也就是任意两个相邻的相同同元素之间距离的一半。

因此,我们只需要记录一下每一个元素出现的所有位置,然后对每一个元素计算一下全部变成该元素所需的时间,然后取出最小值即可。

2. 代码实现

给出python代码实现如下:

class Solution:
    def minimumSeconds(self, nums: List[int]) -> int:
        n = len(nums)
        locs = defaultdict(list)
        for i, x in enumerate(nums):
            locs[x].append(i)
            
        def get_seconds(indexs):
            m = len(indexs)
            if m == 1:
                return n // 2
            dis = [(indexs[i] - indexs[i-1] + n) % n // 2 for i in range(m)]
            return max(dis)
        
        seconds = [get_seconds(indexs) for indexs in locs.values()]
        return min(seconds)

提交代码评测得到:耗时640ms,占用内存49.1MB。

4. 题目四

给出题目四的试题链接如下:

  • 2809. Minimum Time to Make Array Sum At Most x

1. 解题思路

这一题很可惜没能搞定,只是抄了大佬的答案……

思路来说倒是不难理解,或者说多少我也想到了,但是关键部分这样实现为什么可以work就多少有点不太理解了,这里就只是把大佬的思路先写下来,后来有空再回来看看吧……

整体的思路上来说其实还是挺简单的,显然,假设两个数组的和分别为 s 1 , s 2 s_1, s_2 s1,s2,那么如果经过 k k k次操作,其最终的答案一定是:

f ( k ) = s 1 + k ⋅ s 2 − ∑ i = 1 k ( a n i + k ⋅ b n i ) f(k) = s_1 + k \cdot s_2 - \sum\limits_{i=1}^{k} (a_{n_i} + k \cdot {b_{n_i}}) f(k)=s1+ks2i=1k(ani+kbni)

然后,这里的变量其实就是后面的 ∑ i = 1 k ( a n i + k ⋅ b n i ) \sum\limits_{i=1}^{k} (a_{n_i} + k \cdot {b_{n_i}}) i=1k(ani+kbni)部分,要使得整体的 f ( k ) f(k) f(k)最小,就是令 ∑ i = 1 k ( a n i + k ⋅ b n i ) \sum\limits_{i=1}^{k} (a_{n_i} + k \cdot {b_{n_i}}) i=1k(ani+kbni)取最大。其中, n i n_i ni是一组坐标的下标选择。

但是,我自己的话就是卡在这里做不下去了,不知道怎么去做这个问题,然后看大佬们的答案倒是思路也简单,就是在这里用了动态规划,定义 f n ( k ) \mathop{f_n}(k) fn(k)表示经过 k k k次操作之后能够获得的 ∑ i = 1 k ( a n i + k ⋅ b n i ) \sum\limits_{i=1}^{k} (a_{n_i} + k \cdot {b_{n_i}}) i=1k(ani+kbni)的最大值,然后动态规划的求取这个 f n ( k ) \mathop{f_n}(k) fn(k)

但是,就是关于这里为什么大佬们给出的动态规划方式可以work多少有点感觉奇怪,其实现上很简单:

  1. 首先对于位置关于 ( b i , a i ) (b_i, a_i) (bi,ai)的大小进行排序;

  2. 然后从小到大分别取出每一组 ( b i , a i ) (b_i, a_i) (bi,ai),依次更新所有的 f n ( k ) \mathop{f_n}(k) fn(k)为:

    f n ( k ) = m a x ( f n ( k ) , f n ( k − 1 ) + a i + k ⋅ b i ) \mathop{f_n}(k) = \mathop{max}(\mathop{f_n}(k), \mathop{f_n}(k-1) + a_i + k\cdot b_i) fn(k)=max(fn(k),fn(k1)+ai+kbi)

这个递推表达式本身也不难理解,就是对每一个元素,考察是否要取用这个元素作为第 k k k个被取用的元素,但是数学上为什么这样就一定能够获得最终的最优答案,多少还是有点想不太清楚,唉……

2. 代码实现

给出python代码实现如下:

class Solution:
    def minimumTime(self, nums1: List[int], nums2: List[int], x: int) -> int:
        n = len(nums1)
        nums = sorted([(b, a) for a, b in zip(nums1, nums2)])
        fn = [0 for _ in range(n+1)]
        for b, a in nums:
            for i in range(n, 0, -1):
                fn[i] = max(fn[i], fn[i-1] + a+i*b)
        s1 = sum(nums1)
        s2 = sum(nums2)
        for i in range(n+1):
            if s1 + s2*i - fn[i] <= x:
                return i
        return -1

提交代码评测得到:耗时1812ms,占用内存16.8MB。

你可能感兴趣的:(leetcode笔记,力扣双周赛,110,leetcode,2806,leetcode,2807,leetcode,2808,leetcode,2809)