Leek: the sum of two numbers and the sum of three numbers and the sum of four numbers

1. The sum of two numbers:

Idea: We use map to store the traversed data, that is, use map to store traversed elements while traversing, and check whether there is another number we are looking for in the map. Note: In the map, we use
1. The underlying structure of the map is a red-black tree, so the same element will not appear in the container, so the result of count() can only be 0 and 1, which can be used to determine whether the key-value element exists ( Of course, you can also use the find() method to determine whether the key exists).

class Solution {
    
    
public:
    vector<int> twoSum(vector<int>& nums, int target) {
    
    
    unordered_map<int,int> p;
    vector<int> an(2,-1); //返回答案,默认(-1,-1)
    for(int i = 0; i < nums.size();i++){
    
    
        if(p.count(target - nums[i])>0)
        {
    
    
            an[0] = i;
            an[1] = p[target - nums[i]];
            break;
        }
       p[nums[i]] = i;
    }
    return an;
    }
};

1.1 Relevant knowledge points:

The use and optimization of map, the bottom layer of map is an ordered red-black tree, so operations such as rotation and sorting need to be performed every time an element is inserted, which takes time, so unordered_map can be used for optimization.

2. The sum of three numbers

Idea: The goal is to find three numbers that satisfy a + b + c = 0 in an array, and do not output repeated answers. First of all, since we output specific numbers instead of subscripts, we can sort them.

sort(nums.begin(),nums.end());//排序

After sorting, we can first think about the special judgment, what kind of array output is empty?
The first type: the first element in the ordered array is greater than 0, return empty
The second type: the last element in the ordered array is still less than 0, return empty
The third type: all array elements are 0, return an answer directly
The fourth type: the number of array elements is less than 3, return empty

if(nums.size() < 3 || nums[0] > 0 || nums[n-1] < 0) return ans; //剪枝
if(!nums[0] && !nums[n-1]) return {
    
    {
    
    0, 0, 0}}; // 如果数组全为0

The rest is the array that we need to traverse. How to traverse the three numbers so that they satisfy a + b + c = 0? In the three-layer for loop, we are fixed, the first array a, and then the second The number b, traverse the c that meets the condition in the array. Then fix the new number b, find c again, fix a again, and so on.

Thinking: Can we traverse conditionally, we fix the number a, b traverses from front to back in the ordered array, and c traverses from back to front in the ordered array. When a + b + c does not satisfy the condition, there are two cases of a + b + c > 0 or a + b + c < 0.
Then a + b + c > 0 must be caused by too large c, move c to traverse forward.
Then a + b + c < 0 must be caused by too small b, move b to traverse backwards.

for( i = 0 ; i < n - 2; ++i){
    
    
            if( i && nums[i]==nums[i-1]) continue; //消除重复的三元组
            j = i + 1;
            k = n - 1;
            while( j < k){
    
    
                int target = nums[i] + nums[j] + nums[k]; //避免下面加法运算两次
                if(target > 0) --k;       //因为nums已经有序,当target > 0; 说明k太大
                else if (target < 0) ++j; //因为nums已经有序,当target < 0; 说明j太大
                else{
    
    
                    ans.push_back({
    
    nums[i], nums[j], nums[k]}); //target ==0 输出答案
                    ++j;  // i 不变,j增加,k减小。不能同时固定两个数字,一定不满足要求(有序)
                    --k;
                    while(j < k &&nums[j] == nums[j-1]) ++j; // 有序数组,第二个数字不能相同
                    while(j < k && nums[k] == nums[k+1]) --k; //同理
                } 
            }
        }

Putting the code together:

class Solution {
    
    
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
    
    
        vector<vector <int>> ans;
        int n = nums.size();
        ans.reserve( n > 256 ? 256 : n); //预先分配空间,以减少 push_back内存不足的时候重新申请的时间
        int i, j, k ;
        sort(nums.begin(),nums.end());//排序
        if(nums.size() < 3 || nums[0] > 0 || nums[n-1] < 0) return ans; //剪枝
        if(!nums[0] && !nums[n-1]) return {
    
    {
    
    0, 0, 0}}; // 如果数组全为0
        for( i = 0 ; i < n - 2; ++i){
    
    
            if( i && nums[i]==nums[i-1]) continue; //消除重复的三元组
            j = i + 1;
            k = n - 1;
            while( j < k){
    
    
                int target = nums[i] + nums[j] + nums[k]; //避免下面加法运算两次
                if(target > 0) --k;       //因为nums已经有序,当target > 0; 说明k太大
                else if (target < 0) ++j; //因为nums已经有序,当target < 0; 说明j太大
                else{
    
    
                    ans.push_back({
    
    nums[i], nums[j], nums[k]}); //target ==0 输出答案
                    ++j;  // i 不变,j增加,k减小。不能同时固定两个数字,一定不满足要求(有序)
                    --k;
                    while(j < k &&nums[j] == nums[j-1]) ++j; // 有序数组,第二个数字不能相同
                    while(j < k && nums[k] == nums[k+1]) --k; //同理
                } 
            }
        }

        return ans;
    }
};

2.1 Related skills

ans.reserve( n > 256 ? 256 : n); //预先分配空间,以减少 push_back内存不足的时候重新申请的时间
 int i, j, k ;//不要加到循环中,不然每次都要申请会占用运行时间

Guess you like

Origin blog.csdn.net/qq_42573052/article/details/124148108