Leetcode 第 217 场周赛题解 (Python)

Leetcode 第 217 场周赛题解

周赛日期:2020/11/29

题目1:1672. 最富有客户的资产总量  难度: 简单

给你一个 m x n 的整数网格 accounts ,其中 accounts[i][j] 是第 i​​​​​ 位客户在第 j 家银行托管的资产数量。返回最富有客户所拥有的 资产总量 。

客户的 资产总量 就是他们在各家银行托管的资产数量之和。最富有客户就是 资产总量 最大的客户。

 

示例 1:

输入:accounts = [[1,2,3],[3,2,1]]
输出:6
解释:
第 1 位客户的资产总量 = 1 + 2 + 3 = 6
第 2 位客户的资产总量 = 3 + 2 + 1 = 6
两位客户都是最富有的,资产总量都是 6 ,所以返回 6 

题解:简单加和运算

上手题,每行进行求和,然后记录最小的一行和。

class Solution:
    def maximumWealth(self, accounts: List[List[int]]) -> int:
        res = 0
        for account in accounts:
            res = max(sum(account), res)
        return res

 

题目2:1673. 找出最具竞争力的子序列 难度:中等

给你一个整数数组 nums 和一个正整数 k ,返回长度为 k 且最具 竞争力 的 nums 子序列。

数组的子序列是从数组中删除一些元素(可能不删除元素)得到的序列。

在子序列 a 和子序列 b 第一个不相同的位置上,如果 a 中的数字小于 b 中对应的数字,那么我们称子序列 a 比子序列 b(相同长度下)更具 竞争力 。 例如,[1,3,4] 比 [1,3,5] 更具竞争力,在第一个不相同的位置,也就是最后一个位置上, 4 小于 5 。

 

示例 1:

输入:nums = [3,5,2,6], k = 2
输出:[2,6]
解释:在所有可能的子序列集合 {[3,5], [3,2], [3,6], [5,2], [5,6], [2,6]} 中,[2,6] 最具竞争力。
示例 2:

输入:nums = [2,4,3,3,5,4,9,6], k = 4
输出:[2,3,3,4]

题解:单调栈

维护一个单调栈,从左到右遍历数组。

上手题,每行进行求和,然后记录最小的一行和。

1.当前元素大于等于栈顶元素,入栈;否则,将栈中大于当前元素的数一直出栈,再将当前元素压栈,以此保证栈中最小字典序的顺序。

2.其中记录删除了多少元素,题目保留k个元素,即删除n-k个元素,若删除的数目达到上限,则保留栈中元素不再删除。

3.遍历一遍后,若栈中元素数目大于k个(即n-k>0),将多余元素出栈。

class Solution:
    def mostCompetitive(self, nums: List[int], k: int) -> List[int]:
        stack = []
        n = len(nums)
        count = 0
        for num in nums:
            while stack and num < stack[-1] and count < n - k:
                stack.pop(); count += 1
            stack.append(num)
        return stack[:k] 

 

题目3:1674. 使数组互补的最少操作次数 难度:中等

给你一个长度为 偶数 n 的整数数组 nums 和一个整数 limit 。每一次操作,你可以将 nums 中的任何整数替换为 1 到 limit 之间的另一个整数。

如果对于所有下标 i(下标从 0 开始),nums[i] + nums[n - 1 - i] 都等于同一个数,则数组 nums 是 互补的 。例如,数组 [1,2,3,4] 是互补的,因为对于所有下标 i ,nums[i] + nums[n - 1 - i] = 5 。

返回使数组 互补 的 最少 操作次数。

 

示例 1:

输入:nums = [1,2,4,3], limit = 4
输出:1
解释:经过 1 次操作,你可以将数组 nums 变成 [1,2,2,3](加粗元素是变更的数字):
nums[0] + nums[3] = 1 + 3 = 4.
nums[1] + nums[2] = 2 + 2 = 4.
nums[2] + nums[1] = 2 + 2 = 4.
nums[3] + nums[0] = 3 + 1 = 4.
对于每个 i ,nums[i] + nums[n-1-i] = 4 ,所以 nums 是互补的。
示例 2:

输入:nums = [1,2,2,1], limit = 2
输出:2
解释:经过 2 次操作,你可以将数组 nums 变成 [2,2,2,2] 。你不能将任何数字变更为 3 ,因为 3 > limit 。
示例 3:

输入:nums = [1,2,1,2], limit = 2
输出:0
解释:nums 已经是互补的。

