刷题笔记-组装电脑 | 豆包MarsCodeAI刷题

34 阅读10分钟

组装电脑

题目描述

image.png

小U是一位电脑外壳供应商,而小S是一位电脑零件供应商。他们希望合作组装电脑。小U生产了n个电脑外壳,每个外壳的售价是a,而小S生产了n个零件,每个零件的售价是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

1. 初步分析问题

问题理解

需要找到方法使得电脑外壳和零件的配对售价完全相同,并且尽可能多地配对。

数据结构选择

  1. 哈希表(字典):记录每个可能售价的出现次数,帮助统计售价配对数量。

算法步骤

  1. 计算所有可能的售价:遍历外壳售价 a_i 和零件售价 b_j,计算其和 a_i + b_j
  2. 统计每个售价的出现次数:使用哈希表记录每个售价的配对数量。
  3. 找出出现次数最多的售价:遍历哈希表,确定最多可以组装的电脑数量。

关键点

  • 使用哈希表高效统计和查找售价。
  • 遍历所有组合计算售价。

2. 尝试实现代码

def solution(n: int, a: list, b: list) -> int:
    # 初始化哈希表
    price_count = {}
    
    # 遍历所有可能的售价
    for i in range(n):
        for j in range(n):
            price = a[i] + b[j]
            # 更新哈希表
            if price in price_count:
                price_count[price] += 1
            else:
                price_count[price] = 1
    
    # 找出出现次数最多的售价
    max_count = 0
    for count in price_count.values():
        if count > max_count:
            max_count = count
    
    return max_count

# 测试样例
print(solution(n = 4, a = [1, 2, 3, 4], b = [1, 2, 4, 5]))  # 应输出: 3
print(solution(n = 3, a = [1, 1, 2], b = [2, 2, 3]))        # 应输出: 2
print(solution(n = 5, a = [5, 5, 5, 5, 5], b = [1, 2, 3, 4, 5]))  # 应输出: 1

3. 第一次发现问题

后面两组输出错误:

  • print(solution(n = 3, a = [1, 1, 2], b = [2, 2, 3])) 应该输出 2,实际输出 4
  • print(solution(n = 5, a = [5, 5, 5, 5, 5], b = [1, 2, 3, 4, 5])) 应该输出 1,实际输出 5

错误分析

由于重复使用某个零件与多个外壳配对,需确保每个外壳和零件只能组合一次。

4. 尝试解决问题

使用布尔数组来标记每个外壳和零件是否已被使用。这种方法可以有效避免重复使用相同的外壳和零件,同时处理售价重复的情况。

  1. 售价组合生成:首先生成所有可能的售价组合,并存储在 price_count 字典中。
  2. 布尔数组:使用 used_shellsused_parts 布尔数组,分别跟踪外壳和零件的使用情况。
  3. 搭配计算:遍历每个售价的组合,当找到一个未使用的外壳和零件时,将其标记为已使用,并增加可组装电脑的数量。
  4. 结果输出:确保计算出的最大可组装电脑数量符合预期。
def max_computers(n, a, b):
    # 创建一个字典来存储售价及其对应的组合
    price_count = {}

    # 生成每对外壳和零件组合的售价
    for i in range(n):
        for j in range(n):
            price = a[i] + b[j]
            if price not in price_count:
                price_count[price] = []
            price_count[price].append((i, j))

    # 计算可以组装的电脑的最大数量
    max_computer_count = 0

    # 使用布尔数组来跟踪已使用的外壳和零件
    used_shells = [False] * n
    used_parts = [False] * n

    # 遍历每个售价组合,计算可以组装的电脑的数量
    for price, combinations in price_count.items():
        for shell_index, part_index in combinations:
            # 检查该外壳和零件是否已经使用
            if not used_shells[shell_index] and not used_parts[part_index]:
                max_computer_count += 1
                used_shells[shell_index] = True  # 标记外壳为已使用
                used_parts[part_index] = True    # 标记零件为已使用
                break  # 找到一对后跳出内层循环

    return max_computer_count

# 测试样例
print(max_computers(4, [1, 2, 3, 4], [1, 2, 4, 5]))  # 应输出: 3,输出4
print(max_computers(3, [1, 1, 2], [2, 2, 3]))        # 应输出: 2,输出2
print(max_computers(5, [5, 5, 5, 5, 5], [1, 2, 3, 4, 5]))  # 应输出: 1,输出5

5. 第二次发现问题

在尝试解决问题时,发现输出不正确的情况:

  • print(max_computers(4, [1, 2, 3, 4], [1, 2, 4, 5])) 应该输出 3,但实际输出 4。这是因为在计算售价组合时,虽然确保了外壳和零件的唯一性,但未考虑每个售价的组合可能会产生多个计算。
  • print(max_computers(5, [5, 5, 5, 5, 5], [1, 2, 3, 4, 5])) 应该输出 1,但实际输出 5。这表明当售价组合的计算未充分管理重复使用的情况时,可能导致结果的过高预估。

6. 最终解决方案

逻辑思路

  1. 创建售价组合字典:使用字典将每个售价和其对应的组合关系存储起来。
  2. 生成售价组合:通过双重循环遍历所有外壳和零件的组合,记录每种售价下的组合情况。
  3. 排序售价组合:按组合数量对售价进行排序,优先处理可组装数量多的售价。
  4. 计算最大组合数量:遍历排列后的售价组合,检查并计算实际可组装的电脑数量。
  5. 返回最大数量:返回所有售价组合中可以组装的最大电脑数量。

步骤代码详细解释

