问题描述
给定一个长度为 n 的序列a1,a2,…,an,你可以选择删去其中最多 n−1 个数,得到一个新序列 b1,b2,…,bm (1≤m≤n),新序列保留原来的相对顺序。你的目标是删除某些数,使得新序列的第 i 个数 bi=i。现在需要求出最少删除多少个数才能得到这样的序列,如果无法得到,输出 −1。
例如,对于序列 [1, 4, 2, 3, 5],删除第 2 个和第 5 个元素后,可以得到序列 [1, 2, 3]。
问题理解
- 删去至多n-1个数,说明最后满足题意的序列必须不为空。
- 新序列保留原来的相对顺序,删除元素后不能改变原来的相对顺序
- 题目关键是要让第 i 个数 bi = i,据此可以对原序列遍历,只要第 i 个数 bi ≠ i,则把当前位置元素删除,统计个数加一
解题思路
- 由于需要对每一位元素进行判断,固然要用到遍历
- 题目只要求统计删除元素个数,因此定义一个变量
count记录删除元素个数 - 遍历时,判断每一位元素和序列编号是否一致,比如序列第一位必须为1,第二位必须为2,以此类推
- 当删除一个元素后,后面元素位置名义上需要向前移动一位,为了记录当前位置应该是哪一位,可以用一个变量
currentNum记录遍历到当前元素应该是第几位,当删除元素时,count++,currentNum--,即本该是第 i 位的变为第i - 1位。如删除第2位,则第3位应变为第2位。 - 继续遍历之后位元素,直到判断完所有元素是否满足题意
- 若最后删除的元素超过 n - 1 ,则不满足题意,输出 -1
- 最后输出
count就是题目所需的解
代码详解
public static int solution(int n, int[] a) {
// 统计删除元素个数
int count = 0;
// 当前位应为第几位
int currentNum = 1;
for (int i = 0; i < a.length; i++) {
// 当前元素不应该在当前位置,要删除当前元素
if (currentNum != a[i]) {
count++;
currentNum--;
}
currentNum++;
}
if (count > n - 1) return -1;
return count; // placeholder return
}
复杂度计算
时间复杂度:O(n), n是题目给定数组的长度
空间复杂度:O(1)
总结
该思路设计巧妙在于,当判断完前面的元素是否符合题意之后,执行删除完无需重复判断前面的数字,前面的数字已经是满足等于序列号这个条件了,所以可以直接从删除位置下一位开始向后判断。