力扣热题100--day6(c++版)

题目要求:三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

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

解题思路:

1.哈希

        最一开始想到了前几天用两数之和问题的哈希思路,于是开整

        先写代码:

class Solution {

public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ret;
        unordered_map<int,int> map;

        for (int i=0; i<nums.size(); i++){
            for (int j=i+1; j<nums.size(); j++){
                int target = 0-nums[i]-nums[j];
                if (map.find(target) != map.end() && map[target] != i && map[target] != j){
                    ret.push_back({nums[i], nums[j], target});
                }
            }
        }
        return ret;  
    }
};

        点击运行,不出意外报错了。。。。。

        仔细检查一下,嗯,哈希表只在查找第三个数时使用,但没有在外部循环中进行必要的数存储或更新(真脑瘫),还有就是发现没避免重复三元组的出现。于是乎又费了九牛二虎之力改代码。主要问题是去重,先排序!!!!

修改后代码:

class Solution {

public:

    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ret;
        // 先排序
        sort(nums.begin(), nums.end());
        // 建立哈希表,并将每个值存入map对应的键和值
        unordered_map<int,int> map;
        for (int i=0; i<nums.size(); i++){
            map[nums[i]]=i;
        }


        for (int i=0; i<nums.size(); i++){
            if (i>0  && nums[i] == nums[i-1])
                continue;
            for (int j=i+1; j<nums.size(); j++){
                if (j>i+1 && nums[j] == nums[j-1])
                    continue;
                int target = 0-nums[i]-nums[j];
                if (map.find(target) != map.end() && map.find(target)->second > j){
                    ret.push_back({nums[i], nums[j], target});
                }  
            }
        }
        return ret;    
    }
};

成功运行,但击败7.65%,显然还是有其他更高效的方法。

2.排序加双指针

        具体思路就是

  • ij 分别是双指针,i 指向 k 之后的元素,j 指向数组末尾。
  • 通过移动 ij 来寻找满足 nums[k] + nums[i] + nums[j] == 0 的三元组

                              

更详细的图解思路可以参考这个:. - 力扣(LeetCode)

具体代码:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;  // 用于存储结果
        sort(nums.begin(), nums.end());  // 先对数组进行排序
        int n = nums.size();  // 数组大小

        for (int k = 0; k < n - 2; ++k) {
            if (nums[k] > 0) break;  // 如果第一个数大于0,和不可能为0
            if (k > 0 && nums[k] == nums[k - 1]) continue;  // 跳过重复的数字

            int i = k + 1, j = n - 1;  // 双指针,分别指向k之后和数组末尾
            while (i < j) {
                int sum = nums[k] + nums[i] + nums[j];
                if (sum < 0) {
                    ++i;  // 如果和小于0,移动左指针 i
                    while (i < j && nums[i] == nums[i - 1]) ++i;  // 跳过重复元素
                } else if (sum > 0) {
                    --j;  // 如果和大于0,移动右指针 j
                    while (i < j && nums[j] == nums[j + 1]) --j;  // 跳过重复元素
                } else {
                    res.push_back({nums[k], nums[i], nums[j]});  // 找到一个三元组
                    ++i;
                    --j;
                    while (i < j && nums[i] == nums[i - 1]) ++i;  // 跳过重复元素
                    while (i < j && nums[j] == nums[j + 1]) --j;  // 跳过重复元素
                }
            }
        }
        return res;  // 返回结果
    }
};


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值