15 3Sum && 1 2sum

从给定的n位数组中找到所有的数对,从而使得三个数的合为0

输入:n整数数组  输出 数字对的数组,并且数字对各异

思路:emm对于每一个数进行循环,然后2sum?

3sum的特点和2sum不一样,2sum要求和为一个给定的输入值,但是3sum要求和为固定的0

也就是说,其中两者可以当第三者的相反数?2sum循环一遍? 2sum是On。那么3sum就是O?2。可以推导出Ksum的时间复杂度为O??−1

有一个问题:3sum要求出所有的对数,所以固定第一个数后后面的2sum要求出所有的对数,因此要对1的2sum进行改造。

 

2sum之所以只能求出一个对数,就是因为2sum要求输出的是元素的位置,

但是3sum只要求输出元素组合,因此可以输出所有的对数。

那么问题来了,该怎么改?

2sum将所有的数存到map中,相同的会覆盖。所以经过覆盖我们获得了一个不具有相同数字的vector

因此不存在相同的pair每一个都是不同的。

然后写出的代码是这样的

vector<vector<int>> threeSum(vector<int>& nums) {

        vector<vector<int>> result;

        unordered_map<int, int> mapping;

        int size = nums.size();

        for(int i =0 ; i<size; i++){

            mapping[nums[i]] = i; //初始化完成

        }

        //3sum

        for(int i = 0; i< size - 2; i++){

            const int target = 0 - nums[i];

            //然后开始two sum

            for(int j = i+1; j< size - 1; j++){

                const int gap = target - nums[j];

                if(mapping.find(gap) != mapping.end() && mapping[gap] > j){ 

                    vector<int> pair;

                                  pair.push_back(nums[i]);

                    pair.push_back(gap);          

                    pair.push_back(nums[j]);

                    if(find(result.begin(), result.end(),pair ) == result.end()){

                        result.push_back(pair);

                    }

                } 

            }

        }

        return result;

    }

运行比较短的输入还是可以的,但是提交之后就发现超时了。。

 

既然如此,那么只能看看别人的思路了

 

vector<vector<int>> threeSum(vector<int>& nums) {

    std::sort(nums.begin(),nums.end());

    vector<vector<int>> v2;

    for (int c = nums.size()-1; c >= 2; ){

        for (int a = 0, b = c-1; a < b; ){

            int tmp_sum = nums[a]+nums[b];

            if (tmp_sum < -nums[c]){

                ++a;

            } else if (tmp_sum > -nums[c]){

                --b;

            } else {

                vector<int> v = {nums[a], nums[b], nums[c]};

                v2.push_back(v);

                do{//去重复 a b

                    ++a;

                } while (a < b && nums[a-1] == nums[a]);

                do{

                    --b;

                } while (a < b && nums[b+1] == nums[b]);

            }

        }

        do{//去重复 c

            --c;

        } while (c >= 2 && nums[c+1] == nums[c]);

    }

    return v2;

}

执行完毕,发现没超时。来学习一下先进经验吧。

首先,排序。排序保证了后面的过程中可以忽略已经被考虑过的元素。而导致超时的测试用例就是那些输入串很长的用例。

因此从这一点上修改我原来的代码,终于通过了

 

 

 

vector<vector<int>> threeSum(vector<int>& nums) {

        sort(nums.begin(),nums.end());

        vector<vector<int>> result;

        unordered_map<int, int> mapping;

        int size = nums.size();

        for(int i = 0 ; i < size; i++)

            mapping[nums[i]] = i; //初始化完成

        //3sum

        int lastNumI = 0;

        int lastNumJ = 0;

        for(int i = 0; i< size - 2; i++){

            if(i!=0 && lastNumI == nums[i]) continue;

            else lastNumI = nums[i];        

            const int target = 0 - nums[i];

            //然后开始two sum

            for(int j = i+1; j< size - 1; j++){

                if(j!= i+1 && lastNumJ == nums[j])  continue;

                else    lastNumJ = nums[j];

                const int gap = target - nums[j];

                if(mapping.find(gap) != mapping.end() && mapping[gap] > j){ 

                    vector<int> pair = {nums[i], nums[j],gap};

                    result.push_back(pair);

                } 

            }

        }

        return result;

    }

由于是按顺序的,因此通过判断相邻元素相同来忽略所有考虑过的数字。

但是程序的运行速度还算可以,因此再来看有什么其他的因素。

 

三个指针分别代表三个数,然后对第一个指针进行遍历,对另外两个指阵寻找2sum。值得注意的是2sum的方式。首先经过排序,整个nums的顺序是从左至右由小变大,然后跟11题一样,如果两数之和大于想要的数,那么右数左移,反之左数右移。然后两数相遇,则推出里循环,寻找下一个。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值