力扣周赛343

182 阅读4分钟

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 # 返回结果