最近在刷leecode的算法题,发现有好多不会的,就想着做个笔记记录下来,要不时间长久容易忘。在刷题过程中发现用的最熟悉的还是JAVA。花的时间做多,印象越深刻。
计划每天刷两道算法题,坚持总结,总会有改变的。
一.删除排序数组中的重复项 给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。
将最终结果插入 nums 的前 k 个位置后返回 k 。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
判题标准:
系统会用下面的代码来测试你的题解:
1 2 3 4 5 6 7 8 9 10 int [] nums = [...]; int [] expectedNums = [...]; int k = removeDuplicates(nums); assert k = = expectedNums.length;for (int i = 0 ; i < k; i++) { assert nums[i] == expectedNums[i]; }
如果所有断言都通过,那么您的题解将被通过。
示例 1:
1 2 3 4 输入:nums = [1 ,1 ,2 ] 输出:2 , nums = [1 ,2 ,_] 解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1 , 2 。不需要考虑数组中超出新长度后面的元素。
示例 2:
1 2 3 4 输入: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 。不需要考虑数组中超出新长度后面的元素。
提示:
0 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums 已按 升序 排列
作者:力扣 (LeetCode) 链接:https://leetcode.cn/leetbook/read/top-interview-questions-easy/x2gy9m/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
1.双指针解法
题目中要求要是用原地修改输入数组,所以不能创建额外的数组。考虑使用双指针解决。
1.如果左指针和右指针指向的值一样,说明有重复的,左指针不动,右指针继续往右移动。
2.如果左指针和右指针指向的值不一样,左指针右移一位,把右指针指向的值赋给左指针。然后右指针往右移
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 class Solution { public int removeDuplicates (int [] A) { if (A.length==0 || A==null ){ return 0 ; } int left=0 ; for (int right=1 ;right<A.length;right++){ if (A[left]!=A[right]) A[++left]=A[right]; } return ++left; } } 时间复杂度:O(n),其中 n 是数组的长度。快指针和慢指针最多各移动 n次。 空间复杂度:O(1 )。只需要使用常数的额外空间。 ``` >**2. 通用解法** 将原问题的‘’最多保留一位‘’修改为‘’最多保留k位‘’。 对于此类问题,我们应该进行如下考虑: 1. 由于是保留 k 个相同数字,对于前 k 个数字,我们可以直接保留。2. 对于后面的任意数字,能够保留的前提是:与当前写入的位置前面的第 k 个元素进行比较,不相同则保留。举个例子,我们令 k=1 ,假设有样例:[3 ,3 ,3 ,3 ,4 ,4 ,4 ,5 ,5 ,5 ] 1. 设定变量 idx,指向待插入位置。idx 初始值为 0 ,目标数组为 []2. 首先我们先让第 1 位直接保留(性质 1 )。idx 变为 1 ,目标数组为 [3 ]3. 继续往后遍历,能够保留的前提是与 idx 的前面 1 位元素不同(性质 2 ),因此我们会跳过剩余的 3 ,将第一个 4 追加进去。idx 变为 2 ,目标数组为 [3 ,4 ]4. 继续这个过程,跳过剩余的 4 ,将第一个 5 追加进去。idx 变为 3 ,目标数组为 [3 ,4 ,5 ]5. 当整个数组被扫描完,最终我们得到了目标数组 [3 ,4 ,5 ] 和 答案 idx 为 3 。 ```java public int removeDuplicates2 (int [] nums) { return process(nums,1 ) int process (int [] nums,int k) { int index=0 ; for (int x:nums){ if (index<k || nums[index-k]!=x){ nums[index++]=x; } } return index; }
时间复杂度为O(n);空间复杂度为O(1) 利用「通用解法」思路,还能解决题目(k=2 的情况)。参考三叶刷题日记
3.python逆序删除.
1 2 3 4 5 6 7 8 9 10 11 12 13 class Solution : #python逆序删除 def removeDuplicates (self,nums) -> int : for i in range (len(nums) -1 ,0 ,-1 ): if nums[i]==nums[i-1 ]: del nums[i] return len(nums) if __name__ = ="__main__" : nums = [1 ,1 ,2 ] sol = Solution() print("%d,nums=%s" %(sol.removeDuplicates(nums),nums))
时间复杂度:O(n),其中 n 是数组的长度。快指针和慢指针最多各移动 nn次。 空间复杂度:O(1)。只需要使用常数的额外空间。