leetcode-删除排序数组中的重复项/移除元素/两数之和

这篇博客主要讲解了LeetCode中的三个问题:删除排序数组中的重复项、移除元素和两数之和。采用双指针法解决删除排序数组重复项,通过快慢指针移动实现。移除元素提供了双指针法和替换法两种策略。两数之和问题通过排序数组和双指针法寻找解题方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 删除排序数组中的重复项

题目链接:力扣

重点在审题:

1 排序数组

2 原地“删除”重复元素,“删除”不一定指删除,可以是替换

3 不需要考虑数组中超出新长度后面的元素。(返回的是一个数组长度,后台根据长度自动截取)

自力更生:

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if(nums.size()<=1) return nums.size();

        auto first = nums.begin();
        auto second = first+1;
        while(second!=nums.end()){
            if(*first==*second) {
                nums.erase(second);
            }
            else {
                first = second;
                second+=1;
            }
        }

        return nums.size();
    }
};

借鉴他人:双指针法(快慢指针法,i是慢指针,j是快指针)

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

当nums[i]与nums[j]相等时,就把j自增,否则,我们就找到了不同于nums[i]的第一个数字,为了保留一个重复数字,就把i增1,然后被nums[j]覆盖掉即可。直到j越界。

二 移除元素

题目链接:力扣

其实跟第一题满相似的,但是还是不会迁移。。。

法一  双指针法

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

j是快指针,i是慢指针。当nums[j]不是要删除的值时,把该值赋给Num[i],即覆盖,i++,当Num[j]是要删除的值,快指针继续走,直到碰到不是就开始覆盖。

法二 替换法

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

            else
                i++;
        }
        return i;
    }
};

遍历数组,如果是val,就把val与后面的元素调换位置,为了防止后面的元素也是val,就先不把i增1。这适合val值得个数比较少的情况。

三 两数之和

题目链接:力扣

自力更生

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> res;
        if(nums.size()<2)
            return res;
        vector<int> num_copy(nums);
        sort(num_copy.begin(),num_copy.end());
        int i=0;
        int j=nums.size()-1;
        int left,right;
        for(left=num_copy[i],right=num_copy[j];left+right!=target&&i<j;)
        {
            if(left+right>target)
            {
                j-=1;
                right=num_copy[j];
            }
            else
            {
                i+=1;
                left=num_copy[i];
            }
        }
        if(left+right==target&&i<j)
        {
            int index_left=-1,index_right=-1;
            for(int i=0;i<nums.size();i++)
            {
                if(nums[i]==left&&index_left==-1)
                    index_left=i;
                //参考【3,3】,因为一个数如果被left遍历到,一定不可以被right再遍历了
                else if(nums[i]==right&&index_right==-1)
                    index_right=i;
            }
            res.push_back(index_left);
            res.push_back(index_right);
            return res;
        }
        else
            return res;
    }
};

思路:复制一个数组,并排序,然后双指针法一个从前往后,一个从后往前。找到left和right之后,再去原数组中获取下标即可(注意因为同一个数字不可以使用2次,因此如果一个下标是left的,就不可能是right了,反之亦然)

借鉴不同想法

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> res(2,-1);
        if(nums.size()<2)
            return res;
        map<int,int> a;
        for(int i=0;i<nums.size();i++)
        {
            //键是数组元素,值是下标
            a.insert(map<int,int>::value_type(nums[i],i));
        }
        
        for(int i=0;i<nums.size();i++)
        {
            //第二个条件是判断2个数字是不是同一个数字
            if(a.count(target-nums[i])>0&&a[target-nums[i]]!=i)
            {
                res[0]=i;
                res[1]=a[target-nums[i]];
                break;
            }
        }
        return res;
    }
};

关于map的详解:戳这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值