数组篇——删除指定元素、删除重复元素(双指针法)[leetcode26、27、28、844]

文章介绍了三种处理数组中重复元素和特殊字符的方法,包括暴力法、双指针法(快慢指针和双指针遍历),以及在LeetCode问题中的具体应用,如删除重复数字、移动数组中的0和字符串退格字符比较。所有方法都强调了时间复杂度和空间复杂度的优化。
摘要由CSDN通过智能技术生成

 一、暴力法,for循环遍历寻找需删除的元素,然后for循环用后面的元素向前覆盖

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;
    }
};

时间复杂度:O(n^2)

空间复杂度: O(1)

二、双指针法

 快慢双指针法,快指针指向新数组需要的元素,慢指针指向新数组元素的位置

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
       //快慢双指针法,快指针指向新数组需要的元素,慢指针指向新数组元素的位置
       int slow=0;
       for(int quick=0;quick<nums.size();quick++)
       {
            //若快指针指向的是非删除元素,则更新数组元素
            if(nums[quick]!=val) 
            {
                nums[slow]=nums[quick];
                slow++;
            }
       }
       //slow所在位置即新数组的大小
       return slow;

    }
};

时间复杂度:O(n)

空间复杂度: O(1)

 题2:[leetcode 26]

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

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k 。
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
      int slow=0,n=nums.size();
      for(int quick=1;quick<n;quick++)
      {
         if(nums[quick]!=nums[slow]){
             nums[++slow]=nums[quick];
         }
      }
      return slow+1;
    }
};

时间复杂度:O(n)

空间复杂度:O(1)

 题3:[leetcode 28]

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

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

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int n=nums.size();
        int slow=0;
       for(int quick=0;quick<n;quick++)
       {
           if(nums[quick])
           {
             int temp=nums[slow];
             nums[slow]=nums[quick];
             nums[quick]=temp;
             slow++;
           }
       }

    }

};

时间复杂度:O(n)

空间复杂度:O(1)

 4.[leetcode 844]

给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。

注意:如果对空文本输入退格字符,文本继续为空。

解法一: 

class Solution {
public:
    bool backspaceCompare(string s, string t) {
       //双指针法
       //正序遍历很难知道当前字符是否被删除,所以采用逆序遍历
       int i=s.length()-1,j=t.length()-1;
       int skipS=0,skipT=0; //跳过字符数
       while(i>=0||j>=0)
       {
          //筛选有效字符
          while(i>=0)
          {
              //遇到#号
              if(s[i]=='#'){
                  skipS++;
                  i--;
              }
              else if(skipS>0) {
                skipS--;
                i--;
              }
              else{
                  break;
              }
          }
          while(j>=0)
          {
              //遇到#号
              if(t[j]=='#'){
                  skipT++;
                  j--;
              }
              else if(skipT>0) {
                skipT--;
                j--;
              }
              else{
                  break;
              }
          }
          //有效字符比较,可能出现情况:1.匹配,继续遍历 2.其中一个已遍历完成,而另一个还没遍历完成,则不匹配 3.两个都已遍历完成,匹配 4.两个都没遍历完成,但不相等,不匹配
          if(i>=0&&j>=0){
              if(s[i]!=t[j]) return false; //4
              i--;j--; //1(->2/3)
          }
          else{
             if(i<0&&j<0) return true; //3
             else return false;//2
          }

       }
       return true;//(1)

       
    }
};

 解法二[更加推荐]:先分别对s、t进行修改,把有效字符放到字符串尾部,并计算s、t有效字符数。在进行判断时,先比较有效长度,再比较具体字符,更易理解!

class Solution {
public:
    bool backspaceCompare(string s, string t) {
       //双指针法
       int si=s.length()-1,skipS=0,cntS=0;
       int ti=t.length()-1,skipT=0,cntT=0;
      for(int sj=s.length()-1;sj>=0;sj--)
      {
          if(s[sj]=='#') skipS++;
          else if(skipS>0) skipS--;
          else {
              cntS++;
              s[si]=s[sj];
              si--;
          }
      }
      for(int tj=t.length()-1;tj>=0;tj--)
      {
          if(t[tj]=='#') skipT++;
          else if(skipT>0) skipT--;
          else {
              cntT++;
              t[ti]=t[tj];
              ti--;
          }
      }

      if(cntT!=cntS) return false;
      else if(cntT==0) return true;
      else{
          int i=s.length()-1,j=t.length()-1;
          for(int k=0;k<cntT;k++)
          {
              if(s[i--]!=t[j--]) return false;
          }
          return true;
      }
       
       

       
    }
};

时间复杂度:O(m+n)

空间复杂度:O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值