代码随想录学习记录——数组篇-移除数据

114 阅读1分钟

27.移除元素

这题最简单的想法就是直接遍历每一个元素,每发现一个元素就将后面的元素全部前移一位来覆盖,因此可以写出以下代码:

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int sizeNums = nums.size();
        for (int i = 0;i<sizeNums;i++){
            if(nums[i] == val){
                for(int j = i;j<sizeNums-1;j++){
                    nums[j] = nums[j+1];
                }
                i--;
                sizeNums--;
            }
        }
        return sizeNums;
    }
};

两个问题:

  1. 为什么要ii--? :因为如果有两个val连续,例如[3,2,2,3][3,2,2,3]然后val=2val=2,那么当运行到第一个2的时候进行了前移,如果此时没有ii--,那么i++>>>i=3i++ >>> i=3,此时数组为[3,2,3][3,2,3],就错过了刚才前移进来覆盖的那个了。
  2. 为什么要sizeNumssizeNums--?:因为每一次前移整体的长度都会减少,如果不这样做会超时的。

代码随想录的方法为双指针法,可以结合里面的动图加以理解,具体为:

  • 有两个指针,第一个指针称为快指针,其用来寻找减去目标元素后的数组的元素,第二个指针称为慢指针,用来指向需要覆盖的位置,也就是原数组中目标元素的位置
  • 一开始一起移动,当找到目标元素后慢指针指向该位置,只有覆盖之后慢指针才可以移动,快指针就往后找不是目标元素的位置,然后来覆盖。

代码为:

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int fastIndex = 0;
        int slowIndex = 0;
        int numsSize = nums.size();
        int reMoveNums = 0;
        for(;fastIndex < numsSize;fastIndex++){
            if(val != nums[fastIndex]){
                nums[slowIndex++] = nums[fastIndex];
            }
        }
        return slowIndex;
    }
};

26、删除数组中的相同元素

本题和上述题目可以采用相同的思路,同样是快指针和慢指针,但由于需要判断两个元素之间是否相等,那么初始化就快指针指向1,慢指针指向0,然后当它们不相同的时候,慢指针先移动一位,跟快指针位置相同,再执行赋值操作。而相同时慢指针就停止,直到快指针移动到下一个不相同的元素,此时慢指针++,移动到下一个不同元素所应该在的正确位置,再进行赋值即可。

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int fastIndex = 1;
        int slowIndex = 0;
        int sizeNums = nums.size();
        for(;fastIndex < sizeNums;fastIndex++){
            if(nums[slowIndex] != nums[fastIndex]){
                slowIndex++;
                nums[slowIndex] = nums[fastIndex];
            }
        }
        return slowIndex+1;
    }
};

283、移动零

本次也可以采用双指针的形式,一开始我想的是一个指针从头开始一个指针从尾开始,然后交换位置,但考虑到需要保留原来元素的顺序,因此需要两个指针一起从头开始,然后遇到0时慢指针停止等待快指针找到非零元素来交换

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int leftIndex = 0;
        int rightIndex = 0;
        while(rightIndex < nums.size()){
            if(nums[rightIndex] != 0){
                swap(nums[leftIndex],nums[rightIndex]);
                leftIndex++;
            }
            rightIndex++;
        }
    }
};

844、比较含退格的字符串

这题我也是参考了力扣官方的答案,本来是写的将字符串处理之后再比较,但觉得这种双指针更有趣。

关键思路就是只有从字符串的后面开始看起,我们才能够知道哪一些字符需要删除掉,因为字符是否需要删除只跟它后面的退格号有关。

class Solution {
public:
    bool backspaceCompare(string s, string t) {
        int sIndex = s.length() - 1;
        int tIndex = t.length() - 1;
        int skipS = 0; //用来存放遍历中当前字符串s有的退格个数
        int skipT = 0; //用来存放遍历中当前字符串t有的退格个数
        while( sIndex >= 0 || tIndex >= 0){ //需要有一个仍然仍然未遍历结束
            while( sIndex >= 0){
                if ( s[sIndex] == '#'){  //如果等于退格,那么就退格号++,然后继续向前遍历
                    skipS++;
                    sIndex--;
                }else if(skipS > 0){ //不等于退格,但是当前退格号不为0,那么这个字符是需要删除的,不需要比
                    skipS--; //删除掉一个字符,skipS更新
                    sIndex--;
                }else{
                    break; //如果是字符并且sikpS等于0,说明这个字符不用删除掉,那么break来比较
                }
            }

            while(tIndex >= 0){
                if(t[tIndex] == '#'){
                    skipT++;
                    tIndex--;
                }else if(skipT > 0){
                    skipT--;
                    tIndex--;
                }else{
                    break;
                }
            }

            if(sIndex >=0 && tIndex >= 0){
                if(s[sIndex] != t[tIndex]){
                    return false;
                }
            }else{
                if(sIndex >= 0 || tIndex >= 0){
                    return false;
                }
            }
            sIndex--;
            tIndex--;
        }
        return true;
    }
};

977、有序数组的平方

本次最直接的想法就是想平方然后直接排序,排序本来想用自己写的排序算法但想起来还有sort函数,因此代码为:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        for(int i = 0;i < nums.size();i++){
            nums[i] = nums[i] * nums[i];
        }
        sort(nums.begin(),nums.end());
        return nums;
    }
};

另一种方法是找边界,因此如果能够找到正负的边界,我们把正的和负的看成两个数组,然后对它们进行平方后的归并排序,就可以完成了。

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int sizeNums = nums.size();
        int markIndex = -1;
        for(int i = 0; i < sizeNums ; i++){
            if(nums[i] < 0){
                markIndex = i;
            }else{
                break;
            }
        }
        vector<int>reNums;
        int leftIndex = markIndex;
        int rightIndex = markIndex + 1;
        while( leftIndex >= 0 || rightIndex <= sizeNums-1){
            if(leftIndex < 0){
                //说明小于0的已经都归进去了
                reNums.push_back(nums[rightIndex] * nums[rightIndex]);
                rightIndex++;
            }
            else if(rightIndex == sizeNums){
                //说明大于0的已经都归进去了
                reNums.push_back(nums[leftIndex] * nums[leftIndex]);
                leftIndex--;
            }
            else if(nums[leftIndex] * nums[leftIndex] < nums[rightIndex] * nums[rightIndex]){
                reNums.push_back(nums[leftIndex] * nums[leftIndex]);
                leftIndex--;
            }else{
                reNums.push_back(nums[rightIndex] * nums[rightIndex]);
                rightIndex++;
            }
        }
        return reNums;
    }  
};

代码随想录中所采用的是双指针法:因为平方之后,可能的最大值必然在最左侧或者最右侧,那么可以用两个指针来从左右分别向内移动,不断找到最大值然后复制到新的数组之中

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int leftIndex = 0;
        int rightIndex = nums.size() - 1;
        int reIndex = nums.size()-1;
        vector<int> reNums(nums.size(),0);
        while(leftIndex <= rightIndex){
            if(nums[leftIndex] * nums[leftIndex] > nums[rightIndex] * nums[rightIndex]){
                reNums[reIndex] = nums[leftIndex] * nums[leftIndex];
                reIndex--;
                leftIndex++;
            }else{
                reNums[reIndex] =nums[rightIndex] * nums[rightIndex];
                reIndex--;
                rightIndex--;
            }
        }
        return reNums;
    }  
};