两数之和 三数之和 四数之和

两数之和 三数之和 四数之和,第1张

一、 LeetCode 1 两数之和

LeetCode 1.两数之和

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> umap;//value weizhi
        //unordered_map是一种key value的存储结构
        //可以用key保存数值,用value在保存数值所在的下标。
        for(int i=0;i<nums.size();++i)
        {
            umap[nums[i]]=i;//初始化
        }

        for(int i=0;i<nums.size();++i)
        {
            auto it=umap.find(target-nums[i]);
            if(it!=umap.end()&&it->second!=i)
            {
                return {i,it->second};
            } 
        }
        return {};
    }
};

哈希表存储。

二、LeetCode 15 三数之和

LeetCode 15.三数之和

1. 双指针法
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        sort(nums.begin(),nums.end());
        for(int i=0;i<nums.size();++i)
        {
            if(nums[i]>0) break;
            if(i>0&&nums[i]==nums[i-1]) continue;//三元组元素a去重
            
            //双指针 
            int low=i+1,high=nums.size()-1;
            while(low<high)
            {
                if(nums[low]+nums[high]+nums[i]>0)
                {
                    high--;
                    while(low<high&&nums[high]==nums[high+1]) high--;//去重1
                }
                else if(nums[low]+nums[high]+nums[i]<0) 
                {
                    low++;
                    while(low<high&&nums[low]==nums[low-1]) low++;//去重2
                }
                else if(nums[low]+nums[high]+nums[i]==0) 
                {
                    result.push_back({nums[low],nums[high],nums[i]});
                    // 去重逻辑应该放在找到一个三元组之后
                    while(low<high&&nums[high]==nums[high-1]) high--;//去重3
                    while(low<high&&nums[low]==nums[low+1]) low++;//去重4
                    // 找到答案时,双指针同时收缩
                    low++; high--;
                }
            }
        }
        return result;
    }
};

去重的原理都是没有比较过的元素与相邻的元素之间进行的比较。

去重1说明:

去重1中,定义high的位置为pos1,首先进行的是high–,此时high的值为pos2=pos1-1。

因为pos1之前没有进行过比较,因此需要将其与相邻的元素进行比较,即pos2=pos1-1,所以应该比较nums[pos1]和nums[pos1-1]。

由于此时的high=pos1-1,因此,需要比较nums[high]==nums[high+1]。

if(nums[low]+nums[high]+nums[i]>0)
{
   high--;
   while(low<high&&nums[high]==nums[high+1]) high--;//去重1
}

去重2同去重1理。

去重3说明:

去重3中,定义high的位置为pos1,因为pos1之前没有进行过比较,因此需要将其与相邻的元素进行比较,即pos2=pos1-1,所以应该比较nums[pos1]和nums[pos1-1]。由于此时的high=pos1,因此,需要比较nums[high]==nums[high-1]。

while(low<high&&nums[high]==nums[high-1]) high--;//去重3

去重4同去重3理。

2. 哈希解法
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        sort(nums.begin(),nums.end());//-4 -1 -1 0 1 2
        for(int i=0;i<nums.size();++i)
        {
            if(nums[i]>0) break;
            if(i>0&&nums[i]==nums[i-1]) continue;//三元组元素a去重
            
            unordered_set<int> set;
            for(int j=i+1;j<nums.size();++j)
            {
                if(j>i+2&&nums[j]==nums[j-1]&&nums[j-1]==nums[j-2]) continue;// 三元组元素b去重

                int tmp=0-(nums[i]+nums[j]);
                if(set.find(tmp)!=set.end())
                {
                    result.push_back({nums[i],nums[j],tmp});
                    set.erase(tmp);// 三元组元素c去重
                }
                else
                {
                    set.insert(nums[j]);
                }
            }
        }
        return result;
    }
};

哈希解法中需要注意的是去重。

对于a的去重用if语句:

if(i>0&&nums[i]==nums[i-1]) continue;//三元组元素a去重

对于b的去重,则需要进行如下的判断:

if(j>i+2&&nums[j]==nums[j-1]&&nums[j-1]==nums[j-2]) continue;// 三元组元素b去重

对于c的去重,需要如下的 *** 作:

set.erase(tmp);// 三元组元素c去重

结论:方法1(双指针法)更加适合三数之和,判断去重更加的方便。

三、LeetCode 18 四数之和

LeetCode 18.四数之和

基本框架同三数之和的双指针法。

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> result;
        sort(nums.begin(),nums.end());

        for(int i=0;i<nums.size();++i)
        {
            if(i>0&&nums[i]==nums[i-1]) continue;
            for(int j=i+1;j<nums.size();++j)
            {
                if(j>i+1&&nums[j]==nums[j-1]) continue;

                int low=j+1;
                int high=nums.size()-1;

                while(low<high)
                {
                    if(nums[i]+nums[j]>target-(nums[low]+nums[high]))
                    {
                        high--;
                        while(low<high&&nums[high]==nums[high+1]) high--;
                    }
                    else if(nums[i]+nums[j]<target-(nums[low]+nums[high]))
                    {
                        low++;
                        while(low<high&&nums[low]==nums[low-1]) low++;
                    }
                    else if(nums[i]+nums[j]==target-(nums[low]+nums[high]))
                    {
                        result.push_back({nums[i],nums[j],nums[low],nums[high]});
                        while(low<high&&nums[high]==nums[high-1]) high--;
                        while(low<high&&nums[low]==nums[low+1]) low++;
                        low++;
                        high--;
                    }
                }
            }
        }
        return result;
    }
};

需要注意的是需要写成

if(nums[i]+nums[j]>target-(nums[low]+nums[high]))

而不是

if(nums[i]+nums[j]+nums[low]+nums[high]>target)

会报错,如下:

执行出错信息:
Line 19: Char 39: runtime error: signed integer overflow: 2000000000 + 1000000000 cannot be represented in type 'int' (solution.cpp)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:28:39
最后执行的输入:
[1000000000,1000000000,1000000000,1000000000]
0

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/867310.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-12
下一篇 2022-05-12

发表评论

登录后才能评论

评论列表(0条)

保存