力扣周赛318

87 阅读7分钟

第一题:最小化最大值

给你一个整数数组 nums ,你可以对它执行下面操作任意次:

  • 如果 nums[i] == nums[i + 1] ,那么就将 nums[i] 变为原来的两倍,同时将 nums[i + 1] 变为 0 。
  • 将数组中所有非零元素移到数组的左边,所有零元素移到右边。

请你返回执行以上操作后,数组中最大元素的值。

示例 1:

输入:nums = [2,4,1,5,3] 输出:8 解释:最优操作序列为:

  • 将 nums[2] 和 nums[3] 变为 2 * nums[2] = 2 * 1 = 2 ,nums[3] 变为 0 。得到数组 [2,4,2,0,3]
  • 将数组中所有非零元素移到左边,所有零元素移到右边。得到数组 [2,4,2,3,0]
  • 将 nums[0] 和 nums[1] 变为 2 * nums[0] = 2 * 2 = 4 ,nums[1] 变为 0 。得到数组 [4,0,2,3,0]
  • 将数组中所有非零元素移到左边,所有零元素移到右边。得到数组 [4,2,3,0,0]
  • 将 nums[0] 和 nums[1] 变为 2 * nums[0] = 2 * 4 = 8 ,nums[1] 变为 0 。得到数组 [8,0,3,0,0]
  • 将数组中所有非零元素移到左边,所有零元素移到右边。得到数组 [8,3,0,0,0] 数组中最大元素的值为 8 。

题解:

这道题的思路是先遍历一遍数组,找出相邻的相等元素,将前一个元素变为两倍,后一个元素变为零。然后再遍历一遍数组,用一个指针记录非零元素的位置,将非零元素移动到前面,将零元素移动到后面。最后返回数组中的最大值即可。

代码如下:

class Solution:
    def applyOperations(self, nums: List[int]) -> List[int]:
        # 第一遍遍历,找出相邻的相等元素,将前一个元素变为两倍,后一个元素变为零
        for i in range(len(nums) - 1):
            if nums[i] == nums[i + 1]:
                nums[i] *= 2
                nums[i + 1] = 0
        # 第二遍遍历,用一个指针记录非零元素的位置,将非零元素移动到前面,将零元素移动到后面
        j = 0 # 指向非零元素的位置
        for i in range(len(nums)):
            if nums[i] != 0:
                nums[j], nums[i] = nums[i], nums[j]
                j += 1
        # 返回数组中的最大值
        return max(nums)

第二题

给你一个长度为 n 的整数数组 nums 和一个整数 k ,请你找出数组中最大的元素值,要求满足以下条件:

  • 数组中恰好有 k 个不同的元素。
  • 数组中的所有元素都是正整数。

如果不存在满足条件的子数组,返回 -1 。

示例 1:

输入:nums = [1,2,3,2,1], k = 3 输出:3 解释:子数组 [1,2,3] 包含 3 个不同的元素,且最大的元素值为 3 。

题解:

这道题的思路是使用滑动窗口的方法,维护一个双端队列和一个哈希表,双端队列存储当前窗口中的元素,哈希表存储当前窗口中每个元素出现的次数。我们从左到右遍历数组,每次将右边的元素加入窗口,同时更新哈希表,如果窗口中的不同元素个数超过了 k ,则需要从左边移除元素,直到不同元素个数等于 k 。在这个过程中,我们记录下窗口中所有元素的和,最后返回最大的和即可。

代码如下:

class Solution:
    def maximumSubarraySum(self, nums: List[int], k: int) -> int:
        from collections import deque
        # 双端队列存储当前窗口中的元素
        window = deque()
        # 哈希表存储当前窗口中每个元素出现的次数
        count = {}
        # 窗口中所有元素的和
        sum = 0
        # 最大和
        max_sum = -1
        # 遍历数组
        for num in nums:
            # 将右边的元素加入窗口
            window.append(num)
            # 更新哈希表
            count[num] = count.get(num, 0) + 1
            # 更新和
            sum += num
            # 如果窗口中不同元素个数超过了k,则从左边移除元素,直到不同元素个数等于k
            while len(count) > k:
                left = window.popleft()
                count[left] -= 1
                if count[left] == 0:
                    count.pop(left)
                sum -= left
            # 如果窗口中不同元素个数等于k,则更新最大和
            if len(count) == k:
                max_sum = max(max_sum, sum)
        # 返回最大和
        return max_sum

第三题

