青训营X豆包MarsCode 技术训练营之组装电脑 | 豆包MarsCode AI 刷题

157 阅读5分钟

题目描述

小 U 是电脑外壳供应商,有 n 个电脑外壳且每个有售价 aᵢ;小 S 是电脑零件供应商,也有 n 个电脑零件且每个有售价 bᵢ。当一个外壳和一个零件配对时,电脑售价为外壳售价与零件售价之和。问题是找出一些外壳和零件的配对,使得这些配对形成的电脑售价全部相同,求最多可以组装多少部售价相同的电脑。并给出了三个测试样例,包括输入的 n(外壳和零件的数量)、外壳售价列表 a 和零件售价列表 b,以及对应的输出结果(最多可组装的售价相同的电脑数量)。

测试样例

样例1:

输入:n=4,a=[1,2,3,4],b=[1,2,4,5]输出:3

样例2:

输入:n=3,a=[1,1,2],b=[2,2,3]输出:2

样例3:

输入:n=5,a=[5,5,5,5,5],b=[1,2,3,4,5]输出:1

题目分析

首先明确题目要求:找到一些外壳和零件的配对,使得组合成的电脑的售价全部相同,求最多可以组装多少台售价相同的电脑。 分析思路:

问题的核心:寻找两组数a和 b 中元素相加的组合,使得这些组合的和相同且不重复使用元素。即最大化电脑售价相同的配对数。

  • 配对的要求

    • 每次组合的售价需要相同。
    • 配对时,外壳和零件的索引不能重复使用,意味着每个外壳和零件只能用于一次配对。
  • 题目特点

    • 这道题类似于“二分图最大匹配”问题。
    • 我们需要找出最多的“不重叠配对”,满足这些配对的售价一致

算法步骤

考虑到问题要求同时满足组合和不重叠配对,于是我们首先可以先形成一个初步的伪代码思想:

1、找到售价组合。

在这里由于需要记录组合的情况,于是可以利用字典(哈希表)来记录所有的组合结果,键为售价,值为所有产生该售价的 (外壳索引, 零件索引) 配对列表。 示例:假设有售价列表 a = [1, 2, 3]b = [3, 2, 1],构建出的售价和配对字典为:

{4: [(0, 2), (1, 1), (2, 0)]}

2. 寻找最大不重叠配对数

对于字典中每一个售价,我们要找到最多的、不重叠的配对,以形成最大数量的售价相同电脑组合。 思想:利用贪心选择的思想,确保每次选择的配对都不包含已使用的外壳和零件。这样可以避免重复使用元素,从而满足题目要求。

实现方式:对于每种售价对应的配对列表,遍历每一对 (外壳索引, 零件索引)。如果该配对中的外壳和零件都未被使用,则将其计入有效配对,并标记该外壳和零件为已使用。通过这种贪心策略,可以找到每种售价下的最大不重叠配对数。

示例:对于售价为4的配对列表 [(0, 2), (1, 1), (2, 0)],假设我们依次遍历:

  • 选择 (0, 2),标记外壳0和零件2已使用。
  • 选择 (1, 1),标记外壳1和零件1已使用。
  • 选择 (2, 0),标记外壳2和零件0已使用。

最终选择了3个配对,符合题意且是最大不重叠组合数。

3. 找到最大同价电脑的数量

在所有售价中,取不重叠配对数量的最大值作为结果。 思想:题目要求的是最多的售价相同的电脑数量,因此遍历所有售价的结果取最大值即可。

  • 实现方式:使用变量 max_count 来记录所有售价中最大的配对数量,返回该值作为最终答案。

这种算法的关键在于将问题分解为多个售价的独立匹配问题,并使用贪心法确保配对不重叠,从而达到题目要求的最优解。

算法代码解析

  1. 创建售价到配对列表的字典
price_to_pairs = defaultdict(list)
  1. 计算所有可能的售价和对应的配对
    # 计算所有可能的售价和对应的配对
    for i in range(n):
        for j in range(n):
            total_price = a[i] + b[j]
            price_to_pairs[total_price].append((i, j))
  1. 用贪心算法选择不重叠配对

    for pairs in price_to_pairs.values():
        # 使用集合来跟踪已用过的外壳和零件
        used_shells = set()
        used_parts = set()
        count = 0
        
        # 对于每个售价的配对列表,用贪心算法选择不重叠配对
        for shell, part in pairs:
            if shell not in used_shells and part not in used_parts:
                # 选择当前配对
                used_shells.add(shell)
                used_parts.add(part)
                count += 1
  1. 返回结果
   max_count = max(max_count, count)
   return max_count

完整代码

from collections import defaultdict
def solution(n: int, a: list, b: list) -> int:
    # write code here
    # 创建售价到配对列表的字典
    price_to_pairs = defaultdict(list)
    
    # 计算所有可能的售价和对应的配对
    for i in range(n):
        for j in range(n):
            total_price = a[i] + b[j]
            price_to_pairs[total_price].append((i, j))
    
    # 记录最大不重叠配对数
    max_count = 0
    
    # 对每种售价,计算最大不重叠配对数量
    for pairs in price_to_pairs.values():
        # 使用集合来跟踪已用过的外壳和零件
        used_shells = set()
        used_parts = set()
        count = 0
        
        # 对于每个售价的配对列表,用贪心算法选择不重叠配对
        for shell, part in pairs:
            if shell not in used_shells and part not in used_parts:
                # 选择当前配对
                used_shells.add(shell)
                used_parts.add(part)
                count += 1
        
        # 更新最大配对数量
        max_count = max(max_count, count)
    
    return max_count