问题描述
给定一个长度为 nn 的序列 a1,a2,…,ana1,a2,…,an,你可以选择删去其中最多 n−1n−1 个数,得到一个新序列 b1,b2,…,bmb1,b2,…,bm (1≤m≤n1≤m≤n),新序列保留原来的相对顺序。你的目标是删除某些数,使得新序列的第 ii 个数 bi=ibi=i。现在需要求出最少删除多少个数才能得到这样的序列,如果无法得到,输出 −1−1。
例如,对于序列 [1, 4, 2, 3, 5],删除第 2 个和第 5 个元素后,可以得到序列 [1, 2, 3]。
解题思路
- 识别目标序列:我们需要找到一个子序列,使得这个子序列的元素是
[1, 2, 3, ..., k]的形式。 - 计算删除次数:如果存在这样的子序列,计算需要删除的元素个数。如果不存在这样的子序列,返回
-1。
代码步骤
我们可以通过以下步骤来实现这个算法:
- 遍历数组:遍历数组
a,尝试找到一个从1开始的连续递增子序列。 - 记录位置:使用一个数组或字典来记录每个数字的位置。
- 检查连续性:检查是否存在从1开始的连续递增子序列。
- 计算删除次数:如果存在这样的子序列,计算需要删除的元素个数。
def solution(n: int, a: list) -> int:
# 记录每个数字的位置
position = {}
for i in range(n):
position[a[i]] = i
# 初始化最长连续子序列的长度
max_len = 0
# 遍历数组,尝试找到最长连续递增子序列
for num in range(1, n + 1):
if num in position:
# 检查是否连续
if num == 1 or (num - 1 in position and position[num] > position[num - 1]):
max_len += 1
else:
break
else:
break
# 如果最长连续子序列的长度为0,返回-1
if max_len == 0:
return -1
# 计算需要删除的元素个数
return n - max_len
if __name__ == '__main__':
print(solution(5, [1, 4, 2, 3, 5]) == 2)
print(solution(3, [3, 3, 2]) == -1)
print(solution(5, [1, 2, 3, 4, 5]) == 0)
关键步骤
- 记录位置:使用字典
position记录每个数字的位置。 - 检查连续性:遍历数字
1到n,检查是否存在连续递增的子序列。 - 计算删除次数:如果存在连续递增的子序列,计算需要删除的元素个数。
这个问题属于动态规划和贪心算法的结合题型。具体来说,它涉及到寻找一个最长的连续递增子序列,并计算需要删除的最少元素个数。
题型分类
- 动态规划:用于寻找最优解,通常涉及状态转移和子问题最优解的组合。
- 贪心算法:用于在每一步选择当前最优解,以期望最终得到全局最优解。
解题思路
- 理解问题:我们需要找到一个子序列,使得这个子序列的元素是
[1, 2, 3, ..., k]的形式。 - 记录位置:使用一个数据结构(如字典)记录每个数字在原序列中的位置。
- 检查连续性:遍历数字
1到n,检查是否存在连续递增的子序列。 - 计算删除次数:如果存在连续递增的子序列,计算需要删除的元素个数。
解决方法
- 记录位置:使用字典
position记录每个数字的位置。 - 遍历检查:从数字
1开始,检查是否存在连续递增的子序列。 - 动态更新:如果当前数字
num存在且位置连续,则更新最长连续子序列的长度。 - 计算结果:根据最长连续子序列的长度,计算需要删除的元素个数。
关键点
- 记录位置:使用字典
position记录每个数字的位置。 - 检查连续性:遍历数字
1到n,检查是否存在连续递增的子序列。 - 动态更新:如果当前数字
num存在且位置连续,则更新最长连续子序列的长度。 - 计算结果:根据最长连续子序列的长度,计算需要删除的元素个数。
通过这种方法,我们可以有效地解决这类问题。