力扣:两数之和 三数之和 四数之和

1.两数之和:

思想:我们用map来存储已经遍历过的数据,也就是遍历的同时利用map存储遍历过的元素,同时查看map里有没有要找的另外一个数字。注意:map里我们把
1.map底层结构是红黑树,所以容器中不会出现相同的元素,因此count()的结果只能为0和1,可以以此来判断键值元素是否存在(当然也可以使用find()方法判断键值是否存在)。

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相关知识点:

map的使用以及优化,map的底层是有序的红黑树,因此在每次插入元素的时候都要进行旋转排序等操作用占用时间,因此可以使用unordered_map进行优化。

2.三数之和

思想:目标 在一个数组中找出满足a + b + c = 0的三个数,不输出重复答案。首先由于我们输出的是具体数字而不是下标,所以可以进行排序。

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

在排序之后我们可以先想一下特判,什么样的数组输出为空?
第一种:有序数组中第一个元素就大于0,返回空
第二种:有序数组中最后一个元素任然小于0,返回空
第三种:数组元素全部为0,直接返回一个答案
第四种:数组元素数量小于3,返回空

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

剩下的就是需要我们来遍历的数组了,怎样遍历三个数字使他们满足a + b + c = 0呢,在三层for循环中,我们是固定,第一个数组a,再固定第二个数b,在数组中遍历满足条件的c. 然后重新固定新的数b,再找c. 重新固定a等等。

思考:我们是否可以有条件的遍历,我们固定数字a,b在有序数组中从前往后遍历,c在有序数组中从后往前遍历。当a + b + c 不满足条件的时候,有a + b + c > 0 或a + b + c < 0两种情况。
则a + b + c > 0 是一定是c太大造成的,移动c往前遍历。
则a + b + c < 0 是一定是b太小造成的,移动b往后遍历。

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; //同理
                } 
            }
        }

把代码综合起来:

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相关技巧

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

猜你喜欢

转载自blog.csdn.net/qq_42573052/article/details/124148108
今日推荐