哈希表(力扣题解)

文章介绍了哈希表(unordered_map)在解决编程问题中的应用,如查找两数之和、四数之和和字符串构造等场景,展示了使用unordered_map实现高效查找和计数的方法。同时提到了暴力解法和优化策略,如排序和使用set去除重复结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

哈希表

map总结

对于map ,比如:unordered_map<int , int >mymap,
int A = mymap[a+b] 这个代表当map的key值为a+b时,value为 A
后文存在 mymap[a+b]++,value代表a+b存在次数

两数之和

哈希表解法:

map 中 key相当于数组元素,value为数组下标
map<key, value> mmm;

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int ,int>hashtable;
        for(int i =0 ; i<nums.size();i++)
        {
            //auto被定义为自动推断变量的类型
            //这里it被自动推断为map<int, int>::iterator
            auto it = hashtable.find(target - nums[i] );
            if(it != hashtable.end())
            {
                return {it->second,i};
            }
            hashtable[nums[i]] = i;  
            //是将nums[i]的key值放到value值i中
                    
            //map.insert(pair<int, int>(nums[i], i)); 
            //该方法插值更常用
        }
    
        return {};
    }
};

其中auto定义为自动判断变量的类型
map中:
1.it->first 表示的是这个元素的key的值;
2. it->second 表示的是这个元素的value的值。

暴力解法:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        for(int i = 0; i<nums.size();i++)
        {
            for(int j=i+1;j<nums.size();j++)
            {
                int sum = nums[i]+nums[j];
                if(sum  == target)
                {
                    return {i,j};
                }
            }
        }
        return {};
    }
};

四数之和

只要找到A[i] + B[j] + C[k] + D[l] = 0就可以
先将A+B放入map,再将C+D对比是否为0;

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int , int >mymap;
        int i = 0;
        for(vector<int>::iterator it1= nums1.begin(); it1 != nums1.end();it1++)
        {
            for(vector<int>::iterator it2 = nums2.begin();it2 != nums2.end();it2++)
            {
                mymap[*it1+*it2]++;
            }
        }
        int count = 0;
        for(vector<int>::iterator it3= nums3.begin(); it3 != nums3.end();it3++)
        {
        for(vector<int>::iterator it4 = nums4.begin();it4 != nums4.end();it4++)
            {
                if(mymap.find(0-(*it3+*it4)) != mymap.end())
                {
                    count += mymap[0-(*it3+*it4)];
                }
            }
        }
        return count;
    }
};

此处我用的原始迭代器写出的,可以用简洁版

class Solution {
public:
    int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
        unordered_map<int, int> umap; //key:a+b的数值,value:a+b数值出现的次数
        // 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中
        for (int a : A) {
            for (int b : B) {
                umap[a + b]++;
            }
        }
        int count = 0; // 统计a+b+c+d = 0 出现的次数
        // 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来。
        for (int c : C) {
            for (int d : D) {
                if (umap.find(0 - (c + d)) != umap.end()) {
                    count += umap[0 - (c + d)];
                }
            }
        }
        return count;
    }
};

umap 是一个 unordered_map 对象,它是一种关联容器,用于存储键值对。在这里,键是 a + b 的数值,值是 a + b 数值出现的次数。
[a + b] 是一个索引操作符,它用于访问 umap 中键为 a + b 的元素。如果这个键存在于 umap 中,那么就可以通过这个操作符来访问它。
++ 是递增运算符,用于将键 a + b 对应的值增加 1。如果键 a + b 在 umap 中不存在,这个操作将创建一个新的键值对,并将值初始化为1。

赎金信

纯纯双for暴力

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
           for(int i = 0; i< magazine.length();i++)
           {
               for(int j =0 ;j<ransomNote.length();j++)
               {
                   if(magazine[i] == ransomNote[j])
                   {
                       ransomNote.erase(ransomNote.begin()+j);
                       break;
                   }
               }
           } 
           if(ransomNote.size() == 0)
           {
               return true;
           }
           return false;
    }
};

第二种:

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int record[26]  = {0};
        if(ransomNote.size() > magazine.size())
        {
            return false;
        }
        for(int i =0 ;i < magazine.size();i++)
        {
            record[magazine[i] - 'a']++;
        }
        for(int j=0 ;j< ransomNote.size();j++)
        {
            record[ransomNote[j]-'a']--;
            if(record[ransomNote[j]-'a'] < 0 )
            {
                return false;
            }
        }
        return true;
    }
};

第三种采用vector和第二种方法类似。但是其中使用了for( auto &c : magazine),此种方法循环,可以记住

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        vector<int>record(26);
        if(ransomNote.size() > magazine.size())
        {
            return false;
        }
        // for(int i =0 ;i < magazine.size();i++)
        // {
        //     record[magazine[i] - 'a']++;
        // }
        
        for( auto &c : magazine)
        {
            record[c-'a']++;
        }
        for(int j=0 ;j< ransomNote.size();j++)
        {
            record[ransomNote[j]-'a']--;
            if(record[ransomNote[j]-'a'] < 0 )
            {
                return false;
            }
        }
        return true;
    }
};

上文使用for( auto &c : magazine),引用 & 的好处在于,它可以避免在循环中创建字符的副本,从而提高效率。如果不使用引用,即 for(auto c : magazine),那么在每次循环迭代时会创建字符的副本,这可能会占用更多的内存和时间。

三数之和

我最初理解错误,写了个错误代码:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int sum = 0;
        vector<vector<int>>a;
        for(int i = 0;i<nums.size();i++)
        {
            for(int j = i+1;j<nums.size();j++)
            {
                for(int k= j+1;k<nums.size();k++)
                {
                    sum  = nums[i]+nums[j]+nums[k];
                    if(sum == 0)
                    {
                    //a.push_back(nums[i],nums[j],nums[k]);
                    vector<int>triplet = {nums[i],nums[j],nums[k]};
                    a.push_back(triplet);
                    return a ;
 
                    }
                }
            }
        }
        return a;
    }
};

这个代码可以运行,但是我这个就属于找到第一个三元组就结束了,没有进行重复寻找
此时,可以增加一个判断代码,将你的重复问题解决:依旧为暴力解法:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int sum = 0;
        vector<vector<int>>a;
        sort(nums.begin(),nums.end());
        set<vector<int>> uniqueTriplets;
        for(int i = 0;i<nums.size();i++)
        {
            for(int j = i+1;j<nums.size() ;j++)
            {
                for(int k= j+1;k<nums.size();k++)
                {
                    sum  = nums[i]+nums[j]+nums[k];
                    if(sum == 0)
                    {
                    //a.push_back(nums[i],nums[j],nums[k]);
                    vector<int>triplet = {nums[i],nums[j],nums[k]};
                    // if(a.find(triplet) != a.end())
                    // {
                    //     a.push_back(triplet);
                    // }
                    // //return a ;
                    if (uniqueTriplets.find(triplet) == uniqueTriplets.end()) 
                    {
                            a.push_back(triplet);
                            uniqueTriplets.insert(triplet); // 添加到已经存在的集合中
 
                    }
                    }
                }
            }
        }
        return a;
    }
};

这个方法力扣是不能通过的,所以说是暴力揭发,超出时间限制;
数字之和方法,双指针法解万数之和

哈希总结:

在这里插入图片描述
这是常用的容器

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值