周赛日期:2020/11/29
给你一个 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
给你一个整数数组 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]
给你一个长度为 偶数 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
给你一个由 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