008-删除有序数组中的重复项 (Remove Duplicates from Sorted Array)
LeetCode 第26题 - 删除有序数组中的重复项的详细题解
题目描述
给你一个 升序排列 的数组 nums,请你 原地 删除重复出现的元素,使每个元素 只出现一次,返回删除后数组的新长度。
元素的 相对顺序 应该保持 一致。然后返回 nums 中唯一元素的个数。
考虑 nums 的唯一元素的数量为 k,你需要做以下事情确保你的题解可以被通过:
- 更改数组
nums,使nums的前k个元素包含唯一元素,并按照它们最初在nums中出现的顺序排列。nums的其余元素与nums的大小不重要。 - 返回
k。
示例
输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4,_,_,_,_,_]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。解题思路
使用双指针法,一个指针 slow 指向当前唯一元素的最后一个位置,另一个指针 fast 遍历数组。当 fast 指向的元素与 slow 指向的元素不同时,将 fast 指向的元素移动到 slow + 1 的位置。
JavaScript 解决方案
/**
* @param {number[]} nums
* @return {number}
*/
const removeDuplicates = (nums) => {
if (nums.length === 0) return 0;
let slow = 0;
for (let fast = 1; fast < nums.length; fast++) {
// 如果当前元素与前一个元素不同,则移动到下一个位置
if (nums[fast] !== nums[slow]) {
slow++;
nums[slow] = nums[fast];
}
}
return slow + 1;
};复杂度分析
- 时间复杂度:O(n),其中 n 是数组长度
- 空间复杂度:O(1),只使用了常数额外空间
测试用例
// 测试函数
const testRemoveDuplicates = () => {
const testCases = [
{
nums: [1, 1, 2],
expected: 2,
expectedArray: [1, 2]
},
{
nums: [0, 0, 1, 1, 1, 2, 2, 3, 3, 4],
expected: 5,
expectedArray: [0, 1, 2, 3, 4]
},
{
nums: [1, 2, 3],
expected: 3,
expectedArray: [1, 2, 3]
},
{
nums: [1, 1, 1, 1],
expected: 1,
expectedArray: [1]
},
{
nums: [],
expected: 0,
expectedArray: []
},
{
nums: [1],
expected: 1,
expectedArray: [1]
}
];
testCases.forEach((testCase, index) => {
const nums = [...testCase.nums]; // 复制数组避免修改原数组
const result = removeDuplicates(nums);
const resultArray = nums.slice(0, result);
const passed = result === testCase.expected &&
JSON.stringify(resultArray) === JSON.stringify(testCase.expectedArray);
console.log(`测试用例 ${index + 1}: ${passed ? '通过' : '失败'}`);
console.log(`输入: nums = [${testCase.nums}]`);
console.log(`期望: ${testCase.expected}, nums = [${testCase.expectedArray}]`);
console.log(`实际: ${result}, nums = [${resultArray}]\n`);
});
};
// 运行测试
testRemoveDuplicates();关键点总结
- 双指针法:使用快慢指针来原地修改数组
- 原地操作:不创建新数组,直接在原数组上操作
- 相对顺序:保持元素的相对顺序不变
- 边界处理:空数组和单个元素的处理
- 返回值:返回唯一元素的数量
总结
这道题考察了以下重点:
- 双指针技巧:理解快慢指针在数组操作中的应用
- 原地算法:如何在不使用额外空间的情况下修改数组
- 数组遍历:高效地遍历和处理数组元素
- 边界处理:对各种边界情况的考虑
双指针法是最优解,时间复杂度为 O(n),空间复杂度为 O(1)。在实际面试中,建议先解释双指针的思路,然后实现算法。