目录
[1. 两数之和](#1. 两数之和)
[49. 字母异位词分组](#49. 字母异位词分组)
[128. 最长连续序列](#128. 最长连续序列)
[283. 移动零](#283. 移动零)
[11. 盛最多水的容器](#11. 盛最多水的容器)
[15. 三数之和](#15. 三数之和)
[42. 接雨水](#42. 接雨水)
[3. 无重复字符的最长子串](#3. 无重复字符的最长子串)
[438. 找到字符串中所有字母异位词](#438. 找到字符串中所有字母异位词)
哈希:
1. 两数之和
也是很多人写的第一道题吧,学过哈希不难写出进阶条件,简简单单,
遍历数组的同时一边存,一边判断,找到返回。

cpp
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
// 哈希记录下标和值的存在,
unordered_map<int, int> hash;
for(int i = 0; i < nums.size(); ++i){
if(hash.count(target - nums[i])){
return {hash[target - nums[i]], i};
}
else{
hash.emplace(nums[i], i);
}
}
return {0, 0};
}
};

49. 字母异位词分组
博主有的僵化了,hash表先存了下标,又因为最后返回要原本的string,又去copy了一份strs
,算了,懒得优化,理这个题了。官解方法二似乎是用统计的string,每个字母的出现次数去做哈希的key。不管了,知道数据特殊时可以从这里优化key就行

cpp
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
//排序肯定最爽,
vector<string> tmp = strs;
for(auto& str : tmp){
sort(str.begin(), str.end());
}
//给它一个组id,
int id = 0;
unordered_map<string, int> hash;
for(int i = 0; i < tmp.size(); ++i){
if(hash.count(tmp[i])){
continue;
}
else{
hash[tmp[i]] = id++;
}
}
vector<vector<string>> vvs_ret(id);
for(int i = 0; i < strs.size(); ++i){
int ret_id = hash[tmp[i]];
vvs_ret[ret_id].push_back(strs[i]);
}
return vvs_ret;
}
};

128. 最长连续序列
,博主没想到 if(hash.count(num - 1)){ continue; } 这一层,还没想到在set里去重后的去找,真是一直超时,麻了,看了题解才反应过来。

cpp
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
//对于连续的最长序列,找到起始最小的/末尾最大的就可以确定返回,
//遍历数组的时候 去找nums[i] - 1是否存在,找到最小的去计算一下长度
int ret = 0;
unordered_set<int> hash(nums.begin(), nums.end());
// num之后的数量
auto f = [&](int num){
int count = 0;
while(hash.count(num + count)){
count++;
}
return count;
};
for(auto num : hash){
if(hash.count(num - 1)){ continue; }
ret = max(ret, f(num));
//优化
if(ret * 2 >= nums.size()) return ret;
}
return ret;
}
};

双指针:
283. 移动零
没啥好说的,基础题,再优化就是考虑特殊场景进行优化

cpp
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int l = 0, f = 0;
for( ; f < nums.size(); ++f){
if(nums[f] == 0) continue;
nums[l] = nums[f];
++l;
}
for( ; l < nums.size(); ++l){
nums[l] = 0;
}
}
};

11. 盛最多水的容器
这种关于水的,谁做过会忘记啊!

cpp
class Solution {
public:
int maxArea(vector<int>& height) {
//第一眼,前缀和,第二眼,不行,要宽,控制宽度,模拟一下就知道是双指针了
int l = 0, r = height.size() - 1;
int ret = 0;
while(l < r){
ret = max(ret, (r - l) * min(height[l], height[r]));
if(height[l] < height[r]){
++l;
}
else{
--r;
}
}
return ret;
}
};

15. 三数之和
这个方法就是我们常说的「双指针」,当我们需要枚举数组中的两个元素时,如果我们发现随着第一个元素的递增,第二个元素是递减的,那么就可以使用双指针的方法------来自官方题解
不会降维(指O(N^3)->O(N^2)这样的降一重复杂度)不是什么奇怪的事,不会去重也不是什么奇怪的事,看得懂题解,记住诀窍就好。

cpp
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ret;
sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size() - 2; ++i){
if(i != 0 && nums[i - 1] == nums[i]) continue;
int aim = -nums[i];
int l = i + 1, r = nums.size() - 1;
while(l < r){
int tmp = nums[l] + nums[r];
if(tmp > aim){
--r;
}
else if(tmp < aim){
++l;
}
else{
ret.push_back({nums[i], nums[l], nums[r]});
++l;
while(l != 0 && nums[l - 1] == nums[l] && l < r) ++l;
--r;
while(r != 0 && nums[r] == nums[r + 1] && r > l) --r;
}
}
}
return ret;
}
};

42. 接雨水
第一遍写的时候,没学过前缀和可能会没思路,有前缀和经验的,或者做过一遍就会发现,这个题完全是伪装成困难的简单题。,官方题解也很友好,不必看长篇文字,看动画就能理解。

cpp
class Solution {
public:
int trap(vector<int>& height) {
//做过就很简单
//前缀,后缀和
int n = height.size();
if(n < 3) return 0;
vector<int> r(n, 0);
for(int i = n - 2; i > 0; --i){
r[i] = max(r[i + 1], height[i + 1]);
}
int l_max = 0;
int ret = 0;
for(int i = 1; i < n; ++i){
int tmp = min(r[i], max(l_max, height[i - 1]));
ret += tmp > height[i] ? tmp - height[i] : 0;
l_max = max(l_max, height[i - 1]);
}
return ret;
}
};

滑动窗口:
3. 无重复字符的最长子串
滑动数组题目就那几种类型,练一练就会了。(不知道去哪找题?,找灵神呗)

cpp
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_set<char> hash;
int ret = 0;
int l = 0, r = 0;
for( ; r < s.size(); ++r){
if(hash.count(s[r])){
ret = max(r - l, ret);
while(l < r && hash.count(s[r])){
hash.erase(s[l]);
++l;
}
}
hash.emplace(s[r]);
}
ret = max(r - l, ret);
return ret;
}
};

438. 找到字符串中所有字母异位词
有定长滑动,有不定长滑动,都行,(这块儿知道了,c++大部分容器支持互相比较,还有c++11的安全静态数组array)

cpp
//定长
class Solution {
unordered_map<char, int> hash;
public:
bool hashIs0(){
for(auto [a, b] : hash){
if(b > 0) return false;
}
return true;
}
// void print_(){
// for(auto [a, b] : hash){
// cout << '[' << a << ':' << b << ']' << " ";
// }
// cout <<endl;
// }
vector<int> findAnagrams(string s, string p) {
if(p.size() > s.size()) return {};
//想到了
for(char ch = 'a'; ch <= 'z'; ++ch){
hash[ch] = 0;
}
for(auto ch : p){
hash[ch]--;
}
int l = 0, r = 0;
vector<int> ret;
for(; r < p.size(); ++r){
++hash[s[r]];
}
while(r < s.size()){
if(hashIs0()) ret.push_back(l);
hash[s[l]]--;
++l;
hash[s[r]]++;
++r;
}
if(hashIs0()) ret.push_back(l);
return ret;
}
};
