【Leetcode】求和问题专题

【Leetcode】求和问题专题

Author: Xin Pan

Date: 2022.4.27



这次总结一类问题即 求和问题的解法。包括如下具体题目:

  1. 两数之和
  2. 两数之和2-输入有序数组
  3. 三数之和
  4. 四数之和

接下来开始正文内容。

【1】两数之和

输入: 输入的是一个非排序的数组nums,和一个目标值target

输出:和为target的元素的下标。

解析

因为输入是没有排序的数组,所以不能用双指针的做法处理,因为双指针没有回退的操作(这里回退是说指针往初始的方向走,或者说我不知道下一个需要找的值在当前指针左侧或者右侧,这里请仔细体会)。因而我们使用一个hashmap来解决这个问题。

我的答案

class Solution
{
public:
    vector<int> twoSum(vector<int> &nums, int target)
    {
        int nnum = nums.size();
        unordered_map<int, int> map;
        map[nums[0]] = 0;
        for (int i = 1; i < nnum; i++)
        {
            unordered_map<int, int>::iterator iter = map.find(target - nums[i]);
            if (iter != map.end())
            {
                return {i, iter->second};
            }
            else
            {
                map[nums[i]] = i;
            }
        }
        return {-1, -1};
    }
};

【167】两数之和 II - 输入有序数组

输入:非递减顺序排序的数组nums和一个目标值target

输出:和为target的元素的下标。

解析

现在的输入数组是排序过的,因此我们使用双指针的解法来处理,为什么这里可以使用双指针解法?

因为考察头指针,如果nums[头指针]+nums[尾指针]<target那我们知道头指针需要右移,右边肯定是不小于左边的值的。尾指针适用同样的道理。

我的答案

class Solution
{
public:
    vector<int> twoSum(vector<int> &numbers, int target)
    {
        int nl = 0, nr = numbers.size() - 1;
        while (nl < nr)
        {
            int ntmp = numbers[nl] + numbers[nr];
            if (ntmp < target)
            {
                nl++;
            }
            else if (ntmp > target)
            {
                nr--;
            }
            else
            {
                return {nl + 1, nr + 1};
            }
        }
        return {-1, -1};
    }
};

【15】三数之和

输入:输入的是一个非排序的数组nums。目标值target=0。

输出:输出和为0的不重复三元组。

解析

这个题的输入也是非排序的数组。但是做法和之前的两数之和又不一样,区别在于。不能出现重复的三元组,那么如果按着之前两数之和的做法求排列再去做去重,它的时间复杂度大概是 O ( N 3 ) O(N^3) O(N3)。那么我们如何处理好不重复现在看来就是关键了。

对于不重复:

  1. 第二个元素不小于第一个元素;
  2. 第三个元素不小于第二个元素。

这样就可以了即(第一个元素<=第二个元素<=第三个元素)。

答案

class Solution
{
public:
    vector<vector<int>> threeSum(vector<int> &nums)
    {
        int nnum = nums.size();
        vector<vector<int>> vecret;
        sort(nums.begin(), nums.end());
        for (int one = 0; one < nnum; one++)
        {
            if (one > 0 && nums[one] == nums[one - 1])
            {
                continue;
            }
            int three = nnum - 1, ntgt = -nums[one];
            for (int two = one + 1; two < nnum; two++)
            {
                if (two > one + 1 && nums[two] == nums[two - 1])
                {
                    continue;
                }
                while (two < three && nums[two] + nums[three] > ntgt)
                {
                    three--;
                }
                if (two == three)
                {
                    break;
                }
                if (nums[two] + nums[three] == ntgt)
                {
                    vecret.push_back({nums[one], nums[two], nums[three]});
                }
            }
        }
        return vecret;
    }
};

【18】四数之和

输入:输入的是一个非排序的数组nums,和目标值target。

输出:输出和为target不重复四元组。

解析

其实这个题和三数之和是完全一样的做法。如果三数之和理解了,那这题就回了;否则回头重新想想三数之和怎么做。

本题相比三数之和多了一个循环而已。

答案

class Solution
{
public:
    vector<vector<int>> fourSum(vector<int> &nums, int target)
    {
        int nnum = nums.size();
        sort(nums.begin(), nums.end());
        vector<vector<int>> vecret;
        for (int one = 0; one < nnum; one++)
        {
            if (one > 0 && nums[one] == nums[one - 1])
            {
                continue;
            }
            for (int two = one + 1; two < nnum; two++)
            {
                if (two > one + 1 && nums[two] == nums[two - 1])
                {
                    continue;
                }
                int ntgt = target - nums[one] - nums[two];
                int four = nnum - 1;
                for (int three = two + 1; three < nnum; three++)
                {
                    if (three > two + 1 && nums[three] == nums[three - 1])
                    {
                        continue;
                    }
                    while (three < four && nums[three] + nums[four] > ntgt)
                    {
                        four--;
                    }
                    if (three == four)
                    {
                        break;
                    }
                    if (nums[three] + nums[four] == ntgt)
                    {
                        vecret.push_back({nums[one], nums[two], nums[three], nums[four]});
                    }
                }
            }
        }
        return vecret;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值