哈希表
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;
}
};
这个方法力扣是不能通过的,所以说是暴力揭发,超出时间限制;
数字之和方法,双指针法解万数之和
哈希总结:
这是常用的容器