文章目录
- 哈希表
-
- [核心思想:哈希查找 O ( 1 ) O(1) O(1),使用`set`去重](#核心思想:哈希查找 O ( 1 ) O(1) O(1),使用
set去重)
- [核心思想:哈希查找 O ( 1 ) O(1) O(1),使用`set`去重](#核心思想:哈希查找 O ( 1 ) O(1) O(1),使用
- 例题
- 双指针:快慢指针
- 双指针:滑动窗口
- 子串
哈希表
核心思想:哈希查找 O ( 1 ) O(1) O(1),使用set去重
例题
- 只能使用O(n)的算法,因此不能考虑二分。暴力法是两次遍历,考虑仅使用一次遍历。
- 解决方法:将遍历的元素存储在哈希表中,往已有哈希表中查找对应元素,可以实现一次遍历。
- 注意到所有字符串的顺序无关,所以对所有字符串进行排序 ,以排序后的值作为键建立映射关系。
128.最长连续序列:`` - 这题只能使用O(n)的算法。
- 考虑只能遍历一次,将所有数组预先存储到哈希表中方便查找。
- 优化重复遍历:对于非首位元素,不进行查找。
双指针:快慢指针
- 这题就是典型的双指针例题,双指针具有明显的单调特性。
- 假设h[i]<h[j]:说明i是瓶颈,必须移动i,如果i是单调递增,可以计算一次答案,否则可以继续移动i,直到h[i]>=h[j],此时拼接换到j。
cpp
class Solution {
public:
int maxArea(vector<int>& height) {
int ans=INT_MIN;
int i=0,j=height.size()-1;
while(i<j){
int w =j-i;
int h=min(height[i],height[j]);
ans=max(ans,w*h);
while(height[i]<height[j]&&i<j){
i++;
int w =j-i;
int h=min(height[i],height[j]);
ans=max(ans,w*h);
}
while(height[i]>=height[j]&&i<j){
j--;
int w =j-i;
int h=min(height[i],height[j]);
ans=max(ans,w*h);
}
}
return ans;
}
};
- 注意到这题的时间复杂度要求O(n^2)左右即可,因此可以考虑排序数组。
- 第一重循环固定i,第二重循环使用双指针优化。
- 注意数组具有明显的单调性,可以使用双指针用来寻找答案。
排列问题去重 :if a[i]=a[i-1] then continue
- i需要去重
cpp
if(j>i+1&&nums[j]==nums[j-1]){
j++;
continue;
}
- j和k也需要进行去重
cpp
if(j>i+1&&nums[j]==nums[j-1]){
j++;
continue;
}
if(k<nums.size()-1&&nums[k]==nums[k+1]){
k--;
continue;
}
- 暴力做法:对于当前台阶,选择左右两边最高的柱子,然后按照列的方式计算当前台阶的雨水量。
- 简单优化:加速寻找最大台阶的步数,使用单调容器获得比当前柱子大的最近一个元素所在的位置 。时间复杂度快一点,但是最坏仍然是平方。
cpp
class Solution {
public:
typedef struct node{
int idx,val;
node(int x,int y):idx(x),val(y){};
};
int trap(vector<int>& height) {
vector<int>left(height.size(),-1);
vector<int>right(height.size(),-1);
deque<node>q;
for(int i=0;i<height.size();i++){
while(q.size()&&q.back().val<=height[i]){
q.pop_back();
}
if(q.size()){
left[i]=q.back().idx;
}
q.push_back(node(i,height[i]));
}
q.clear();
for(int i=height.size()-1;i>=0;i--){
while(q.size()&&q.back().val<=height[i]){
q.pop_back();
}
if(q.size()){
right[i]=q.back().idx;
}
q.push_back(node(i,height[i]));
}
int res=0;
for(int i=0;i<height.size();i++){
int j=i,k=i;
while(left[j]!=-1)j=left[j];
while(right[k]!=-1)k=right[k];
if(i==j||j==k)continue;
int h = min(height[j],height[k])-height[i];
res+=h;
}
return res;
}
};
- 优化思路2:按照行的形式问题,之前的元素递减时不需要计算,一旦出现递增的情况,就要横向计算雨水量 。发现可以使用单调栈来模拟这一个过程。
一定要使用行的形式计算雨水!!!

双指针:滑动窗口
- 双指针:当出现重复就增加指针j,试图删去重复元素。
438.找到字符串中所有字母异位词
- 异位词:位置不同,字符种类和数量一致。
- 排序后可以作为键。
- 如果连续,子串可以共用一个hash数组 ;如果不连续的子串需要使用两个hash数组进行控制。判断是否是一个词可以直接暴力,复杂度取决于种类 。例如26个字母复杂度为 O ( 26 ) O(26) O(26)
子串
560.和为K 的子数组
- 使用hash表加速查询,使用前缀和加速求和运算。
239.滑动窗口最大值
- 单调队列模板题
76.最小覆盖子串
-
子串的暴力比较算法:遍历哈希表中每一个种类;然后使用双指针即可。
-
时间复杂度1e7,勉强能过
-
不暴力比较的方法
优化方法