leetcode No.15-16 三数之和相关问题

leetcode 15. 三数之和

题目

链接:https://leetcode-cn.com/problems/3sum

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例:

给定数组 nums = [-1, 0, 1, 2, -1, -4],

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

C++代码

首先最直接的解法显然是暴力循环,将所有可能的情况都遍历一遍。

这样所需要嵌套三个for循环,因此时间复杂度O(N3),显然无法接受。

如何优化呢?我没有思路,考虑先将问题简化。

可以对给定数组进行排序,变为有序数组,而排序的时间复杂度时O(NlogN),在暴力法面前不值一提,因此这个思路可行。

当数组有序时,我们就有办法处理了。问题变为了:

固定三元组中的最小数,找到 b + c = -a

既然是有序数组,我们就可以用双指针法,不断缩小可取值的范围,直到左指针l<右指针r的条件不满足

另外,需要思考下如何处理满足条件的三元组不唯一的情况,以及如何去重。

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int target;
        vector<vector<int>> ans;
        sort(nums.begin(), nums.end());
        for (int i = 0; i < nums.size(); i++) {
            if (i > 0 && nums[i] == nums[i - 1]) continue;
            if ((target = nums[i]) > 0) break;
            int l = i + 1, r = nums.size() - 1;
            while (l < r) {
                if (nums[l] + nums[r] + target < 0) ++l;
                else if (nums[l] + nums[r] + target > 0) --r;
                else {
                    ans.push_back({target, nums[l], nums[r]});
                    ++l, --r;
                    while (l < r && nums[l] == nums[l - 1]) ++l;
                    while (l < r && nums[r] == nums[r + 1]) --r;
                }
            }
        }
        return ans; 
    }
};

leetcode 16. 最接近的三数之和

题目

链接:https://leetcode-cn.com/problems/3sum-closest/

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.

与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).

C++代码

依旧延续leetcode NO.15 三数之和的方案,没有思路,先将问题简化,对数组nums进行排序,转为有序数组。

此时,我们依然可以使用双指针法来求解本问题。

注意思考:如何证明双指针法在逐渐收缩的过程中不会错过最优解?

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        int total_best_sum = -1;
        int total_min_dict = INT_MAX;
        if(nums.size() < 3)
            return total_best_sum;
        // 首先对数组进行排序
        sort(nums.begin(), nums.end());
        for(int i = 0; i < nums.size() - 2; i++){
            int a = nums[i];
            int residual = target - a;
            int l = i + 1;
            int r = nums.size() - 1;
            int min_dict = INT_MAX;
            int best_sum = -1;
            while(l < r){
                int cur_threeSum = a + nums[l] + nums[r];
                int cur_dict = abs(target - cur_threeSum);
                if(cur_dict == 0)
                    return target;
                if(cur_dict < min_dict){
                    min_dict = cur_dict;
                    best_sum = cur_threeSum;
                }
                if(target - cur_threeSum > 0)
                    l++;
                else
                    r--;
            }
            // 结束了a = nums[i]时最优三元组的寻找,判断是否为总体最优
            if(min_dict < total_min_dict){
                total_min_dict = min_dict;
                total_best_sum = best_sum;
            }
        }
        return total_best_sum;
    }
};

执行用时: 4 ms, 在所有 C++ 提交中击败了 99.46% 的用户

内存消耗: 12.2 MB, 在所有 C++ 提交中击败了 5.14% 的用户

发布了93 篇原创文章 · 获赞 351 · 访问量 54万+

猜你喜欢

转载自blog.csdn.net/u011583927/article/details/104685851