利用快排双色分区partition思想,O(N),O(1)
维护两个指针,将数组分成三个区:
[0 ... validRange]为有效区(全是有效数) (validRange ... curIndex)为垃圾区(全是垃圾数) [curIndex ...]为未知区(还没看的数)
同时记录前一个数preNum和当前数出现次数count,遍历每个数,判断是否垃圾:
当前数首次出现,有效数,发货到有效区,同时扩充有效区; 当前数出现次数<2,有效数,发货到有效区,同时扩充有效区; 当前数出现次数已经>=2,垃圾数,扩充垃圾区;
public int removeDuplicates(int[] nums) {
int n = nums.length;
if (n <= 2) return n;
// [0 ... validRange]为有效区,(validRange ... curIndex)为垃圾区,[curIndex ...]为未知区
int validRange = 0, curIndex = 1; // 有效区右边界,当前处理位置
int preNum = nums[0], count = 1; // 前一个数,出现次数
while (curIndex < n) {
int curNum = nums[curIndex];
if (curNum != preNum) { // 当前数首次出现,有效数
nums[++validRange] = nums[curIndex++]; // 发货到有效区,扩充有效区
preNum = curNum; // 记录该数
count = 1;//出现次数
} else if (count < 2) { // 当前数出现次数<2,有效数,发货到有效区,扩充有效区
nums[++validRange] = nums[curIndex++]; // 发货到有效区,扩充有效区
count++;
} else { // 当前数出现次数已经>=2,垃圾数
curIndex++; // 扩充垃圾区
}
}
return validRange + 1;
}