[上岸算法练习第三天]4 三数之和

154 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

一、题目:

三数之和

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

示例 1:

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
​
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]

二、题解:

1.解读

已知目标值,遍历数据找出两个数,且和为目标值。首先想到的就是暴力求解,也可以排序后二分,更好的方法也可以用Hash求解。

2.思路1

在思考两数之和解决方法的时候,我们使用了两层循环把所有的结果给求出来,相信大家很快就想到三数之和我就用三个循环,很棒,思路是一样,只是之前的a+b=0,现在的b=c+d了。好了代码呈上。

3.思路2

  • 第一步将整个数组排序
  • 从左侧开始,选定第一个数为定值比如下面的-4,然后左右指针分别指向对应位置如下图,是不是很像快排。
  • 定义的左右和定值相加

    • 如果等于0,记录下三个值
    • 如果小于0,左指针右移动
    • 如果大于0,右指针左移
  • 然后定值右移,重复这个步骤

4.实现

在前面的两数之和的基础上,将目标值移动到左边等于0就转换为了上一次的练习题。二第二种方式采用先排队,然后两边夹击的方式求解。

三、代码:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        //int result[]={0.1};
        int i=  0;
        int j=0;
        for(i;i<nums.size()-1;i++)
        {
            for(j=i+1;j<nums.size();j++)
            {
                if(nums[i]+nums[j]==target)//numb i + numbs[j] - target = 0
                {
                    return {i,j};
                }
            }
        }
        return {i,j};
    }
};
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 left = i + 1, right = nums.size() - 1;
            //取出三个数 所以不用left=right
            while (left < right) {
                if (nums[left] + nums[right] + target < 0) ++left;
                else if (nums[left] + nums[right] + target > 0) --right;
                else {
                    ans.push_back({target, nums[left], nums[right]});
                    ++left, --right;
                    //去重 
                    //测试数据[-2,0,0,2,2]
                    while (left < right && nums[left] == nums[left - 1]) ++left;
                    while (left < right && nums[right] == nums[right + 1]) --right;
                }
            }
        }
        return ans; 
    }
};

时间复杂度:O(n ^ 2)

空间复杂度:O(n)

四、总结

文中使用了两种方式来解决这个问题,第一种为复杂度较高的暴力解答,第二种使用了类似快排思想的双指针法,后面还会有更多关于双指针的用法,敬请期待。至此,想想有学会点什么了?

\