2660. 保龄球游戏的获胜者
题目描述:给你两个下标从 0 开始的整数数组 player1 和 player2 ,分别表示玩家 1 和玩家 2 击中的瓶数。保龄球比赛由 n 轮组成,每轮的瓶数恰好为 10 。假设玩家在第 i 轮中击中 x_i 个瓶子。玩家第 i 轮的价值为:
- 如果玩家在前两轮中击中了 10 个瓶子,则为 2x_i。
- 否则,为 x_i。
玩家的得分是其 n 轮价值的总和。返回
- 如果玩家 1 的得分高于玩家 2 的得分,则为 1;
- 如果玩家 2 的得分高于玩家 1 的得分,则为 2;
- 如果平局,则为 0。
解题思路:这道题比较简单,只需要遍历两个数组,计算每个玩家的得分,然后比较即可。注意处理前两轮是否击中了10个瓶子的情况。
代码如下:
class Solution:
def bowlingGameWinner(self, player1: List[int], player2: List[int]) -> int:
# 计算一个玩家的得分
def get_score(player):
score = 0 # 总得分
strike = False # 上一轮是否全中
for i in range(len(player)):
x = player[i] # 当前轮击中的瓶数
if i < 2 and x == 10: # 前两轮全中
score += x * 2 # 得分加倍
strike = True # 标记全中
elif strike: # 上一轮全中
score += x * 2 # 得分加倍
strike = False # 取消标记
else: # 其他情况
score += x # 正常得分
return score
# 计算两个玩家的得分
score1 = get_score(player1)
score2 = get_score(player2)
# 比较得分并返回结果
if score1 > score2:
return 1
elif score1 < score2:
return 2
else:
return 0
2661. 找出叠涂元素
题目描述:给你一个下标从 0 开始且长度为 n 的整数数组 nums ,以及一个整数 k 。定义 nums 的一个 子数组 是一个长度至少为 k 的连续数组切片。例如,nums[3:7] 就是 nums 的一个子数组。
如果 nums 中存在某个元素 a ,使得 a 在 nums 中至少在 k / (n / k) = n / k^2 不同子数组中出现过,那么我们称 a 是 nums 中的一个 叠涂元素 。注意:n / k^2 是向下取整。
返回 nums 中所有叠涂元素组成的有序列表。如果不存在任何叠涂元素,则返回一个空列表。
解题思路:这道题可以用哈希表来统计每个元素在不同子数组中出现的次数。具体地,我们可以遍历nums,每次取长度为k的子数组,并用一个集合记录其中出现过的元素。然后用一个哈希表记录每个元素在多少个不同集合中出现过。最后遍历哈希表,找出满足条件的叠涂元素,并排序返回。
代码如下:
class Solution:
def findRepeatedElements(self, nums: List[int], k: int) -> List[int]:
n = len(nums) # 数组长度
threshold = n // (k * k) # 叠涂元素出现次数的阈值
freq = {} # 哈希表记录每个元素在多少个不同集合中出现过
for i in range(n - k + 1): # 遍历nums,每次取长度为k的子数组
seen = set() # 集合记录当前子数组中出现过的元素
for j in range(i, i + k): # 遍历当前子数组
x = nums[j] # 当前元素
if x not in seen: # 如果没有出现过
seen.add(x) # 加入集合
freq[x] = freq.get(x, 0) + 1 # 更新哈希表
ans = [] # 结果列表
for x in freq: # 遍历哈希表
if freq[x] >= threshold: # 如果满足条件
ans.append(x) # 加入结果
ans.sort() # 排序
return ans # 返回结果
2662. 两个子序列的最大点积
题目描述:给你两个长度都是 n 的整数数组 nums1 和 nums2 。请你求出它们所有可能形成的 m 子序列对 (x, y) 的 最大点积 。m 子序列对 (x, y) 的点积是对应位置上乘积之和:x[0] * y[0] + x[1] * y[1] + ... + x[m - 1] * y[m - 1] 。注意:m 子序列对 (x, y) 中不一定要取到 nums1 和 nums2 中所有元素。
解题思路:这道题可以用动态规划来解决。我们可以定义dp[i][j]表示nums1前i个元素和nums2前j个元素形成m子序列对时能达到的最大点积。那么状态转移方程有以下几种情况:
- 如果nums1[i - 1]和nums2[j - 1]都被选入子序列对,那么dp[i][j] = dp[i - 1][j - 1] + nums1[i - 1] * nums2[j - 1]。
- 如果nums1[i - 1]被选入子序列对,而nums2[j - 1]没有被选入,那么dp[i][j] = dp[i - 1][j]。
- 如果nums1[i - 1]没有被选入子序列对,而nums2[j - 1]被选入,那么dp[i][j] = dp[i][j - 1]。
- 如果nums1[i - 1]和nums2[j - 1]都没有被选入子序列对,那么dp[i][j] = dp[i - 1][j - 1]。
综上所述,dp[i][j]应该取以上四种情况中的最大值。最终答案就是dp[n][n]。
代码如下:
class Solution:
def maxDotProduct(self, nums1: List[int], nums2: List[int]) -> int:
n = len(nums1) # 数组长度(相等)
dp = [[0 for _ in range(n + 1)] for _ in range(n + 1)] # 动态规划数组
# 初始化边界条件
for i in range(1, n + 1):
dp[i][0] = dp[0][i] = float('-inf') # 如果有一个数组为空,那么点积为负无穷
# 状态转移
for i in range(1, n + 1):
for j in range(1, n + 1):
# 取四种情况中的最大值
dp[i][j] = max(dp[i - 1][j - 1] + nums1[i - 1] * nums2[j - 1], # 都选入
dp[i - 1][j], # 只选nums1
dp[i][j - 1], # 只选nums2
dp[i - 1][j - 1]) # 都不选
# 返回结果
return dp[n][n]
2663. 最小操作次数使数组递增
题目描述:给你一个长度为 n 的整数数组 nums 。每一次操作中,你可以将 nums 中的任意一个元素替换成任意整数。如果 nums 满足以下条件,那么它是 连续递增的 :
- 如果数组中仅有一个元素,那么它是连续递增的。
- 如果数组中有多个元素,那么对于每个 i (0 <= i < nums.length - 1) ,都满足 nums[i] < nums[i + 1] 。
返回使数组 连续递增 的 最小操作次数 。
解题思路:这道题可以用贪心算法来解决。我们可以从左到右遍历数组,维护一个变量prev表示当前最大的元素。如果遇到一个比prev小或等于的元素,那么我们就需要将其替换成prev+1,并更新操作次数。否则,我们就直接更新prev为当前元素。最后返回操作次数即可。
代码如下:
class Solution:
def minOperations(self, nums: List[int]) -> int:
prev = float('-inf') # 当前最大的元素
ans = 0 # 操作次数
for x in nums: # 遍历数组
if x <= prev: # 如果比prev小或等于
prev += 1 # 将其替换成prev+1
ans += prev - x # 更新操作次数
else: # 否则
prev = x # 直接更新prev
return ans # 返回结果