class Solution {
public int removeDuplicates(int[] nums) {
int firstDuplicateMark = 0;
//数组已经是升序了
for (int i = 1;i < nums.length; i++) {//总是数组中要比较的前一个数
if(nums[i-1]==nums[i])
continue;
//定位到不重复的数据
//这里选择不处理“刚好下一个不重复”的情况
nums[++firstDuplicateMark]=nums[i];
}
return firstDuplicateMark+1;
}
}
这题比较简单。我使用for循环构建双指针,实际上和官方解答思路是一致的;但是官方解答在多定义了一个int类型变量的情况下居然内存的表现比我好,这是我没搞懂的。
当然我的源代码还可以继续改进:针对输入先进行if判断,如果nums为null或者长度为0的话,可以直接返回0,这样子程序可以更快。
class Solution {
public int removeDuplicates(int[] nums) {
int n = nums.length;
if (n == 0) {
return 0;
}
int fast = 1, slow = 1;
while (fast < n) {
if (nums[fast] != nums[fast - 1]) {
nums[slow] = nums[fast];
++slow;
}
++fast;
}
return slow;
}
}
时间复杂度
O
(
n
)
O(n)
O(n),因为要遍历整个数组;空间复杂度
O
(
1
)
O(1)
O(1),只用使用常数个额外空间。
顺便补充扩展,假设每次保留至多两位重复的数字而非一位呢?有个前辈给出了扩展:
class Solution {
public int removeDuplicates(int[] nums) {
return process(nums, 2);
}
int process(int[] nums, int k) {//k为保留的数位
int idx = 0;
for (int x : nums) {
//数组的前k位无论什么条件都是直接复制
//idx表示已排序数组的最后一个元素坐标
if (idx < k || nums[idx - k] != x) nums[idx++] = x;
}
return idx;
}
}
对于此类问题,我们应该进行如下考虑:
- 由于是保留 k 个相同数字,对于前 k 个数字,我们可以直接保留。
- 对于后面的任意数字,能够保留的前提是:与当前写入的位置前 k 个元素进行比较,不相同则保留。
idk指向元素待插入位置
注意这种方法是必须要求数组已经升序排序的。