leetcode刷题——数组篇(二)

本文已参与[新人创作礼]活动,一起开启掘金创作之路

数组篇(二)

参考解法来源——代码随想录

leetcode27——27. 移除元素

自己思路

对于题目要求——

  • 对数组删除指定的整数
  • 输出删除后的数组长度
  • 输出删除后的数组
  • 只能使用O(1)的额外空间
  • 只能原地处理数组

错误代码:

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int i;
        int x;
        for(i = 0 ;i < nums.size(); i++){
            if (nums[i] == val){
                auto x = nums.erase(nums.begin()+i);
            }
        }
        cout << "" << nums.size()<<endl;
        for (i = 0; i < nums.size(); i++){
            cout << nums[i] <<"";
        }
        return nums.size();
    }
};

我原本想的是利用vector 的erase函数来删除该数组中的目标数字,结果在([0,1,2,2,3,0,4,2] 2)出错,究其原因,

非常惊艳:!!!!!

思路没有问题,但最重要的是——没有考虑到再erase进行删除时,for循环中的i实际上在新的数组中是i+1,因此在if的条件中应该加上一条——“i--”

于是——————就成功了!!!!!

附上代码:

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int i;
        int x;
        for(i = 0 ;i < nums.size(); i++){
            if (nums[i] == val){
                auto x = nums.erase(nums.begin()+i);
                i --;//此处是关键
            }
        }
        cout << "" << nums.size()<<endl;
        for (i = 0; i < nums.size(); i++){
            cout << nums[i] <<"";
        }
        return nums.size();
    }
};

image.png

随想录思路

  1. 就是暴力解法,他是自己用两个for循环完成的

    (一个for循环遍历数组元素 ,第二个for循环更新数组)

    采用数组的直接覆盖

    // 时间复杂度:O(n^2)
    // 空间复杂度:O(1)
    class Solution {
    public:
        int removeElement(vector<int>& nums, int val) {
            int size = nums.size();
            for (int i = 0; i < size; i++) {
                if (nums[i] == val) { // 发现需要移除的元素,就将数组集体向前移动一位
                    for (int j = i + 1; j < size; j++) {
                        nums[j - 1] = nums[j];
                    }
                    i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                    size--; // 此时数组的大小-1
                }
            }
            return size;
    ​
        }
    };
    
    1. 最受欢迎的双指针法(快慢指针法):

    通过一个快指针和慢指针在一个for循环下完成两个for循环的工作

    常用于数组和链表

    // 时间复杂度:O(n)
    // 空间复杂度:O(1)
    class Solution {
    public:
        int removeElement(vector<int>& nums, int val) {
            int slowIndex = 0;
            for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
                if (val != nums[fastIndex]) {
                    nums[slowIndex++] = nums[fastIndex];
                }
            }
            return slowIndex;
        }
    };
    

    分析:也是先分成三个情况:

    • 目标有元素在数组开头
    • 目标元素都在数组中间
    • 目标有元素在数组尾端

    该双指针法的主要思想是将输出的数组全放在slowindex里,

    • 如果右指针指向的元素不等于val,它一定是输出数组的一个元素,我们就将右指针指向的元素复制到左指针位置,然后将左右指针同时右移;
    • 如果右指针指向的元素等于 val,它不能在输出数组里,此时左指针不动,右指针右移一位。
    • 区间 [0,left) 中的元素都不等于 val。当左右指针遍历完输入数组以后,left 的值就是输出数组的长度。

image.png

衍生题目

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

283、移动零

844. 比较含退格的字符串

977. 有序数组的平方

总结:

  • 数组题目默认是不能调换数组的顺序的
  • 在数组题目的增删改查加入循环时要密切注意i,j等标记点的变化
  • 明白了双指针的用法——对数组和链表的操作有帮助。
posted @ 2022-05-04 11:23  Luciferpluto  阅读(1)  评论(0)    收藏  举报  来源