创建售价组合字典:
price_count = {}
  • 初始化一个空字典 price_count。这个字典将用于存储不同售价(外壳和零件组合的和)及其对应的组合信息。
  • 通过字典的方式管理售价和组合的关系,使得后续的查找和处理更为高效。
生成售价组合:
for i in range(n):
    for j in range(n):
        price = a[i] + b[j]
        if price not in price_count:
            price_count[price] = []
        price_count[price].append((i, j))
  • 使用双重循环遍历外壳 a 和零件 b 的所有组合。
  • 计算售价 price,即外壳和零件的和。
  • 如果该售价在字典中尚不存在,则初始化一个空列表。
  • 将当前组合的索引 (i, j) 添加到对应售价的列表中。
  • 这一步创建了一个售价和其对应组合的映射,方便后续根据售价进行组合数量的计算。
  • 将组合的索引存储在列表中,能够在后续步骤中快速检索和使用。
排序售价组合:
sorted_prices = sorted(price_count.items(), key=lambda x: len(x[1]), reverse=True)
  • 对字典 price_count 中的项进行排序,按照每个售价对应组合的数量进行降序排列。
  • 这样做的目的是优先处理那些组合数量较多的售价,从而提高了可能组装电脑的效率。
  • 通过使用 len(x[1]) 计算每个售价对应的组合数量,确保我们处理的是最有潜力的售价。
计算最大组合数量:
new_max_computer_count = []
  • 初始化一个空列表 new_max_computer_count,用于存储每个售价下可以组装的最大电脑数量。
  • 在后续处理中,我们将记录每个售价组合的最大可组装数量,以便最后返回整体的最大值。
遍历售价组合并计算可组装数量:
for price, combinations in sorted_prices:
    max_computer_count = len(combinations)
    current_count = 0
    used_shells = [False] * n
    used_parts = [False] * n
  • 对每个售价及其组合进行遍历。
  • 初始化 max_computer_count 为当前售价组合的数量。
  • 初始化 current_count0,用于跟踪当前售价下实际可以组装的数量。
  • 创建两个布尔数组 used_shellsused_parts,用于标记哪些外壳和零件已经被使用。
  • 这一步为计算提供了基础,确保我们能追踪每个售价的组合使用情况,避免重复使用外壳和零件。
检查并计数可用组合:
for shell_index, part_index in combinations:
    if not used_shells[shell_index] and not used_parts[part_index]:
        current_count += 1
        used_shells[shell_index] = True
        used_parts[part_index] = True
  • 遍历当前售价的所有组合,检查每个组合中的外壳和零件是否已被使用。
  • 如果外壳和零件都未被使用,则增加 current_count,并将对应的外壳和零件标记为已使用。
  • 通过这一步,实际上计算出在当前售价条件下,可以组装的电脑数量,确保外壳和零件没有重复使用。
更新最大组合数量:
max_computer_count = min(max_computer_count, current_count)
new_max_computer_count.append(max_computer_count)
  • 使用 min() 函数将 current_countmax_computer_count 进行比较,确保只保留最小值。
  • 将这个值存入 new_max_computer_count 列表中。
  • 保证每个售价返回的组合数量是基于实际可组装数量而更新的,避免过高的预估。
返回最大数量:
return max(new_max_computer_count)
  • 返回列表 new_max_computer_count 中的最大值。
  • 最终的返回值是所有售价组合中可以组装的最大电脑数量,符合题目要求。

完整代码

def solution(n, a, b):
    price_count = {}
    for i in range(n):
        for j in range(n):
            price = a[i] + b[j]
            if price not in price_count:
                price_count[price] = []
            price_count[price].append((i, j))
    sorted_prices = sorted(price_count.items(), key=lambda x: len(x[1]), reverse=True)
    new_max_computer_count = []
    for price, combinations in sorted_prices:
        max_computer_count = len(combinations)
        current_count = 0
        used_shells = [False] * n
        used_parts = [False] * n
        for shell_index, part_index in combinations:
            if not used_shells[shell_index] and not used_parts[part_index]:
                current_count += 1
                used_shells[shell_index] = True
                used_parts[part_index] = True
        max_computer_count = min(max_computer_count, current_count)
        new_max_computer_count.append(max_computer_count)
    return max(new_max_computer_count)

print(solution(4, [1, 2, 3, 4], [1, 2, 4, 5]))  
print(solution(3, [1, 1, 2], [2, 2, 3]))        
print(solution(5, [5, 5, 5, 5, 5], [1, 2, 3, 4, 5]))  

image.png

7. 总结与收获

  • 深入问题分析:在解决问题的过程中,仔细理解题目要求是关键。通过明确问题的核心,能够更高效地找到合适的解决方案,避免在不必要的细节上浪费时间。

  • 数据结构的巧妙运用:哈希表和布尔数组在解题中发挥了重要作用。哈希表帮助管理售价组合,提升了代码的清晰度,而布尔数组有效地追踪了已使用的外壳和零件,使数据管理变得更加简便。

  • 逐步调试的重要性:多次测试和细致的检验彰显了调试过程的必要性。及时发现并修复错误,确保了最终结果的准确性。每一次小问题的解决都带来了成就感,让整个过程更具乐趣。

  • 算法优化的乐趣:对售价组合的排序优化了计算效率,优先处理组合数量多的售价,使得整体流程更加流畅。这个过程不仅提高了程序的运行速度,也增强了对算法设计的理解。

  • 实践中的成长:编码过程中不断尝试和调整,加深了对数据结构和算法应用的认识。每个挑战都是一个学习的机会,积累的经验为未来处理类似问题打下了坚实基础。

  • 注重代码注释与文档化:为代码添加详细注释,使得在后续回顾和维护时能够迅速理解逻辑。