问题描述
小M有一个独特的方式来收拾家中的盘子。每次用餐后,他会将盘子按照他们的序号顺序叠放。盘子的序号都是唯一的整数,并且在收拾前就是递增的。小M的叠放规则是,每一堆盘子的序号都是连续递增的,并且至少包含3个盘子。需要编写程序帮助小M确定盘子的叠放方式。
例如,输入的盘子序号是 [-3, -2, -1, 2, 10, 15, 16, 18, 19, 20],按照小M的规则,连续递增序列 -3, -2, -1 可以叠在一起表示为 -3--1,而 18, 19, 20 可以叠在一起表示为 18-20。不满足连续递增至少3个的,如 2, 10, 15, 16 都应单独列出。
输入参数
plates: 一个整数数组,表示盘子的序号n: 盘子总数
测试样例
输入:plates = [-3, -2, -1, 2, 10, 15, 16, 18, 19, 20], n = 10
输出:"-3--1,2,10,15,16,18-20"
思路
这个问题的目标是将一个升序排列的盘子序号列表,按照每一段连续递增的序列(至少3个元素)进行分类。如果一个序列的长度小于3,就将这些元素单独列出。最终的输出是一个字符串,每个序列或单个盘子之间用逗号,隔开。
可以用滑动窗口来实现。通过使用两个指针left和right来划定一个窗口,left指针表示当前序列的起始位置,right指针表示当前序列的结束位置。扩展right指针来找到所有连续递增的盘子,然后判断它们的长度。
具体实现
-
初始化:
- 创建一个空的结果列表
res,用于存储最终的结果。 - 使用两个指针:
left = 0表示当前序列的起始位置,right = 1表示当前序列的结束位置。
- 创建一个空的结果列表
-
扩展右指针:
- 使用right指针遍历盘子序列,直到plates[right] != plates[right - 1] + 1为止,即找不到连续递增的序列时,停止扩展。
-
判断当前序列的长度:
- 如果
right - left >= 3,说明当前序列的长度大于等于3,将其表示为一个范围plates\[left]-plates\[right - 1]并加入res。 - 如果
right - left < 3,则将每个元素单独添加到res中。
- 如果
-
更新指针:
- 更新
left = right,即将left指向下一个新的序列的起始位置。 - 更新
right = left + 1,即right指向下一个新的盘子,准备继续判断下一个序列。
- 更新
-
返回结果:
- 最终将结果列表
res中的元素通过逗号,连接成一个字符串返回。
- 最终将结果列表
def solution(plates: list[int], n: int) -> str:
res = []
left = 0
right = 1
while left < n:
# 扩展 right 指针,直到不再连续递增
while right < n and plates[right] == plates[right - 1] + 1:
right += 1
# 判断当前序列的长度
if right - left >= 3:
# 将连续递增序列合并为一个范围表示
res.append(f"{plates[left]}-{plates[right - 1]}")
else:
# 单独列出每个元素,并确保它们是字符串类型
for j in range(left, right):
res.append(str(plates[j]))
# 更新 left 指针
left = right
right = left + 1
# 拼接结果
return ",".join(res)
时间复杂度:
时间复杂度是 O(n) ,其中n是盘子序号的数量,因为每个盘子序号最多会被处理两次(一次通过left指针处理,一次通过right指针扩展)。
遇到的问题及解决方案
在原始代码中,对res列表添加元素时,直接添加的 int 类型的盘子序号plates\[j],当执行 ",".join(res) 时,所以发生 TypeError,因为 ",".join() 只支持字符串类型的元素。
只要在res.append(plates\[j])的时候将新添加的元素转换成str型就可以了,即res.append(str(plates\[j]))。