15. 三数之和,16. 最接近的三数之和,18. 四数之和 - leetcode 刷题(C++)

一、题目

15. 三数之和
16. 最接近的三数之和
18. 四数之和

二、分析

  1. 这个题与两数之和类似,可以采用双指针法,但是需要先排序。这样快排的时间复杂度是 O ( n ⋅ l o g n ) O(n·logn) O(nlogn),遍历第一个数时间复杂度为 O ( n ) O(n) O(n),双指针找两数和问题时间复杂度为 O ( n ) O(n) O(n),所以总体的时间复杂度是 O ( n 2 + n ⋅ l o n g n ) = O ( n 2 ) O(n^2+n·longn)=O(n^2) O(n2+nlongn)=O(n2)。没有用到额外的辅助数组,所以空间复杂度是 O ( 1 ) O(1) O(1)
    关键是如何去重:
例如:-5 -3 -2 -1 0 0 0 1 1 1 3 3 4 4 4
对于-5来说,要找两个数与其和为0;
当left移动到第一个1,right在最后一个4时,满足条件。
接下来的left和right和上一步的完全相等,所以一定是重复答案。直接跳过

  1. 将判断条件换了就可以,如果大于target,right就往左移,反之left往右移动,移动结束的时候就是离target最近的时候。
  2. 四数之和
    直接套用三数之和做。
    也可以改为3个指针移动!

三、代码

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n(nums.size());
        if(n < 3) return vector<vector<int>>();
        vector<vector<int>> res;
        

        sort(nums, 0, n-1);
        int left(0), right(0);
        for(int i = 0; i < n-2; i ++){
            if(i>0 && nums[i-1] == nums[i]) continue;
            left = i+1;
            right = n-1;
            while(left < right){
            	//去重
                if(left>i+1 && right < n-1 && nums[left] == nums[left-1] && nums[right] == nums[right+1]){
                    left++;
                    right --;
                    continue;
                }
                //满足条件,加入到结果集
                if(nums[i] + nums[left] + nums[right] == 0){
                    vector<int> temp(3);
                    temp[0] = nums[i];
                    temp[1] = nums[left];
                    temp[2] = nums[right];
                    res.push_back(temp);
                    right --;
                    left ++;
                }else if(nums[i] + nums[left] + nums[right] > 0){
                	//大于0说明右侧的数太大,左移减小之
                    right --;
                }else{
                    left ++;
                }
            }
        }
        return res;
    }
	//快排
    void sort(vector<int> &nums, int low, int high){
        if(low < high){
            int X(nums[low]), i(low), j(high);
            while(i < j){
                while(i < j && nums[j] >= X) j --;
                if(i < j) nums[i++] = nums[j];
                while(i < j && nums[i] <= X) i ++;
                if(i < j) nums[j--] = nums[i];
            }
            nums[i] = X;
            sort(nums, low, i -1);
            sort(nums, i+1, high);
        }
    }
};

执行用时:176 ms, 在所有 C++ 提交中击败了14.36的用户
内存消耗:20.8 MB, 在所有 C++ 提交中击败了21.31%的用户
为什么我的算法执行时间如此之长!

  1. 最接近的三数之和
class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        int n(nums.size());
        int res = nums[0] + nums[1] + nums[2];

        sort(nums, 0, n-1);
        int left(0), right(0);
        for(int i = 0; i < n-2; i ++){
            if(i>0 && nums[i-1] == nums[i]) continue;
            left = i+1;
            right = n-1;
            while(left < right){
                if(left>i+1 && right < n-1 && nums[left] == nums[left-1] && nums[right] == nums[right+1]){
                    left++;
                    right --;
                    continue;
                }
                // 只改了这里这一部分,每次记录新的结果
                int mius = nums[i] + nums[left] + nums[right];
                if(abs(target - res) > abs(mius - target))
                	res = nums[i] + nums[left] + nums[right];
                if(mius > target){
                // 同时也改了判断条件
                    right --;
                }else{
                    left ++;
                }
            }
        }
        return res;
    }
    void sort(vector<int> &nums, int low, int high){
        if(low < high){
            int X(nums[low]), i(low), j(high);
            while(i < j){
                while(i < j && nums[j] >= X) j --;
                if(i < j) nums[i++] = nums[j];
                while(i < j && nums[i] <= X) i ++;
                if(i < j) nums[j--] = nums[i];
            }
            nums[i] = X;
            sort(nums, low, i -1);
            sort(nums, i+1, high);
        }
    }
};

执行用时:20 ms, 在所有 C++ 提交中击败了37.11%的用户
内存消耗:9.6 MB, 在所有 C++ 提交中击败了74.84%的用户

  1. 四数之和
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        int n(nums.size());
        if(n < 4) return vector<vector<int>>();
        sort(nums, 0, n-1);
        vector<vector<int>> res;
        for(int i = 0; i < n; i ++){
            if(i>0 && nums[i-1] == nums[i]) continue;
            vector<vector<int>> temp = threeSum(nums, i+1, target-nums[i]);
            for(int j = 0;j < temp.size(); j++){
                vector<int> aaa(4);
                aaa[0] = nums[i];
                aaa[1] = temp[j][0];
                aaa[2] = temp[j][1];
                aaa[3] = temp[j][2];
                res.push_back(aaa);
            }
        }
        return res;
    }
    vector<vector<int>> threeSum(vector<int>& nums, int start, int target) {
        int n(nums.size());
        if(n < 3) return vector<vector<int>>();
        vector<vector<int>> res;
        int left(start), right(start);
        for(int i = start; i < n-2; i ++){
            if(i>start && nums[i-1] == nums[i]) continue;
            left = i+1;
            right = n-1;
            while(left < right){
                if(left>i+1 && right < n-1 && nums[left] == nums[left-1] && nums[right] == nums[right+1]){
                    left++;
                    right --;
                    continue;
                }
                if(nums[i] + nums[left] + nums[right] == target){
                    vector<int> temp(3);
                    temp[0] = nums[i];
                    temp[1] = nums[left];
                    temp[2] = nums[right];
                    res.push_back(temp);
                    right --;
                    left ++;
                }else if(nums[i] + nums[left] + nums[right] > target){
                    right --;
                }else{
                    left ++;
                }
            }
        }
        return res;
    }

    void sort(vector<int> &nums, int low, int high){
        if(low < high){
            int X(nums[low]), i(low), j(high);
            while(i < j){
                while(i < j && nums[j] >= X) j --;
                if(i < j) nums[i++] = nums[j];
                while(i < j && nums[i] <= X) i ++;
                if(i < j) nums[j--] = nums[i];
            }
            nums[i] = X;
            sort(nums, low, i -1);
            sort(nums, i+1, high);
        }
    }
};

执行用时:124 ms, 在所有 C++ 提交中击败了34.79%的用户
内存消耗:12.8 MB, 在所有 C++ 提交中击败了38.69%的用户

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值