给你一个长度为 n 的正整数数组 costs ,数组中的每个元素表示修理一辆机器人的成本。你需要修理 k 辆机器人,但是你只能选择其中的一些进行修理。

你可以按照以下规则选择修理哪些机器人:

  • 你可以选择任意数量的机器人进行修理,但是不能超过 k 辆。
  • 你必须按照数组中的顺序选择要修理的机器人,也就是说,如果你选择了第 i 个机器人进行修理,那么你不能再选择第 i - 1 个或者更前面的机器人进行修理。
  • 如果你选择了第 i 个机器人进行修理,那么你必须支付 costs[i] 的成本。
  • 如果你选择了多个相邻的机器人进行修理,那么你必须额外支付这些机器人之间的碰撞费用。碰撞费用等于这些机器人之间的距离之和。例如,如果你选择了第 2、3、4 个机器人进行修理,那么碰撞费用等于 (costs[2] - costs[1]) + (costs[3] - costs[2]) + (costs[4] - costs[3]) = costs[4] - costs[1] 。

请你返回最小化总成本(包括修理成本和碰撞费用)的方案下,需要支付的总成本。

示例 1:

输入:costs = [1,3,5,7,9], k = 3 输出:6 解释:最优方案是选择第 1、3、5 个机器人进行修理,总成本为 costs[0] + costs[2] + costs[4] = 1 + 5 + 9 = 15 ,碰撞费用为 (costs[2] - costs[0]) + (costs[4] - costs[2]) = (5 - 1) + (9 - 5) = 8 ,所以最终需要支付的总成本为 15 - 8 = 7 。

题解:

这道题的思路是使用动态规划的方法,维护一个二维数组 dp ,其中 dp[i][j] 表示用 [i, n - 1] 的工厂修理 [j, m - 1] 的机器人所需的最小总成本。我们从右下角开始递推,对于每个 dp[i][j] ,我们有两种选择:

  • 不用第 i 个工厂修理任何机器人,那么 dp[i][j] = dp[i + 1][j] ,即跳过当前工厂,直接考虑下一个工厂。
  • 用第 i 个工厂修理一些机器人,那么我们需要枚举这些机器人的数量 k ,满足 j + k - 1 < m 和 k <= factory[i][1] ,即不超过剩余的机器人数量和当前工厂的容量。对于每个 k ,我们需要计算当前工厂修理这些机器人所需的成本 sum ,以及下一个工厂开始修理剩余机器人所需的最小总成本 dp[i + 1][j + k] ,然后取最小值作为 dp[i][j] 的值。

最后返回 dp[0][0] 即可。

代码如下:

class Solution:
    def totalCost(self, costs: List[int], k: int, factory: List[List[int]]) -> int:
        # 定义无穷大
        inf = float('inf')
        # 获取工厂和机器人的数量
        n = len(factory)
        m = len(costs)
        # 如果需要修理的机器人数量大于数组长度,直接返回-1
        if k > m:
            return -1
        # 定义动态规划数组,dp[i][j]表示用[i, n - 1]的工厂修理[j, m - 1]的机器人所需的最小总成本
        dp = [[inf] * (m + 1) for _ in range(n + 1)]
        # 初始化边界条件,如果没有机器人需要修理,那么总成本为0
        for i in range(n + 1):
            dp[i][m] = 0
        # 从右下角开始递推
        for i in range(n - 1, -1, -1):
            for j in range(m - 1, -1, -1):
                # 不用第i个工厂修理任何机器人,那么dp[i][j] = dp[i + 1][j]
                dp[i][j] = dp[i + 1][j]
                # 用第i个工厂修理一些机器人,枚举这些机器人的数量k,满足j + k - 1 < m 和 k <= factory[i][1]
                sum = 0 # 当前工厂修理这些机器人所需的成本
                for k in range(1, min(m - j, factory[i][1]) + 1):
                    # 累加当前工厂修理第j + k - 1个机器人所需的成本
                    sum += costs[j + k - 1]
                    # 更新dp[i][j]为当前工厂修理这些机器人所需的成本和下一个工厂开始修理剩余机器人所需的最小总成本之和的最小值
                    dp[i][j] = min(dp[i][j], sum + dp[i + 1][j + k])
        # 返回dp[0][0]即可
        return dp[0][0]

第四题

