leetcode——双指针

前言

记录一下leetcode双指针部分题目的刷题笔记,顺序参考代码随想录中,但不仅限于这些,可以扩展记录。

27. 移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1:

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

思路:双指针

快慢指针

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public int removeElement(int[] nums, int val) {
int slowPtr = 0;
for(int fastPtr = 0 ; fastPtr < nums.length;fastPtr++){
if(nums[fastPtr] != val){
nums[slowPtr] = nums[fastPtr];
slowPtr++;
}
}
return slowPtr;
}
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

26. 删除有序数组中的重复项

给你一个 升序排列 的数组 nums ,请你** 原地** 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致

示例 1:

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

思路1:哈希+双指针

双指针的思想和前面一题一样,但这里我个人采用哈希来判断是否出现重复,但好像时间复杂度比较高

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public int removeDuplicates(int[] nums) {
int slowPtr = 0;
Map<Integer,Integer> map = new HashMap<>();
for(int fastPtr = 0 ; fastPtr < nums.length ; fastPtr++){
if(!map.containsKey(nums[fastPtr])){
map.put(nums[fastPtr],fastPtr);
nums[slowPtr] = nums[fastPtr];
slowPtr++;
}
}
return slowPtr;
}
}

思路2:直接双指针

发下前面自己想的有点简单,题目中升序排列这个条件没有用到,所以不用担心可能出现[1,2,3,1,2,3]这种情况,所以根本不用哈希

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public int removeDuplicates(int[] nums) {
int fastPtr = 1 , slowPtr = 1 ,ans = 0;
while(fastPtr < nums.length ){
if(nums[fastPtr] != nums[fastPtr-1]){
nums[slowPtr] = nums[fastPtr];
slowPtr++;
}
fastPtr++;
}
return slowPtr;
}
}

283. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

1
2
3
4
示例 1:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

思路1:双指针(两次遍历)

先将所有非0的数填充到数组前面,同时更新slowPtr,再将从slowPtr 到len-1的部分全部填充为0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public void moveZeroes(int[] nums) {
int slowPtr = 0 , len = nums.length;
for(int fastPtr = 0 ; fastPtr < len ; fastPtr++){
if(nums[fastPtr] != 0){
nums[slowPtr] = nums[fastPtr];
slowPtr++;
}
}
for(;slowPtr < len ; slowPtr++){
nums[slowPtr] = 0;
}
}
}
  • 执行用时:1 ms, 在所有 Java 提交中击败了100.00%的用户
  • 内存消耗:42.8 MB, 在所有 Java 提交中击败了45.63%的用户
  • 通过测试用例:74 / 74

思路2:双指针(一次遍历)

283_2.gif

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public void moveZeroes(int[] nums) {
if(nums == null) return ;
int j = 0 ;
for(int i = 0 ; i <nums.length ; i++){
if(nums[i] != 0 ){
int temp = nums[i];
nums[i] = nums[j];
nums[j++] = temp;
}
}
}
}
  • 执行用时:1 ms, 在所有 Java 提交中击败了100.00%的用户,O(n)
  • 内存消耗:42.4 MB, 在所有 Java 提交中击败了93.05%的用户,O(1)