力扣383赎金信
首先看到小写字母作为元素,并且是对于两个字符串比较ransomNote是否包含在magazine中,所以如果使用一个哈希表来映射是不可能的。理由是,假设我们使用flag[26]作为哈希数组,ransomNote中出现字母则flag[i]++,magazine中出现字母则flag[i]--,那么最终我们只能找flag[i]为零的情况,因为如果不为零的话就说明要么ransom有,要么magazine有,反正不是都有。
但是我们找的情况不符合题意,因为如果ransomNote="aa",magazine="aab",那么其实应该返回true,但是我们的单个哈希映射会导致flag['b'-'a']=-1。单个哈希映射当然认为这是返回false。
所以应该使用两个哈希数组,并且保证magazine的哈希数组中每个元素的值都大于等于ransomNote。
首先看大于的情况:那就是要么magazine(ba)有ransomNote(a)没有,要么就是magazine(aa)有的比ransomNote(a)多;然后看等于的情况,要么是二者都没有,要么是二者都有相同数量的字母。其实我们也要根据这个题目来拓宽我们处理哈希、字符串、数组问题的思路:我们可以使用两个哈希数组。
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int flag1[26]={0};#存放ransomNote哈希
int flag2[26]={0};#存放magazine哈希
int len1=ransomNote.length();
int len2=magazine.length();
for(int i=0;i<len1;++i)
{
int temp=ransomNote[i]-'a';
flag1[temp]++;
}
for(int j=0;j<len2;++j)
{
int temp=magazine[j]-'a';
flag2[temp]++;
}
int k;
for(k=0;k<26;++k)
{
if(flag2[k]<flag1[k])#保证flag2每个元素都大于等于flag1
break;
}
if(k==26)
return true;
else
return false;
}
};
力扣15三数之和
首先看到这道题目脑子里没有任何的思路,即使我知道这道题放到了哈希的归类里面,我绞尽脑汁也没有想出任何和哈希有关的解法。但是隐约的感觉这道题需要用双指针,双指针left和right左右移动找到结果。随后看了《代码随想录》的解析,分析如下:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;//注解1
sort(nums.begin(),nums.end());//注解2
for(int i=0;i<nums.size();++i)
{
if(nums[i]>0)//注解3
return result;
if(i>0&&nums[i]==nums[i-1])//注解4
continue;
int left=i+1;//注解5
int right=nums.size()-1;
while(left<right)
{
if((nums[i]+nums[left]+nums[right])>0)//注解6
right--;
else if((nums[i]+nums[left]+nums[right])<0)//注解7
left++;
else
{
result.push_back(vector<int>{nums[i],nums[left],nums[right]});//注解8
while(left<right&&nums[right]==nums[right-1])right--;
while(left<right&&nums[left]==nums[left+1])left++;//注解9
left++;
right--;
}
}
}
return result;
}
};
1.注解1:定义的是二维容器,注意二维容器的定义,方便后面直接push_back进去找到的答案,如果使用二维数组,就要考虑下标的问题。
2.注解2:sort函数用来将nums排序,这也是注解3中后面检查nums中究竟有没有三数之和的关键,如果排序之后{1,2,3,4}第一个元素1都大于0,那么整个数组不存在三个数使和为0。
3.注解4:如果nums[i]==nums[i-1],也就是说{-1,-1,-1,1,1,2,3}中第一个-1可以用来作为三数之和中的nums[i],第二个-1用来做三数之和中的nums[left],但是当nums[i]为第二个-1的时候,就不需要继续保存-1,-1,2了,避免重复。后面注解8,注解9对于left,right也是这个道理。
力扣18四数之和
认为这个题目和三数之和是相同的思路,不过多了一重循环,也多了一种减少运行时间的方式。
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>>quadruplets;
if(nums.size()<4)//不满足题目直接返回空vector
return quadruplets;
sort(nums.begin(),nums.end());
int length=nums.size();
for(int i=0;i<length-3;++i)
{
if(i>0&&nums[i]==nums[i-1])//去重
continue;
if((long)nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target)
break;//最初的四个都大于target,那么后面肯定不大于
if((long)nums[i]+nums[length-3]+nums[length-2]+nums[length-1]<target)
continue;//最后面的加上最初的都小于target那么遍历从i开始后面的也没有意义,直接增大i,增大和
//可以看做缩短运行时间的一种操作
for(int j=i+1;j<length-2;j++)//不同于三数之和,多了一重循环
{
if (j > i + 1 && nums[j] == nums[j - 1]) {//以下三种去重方式同上面的去重方式
continue;
}
if ((long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
break;
}
if ((long) nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
int left=j+1,right=length-1;
while(left<right)
{
long sum=(long)nums[i]+nums[j]+nums[left]+nums[right];
if(sum==target)
{
quadruplets.push_back({nums[i],nums[j],nums[left],nums[right]});
while(left<right&&nums[left]==nums[left+1])
{
left++;//去重第三个
}
left++;//去重结束之后移动
while(left<right&&nums[right]==nums[right-1])
{
right--;
}
right--;
}
else if(sum<target)
{
left++;
}
else
{
right--;
}
}
}
}
return quadruplets;
}
关于哈希表C++关联式容器的总结详见:STL详解(十)—— set、map、multiset、multimap的介绍及使用_map、set、multiset、multimap底层原理-CSDN博客