给你一个长度为 n 的整数数组 nums ,数组中的每个元素表示一辆机器人的位置。你需要将这些机器人分配到 m 个工厂中,工厂的位置也是用整数表示的。你可以按照以下规则分配机器人:

  • 你可以选择任意数量的机器人分配到任意一个工厂,但是不能超过工厂的容量。
  • 你必须按照数组中的顺序分配机器人,也就是说,如果你将第 i 个机器人分配到某个工厂,那么你不能再将第 i - 1 个或者更前面的机器人分配到其他工厂。
  • 如果你将第 i 个机器人分配到第 j 个工厂,那么你必须支付 abs(nums[i] - factory[j][0]) 的成本,其中 abs(x) 表示 x 的绝对值。
  • 如果你将多个相邻的机器人分配到同一个工厂,那么你必须额外支付这些机器人之间的碰撞费用。碰撞费用等于这些机器人之间的距离之和。例如,如果你将第 2、3、4 个机器人分配到同一个工厂,那么碰撞费用等于 (nums[2] - nums[1]) + (nums[3] - nums[2]) + (nums[4] - nums[3]) = nums[4] - nums[1] 。

请你返回最小化总成本(包括分配成本和碰撞费用)的方案下,需要支付的总成本。

示例 1:

输入:nums = [1,2,3,4,5], m = 2, factory = [[1,2],[3,2]] 输出:6 解释:最优方案是将第 1、2 个机器人分配到第一个工厂,将第 3、4、5 个机器人分配到第二个工厂,总成本为 abs(1 - 1) + abs(2 - 1) + abs(3 - 3) + abs(4 - 3) + abs(5 - 3) = 0 + 1 + 0 + 1 + 2 = 4 ,碰撞费用为 (2 - 1) + (3 - 2) + (4 - 3) + (5 - 4) = 4 ,所以最终需要支付的总成本为 4 + 4 = 8 。

题解:

这道题的思路是使用动态规划的方法,维护一个二维数组 dp ,其中 dp[i][j] 表示用 [i, m - 1] 的工厂修理 [j, n - 1] 的机器人所需的最小总成本。我们从右下角开始递推,对于每个 dp[i][j] ,我们有两种选择:

  • 不用第 i 个工厂修理任何机器人,那么 dp[i][j] = dp[i + 1][j] ,即跳过当前工厂,直接考虑下一个工厂。
  • 用第 i 个工厂修理一些机器人,那么我们需要枚举这些机器人的数量 k ,满足 j + k - 1 < n 和 k <= factory[i][1] ,即不超过剩余的机器人数量和当前工厂的容量。对于每个 k ,我们需要计算当前工厂修理这些机器人所需的成本 sum ,以及下一个工厂开始修理剩余机器人所需的最小总成本 dp[i + 1][j + k] ,然后取最小值作为 dp[i][j] 的值。

最后返回 dp[0][0] 即可。

代码如下:

class Solution:
    def minimumTotalDistance(self, nums: List[int], m: int, factory: List[List[int]]) -> int:
        # 定义无穷大
        inf = float('inf')
        # 获取工厂和机器人的数量
        n = len(factory)
        m = len(nums)
        # 将工厂和机器人按位置排序
        factory.sort()
        nums.sort()
        # 定义动态规划数组,dp[i][j]表示用[i, n - 1]的工厂修理[j, m - 1]的机器人所需的最小总成本
        dp = [[inf] * (m + 1) for _ in range(n + 1)]
        # 初始化边界条件,如果没有机器人需要修理,那么总成本为0
        for i in range(n + 1):
            dp[i][m] = 0
        # 从右下角开始递推
        for i in range(n - 1, -1, -1):
            for j in range(m - 1, -1, -1):
                # 不用第i个工厂修理任何机器人,那么dp[i][j] = dp[i + 1][j]
                dp[i][j] = dp[i + 1][j]
                # 用第i个工厂修理一些机器人,枚举这些机器人的数量k,满足j + k - 1 < m 和 k <= factory[i][1]
                sum = 0 # 当前工厂修理这些机器人所需的成本
                for k in range(1, min(m - j, factory[i][1]) + 1):
                    # 累加当前工厂修理第j + k - 1个机器人所需的成本
                    sum += abs(nums[j + k - 1] - factory[i][0])
                    # 更新dp[i][j]为当前工厂修理这些机器人所需的成本和下一个工厂开始修理剩余机器人所需的最小总成本之和的最小值
                    dp[i][j] = min(dp[i][j], sum + dp[i + 1][j + k])
        # 返回dp[0][0]即可
        return dp[0][0]