初级算法刷题系列一


  • 最近在刷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)。只需要使用常数的额外空间。



Author: cole
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source cole !
  TOC