leetcode 15. 三数之和

代码随想录 哈希表-8

15. 三数之和

中等 

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

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

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

示例 2:

输入:nums = []
输出:[]

示例 3:

输入:nums = [0]
输出:[]

方法1:自己尝试

千辛万苦勉强能跑,但是时间复杂度太高了,能通过225/331个样例,牛客网能通过24/25个样例(最后是因为空间超了)。麻了,大体思路是跟两数之和和四数之和差不多,先遍历一遍求出两个数的和,存放在哈希表mp和mp_index里(还得存两个哈希表,两个哈希表的key都是两数的和,value一个存数值,另一个存下标),最后再遍历一遍找mp中有无key 为每个元素的相反数的,如果有,插入到最后的result。(在插入Result 时也有很多细节问题,比如 vector不能vector.find,只能find(vector.begin(),vector.end(),k),  再比如提取vector倒数第二个元素需要用*(vector.end()-2) ,.end() 返回终止迭代器,-2 以后返回的还是迭代器,得取*才能取回元素。等等)

可惜的是最后也没有完全通过,搞了2个半小时,不过也挺有进步的。

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        // 自己尝试,2022年7月20日 16点55分--17:43 没做出来----19:00继续做--20:49 d大概能通过了,就是时间复杂度太高
        // 暴力解,先两重for 遍历填满两数和,再找第三个数
        // 哈希表key是两数和,value 存两个值(多个值,可能不只两对)
        unordered_map<int, vector<int>> mp;
        unordered_map<int, vector<int>> mp_index;
        for(int i = 0; i < nums.size(); i++){
            for(int j = i + 1; j < nums.size(); j++){ 
                mp[nums[i] + nums[j]].push_back(nums[i]);
                mp[nums[i] + nums[j]].push_back(nums[j]);
                mp_index[nums[i] + nums[j]].push_back(i);
                mp_index[nums[i] + nums[j]].push_back(j);                
            }
        }

        vector<vector<int>> result;
        for(int k = 0; k < nums.size(); k++){
            auto it = mp.find(-nums[k]);
            if(it != mp.end()){
                // 还得保证 nums[k] 与之前两个数不重复----不对,是之前两个下标
                auto it_index = mp_index.find(-nums[k]);
                vector<int> sum_index = it_index->second;

                // 注意:vector不能用 vector.find,因为find不是vector的属性
                // 而是 vector 的函数,只可以 find(vector.begin(),vector.end(),3)
                // find(sum.begin(),sum.end(),nums[k]) == sum.end()

                // cout <<"和为:"<< it->first << ": {"; 
                // for(int nuu : it->second){
                //     cout << nuu <<" ";
                // }
                // cout <<"}" << "下标为:{";

                // for(int nnu : sum_index){
                //     cout << nnu <<" ";
                // }
                // cout <<"}" <<endl;
                    
                while(!it->second.empty()){
                    //nums[k] 与数组最后两个数[的下标]不重复,插入    
                    if(find(sum_index.end()-2,sum_index.end(),k) == sum_index.end()){
                        vector<int> tmp;
                        tmp.push_back(nums[k]);
                        //从后面插两个再删掉最后两个,直到没了
                        tmp.push_back(it->second.back());
                        // 倒数第二个,必须用end()-2,然后用*取值
                        tmp.push_back(*(it->second.end()-2));
                        
                        result.push_back(tmp);
                    }
                    it->second.pop_back();
                    it->second.pop_back();
                    // sum_index 也得pop_back---第二次提交的错误发现
                    sum_index.pop_back();
                    sum_index.pop_back();
                }

                // //删除结果中的重复元素
                // for(int m = 0; m < result.size(); m++){
                //     vector<int> tmp1 = result[m];
                //     sort(tmp1.begin(),tmp1.end());
                //     for(int n = m+1; n < result.size(); n++){
                //         vector<int> tmp2 = result[n];
                //         sort(tmp2.begin(),tmp2.end());
                //         if(tmp1 == tmp2){
                //             result.erase(result.begin() + n);
                //             n--;
                //         }
                //     }
                // }

                // 用set 来删除重复元素会不会快一点
                for(int m = 0; m < result.size(); m++){
                    unordered_set<int> set1(result[m].begin(),result[m].end()); 
                    for(int n = m+1; n < result.size(); n++){
                        unordered_set<int> set2(result[n].begin(),result[n].end());
                        if(set1 == set2){
                            result.erase(result.begin() + n);
                            n--;
                        }
                    }
                }



                // for(vector<int> out_res : result){
                //     cout << "[";
                //     for(int in_res: out_res){
                //         cout<< in_res <<", ";
                //     }
                //     cout << "],";
                // }
                // cout <<endl;   
            }
        }

        // //最后再删一下结果中的重复元素
        // for(int m = 0; m < result.size(); m++){
        //     vector<int> tmp1 = result[m];
        //     sort(tmp1.begin(),tmp1.end());
        //     for(int n = m+1; n < result.size(); n++){
        //         vector<int> tmp2 = result[n];
        //         sort(tmp2.begin(),tmp2.end());
        //         if(tmp1 == tmp2){
        //             result.erase(result.begin() + n);
        //             // erase后result.size()会减1,所以n 也得减,
        //             // 测试用例222 [3,0,3,2,-4,0,-3,2,2,0,-1,-5] 发现
        //             n--;
        //         }
        //     }
        // }

        // // 用set 来删除重复元素会不会快一点
        // for(int m = 0; m < result.size(); m++){
        //     unordered_set<int> set1(result[m].begin(),result[m].end()); 
        //     for(int n = m+1; n < result.size(); n++){
        //         unordered_set<int> set2(result[n].begin(),result[n].end());
        //         if(set1 == set2){
        //             result.erase(result.begin() + n);
        //             n--;
        //         }
        //     }
        // }

        return result;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值