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题一样,如果两数之和大于想要的数,那么右数左移,反之左数右移。然后两数相遇,则推出里循环,寻找下一个。

`sum &amp; sum - 1` 是一个位运算表达式,其中 `&amp;` 是按位与运算符,用于对两个操作数的对应二进制位进行逻辑与运算。该表达式的用途主要与二进制数的位操作相关,下面详细解释其含义和常见用途。 ### 含义 在该表达式中,首先计算 `sum - 1`,得到 `sum` 减去 1 的结果。然后,将 `sum` 和 `sum - 1` 进行按位与运算。按位与运算的规则是:当两个对应位都为 1 时,结果位才为 1,否则为 0。 ### 用途 1. **判断一个数是否为 2 的幂**:如果一个正整数 `sum` 是 2 的幂,那么它的二进制表示中只有一位是 1,其余位都是 0。例如,2 的二进制是 `10`,4 的二进制是 `100`,8 的二进制是 `1000` 等。对于这样的数,`sum &amp; sum - 1` 的结果为 0。因为 `sum - 1` 会将 `sum` 中唯一的 1 变为 0,并将其后的所有 0 变为 1,按位与运算后结果为 0。以下是一个 Python 示例代码: ```python def is_power_of_two(sum): return sum &gt; 0 and (sum &amp; (sum - 1)) == 0 # 测试 print(is_power_of_two(4)) # 输出: True print(is_power_of_two(5)) # 输出: False ``` 2. **统计一个数的二进制表示中 1 的个数**:每次执行 `sum = sum &amp; sum - 1` 操作,都会将 `sum` 的二进制表示中最右边的 1 变为 0。通过不断执行这个操作,直到 `sum` 变为 0,可以统计出 `sum` 中 1 的个数。以下是一个 Python 示例代码: ```python def count_ones(sum): count = 0 while sum: sum = sum &amp; (sum - 1) count += 1 return count # 测试 print(count_ones(7)) # 输出: 3,因为 7 的二进制是 111 ``` ### 总结 `sum &amp; sum - 1` 是一个常见的位运算表达式,主要用于判断一个数是否为 2 的幂以及统计一个数的二进制表示中 1 的个数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值