目录
1.洛谷------UVA11572唯一的雪花

解题思路:hash表+滑动窗口
- hash表可以用一个int数组来模拟
- 滑动窗口即"同向双指针",具体看笔者的leetcode滑动窗口文章
- 题目最后的cout需要加上换行符(卡了笔者10分钟的地方)
代码:
cpp
#include<iostream>
#include<vector>
using namespace std;
int for_solution(int n, vector<int>& snowflakes)
{
//双指针的运用
vector<int> flag(n,0); //simulate hash array
int count = 0,max = -1;
for(int left=0,right=0;right<=n-1;right++)
{
//进窗口
int in = snowflakes[right];
count++;
flag[in]++;
//判断是否需要出窗口
while(flag[in]>1)
{
//开始出窗口
int out = snowflakes[left++];
count--;
flag[out]--;
}
//每次进出完窗口,判断一下是否为最优解
if(count>max) max = count;
}
return max;
}
int main()
{
int T;
cin>>T;
for(int i=1;i<=T;i++)
{
int n;
cin>>n;
vector<int> snowflakes(n,0);
for(int j=0;j<=n-1;j++) cin>>snowflakes[j];
int ret = for_solution(n,snowflakes);
cout<<ret<<endl;
}
return 0;
}
2.洛谷------逛画展

滑动窗口+hash表+count变量统计有效字符个数+数组下标从1开始(为了和题设重合)
注:INT_MAX 在 <climits> 头文件中
代码:
cpp
#include<iostream>
#include<vector>
#include<climits>
using namespace std;
int main()
{
int m,n;
cin>>n>>m;
vector<int> paintings(n+1,0);
for(int i=1;i<=n;i++) cin>>paintings[i];
int min = INT_MAX;
int left_min=0,right_min=0;
vector<int> hash(m+1,0);
for(int left=1,right=1,count=0;right<=n;right++)
{
//进窗口+有效字符添加判断
int in = paintings[right];
if(!hash[in]) count++;
hash[in]++;
//出窗口判断,count不为m时不可能作为答案,所以循环条件为 count == m
while(count==m)
{
//count为m时开始统计结果,此时不断出窗口,每次出窗口前更新一次结果
if(right-left+1<min)
{
min = right-left+1;
left_min = left;
right_min = right;
}
//出窗口+有效字符删除判断
int out = paintings[left++];
if(hash[out]==1) count--;
hash[out]--;
}
}
cout<<left_min<<" "<<right_min<<endl;
return 0;
}
3.牛客网------字符串

滑动窗口+hash表+表中字符逐一确认
代码:
cpp
#include<iostream>
#include<string>
#include<vector>
#include<stdbool.h>
#include<climits>
using namespace std;
bool check(vector<int>& hash)
{
//逐一判断
for(int i=0;i<=25;i++)
if(!hash[i]) return false;
return true;
}
int main()
{
string my_str;
cin>>my_str;
vector<int> hash(26,0);
int min=INT_MAX;
for(int left=0,right=0;right<=my_str.size()-1;right++)
{
//进窗口
char in = my_str[right];
hash[in-'a']++;
while(check(hash))
{
//更新结果
if(right-left+1<min) min = right-left+1;
//出窗口
char out = my_str[left++];
hash[out-'a']--;
}
}
cout<<min;
return 0;
}
4.牛客网------丢手绢

如下图所示,n个小朋友围成一个圈,相邻小朋友之间距离不定,现求两个小朋友之间最远距离(可以是相邻也可以是非相邻)

如下图1所示,从1到2共有顺时针、逆时针两种方式;顺时针距离为1,逆时针距离为5,因此距离为1;因此每个同学之间需要计算顺时针、逆时针两种情况,并选择其中更短的一种情况
**重点:**此时我们可以把所有同学的距离相和,得到一个结果sum,统计结果加到 k 变量中;如下图2所示,当 k < sum / 2 时,得到的结果都是逆时针距离大于顺时针距离(此时逆时针距离 >= sum / 2 ),统计顺时针距离 k 为结果;当 k >= sum / 2 时,得到的结果都是逆时针距离小于顺时针距离,统计逆时针距离 sum - k 为结果
通过图2,我们也不难看出left、right移动对结果的单调性;left移动时k就减小,right移动时k就增大,k减小时right回到left位置就没有必要了,所以可以通过滑动窗口(同向双指针)来解决这道题
- k < sum / 2 -> 进窗口 + 统计顺时针距离 k
- k >= sum / 2 -> 出窗口 + 统计逆时针距离 sum - k
- k >= sum / 2 容易出现精度问题,因此换成 2k >= sum
- 出窗口要在统计顺时针距离 k 前,要不然无法保证统计顺时针距离时 k < sum / 2
- 统计逆时针距离 sum - k 要在出窗口前,要不然会有情况(刚刚好达成进入循环时的情况)不被统计进结果

图1

图2
代码:
cpp
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int num,sum=0,max = -1;
cin>>num;
vector<int> friends(num+1,0);
for(int i=1;i<=num;i++)
{
int in;
cin>>in;
sum+=in;
friends[i] = in;
}
//准备工作
for(int left=1,right=1,k=0;right<=num;right++)
{
//进窗口
k+=friends[right];
//出窗口+统计逆时针结果
while(2*k>=sum)
{
//统计逆时针结果
if((sum-k)>max) max = sum - k;
//出窗口
k-=friends[left++];
}
//统计顺时针结果
if(k>max) max = k;
}
cout<<max;
return 0;
}