30. 串联所有单词的子串 - 力扣(LeetCode)
class Solution {
public:
unordered_map<string, int> mp;
vector<int> findSubstring(string s, vector<string>& words) {
//单词长度相同
int n = s.size();
int m = words[0].size();
int cnt = words.size();
for(auto s: words) mp[s] ++;
vector<int> ans;
for(int i = 0; i <= n - m * cnt; i ++ )
{
unordered_map<string, int> mp1;
string t = s.substr(i, m);
int r = i;
while(++ mp1[t] <= mp[t])//第一个匹配成功
{
r += m;
t = s.substr(r, m);
}
if(r - i == cnt * m) ans.push_back(i);
}
return ans;
}
};
优化方案是按照对单词的长度取余进行分类,然后进行滑动窗口
class Solution {
public:
unordered_map<string, int> mp;
int n, m, cnt;
vector<int> ans;
vector<int> findSubstring(string s, vector<string>& words) {
//单词长度相同
n = s.size();
m = words[0].size();
cnt = words.size();
for(auto s: words) mp[s] ++;
for(int i = 0; i < m; i ++ )//起点
slide(i, s, words);
return ans;
}
void slide(int l, string s, vector<string>& words)
{
int r = l;
unordered_map<string, int> mp1;
while(l <= n - m * cnt)
{
string t = s.substr(r, m);//第一个单词
while(mp1[t] < mp[t])
{
mp1[t] ++;
r += m;
t = s.substr(r, m);//后一个
}
if(r - l == m * cnt) ans.push_back(l);
mp1[s.substr(l, m)] --;
l += m;
}
}
};
字符串hash可以防止字符串长度过长导致内存过大
class Solution {
public:
typedef unsigned long long ULL;
static const int P = 131;
ULL h[100010], p[100010];
vector<string> findRepeatedDnaSequences(string s) {
int n = s.size();
//h[k]为哈希值,p[k] 为 p^k
p[0] = 1;//字符串从1开始标号
for(int i = 0; i < n; i ++ )
{
p[i + 1] = p[i] * P;
h[i + 1] = h[i] * P + s[i];
}
unordered_map<ULL, int> mp;
vector<string> ans;
for(int i = 10; i <= n; i ++)
{
int j = i - 10 + 1;
ULL t = find(j, i);
if(mp[t] == 1) ans.push_back(s.substr(j - 1, 10));
mp[t] ++;
}
return ans;
}
ULL find(int l, int r)
{
return h[r] - h[l - 1] * p[r - l + 1];
}
};
480. 滑动窗口中位数 题解 - 力扣(LeetCode)
#define LL long long
class Solution {
public:
priority_queue<int> small;//大根堆维护小的值1 --- k/2
priority_queue<int, vector<int>, greater<int> > big;//小根堆维护大的值 k/2 --- k
unordered_map<int, int> mp;
double get(int& k){
if(k % 2) return small.top();
else return ((LL)small.top() + big.top()) * 0.5;
}
vector<double> medianSlidingWindow(vector<int>& nums, int k) {
for(int i = 0; i < k; i ++ ) small.push(nums[i]);
for(int i = 0; i < k / 2; i ++ ){
big.push(small.top()); //将大根堆的值放入小堆
small.pop();
}
vector<double> ans{get(k)};//初始窗口
for(int i = k; i < nums.size(); i ++ )
{
int balance = 0;
int l = nums[i - k];
mp[l] ++;//将要删除的值欠账
if(!small.empty() && l <= small.top()) balance --;
else balance ++;
if(!small.empty() && nums[i] <= small.top()){
small.push(nums[i]);
balance ++;
}
else{
big.push(nums[i]);
balance --;
}
if(balance > 0){
big.push(small.top());
small.pop();
}
if(balance < 0){
small.push(big.top());
big.pop();
}
while(!small.empty() && mp[small.top()] > 0){
mp[small.top()] --;
small.pop();
}
while(!big.empty() && mp[big.top()] > 0){
mp[big.top()] --;
big.pop();
}
ans.push_back(get(k));
}
return ans;
}
};
295. 数据流的中位数 - 力扣(LeetCode)
#define LL long long
class MedianFinder {
public:
priority_queue<int> small;//大根堆
priority_queue<int, vector<int>, greater<int> > big;
int k;
MedianFinder() {
k = 0;
}
void addNum(int num) {
if(small.empty() || num <= small.top())
small.push(num);//先往small中加,如果num小也往small里加
else big.push(num);
while(small.size() >= big.size() + 2)//不要减,size是无符号的,保证small比big最多多一个
{
big.push(small.top());
small.pop();
}
while(big.size() >= small.size() + 1)
{
small.push(big.top());
big.pop();
}
k ++;//记录奇数还是偶数
}
double findMedian() {
if(k % 2) return small.top();
return ((LL)small.top() + big.top()) * 0.5;
}
};
567. 字符串的排列 - 力扣(LeetCode)
class Solution {
public:
bool checkInclusion(string s1, string s2) {
int m = s1.size(), n = s2.size();
if(n < m) return false;
unordered_map<char, int> mp;
unordered_map<char, int> mp2;
for(auto c: s1) mp[c] ++;
int l = 0, r = 0;
while(l <= n - m)
{
while(r < n && mp2[s2[r]] < mp[s2[r]])
{
mp2[s2[r]] ++;
r ++;
}
if(r - l == m) return true;
// cout << l << " " << r << endl;
if(r > l)//说明有匹配
{
mp2[s2[l]] --;
}
else r = l + 1;
l ++;
}
return false;
}
};
1438. 绝对差不超过限制的最长连续子数组 - 力扣(LeetCode)
class Solution {
public:
int longestSubarray(vector<int>& nums, int limit) {
//有序集合
multiset<int> se;
int l = 0, r = 0;
int ans = 0;
int n = nums.size();
while(r < n)
{
se.insert(nums[r]);
r ++;
while(*se.rbegin() - *se.begin() > limit)
{
se.erase(se.find(nums[l]));
l ++;
}
ans = max(ans, r - l);
}
return ans;
}
};
1838. 最高频元素的频数 - 力扣(LeetCode)
或者二分窗口大小
class Solution {
public:
int maxFrequency(vector<int>& nums, int k) {
const int n = nums.size();
std::sort(nums.begin(),nums.end());
long cost = 0;//已消耗的操作次数
int l = 0, r = 1;
int ans = 1;
while(r < n)
{
cost += (long)(nums[r] - nums[r-1])*(r - l);//[l,r-1]的所有元素都要加上 nums[r] - nums[r-1]
while(cost > k)//窗口右边界不能拉到 r
{
//注意,这里不是 cost -= (nums[r] - nums[l]); 害我debug 了好久
cost -= (nums[r] - nums[l]);//压缩窗口,回收消耗的操作次数
++l;
}
ans = max(ans, r - l + 1);// [l,r] 的所有元素在执行最多 k 次操作后,都成为 nums[r]
r++;
}
return ans;
}
};