【算法】2SUM/3SUM/4SUM问题

之前就总结过一些Leetcode上各种sum问题,今天再拿出来完整得总结一番。
nSUM问题是指,在一个数组中,找出n个数相加和等于给定的数,这个叫做nSUM问题。
常见的有2SUM,3SUM,4SUM问题,还有各种SUM问题的变种.
Leetcode上SUM问题包括:
1. 2SUM
15. 3Sum
16. 3Sum Closest
18. 4Sum
454. 4Sum II

2SUM问题

最常见的是2SUM问题(1. 2SUM),就是数组中找出两个数相加和为给定的数。
这道题有两种思路:
1. 一种思路从首尾搜索两个数的和,并逐步逼近。
2. 另外一种思路是固定一个数A,看SUM-A是否在这个数组之中。

对于第一种思路如下:

此方法是先将数组从小到大排序
设置两个指针,一个指向数组开头,一个指向数组结尾,从两边往中间走。直到扫到满足题意的为止或者两个指针相遇为止。
此时这种搜索方法就是类似于杨氏矩阵的搜索方法,就是从 杨氏矩阵的左下角开始搜索,直到找到为止。
如果此时题目条件变为如果没有找出最接近的2SUM和问题,解决方法跟上面是一样的
用这种方法2SUM问题的时间复杂度是 O(nlogn) 的,主要在于排序的时间。

第二种思路方法如下:

对数组中的每个数建立一个map/hash_map 然后再扫一遍这个数组,判断target-nums[i]是否存在,如果存在则说明有,不存在继续找。当然这样做的话,需要处理一个细节:判重的问题。
代码如下【注意因为题目中说一定有解所以才下面这样写,如果不一定有解,则还要再加一些判断】

vector<int> twoSum(vector<int>& nums, int target) {
    unordered_map<int,vector<int>> mark;
    for(int i=0;i<nums.size();i++)
        mark[nums[i]].push_back(i);
    for(int i = 0;i<nums.size();i++){
        if(target-nums[i] == nums[i]){
            if(mark[nums[i]].size() > 1){
                vector<int> tmp{i,mark[nums[i]][1]};
                return tmp;
            }
        }else{
            if(mark.find(target-nums[i]) != mark.end()){
                vector<int> tmp{i,mark[target-nums[i]][0]};
                return tmp;
            }
        }
    }
}

这种方法的时间复杂度为 O(n)

比较一下这两个方法:

第一种方法的思路还是比较好的,鲁棒性好,而且写起来比较容易,但是因为预处理——排序的时间复杂度占了大头,所以其总时间复杂度为 O(nlogn)
第二种方法,时间复杂度低,但是需要处理重复情况,略麻烦

3SUM问题

然后对于3 Sum问题,解决方法就是最外层遍历一遍,等于选出一个数,
之后的数组中转化为找和为target-nums[i]的2SUM问题。
因为此时排序复杂度在3SUM问题中已经不占据主要复杂度了,所以直接采用思路1的方法就好。

void two_sum(vector<int>& nums,int i,int target,vector<vector<int>> &result){
    int j = nums.size()-1;
    int b = i-1;
    while(i<j){
        if(nums[i]+nums[j] == target){
            result.push_back(vector<int>{nums[b],nums[i],nums[j]});
            //处理重复的情况
            i++;
            j--;
            while(i<j && nums[i] == nums[i-1]) i++;
            while(i<j && nums[j+1] == nums[j]) j--;
        }else{
            if(nums[i]+nums[j] < target)
                i++;
            
  • 11
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值