c++数据结构与算法(7)——数组(四数之和)

1. 两数之和

167. 两数之和 II - 输入有序数组

15. 三数之和

18. 四数之和

————————————————————————

1. 两数之和

我个人喜欢哈希表,还是挺好理解的,保存每次遍历过的值,遍历后面时,找下是否有符合要求的前值

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> ret(2, 0);
        int size = nums.size();
        unordered_map<int, int> mp;
        for (int i = 0; i < size; i++) {
            if (mp.find(target-nums[i]) != mp.end()) {
                ret[0] = mp[target-nums[i]];
                ret[1] = i;
                break;
            }
            mp[nums[i]] = i;
        }
        return ret;
    }
};

167. 两数之和 II - 输入有序数组

跟上一题的区别是数组有序,当然也可以使用哈希表,不过因为是有序数组,我们还很容易想到双指针、二分法技巧。这里我用的是双指针,这个方法过于普遍,以至于针对这个题型扩展有了更多、更复杂的题。

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int size = numbers.size();
        int lo = 0, hi = size-1;
        while (lo < hi) {
            int sum = numbers[lo] + numbers[hi];
            if (sum < target) lo++;
            else if (sum > target) hi--;
            else return {lo+1, hi+1};
        }
        return {-1, -1};
    }
};

15. 三数之和

三数之和,这个比较复杂了,理论上是可以用哈希表保存所有两数之和,然后输出符合条件的三元数组,不过重复问题处理起来很头疼,有了上面双指针的基础,有序数组处理重复问题就很轻松了,这里稍微变通下就可以解决了。

先解决一个问题输出所有符合条件两数之和

    vector<vector<int>> twoSum(vector<int>& numbers, int start, int target) {
        sort(numbers.begin(), numbers.end());
        vector<vector<int>> ret;
        int size = numbers.size();
        int lo = start, hi = size-1;
        while (lo < hi) {
            int sum = numbers[lo] + numbers[hi];
            int left = numbers[lo], right = numbers[hi];
            if (sum < target) {
                while(lo < hi && numbers[lo] == left) lo++
            }
            else if (sum > target) {
                while (lo < hi && numbers[hi == right) hi--;
            }
            else {
                ret.push_back({numbers[lo], numbers[hi]});
                //跳过重复元素
                while (lo < hi && numbers[lo] == left) lo++;
                while (lo < hi && numbers[hi == right) hi--;
            }
        }
        return ret;
    }

在此基础给出结果

class Solution {
    public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ret;
        sort(nums.begin(), nums.end());
        int size = nums.size();
        for (int i = 0; i < size; i++) {
            vector<vector<int>> tupls = twoSum(nums, i+1, 0-nums[i]);
            for (vector<int> tuple : tupls) {
                tuple.push_back(nums[i]);
                ret.push_back(tuple);
                //跳过重复元素
                while (i < size-1 && nums[i] == nums[i+1]) i++;
            }
        }
        // n 为 3,从 nums[0] 开始计算和为 0 的三元组
        return ret;
    }
    vector<vector<int>> twoSum(vector<int>& numbers, int start, int target) {
        vector<vector<int>> ret;
        int size = numbers.size();
        int lo = start, hi = size-1;
        while (lo < hi) {
            int sum = numbers[lo] + numbers[hi];
            int left = numbers[lo], right = numbers[hi];
            if (sum < target) {
                while(lo < hi && numbers[lo] == left) lo++;
            }
            else if (sum > target) {
                while (lo < hi && numbers[hi] == right) hi--;
            }
            else {
                ret.push_back({numbers[lo], numbers[hi]});
                //跳过重复元素
                while (lo < hi && numbers[lo] == left) lo++;
                while (lo < hi && numbers[hi] == right) hi--;
            }
        }
        return ret;
    }
};

18. 四数之和

有了三数之和的基础,稍微变通下可以得出以下答案

class Solution {
public:
    vector<vector<int>> nsum(vector<int>& nums, int target, int n, int start) 
    {
        vector<vector<int>> ret;
        int size = nums.size();
        if (size < n || n < 2) return ret;
        if (n == 2) {
            int low = start, hi = size-1;
            while (low < hi) {
                int left = nums[low], right = nums[hi], sum = left + right;
                if (sum < target) {
                    while(low < hi && left == nums[low]) low++;
                }
                else if (sum > target) {
                    while(low < hi && right == nums[hi]) hi--;
                }
                else {
                    ret.push_back({left, right});
                    //去掉重复的
                    while (low < hi && left == nums[low]) low++;
                    while (low < hi && right == nums[hi]) hi--;
                }
            }
        } else {
            for (int i = start; i < size; i++) {
                vector<vector<int>> tuples = nsum(nums, target-nums[i], n-1, i+1);
                //tuples是符合要求的二元数组,加上nums[i]就是想要的结果
                for (vector<int> &tuple : tuples) {
                    tuple.push_back(nums[i]);
                    ret.push_back(tuple);
                }
                //num[i]不重复
                while (i < size-1 && nums[i] == nums[i+1]) i++;
            }
        }
        return ret;
    }
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        return nsum(nums, target, 4, 0);
    }
};

这样不管多少数之和都不在话下了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值