算法学习笔记——专题拓展1:一个方法团灭nSum问题

1. 两数之和

分析

因为需要排序,然后还需要原来的下标,所以只能构造一个vector<pair<int, int>>数组携带者原来的下标信息一起排序。最后才可以得到原来的下标信息。

代码

双指针思路:使用范式解题,排序加双指针相向而行

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int n = nums.size();
        vector<int> ans;
        vector< pair<int, int>> numsi;
        for(int i = 0; i< nums.size(); i++){
            numsi.emplace_back(nums[i], i);
        }
        sort(numsi.begin(), numsi.end());
        int left = 0, right = n-1;
        int lastL = INT_MAX, lastR=INT_MAX;
        int sum;
        while(left < right){
            if(numsi[left].first == lastL){
                left++; continue;
            }
            if(numsi[right].first == lastR){
                right--; continue;
            }
            sum = numsi[left].first + numsi[right].first;
            if( sum == target){
                ans.emplace_back(numsi[left].second);
                ans.emplace_back(numsi[right].second);
                lastL = left; lastR = right;
                left++; right--;
            }
            else if(sum < target){
                left++;
            }
            else{
                right--;
            }
        }
        return ans;
    }
};

直接查找思路:使用find函数和distance函数直接找出对应的一对

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int n = nums.size();
        int dis;
        for(int  i = 0; i< n; i++){
            auto it = find(nums.begin(), nums.end(), target - nums[i]); 
            if( it != nums.end() && (dis = distance(nums.begin(), it)) != i){
                return {i, dis};
            }
        }
        return {};
    }
};

 

2. 三数之和

分析:固定一个指针,动两个指针,转化为两数之和问题

注意点:需要三个指针都需要跳过相同的值,其中两个自由指针在每次固定指针移动的时候,上一次的值(LastL/LastR)都需要更新,也就是说,lastL/lastR和lasti的初始化(或声明)位置不同。

代码

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ans;
        sort(nums.begin(), nums.end()); 
        int n = nums.size();
        int lasti = INT_MAX;
        int lastL, lastR;
        int left, right, sum;
        for(int i  =0; i< n-2; i++){
            lastL= INT_MAX, lastR= INT_MAX;
            left = i+1, right = n-1;
            if(nums[i] == lasti){
                continue;
            }
            lasti = nums[i];
            while(left < right){
                //跳过相同数的业务逻辑
                if(nums[left] == lastL){
                    left++;
                    continue;
                }
                if(nums[right] == lastR){
                    right--;
                    continue;
                }
                //判断是否满足要求
                sum  =nums[left] + nums[right];
                if(sum + nums[i] == 0){
                    lastL = nums[left];
                    lastR = nums[right];
                    ans.push_back({nums[left],nums[i],  nums[right]});
                    left++; right--;
                }
                else if(sum + nums[i] > 0){
                    right--;
                }
                else{
                    left++;
                }
            }
        }
        return ans;
    }
};

总结

i)C++的 变量 没有初始化会自动赋初值,int为0

ii)最好不要在数组下标里面加减 

3. 四数之和

分析:先写一个三数之和,然后写一个for函数调用三数之和

注意:i)for循环里面也要跳过重复数字

           ii)三数之和模板里面, left是++, right是--,不要搞错了,debug起来很麻烦。

代码

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums,int start, int target){ 
        vector<vector<int>> ans;
        // [-2, -1, 0, 0, 1, 2 ]
        int lastL, lastR, lasti = INT_MAX;
        int left, right;
        signed long sum;
        int n = nums.size();
        for(int i = start; i<n-2; i++){
            lastL = INT_MAX; lastR = INT_MIN;
            if(nums[i] == lasti){
                continue;
            }
            lasti = nums[i];
            left = i+1; right = n-1;
            while(left < right){
                if(nums[left] == lastL){
                    left++;
                    continue;
                }
                if(nums[right] == lastR){
                    right--;
                    continue;
                }
                sum = nums[left] + nums[right];
                if(sum + nums[i] == target){
                    ans.push_back({nums[i], nums[left], nums[right]});
                    lastL = nums[left]; lastR = nums[right];
                    left++; right--;
                }
                else if(sum + nums[i] < target){
                    left++;
                }
                else{
                    right--;
                }
            }
        }
        return ans;
    }
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        int n = nums.size();
        int lasti = INT_MAX;
        vector<vector<int>> ans, threeSumAns;
        for(int i = 0; i < n-3; i++){
            if(nums[i] == lasti){
                continue;
            }
            lasti = nums[i];
            threeSumAns = threeSum(nums, i+1, target-nums[i]);
            for(auto v : threeSumAns){
                v.insert(v.begin(), nums[i]);
                ans.push_back(v);
            }
        }
        return ans;
    }
};

总结:

i)C++插入元素到开头,v.insert( v.begin(), nums[i])

ii)  C++中,用另一个函数得begin()作为数组运算的指针也会出现栈溢出这种数组越界的错误。 

iii)数组传引用的作用是加速!!

总结:

技巧:

1. 如何在排序后保持原数组的下标信息?

答:创建一个vector<pair<int, int>> 向量,其中包含下标信息,排序的时候会跟着排序,并且排序默认使用pair的第一个变量排序

2. 如何通过迭代器得到下标?

答: 使用 distance(nums.begin(), iterator)

3. 如何找到某个数字在数组中第一次出现的位置?

答: 使用 find( nums.begin(), nums.end(), integer ),得到的是迭代器,如果没有找到返回 nums.end()

4. emplace_back是比push_back更高效的方式,不需要先构造一个对象,然后再将其添加到容器中。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值