力扣27、移除元素(简单)

1 题目描述

力扣27、移除元素(简单)_第1张图片 图1 题目描述

2 题目解读

        对于给定的数组nums,要求移除其中值为val的元素,且不使用额外的数组空间,返回移除后数组的新长度。

        数组nums中元素的顺序可以改变。

3 解法一:双指针

        双指针法是解算法题常用且非常有效的一种方法。

3.1 解题思路

        设置双指针left和right,指针right从左向右遍历数组元素,指针left更新数组nums中的元素。函数返回left。

3.2 设计代码

#include 
#include 
using namespace std;
class Solution {
public:
    int removeElement(vector& nums, int val) {
        int n = nums.size();
        int left = 0;
        for (int right = 0; right < n; right++) {
            if (nums[right] != val) {
                nums[left] = nums[right];
                left++;
            }
        }
        return left;
    }
};
int main() {
    int x[] = { 3,2,2,3 };
    int val = 3;
    vector nums;
    for (int i = 0; i < 4; i++)
    {
        nums.push_back(x[i]);
    }
    Solution S;
    int ans = S.removeElement(nums, val);
    cout << ans << endl;
    return 0;
}

3.3 复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

3.4 提交结果

力扣27、移除元素(简单)_第2张图片 图2 双指针法代码执行结果

4 解法二:前移法

        前移法是与双指针法非常相似的一种方法。不同的是,双指针法的left指针用于放置元素,前移法的变量k用于统计要删除的元素个数并将保留的元素前移k个位置。

4.1 解题思路

        指针right遍历数组nums的元素,变量k统计要删除的元素的个数,同时将指针right扫描到的要保留的元素前移k个位置。

4.2 设计代码

#include 
#include 
using namespace std;
class Solution {
public:
    int removeElement(vector& nums, int val) {
        int n = nums.size();
        int k = 0; //k累计当前等于val的元素个数
        for (int right = 0; right < n; right++) {
            if (nums[right] == val) {
                k++;
            }
            else {
                nums[right - k] = nums[right];
            }
        }
        return n - k;
    }
};
int main() {
    int x[] = { 3,2,2,3 };
    int val = 3;
    vector nums;
    for (int i = 0; i < 4; i++)
    {
        nums.push_back(x[i]);
    }
    Solution S;
    int ans = S.removeElement(nums, val);
    cout << ans << endl;
    return 0;
}

4.3 复杂度分析

  • 时间复杂度:O(n)。指针right遍历了一遍数组元素。
  • 空间复杂度:O(1)

4.4 提交结果

力扣27、移除元素(简单)_第3张图片 图3 前移法代码执行结果

5 解法三:双指针优化

        对于这一题,可以将双指针法进行优化。

5.1 解题思路

        本题数组nums中元素的顺序可以改变,所以可以使用while循环,通过双指针left和right,分别从左、从右扫描数组元素。指针left不仅遍历数组元素,也放置新元素。

        当指针left和指针right重合时,结束循环。

5.2 设计代码

#include 
#include 
using namespace std;
class Solution {
public:
    int removeElement(vector& nums, int val) {
        int left = 0, right = nums.size();
        while (left < right) {
            if (nums[left] == val) {
                nums[left] = nums[right - 1];
                right--;
            }
            else {
                left++;
            }
        }
        return left;
    }
};
int main() {
    int x[] = { 3,2,2,3 };
    int val = 3;
    vector nums;
    for (int i = 0; i < 4; i++)
    {
        nums.push_back(x[i]);
    }
    Solution S;
    int ans = S.removeElement(nums, val);
    cout << ans << endl;
    return 0;
}

5.3 复杂度分析

  • 时间复杂度:O(n)。指针left和指针right共同遍历了一遍数组元素。
  • 空间复杂度:O(1)。没有使用额外数组空间。

5.4 提交结果

力扣27、移除元素(简单)_第4张图片 图4 双指针优化代码执行结果

6 解题心得

  • 对于一道算法题,可以写出多种版本的代码,可以有多种解法。
  • 双指针法没有改变数组nums中元素的顺序,双指针优化法改变了数组nums中元素的顺序,但避免了一些不必要的数组元素的移动。
  • 前移法与双指针法有着非常相似的思想。

你可能感兴趣的:(力扣LeetCode,leetcode,算法,数据结构,c++)