文章目录
参考自: https://gitee.com/programmercarl/leetcode-master/blob/master/problems/
前置知识点:
(1)哈希表都是用来快速判断一个元素是否出现集合里,但是牺牲了空间来换取时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。
(2)哈希碰撞的解决办法:
- 拉链法:发生冲突的元素都被存储在链表中(选择适当的哈希表的大小,这样既不会因为数组空值而浪费大量内存,也不会因为链表太长而在查找上浪费太多时间)
- 线性探测法:一定要保证tableSize大于dataSize,用哈希表中的其他的空位来解决碰撞问题
(3)使用哈希法来解决问题时,选择数组、set(集合)、map(映射)三种数据结构
leetcode 1002. 查找共用字符
https://leetcode-cn.com/problems/find-common-characters/
参考自代码随想录的思路:
class Solution {
public:
vector<string> commonChars(vector<string>& words) {
map<char,int> hash;
vector<string> res;
// 给hash初始化
for(int i=0;i<words[0].size();i++){
hash[words[0][i]] ++;
}
// 遍历其他的单词
for(int i=1;i<words.size();i++){
// 初始化tmp
map<char,int> tmp;
for(int j=0;j<words[i].size();j++){
tmp[words[i][j]] ++;
}
// 更新hash
for(char i='a';i<='z';i++){
if(tmp[i] < hash[i]) hash[i] = tmp[i];
}
}
// 只要map中的value不为0就将key放入结果集中
for(char i='a';i<='z';i++){
while(hash[i]!=0){
string a="";
a+=(char)i;
res.push_back(a);
hash[i]--;
}
}
return res;
}
};
leetcode 349. 两个数组的交集
https://leetcode-cn.com/problems/intersection-of-two-arrays/
解:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
// 必须用set使得结果中的元素唯一
unordered_set<int> res;
// 把nums1中的元素统计到tmp中,使得元素唯一
unordered_set<int> tmp(nums1.begin(),nums1.end());
for(int num : nums2){
// 看tmp中有没有nums2中的元素,找到说明是重复元素
if(tmp.find(num) != tmp.end()){ //找一遍后没有到末尾说明找到了
res.insert(num);
}
}
// 把unrodered_set中的元素放到vector中
return vector<int>(res.begin(),res.end());
}
};
leetcode 202. 快乐数
https://leetcode-cn.com/problems/happy-number/
不断地对结果各位取平方和,当和为1时返回true,当进入死循环说明sum的值出现过(用set记录)此时返回false
class Solution {
public:
// 求n各位之和
int getSum(int n){
int i,sum=0;
while(n!=0){
i = n % 10;
sum += i * i;
n /= 10;
}
return sum;
}
bool isHappy(int n) {
unordered_set<int> set;
while(1){
int sum = getSum(n);
if(sum == 1) return true;
//出现在set中表示进入死循环
if(set.find(sum) != set.end()){
return false;
}else{
set.insert(sum);
}
n = sum;
}
}
};![请添加图片描述](https://img-blog.csdnimg.cn/bafdd782df97404cb1d750aeae5d402d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBATmVmdV9seWg=,size_20,color_FFFFFF,t_70,g_se,x_16)
JZ75 字符流中第一个不重复的字符
https://www.nowcoder.com/practice/00de97733b8e4f97a3fb5c680ee10720
class Solution
{
public:
queue<char> q;
unordered_map<char,int> m;
//Insert one char from stringstream
void Insert(char ch) {
//没有出现过,则放入队列中
if(m.find(ch) == m.end()) q.push(ch);
// 记录每个单词出现次数
m[ch]++;
}
//return the first appearence once char in current stringstream
char FirstAppearingOnce() {
while(!q.empty()){
char ch = q.front();
if(m[ch]==1){
return ch;
}else{
q.pop();
}
}
return '#';
}
};
leetcode1. 两数之和
https://leetcode-cn.com/problems/two-sum/
在map里存<元素,元素下标>, 找当前元素的key是否在map中有值,有则返回当前的下标和互补数的下标。没有则将<元素,下标>存入map中
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> m;
for(int i=0;i<nums.size();i++){
auto iter = m.find(target - nums[i]);
if(iter != m.end()) return {iter->second,i};
m.insert({nums[i],i});
}
return {};
}
};
两数之和不能使用双指针法,因为两数之和要求返回的是索引下标, 而双指针法一定要排序,一旦排序之后原数组的索引就被改变了。如果要求返回的是数值的话,就可以使用双指针法。
leetcode 15. 三数之和
https://leetcode-cn.com/problems/3sum/
用三个指针 i、l、r 分别指向当前遍历元素nums[i]、nums[i+1]、最后一个元素nums[nums.size()-1]
- 当三者的和>0,r - -
- 当三者的和<0,l - -
- 当三者的和==0,将三个元素放入res,同时将与当前元素相同的值去除,收缩 l r 的查找范围
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(),nums.end());
for(int i = 0; i<nums.size();i++){
// 剪枝:如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回
if (nums[i] > 0) return res;
// i相同只需要一个结果
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int a = nums[i];
int l = i + 1, r = nums.size() - 1;
while(l<r){
int b = nums[l], c = nums[r];
if(a + b + c < 0) l ++;
else if(a + b + c > 0) r --;
else {
res.push_back({a,b,c});
while (l < r && nums[l] == nums[l + 1]) l++;
while (l < r && nums[r] == nums[r - 1]) r--;
//找到结果集时搜索范围变小
l++;
r--;
}
}
}
return res;
}
};