2022-02-14Leetcode训练营_数组(双指针)

本文介绍了如何通过排序和双指针优化解决LeetCode上的三数之和问题,避免暴力三层循环导致的时间复杂度过高。分别展示了排序后的三层循环解法和双指针解法,并探讨了如何在数组中移除元素和删除有序数组中的重复项,强调了原地处理和双指针在数组操作中的高效性。

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

天池训练营链接

天池leetcode训练营

三数之和

链接
摘自题解:
「不重复」的本质是什么?我们保持三重循环的大框架不变,只需要保证:
第二重循环枚举到的元素不小于当前第一重循环枚举到的元素;
第三重循环枚举到的元素不小于当前第二重循环枚举到的元素。

也就是说,我们枚举的三元组(a,b,c) 满足 a<=b<=c,保证了只有 (a,b,c)这个顺序会被枚举到,而(b,a,c) 、(c,b,a) 等等这些不会,这样就减少了重复。要实现这一点,我们可以将数组中的元素从小到大进行排序,随后使用普通的三重循环就可以满足上面的要求。

同时,对于每一重循环而言,相邻两次枚举的元素不能相同,否则也会造成重复。

暴力3层循环+去重1

这段代码,3重循环全都从前往后,结果是超时,逻辑错

class Solution {
    //暴力3层循环+去重
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        //注意排序
        vector<vector<int>> res;
        if(nums.size() < 3){
            return res;
        }
        for(int i=0;i<nums.size()-2;++i){
            if(i!=0 && nums[i] == nums[i-1]){
                //++i;
                continue;
            }
            for(int j=i+1; j<nums.size()-1;++j){
                if(j>i+1 && nums[j] == nums[j-1]){
                    //++j;
                    continue;
                }
                for(int k=j+1; k<nums.size();++k){
                    if(k>j+1 && nums[k] == nums[k-1]){
                        //++k;
                        continue;
                    }
                    if(nums[i]+nums[j]+nums[k] == 0){
                        //vector<int> temp;
                        //temp.push_back(nums[i]);
                        //temp.push_back(nums[j]);
                        //temp.push_back(nums[k]);
                        res.push_back({nums[i],nums[j],nums[k]});
                        //可以直接组好push进去
                    }
                    //建vec并push 3个
                   // vec push进res
                }
            }
        }
        return res;
    }
};

双指针

换命名,first,second,third,三数和在第二层循环开始转化为两数和来处理,后面就是模板
时间复杂度O(n^2)

class Solution {
    //暴力3层循环+去重
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        //注意排序
        vector<vector<int>> res;
        if(nums.size() < 3){
            return res;
        }
        int n=nums.size();
        for(int first=0;first<nums.size()-2;++first){
            if(first!=0 && nums[first] == nums[first-1]){
                //++i;
                continue;
            }
           // int n=nums.size();
            int third = n-1;
            int target = -nums[first];
            
            for(int second=first+1; second<third;++second){
                if(second>first+1 && nums[second] == nums[second-1]){
                    //注意j>i+1这里,二层循环不能重复,但j=i+1可以和前面一样
                    //++j;
                    continue;
                }
                while(second < third && nums[second] + nums[third] > target){
                    --third;
                }
                if(second == third){
                    break;
                }
                if(nums[second]+nums[third] == target){
                        //vector<int> temp;
                        //temp.push_back(nums[i]);
                        //temp.push_back(nums[j]);
                        //temp.push_back(nums[k]);
                    res.push_back({nums[first],nums[second],nums[third]});
                        //可以直接组好push进去
                }
                    //建vec并push 3个
                   // vec push进res
                
            }
        }
        return res;
    }
};

移除元素

链接
感触就是数组原地处理的题直接双指针,和链表差不多处理方式

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

删除有序数组中的重复项

链接
仍然双指针,和上一题差不多

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        //排序
        sort(nums.begin(), nums.end());
        //这句,有序数组不需要..
        int n = nums.size();
        int cur = 0;//当前指针
        if(n==0) return 0;
        if(n==1) return 1;
        for(int i=1; i<n; ++i){
            if(nums[cur] != nums[i]){
                cur+=1;
                nums[cur]=nums[i];
            }
        }
        return cur+1;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值