问题描述
小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. 实现步骤
-
统计每个序号的出现次数:
- 使用哈希表(如Python中的
Counter)统计每个序号出现的次数。
- 使用哈希表(如Python中的
-
检查每个序号的次数是否为5的倍数:
- 遍历哈希表中的每个值,检查是否可以被5整除。
-
返回结果:
- 如果所有序号的次数都是5的倍数,返回
"True";否则,返回"False"。
- 如果所有序号的次数都是5的倍数,返回
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") # 大组
代码说明
-
导入
Counter:Counter是Python标准库collections中的一个类,用于统计可哈希对象的元素数量。
-
统计次数:
counts = Counter(nums)会返回一个字典,键为序号,值为该序号出现的次数。
-
检查每个序号的次数:
- 使用
for count in counts.values():遍历所有序号的出现次数。 - 如果有任何一个
count不能被5整除,立即返回"False"。
- 使用
-
返回结果:
- 如果所有序号的次数都是5的倍数,循环结束后返回
"True"。
- 如果所有序号的次数都是5的倍数,循环结束后返回
-
测试用例:
- 包含了问题描述中的样例和一些额外的边界情况,确保代码的正确性。
运行结果
运行上述代码,输出应为:
True
True
True
True
True
True
True
True
True
True
每个print语句比较solution的输出与预期结果是否相等,返回True表示测试通过。
可能的优化与扩展
-
提前终止:
- 在统计过程中,如果发现某个序号的数量超过了5的倍数(例如多于5但不足10),可以提前判断无法分组。
-
输入验证:
- 检查输入是否为列表,且其中的元素是否为整数。
-
处理大数据:
- 虽然当前的时间复杂度已经足够高效,但在处理极大的数据集时,可以考虑并行处理或优化哈希表的使用。
-
扩展问题:
- 例如,允许组内棋子的序号可以有一定的差异(如相差1),或者组的大小不是固定的5个。
总结
本题通过统计每个棋子序号的出现次数,并检查这些次数是否都是5的倍数,来判断是否可以将棋子分组。该方法简单高效,适用于各种规模的输入。理解问题的关键在于明确分组的条件,并利用适当的数据结构(如哈希表)来高效地实现统计和检查过程。