• 18-四数之和


    题目:

    给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

    注意:

    答案中不可以包含重复的四元组。

    示例:

    给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。

    满足要求的四元组集合为:
    [
    [-1, 0, 0, 1],
    [-2, -1, 1, 2],
    [-2, 0, 0, 2]
    ]

    解答:

    自己解答代码:

    vector<vector<int>> fourSum(vector<int>& nums, int target) 
    {
        vector<vector<int>> result;
        sort(nums.begin(), nums.begin() + nums.size());
    
        auto isExist = [&](vector<int>& vec)
        {
            for (auto val : result)
            {
                if (val.at(0) != vec.at(0))
                    continue;
                if (val.at(1) != vec.at(1))
                    continue;
                if (val.at(2) != vec.at(2))
                    continue;
                if (val.at(3) != vec.at(3))
                    continue;
    
                return true;
            }
            return false;
        };
    
        int idx1 = 0, idx2;
        for (int i = 0; i < nums.size(); i++)
        {
            if (i > 0 && nums.at(i) == nums.at(i - 1))//跟上一个重复,不处理
                continue;
    
            for (int j = i+1; j < nums.size(); j++)
            {
                idx1 = j + 1;
                idx2 = nums.size() - 1;
                while (idx1 < idx2)
                {
                    if (idx1 > j + 1 && nums.at(idx1) == nums.at(idx1 - 1))
                    {
                        idx1++;
                        continue;
                    }
    
                    int val = nums.at(i) + nums.at(j) + nums.at(idx1) + nums.at(idx2);
                    if (val < target)
                    {
                        idx1++;
                    }
                    else if (val > target)
                    {
                        idx2--;
                    }
                    else
                    {
                        vector<int> vec = { nums.at(i), nums.at(j), nums.at(idx1), nums.at(idx2) };
                        bool has = isExist(vec);
                        if (!has)
                            result.push_back({ nums.at(i), nums.at(j), nums.at(idx1), nums.at(idx2) });
                        
                        idx1++;
                        idx2--;
                    }
                }
            }
        }
        return result;
    }

    问题:1.去重部分太复杂,使用lambda表达式每次遍历一遍是否重复,太耗时

    参考三数之和的去重,解答如下:

    vector<vector<int>> fourSum2(vector<int>& nums, int target)
    {
        vector<vector<int>> result;
        sort(nums.begin(), nums.begin() + nums.size());
    
        int idx1 = 0, idx2;
        for (int i = 0; i < nums.size(); i++)
        {
            if (i > 0 && nums.at(i) == nums.at(i - 1))//只有上一个是找到的才跳过,跟上一个重复,不处理
                continue;
    
            for (int j = i + 1; j < nums.size(); j++)
            {
                if (j > i + 1 && nums.at(j) == nums.at(j - 1))
                {
                    continue;//这里的j不用j++了,因为continue后j就自动++了
                }
    
                idx1 = j + 1;
                idx2 = nums.size() - 1;
                while (idx1 < idx2)
                {
                    if (idx1 > j + 1 && nums.at(idx1) == nums.at(idx1 - 1))
                    {
                        idx1++;
                        continue;
                    }
    
                    int val = nums.at(i) + nums.at(j) + nums.at(idx1) + nums.at(idx2);
                    if (val < target)
                    {
                        idx1++;
                    }
                    else if (val > target)
                    {
                        idx2--;
                    }
                    else
                    {
                        result.push_back({ nums.at(i), nums.at(j), nums.at(idx1), nums.at(idx2) });
    
                        idx1++;
                        idx2--;
                    }
                }
            }
        }
        return result;
    }

    问题:整个代码的主体流程与解答一致,但是运行速度较差,比较了解答,发现有许多判断条件用于减少循环次数,修改代码如下:

    vector<vector<int>> fourSum3(vector<int>& nums, int target)
    {
        vector<vector<int>> result;
        if (nums.size() < 4)    //如果输入小于4个则直接返回空vec
            return result;
    
        sort(nums.begin(), nums.begin() + nums.size());
    
        int idx1 = 0, idx2;
        for (int i = 0; i < nums.size(); i++)
        {
            if (i > 0 && nums.at(i) == nums.at(i - 1))//只有上一个是找到的才跳过,跟上一个重复,不处理
                continue;
    
            //在这里判断是否有继续执行的必要,即i i+1 i+2 i+3之和大于target则退出循环
            if (i + 3 < nums.size() && (nums.at(i) + nums.at(i + 1) + nums.at(i + 2) + nums.at(i + 3) > target))
                break;
    
            for (int j = i + 1; j < nums.size(); j++)
            {
                if (j > i + 1 && nums.at(j) == nums.at(j - 1))
                {
                    continue;//这里的j不用j++了,因为continue后j就自动++了
                }
    
                //i加上j j+1 j+2如果大于target则直接break
                if ((j+2)<nums.size() && nums.at(i) + nums.at(j) + nums.at(j + 1) + nums.at(j + 2) > target)
                    break;
    
                idx1 = j + 1;
                idx2 = nums.size() - 1;
                while (idx1 < idx2)
                {
                    int val = nums.at(i) + nums.at(j) + nums.at(idx1) + nums.at(idx2);
                    if (val < target)
                    {
                        idx1++;
                    }
                    else if (val > target)
                    {
                        idx2--;
                    }
                    else
                    {
                        result.push_back({ nums.at(i), nums.at(j), nums.at(idx1), nums.at(idx2) });
    
                        while (idx1 < idx2 && nums.at(idx1) == nums.at(idx1 + 1))
                        {
                            idx1++;
                        }
                        while (idx1 < idx2 && nums.at(idx2) == nums.at(idx2 - 1))
                        {
                            idx2--;
                        }
                        idx1++;
                        idx2--;
                    }
                }
            }
        }
        return result;
    }

    总结:

    1.同样的算法,一些预处理、判断条件的不同,最终运行速度也会差的很大;

    2.在循环中对i j++时要注意,因为for每次循环后都会自动++,而while需要手动++,注意针对不同情况的写法,很容易引入bug。

  • 相关阅读:
    数组中重复的数字-剑指Offer
    不用加减乘除做加法-剑指Offer
    扑克牌顺子-剑指Offer
    左旋转字符串-剑指Offer
    翻转单词顺序列-剑指Offer
    和为S的连续正数序列-剑指Offer
    和为S的两个数字-剑指Offer
    数组中只出现一次的数字-剑指Offer
    平衡二叉树-剑指Offer
    二叉树的深度-剑指Offer
  • 原文地址:https://www.cnblogs.com/zyk1113/p/13983731.html
Copyright © 2020-2023  润新知