虚无的纽扣头像

【力扣刷题】第四天:三数之和、四数之和

博客横幅图

自律是普通人最大的武器

系列专栏直达链接
🐧 Linux进入专栏 →
🔤 C语言进入专栏 →
🔧 C++进入专栏 →
🐬 MySQL进入专栏 →
🧩 算法刷题进入专栏 →

🏠 博客主页:虚无的纽扣
📦 作者仓库:github | gitee

引言

        最近因为一些原因拖更了很长时间的算法文章,后续我会慢慢补回来,今天要讲解的是三数之和、四数之和。

三数之和

        原题:15. 三数之和 - 力扣(LeetCode)。

        接下来我们先来解析一下这个题目,该题目的要求是要求我们找到三个数,并且这三个数的和为零,通过题目要求我们可以发现:一个三元组除了在全零的情况下,一定至少要存在一个数为负数,不然相加无法得到零,并且该数组为递增数组。根据这个发现,接下来我们来讲解这道题的解题思路。

        首先根据我们上面的发现,我们可以先将下标为0的数固定下来,记作con,然后让left等于1,right等于n-1,当它们三个相加之和大于0时,right就减减,当相加之和小于0时,left就加加。而当它们三个的和等于0时就记录下结果,并且很明显如果left或right下一次移动时的数和当前数字一样,那么结果还是0,就没必要重复计算,所以我们直接进行判断并且跳过所有的重复数字,直接进行运算,就可以节省一点时间。当left大于或等于right后,第一次循环结束,将让con加加,进行第二轮循环,直到con对应的位置大于零为止。

        通过上面的讲解相信大家应该大致理解了一点思路,接下来贴出源代码,结合着思路和代码很容易就能理解这道题

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int con = 0;
        vector<vector<int>> ve;
        while (nums.size() - con > 2 && nums[con] <= 0)
        {
            int left = con + 1, right = nums.size() - 1;
            while (left < right)
            {
                if (nums[left] + nums[right] + nums[con] > 0)
                {
                    right--;
                }
                else if (nums[left] + nums[right] + nums[con] < 0)
                {
                    left++;
                }
                else
                {   
                    ve.push_back({nums[left++], nums[right--], nums[con]});
                    while (left < right && nums[left] == nums[left - 1])
                        left++;
                    while (left < right && nums[right] == nums[right + 1])
                        right--;
                }
            }
            con++;
            while (con < nums.size() && nums[con] == nums[con - 1])
            {
                con++;
            }
        }
        return ve;
    }
};

四数之和

        原题:18. 四数之和 - 力扣(LeetCode)。

        四数之和是三数之和的超级加强版,写起来特别的恶心和复杂,题目解析就不做了,和上面的三数之和差不多,我们直接进入解析

        首先该数组并不是有序的,我们先用排序将它变成有序,然后我们还是一样先把数组前面的数固定,不一样的是这次要固定两个,并且如果数组的最小值加数组最大的三个值就已经大于目标值,就代表该数组无论如何都找不到结果,直接返回空。

        我们要写一个深度超级深的大循环,第一层循环跟三数之和一样,固定最小值,设为i,如果i、i+1、i+2、i+3的值加起来已经大于目标值,则说明不管怎么移动都会比目标值大,没有意义,直接break。而如果i、n-1、n-2、n-3的值加起来小于目标值,也没有意义,不管怎么移动都不可能大于或等于目标值,所以直接进入下一轮循环。

        固定下来i值后,我们再固定下来j值等于i+1,接着重复上一级循环的两个判断,如果都通过了,就设left和right,接下来的写法就不用我说了,直接用三数之和的解法来写就行。需要注意的是,因为数据过多,可能会导致四数之和超出int的范围,所以最好将记录结果的值设为long或者long long类型,在进行计算时最好也进行一次强转。

        这题究极臃肿,究极复杂,究极恶心,并没有任何价值,大家大概理解就行,下附源代码

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> quadruplets;
        if (nums.size() < 4) {
            return quadruplets;
        }
        sort(nums.begin(), nums.end());
        int length = nums.size();
        for (int i = 0; i < length - 3; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            if ((long) nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
                break;
            }
            if ((long) nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {
                continue;
            }
            for (int j = i + 1; j < length - 2; j++) {
                if (j > i + 1 && nums[j] == nums[j - 1]) {
                    continue;
                }
                if ((long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
                    break;
                }
                if ((long) nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) {
                    continue;
                }
                int left = j + 1, right = length - 1;
                while (left < right) {
                    long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum == target) {
                        quadruplets.push_back({nums[i], nums[j], nums[left], nums[right]});
                        while (left < right && nums[left] == nums[left + 1]) {
                            left++;
                        }
                        left++;
                        while (left < right && nums[right] == nums[right - 1]) {
                            right--;
                        }
                        right--;
                    } else if (sum < target) {
                        left++;
                    } else {
                        right--;
                    }
                }
            }
        }
        return quadruplets;
    }
};

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/button__c/article/details/167916064

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--