题解:差分

假设 res[x] 表示的是,nums[i] + nums[n - 1 - i] 为 x 的时候,需要多少次操作。我们只需要计算出所有的 x 对应的 res[x], 取最小值就好了。

根据题意,nums[i] + nums[n - 1 - i] 最小是 2,即将两个数都修改为 1;最大是 2 * limit,即将两个数都修改成 limit。

所以,res[x] 中 x 的取值范围是 [2, 2 * limit]。

假设 nums[i] 为 A;nums[n - 1 - i] 为 B。

1. 如果修改后两个数字的和是 A + B,我们使用的操作数是 0 (没有修改));

2. 如果修改后两个数字和在 [1 + min(A, B), limit + max(A, B)] 的范围,我们使用的操作数是 1 (只需要修改 A 或者 B 就好);

3. 如果修改后两个数字和在 [2, 2 * limit] 的范围,我们使用的操作数是 ``2`(两个数字都要修改));

所以,我们的算法是遍历每一组 nums[i] 和 nums[n - 1 - i],然后:

先将 [2, 2 * limit] 的范围需要的操作数 + 2;

之后,将 [1 + min(A, B), limit + max(A, B)] 的范围需要的操作数 - 1(即 2 - 1 = 1,操作 1 次);

之后,将 [A + B] 位置的值再 -1(即 1 - 1 = 0,操作 0 次)。

最后计算每一个res[x] 对其取最小值

class Solution:
    def minMoves(self, nums: List[int], limit: int) -> int:
        n = len(nums) // 2
        s = [0]*(2*limit+2)
        for i in range(n):
            a, b = nums[i], nums[len(nums)-i-1]
            s[2] += 2; s[2*limit+1] -= 2 # 先在前面+2
            l, r = 1 + min(a, b), limit + max(a, b) # 此区域操作数为1,则将原来的减1
            s[l] -= 1; s[r+1] += 1
            # A + B 再减1
            s[a+b] -= 1; s[a+b+1] += 1
        res = n
        count = 0
        for i in range(2, 2*limit+1):
            count += s[i]
            res = min(res, count)
        return res

 

题目4:1675. 数组的最小偏移量 难度:困难

给你一个由 n 个正整数组成的数组 nums 。

你可以对数组的任意元素执行任意次数的两类操作:

如果元素是 偶数 ,除以 2
例如,如果数组是 [1,2,3,4] ,那么你可以对最后一个元素执行此操作,使其变成 [1,2,3,2]
如果元素是 奇数 ,乘上 2
例如,如果数组是 [1,2,3,4] ,那么你可以对第一个元素执行此操作,使其变成 [2,2,3,4]
数组的 偏移量 是数组中任意两个元素之间的 最大差值 。

返回数组在执行某些操作之后可以拥有的 最小偏移量 。

 

示例 1:

输入:nums = [1,2,3,4]
输出:1
解释:你可以将数组转换为 [1,2,3,2],然后转换成 [2,2,3,2],偏移量是 3 - 2 = 1
示例 2:

输入:nums = [4,1,5,20,3]
输出:3
解释:两次操作后,你可以将数组转换为 [4,2,5,5,3],偏移量是 5 - 2 = 3
示例 3:

输入:nums = [2,10,8]
输出:3

题解:有序队列 

 一个数的变化范围有限, 比如所有的奇数都只能做一次乘 2 操作, 偶数可以做若干次除以 2 的操作.

把所有数都变成自己可变化范围的最大值. (即所有奇数都乘2),然后再缩小范围

而偏移量 = 最大值 - 最小值, 所以我们要做的就是缩小最大值. (缩小其他数值也无法优化偏移量)

那么操作就是: 不断缩小当前的最大值即可, 直到不能缩小, 期间不断维护答案.

这里可以使用有序队列来维护一个有序的数组,slist[0]为最小值,slist[-1]为最大值。

class Solution:
    def minimumDeviation(self, nums: List[int]) -> int:
        from sortedcontainers import SortedList
        slist = SortedList()
        for num in nums:
            if num % 2: slist.add(num*2)
            else: slist.add(num)
        res = slist[-1] - slist[0]
        while slist[-1] % 2 == 0:
            MAX = slist.pop()
            slist.add(MAX // 2)
            res = min(slist[-1]-slist[0], res)
        return res

 

你可能感兴趣的:(Leetcode周赛,Python,算法,数据结构,队列,算法,leetcode,python)