飞行棋棋子分组问题 | 豆包MarsCode AI刷题

92 阅读5分钟

问题描述

小M和小F在玩飞行棋。游戏结束后,他们需要将桌上的飞行棋棋子分组整理好。现有N个棋子,每个棋子上有一个数字序号。小M的目标是将这些棋子分成M组,每组恰好5个,并且组内棋子的序号相同。需要判断是否可以按照这种方式对棋子进行分组。

示例

  • 样例1:

    • 输入:nums = [1, 2, 3, 4, 5]
    • 输出:"False"
    • 解释:虽然有5个棋子,但序号各不相同,无法组成有效的组。
  • 样例2:

    • 输入:nums = [1, 1, 1, 1, 2, 1, 2, 2, 2, 2]
    • 输出:"True"
    • 解释:可以分为两组,每组5个棋子,分别为五个1和五个2
  • 样例3:

    • 输入:nums = [5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
    • 输出:"True"
    • 解释:所有棋子序号相同,可以组成两组。
  • 样例4:

    • 输入:nums = [7, 7, 7, 8, 8, 8, 8, 8, 7, 7]
    • 输出:"True"
    • 解释:可以分为两组,五个7和五个8
  • 样例5:

    • 输入:nums = [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
    • 输出:"False"
    • 解释:总共有11个棋子,无法完全分成每组5个。

解题思路

1. 理解问题

  • 目标:将所有棋子分成若干组,每组恰好5个,且组内棋子的序号相同。
  • 条件
    • 每个组必须有5个棋子。
    • 同一组内的棋子序号相同。
    • 所有棋子必须被分组,且不能剩余。

2. 分析

为了满足条件,每个棋子的数量必须是5的倍数。这意味着:

  • 对于每个不同的序号,其出现次数必须能够被5整除。
  • 如果有任意一个序号的出现次数不是5的倍数,无法完全分组。

此外,组的总数应当是所有棋子数目除以5,即 M = N / 5。但关键在于每个序号的数量是否符合5的倍数。

3. 实现步骤

  1. 统计每个序号的出现次数

    • 使用哈希表(如Python中的Counter)统计每个序号出现的次数。
  2. 检查每个序号的次数是否为5的倍数

    • 遍历哈希表中的每个值,检查是否可以被5整除。
  3. 返回结果

    • 如果所有序号的次数都是5的倍数,返回"True";否则,返回"False"

4. 边界条件

  • 空列表:没有棋子,可以认为满足条件,返回"True"
  • 少于5个棋子:如果总数不是5的倍数,或某个序号的数量不足5个,返回"False"
  • 棋子总数不是5的倍数:直接返回"False",因为无法完全分组。

5. 时间和空间复杂度

  • 时间复杂度

    • 统计次数:O(N),其中N是棋子的数量。
    • 检查每个序号的次数:O(K),其中K是不同序号的数量。
    • 总体时间复杂度为O(N + K),在最坏情况下,K= N(每个棋子序号不同),时间复杂度为O(N)。
  • 空间复杂度

    • 需要额外的空间存储哈希表,空间复杂度为O(K)。

代码实现

以下是基于上述思路的Python实现:

def solution(nums):
    from collections import Counter
    counts = Counter(nums)
    for count in counts.values():
        if count % 5 != 0:
            return "False"
    return "True"

if __name__ == "__main__":
    # 测试样例
    print(solution([1, 2, 3, 4, 5]) == "False")  # 样例1
    print(solution([1, 1, 1, 1, 2, 1, 2, 2, 2, 2]) == "True")  # 样例2
    print(solution([5, 5, 5, 5, 5, 5, 5, 5, 5, 5]) == "True")  # 样例3
    print(solution([7, 7, 7, 8, 8, 8, 8, 8, 7, 7]) == "True")  # 样例4
    print(solution([9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]) == "False")  # 样例5

    # 额外测试用例
    print(solution([]) == "True")  # 边界情况:空列表
    print(solution([1,1,1,1,1]) == "True")  # 恰好一组
    print(solution([1,1,1,1,1,2,2,2,2,2,3,3,3,3,3]) == "True")  # 多组
    print(solution([1,1,1,1,1,2,2,2,2]) == "False")  # 不完整的组
    print(solution([4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]) == "True")  # 大组

代码说明

  1. 导入Counter

    • Counter是Python标准库collections中的一个类,用于统计可哈希对象的元素数量。
  2. 统计次数

    • counts = Counter(nums)会返回一个字典,键为序号,值为该序号出现的次数。
  3. 检查每个序号的次数

    • 使用for count in counts.values():遍历所有序号的出现次数。
    • 如果有任何一个count不能被5整除,立即返回"False"
  4. 返回结果

    • 如果所有序号的次数都是5的倍数,循环结束后返回"True"
  5. 测试用例

    • 包含了问题描述中的样例和一些额外的边界情况,确保代码的正确性。

运行结果

运行上述代码,输出应为:

True
True
True
True
True
True
True
True
True
True

每个print语句比较solution的输出与预期结果是否相等,返回True表示测试通过。

可能的优化与扩展

  1. 提前终止

    • 在统计过程中,如果发现某个序号的数量超过了5的倍数(例如多于5但不足10),可以提前判断无法分组。
  2. 输入验证

    • 检查输入是否为列表,且其中的元素是否为整数。
  3. 处理大数据

    • 虽然当前的时间复杂度已经足够高效,但在处理极大的数据集时,可以考虑并行处理或优化哈希表的使用。
  4. 扩展问题

    • 例如,允许组内棋子的序号可以有一定的差异(如相差1),或者组的大小不是固定的5个。

总结

本题通过统计每个棋子序号的出现次数,并检查这些次数是否都是5的倍数,来判断是否可以将棋子分组。该方法简单高效,适用于各种规模的输入。理解问题的关键在于明确分组的条件,并利用适当的数据结构(如哈希表)来高效地实现统计和检查过程。