Day07
454 .四数相加II
一开始还是没思路,知道是哈希的应用,
思路如下:首先是4个数的哈希肯定没法用,已知两数之和可以找,所以两两分组,将a+b放在map中,然后通过遍历c+d,看0-(c+d)在没在map中,如果在,就说明可以相加为0。
次数计算的逻辑:首先将map的vlaue中存放可能得到a+b的和的次数。然后由于c+d是直接遍历的,所以每存在一个a+b,直接将value累加就好了。
重点:对于一个map,如果在map的key中存在i 则map[i]返回的是这个位置的value值。
如果不存在,则将i插入,然后将value初始化为0;
本题中的map[a+b]++就是将a+b这个key的value值自加1.
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
std::unordered_map<int,int> umap;
for(int a:nums1){
for(int b:nums2){
umap[a+b]++;
}
}
int count=0;
for(int c:nums3){
for(int d:nums4){
if(umap.find(0-(c+d))!=umap.end()){
count+=umap[0-(c+d)];
}
}
}
return count;
}
};
383. 赎金信
第一时间想到用map解决,
思路:首先将magazine的字符放入map中,然后使用ransomNote进行比对(哈希表),条件:没找到或者该字符value的值为负(也就是magazine中不够用),就输出false。
重点:这里使用的字符要用char,而不是string, map中可以使用的数据类型很多,复合数据类型也可以,包括自定义结构体或类等, 比如std::pair<int, int>
作为键类型
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
std::unordered_map<char,int> umap;
for(int i=0; i<magazine.length();i++){
umap[magazine[i]]++;
}
for(int i=0;i<ransomNote.length();i++){
if(umap.find(ransomNote[i])==umap.end()){
return false;
}
else{
umap[ransomNote[i]]--;
}
if(umap[ransomNote[i]]<0){
return false;
}
}
return true;
}
};
本题因为是有限的数据,只要存储26个字符(使用数组来做哈希的题目,是因为题目都限制了数值的大小。)
小tips:magazine.size()与magazine.length() 没有区别,可互换,都是返回字符串长度。
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.length();i++){
record[magazine[i]-'a']++;
}
for(int i=0;i<ransomNote.length();i++){
record[ransomNote[i]-'a']--;
if(record[ransomNote[i]-'a']<0){
return false;
}
}
return true;
}
};
5. 三数之和
有时间看下哈希
本题用双指针,因为去重好考虑。
在对数组排序后,可能重复的就只有a与b之间,b与c之间 ,首先a的重复:a前后一个值,然后b与c与上面值一样,比如-1,-1,0,1。a移动,但是bc不动,还是-1 0 1。
b与c的重复,在找到一组值之后,移动前后b与c的值不变。-2 -1 -1 3 3,都是-2 -1 3。
上面的处理都是找到下一个变化的值。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size();i++){
if(nums[i]>0){
return result;
}
if(i>0 && nums[i-1]==nums[i]){
continue;
}
int left = i+1;
int right = nums.size()-1;
while(left<right){
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]});
while(left<right && nums[left]==nums[left+1]){ left++;}
while(left<right && nums[right]==nums[right-1]){ right--;}
left++;
right--;
}
}
}
return result;
}
};
18. 四数之和
这个就是三数之和外面再加上个for循环,其次需要注意的就是第二层循环的判断条件。
对于第二层for循环的去重条件,这里要写成j>i+1的形式,这个去重的前面j的范围不仅仅是保证前面是存在数的(这个是三数求和 for循环去重条件为什么要写成 i >0),还要保证 j 的第一次循环可以进行下去。举例:[2,2,2,2,2] target=8.
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> result;
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size();i++){
if(nums[i]>target && nums[i]>0){
break;
}
if(i>0 && nums[i]==nums[i-1]){
continue;
}
for(int j=i+1;j<nums.size();j++){
if(nums[j]+nums[i]>target && nums[j]+nums[i]>0){
break;
}
if(j>i+1 && nums[j]==nums[j-1]){
continue;
}
int left=j+1;
int right=nums.size()-1;
while(left<right){
if((long)nums[i]+nums[j]+nums[left]+nums[right]>target) right--;
else if((long)nums[i]+nums[j]+nums[left]+nums[right]<target) left++;
else{
result.push_back(vector<int>{nums[i],nums[j],nums[left],nums[right]});
while(left<right && nums[left]==nums[left+1]) left++;
while(left<right && nums[right]==nums[right-1]) right--;
left++;
right--;
}
}
}
}
return result;
}
};
总结
哈希表的作用:用于快速查找数据,分为数组,set和map,数组一般用于数组可能得情况有限(一般是26英文字母这种),set是只用一个key值就可以,map是有key和value两个。