第454题.四数相加II
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int,int> umap; // key 为a+b的值,value为a+b出现的次数
// 遍历A和B两个数组,统计两个数组的元素之和,出现的次数,放到map中
for(int a : nums1){
for(int b : nums2){
umap[a+b] ++; // 通过下标访问map: map[key] = value
}
}
int count = 0; // 统计a+b+c+d=0的次数
for(int c : nums3){
for(int d : nums4){
if(umap.find(0 - (c + d)) != umap.end()){
count += umap[0 - (c + d)];
}
}
}
return count;
}
};
map是STL(中文标准模板库)的一个关联容器。
- 可以将任何基本类型映射到任何基本类型。如int array[100]事实上就是定义了一个int型到int型的映射。
- map提供一对一的数据处理,key-value键值对,其类型可以自己定义,第一个称为关键字,第二个为关键字的值
- map内部是自动排序的
二、map的用法
- 必须引入包
#include<map>
2.map的定义
map<type1name,type2name> maps;//第一个是键的类型,第二个是值的类型
map<string,int> maps;
3.map容器内元素的访问
- 通过下标进行访问
如:maps['c']=5;
- 通过迭代器进行访问
map可以使用it->first来访问键,使用it->second访问值
#include<map>
#include<iostream>
using namespace std;
int main()
{
map<char,int>maps;
maps['d']=10;
maps['e']=20;
maps['a']=30;
maps['b']=40;
maps['c']=50;
maps['r']=60;
for(map<char,int>::iterator it=mp.begin();it!=mp.end();it++)
{
cout<<it->first<<" "<<it->second<<endl;
}
return 0;
}
4.map的常用用法
- maps.insert() 插入
// 定义一个map对象
map<int, string> m;
//用insert函数插入pair
m.insert(pair<int, string>(111, "kk"));
// 用insert函数插入value_type数据
m.insert(map<int, string>::value_type(222, "pp"));
// 用数组方式插入
m[123] = "dd";
m[456] = "ff";
- maps.find() 查找一个元素
find(key): 返回键是key的映射的迭代器
map<string,int>::iterator it;
it=maps.find("123");
- maps.clear()清空
- maps.erase()删除一个元素
//迭代器刪除
it = maps.find("123");
maps.erase(it);
//关键字删除
int n = maps.erase("123"); //如果刪除了返回1,否则返回0
//用迭代器范围刪除 : 把整个map清空
maps.erase(maps.begin(), maps.end());
//等同于mapStudent.clear()
- maps.szie()长度
int len=maps.size();获取到map中映射的次数
- maps.begin()返回指向map头部的迭代器
- maps.end()返回指向map末尾的迭代器
//迭代
map< string,int>::iterator it;
for(it = maps.begin(); it != maps.end(); it++)
cout<<it->first<<" "<<itr->second<<endl;//输出key 和value值
- maps.rbegin()返回指向map尾部的逆向迭代器
- maps.rend()返回指向map头部的逆向迭代器
//反向迭代
map<string,int>::reverse_iterator it;
for(it = maps.rbegin(); it != maps.rend(); it++)
cout<<it->first<<' '<<it->second<<endl;
- maps.empty()判断其是否为空
- maps.swap()交换两个map
-
[383] 赎金信
bool canConstruct(string ransomNote, string magazine) {
// 使用哈希表判断ransomNote中的元素能否被magazine中元素组成
// 使用hash储存magazine中的元素
// 仅有小写故26个
int hash[26] = {0};
for(int i = 0; i < magazine.size(); i++){
hash[magazine[i] - 'a'] ++;
}
for(int j = 0; j < ransomNote.size(); j ++){
hash[ransomNote[j] - 'a'] --;
if(hash[ransomNote[j] - 'a'] < 0){
return false;
}
}
return true;
}
此题目与异构词思路相同。
15.三数之和
// 使用双指针法
vector<vector<int>> result;
sort(nums.begin(), nums.end());
// 找出a+b+c=0
// a = nums[i], b=nums[left],c=nums[right]
for(int i = 0; i < nums.size(); i++){
// 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
if (nums[i] > 0) {
return result;
}
// 错误去重a方法,将会漏掉-1,-1,2 这种情况
/*
if (nums[i] == nums[i + 1]) {
continue;
}
*/
// 正确去重a方法
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.size() - 1;
while (right > left) {
// 去重复逻辑如果放在这里,0,0,0 的情况,可能直接导致 right<=left 了,从而漏掉了 0,0,0 这种三元组
/*
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
*/
if (nums[i] + nums[left] + nums[right] > 0) right--;
else if (nums[i] + nums[left] + nums[right] < 0) left++;
else {
result.push_back(vector<int>{nums[i], nums[left], nums[right]});
// 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
// 找到答案时,双指针同时收缩
right--;
left++;
}
}
}
return result;
首先经过排序三个指针,一个遍历, 两个相向而行找到合适的值,此题的哈希表和双指针法都需要仔细回味一下
18.四数之和
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());//先排序
for (int k = 0; k < nums.size(); k++) {
// 剪枝处理
if (nums[k] > target && nums[k] >= 0) {
break; // 这里使用break,统一通过最后的return返回
}
// 对nums[k]去重
// 经过了排序,重复元素必相邻,仅需判断相邻元素是否相同,即可全面去重
if (k > 0 && nums[k] == nums[k - 1]) {
continue;
}
for (int i = k + 1; i < nums.size(); i++) {
// 二级剪枝处理
if(nums[k] + nums[i] > target && nums[k] + nums[i] >= 0){
break;
}
// 对 num[i] 去重
if (i > k + 1 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.size() - 1;
while(right > left){
// nums[k] + nums[i] + nums[left] + nums[right] > target 会溢出
if ((long) nums[k] + nums[i] + nums[left] + nums[right] > target) {
right--;
// nums[k] + nums[i] + nums[left] + nums[right] < target 会溢出
} else if ((long) nums[k] + nums[i] + nums[left] + nums[right] < target) {
left++;
} else {
result.push_back(vector<int>{nums[k], nums[i], nums[left], nums[right]});
// 对nums[left]和nums[right]去重
// 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
// 找到答案时,双指针同时收缩
right--;
left++;
}
}
}
}
return result;
}
这位更是重量级。。。。
总体看下来对边界条件的控制和适当位置的去重是整个算法顺利跑下来的关键要素