最近打算开始找工作了,现在算法是程序员必考的一项,因此在训练算法过程中,顺便把题解写下来,自己理解的同时,也尝试让别人理解,进而巩固算法思路。
1. 题意解析
题目中已经标明了一些关键字,我们不妨从这些“提示”中尝试理解一下题意:数组、升序排列、不使用额外空间。
数组:对数组来说,其内存空间地址是连续的,因此不能直接删除某个下标的值,正确的操作应该是用新值替换掉旧值。升序排列:对一个升序数组来说,重复元素,一定是相邻的,所以对重复元素的判断,其实就是相邻元素的比较。不使用额外空间:其空间复杂度为 O(1)。
如果可以用新数组的话,我们可以按这样的步骤来:
- 定义一个新数组,下标从0开始;
- 对原数组进行遍历,遍历过程中进行相邻元素的比较,然后将不重复的元素插入到新数组中,新数组下标+1。
但有了空间复杂度的限制,我们只能将上面两步在同一个数组中进行。
2. 题解
根据上面的分析,我们可以列出以下步骤:
首先,定义两个指针fast、slow并明确其含义:
- fast:对数组元素进行遍历的指针,用来寻找不重复元素;
- slow: “新”数组的下标,指向更新的元素;
在fast指针进行遍历的时候,如果nums[fast] != nums[fast - 1]的话,表明nums[fast]是不重复的元素,因此将nums[fast]赋值给nums[slow],同时slow++。
需要注意的是,因为nums[fast]是和它的前一个元素进行比较,因此fast要从1开始。 同时,因为fast=0时不需要比较,直接更新成新数组的第一个元素即可,因此存在nums[fast]=nums[slow]=nums[0]。
最后,因为slow和fast都是从1开始的,在赋值元素时slow+1,所以最终slow就是新数组的长度。
3.代码
class Solution {
public int removeDuplicates(int[] nums) {
int slow = 1;
for (int fast = 1; fast < nums.length; fast++) {
if (nums[fast] != nums[fast - 1]) {
nums[slow++] = nums[fast];
}
}
return slow;
}
}
4.总结
这道题的关键在于,用双指针将比较操作和更新操作区分开,这样就不用开辟新数组来保存新元素了,就能满足原地操作并得到最终结果。