该节运用到很多c++特有的语法,后面会专门发一个涉及到的c++讲解。
一、前言:首先介绍一下哈希表,哈希表是通过关键值直接访问数据结构,关键值是通过哈希函数根据内容映射到关键值上,如果映射到同一个关键值上就需要另一个关键的哈希冲突,这里不细讲。
在使用哈希法解决问题时候一般会采用如下三种数据结构:
1.数组
2.set(集合)
set可以看作是我们数学中学到的集合,所记录的值也只有1个,所以一般判断是否存在这种问题上采用set比较合适。
3.map(映射)
map可以看作一个一个的键值对(<key,value>),通过关键值key来找到value。map一般用于比较复杂的判断。
二、有效的字母异位词
1.题目描述:判断2个字符串是否可以通过调换顺序使其相同。
2.思路分析:可以很清晰的知道出现的字符是固定的26个英文字母,这样他们的关键值就已经确定,可以通过一个数组来记录其出现过的次数,只要另一个字符串将这些清零就符合要求。
3.注意事项:提升效率的方法:通过判断字符个数是否相同可以直接判断,如果相同的话后面只要每一个字符都满足,不需要重新判断是否清零也可以判断。
三、俩个数组的交集
1.题目描述:求2个数组的交集,不能有重复的数据。
2.思路分析:求2个数组的交集而且不能有重复的数据,这个只需要记录交集的数据就行了,通过查找数据得出交集的数据即可,也就是说只需要一个数据,这时候我们想到的就是set集合,又因为不用考虑顺序和不能重复,采用unordered_set。
3.注意事项:这里需要注意unordered_set的函数应用。
unordered_set<int> nums_set(nums1.begin(),nums1.end())
//将nums1转换成unordered_set降重,nums1.begin(),nums1.end()为迭代器。
nums_set.find(num)
//在set中查找num值,如果存在则返回指向该值的迭代器,否则返回end()迭代器
四、俩数之和
1.题目描述:在数组中找到俩个数值之和等于target,返回这2个数值的下标。
2.思路分析:很明显可知需要放回的是数值的下标,同时也需要通过数值来查找,所以需要记录的是2个数据,这里使用set就不太合适,这时候应该使用map。
unordered_map<int, int> map;
auto iter = map.find(target - nums[i])
//auto定义一个迭代器,看是否能找到另外一个符合要求的加数。
if(iter != map.end())result {iter ->second,i}
\\iter->second找的是<key,value>的value。
else map.insert(pait<int ,int>(nums[i],i))
//没找到将数据传入map中。
五、四数相加(数据独立且可以重复)
1.题目描述:四个独立的数组,每个数组找一个相加等于0,共有多少种。
2.思路描述:通过遍历2个数组,将每种和的组合统计次数,通过map储存起来,再遍历另外2个数组,通过四、俩数之和的思路可以得出答案。
3.注意:不需要考虑重复的情况。
六、三数相加(数据不独立且不能重复)
1.题目描述:在一个数组中,寻找加起来等于0的组合,不能重复。
2.思路描述:可能会考虑上面的2种方法,通过向确定2个数通过哈希表来找另外一个数,但是这里有个核心问题就是不能重复,当然也可以找出答案后去重,但是这样太复杂了。
因此这里最好采用双指针法。首先排序,再通过一个循环来定死一个数,再通过2个指针来指向另外2个数,进行判断。
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] == nums[i-1])continue;//每次都与前一个对比,达到去重效果
int left = i + 1;
int right = nums.size()-1;
while(left < right){
if(nums[left] + nums [right] + nums[i] > 0)right--;
else if(nums[left] + nums [right] + nums[i] < 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的去重语句,这个语句一定要当找到一个符合的组才能去重,不然会丢失【0,0,0】这种情况。因为left和right去重语句是通过与下一个数据进行比较的,如果直接进行比较,会造成符合条件的情况丢失。
left++;right--;}
}
}return result;
}
};
七、四数之和
1.题目描述:与六相同,只是数据变成四个,0变成另一target。
2.思路描述:与六相同,只是多加一层循环,但是要注意剪枝已经不再适用,因为target不再是0;