【倒计时4day 35/155】
基础算法与数据结构
1057 Stack栈
对顶堆问题
,不断插入数,不断的输出中位数——数据流的中位数
堆stl中不可以删除——用集合代替 multiset
新数据结构:对顶堆
multiset中,允许元素重复
1.调整堆
如果up的堆数量小于down的堆数量,那么需要调整(将down中的最大元素插入到up中,并在down中删除这个元素)
如果down的堆数量小于up的堆数量+1,那么需要调整(将up中的最小元素插入到down中,并在up中删除这个元素)
2.堆性质
up(小——大)
down(小——大)
呈沙漏形状
down的最大值为全部数的中值,因此down的数量=up的数量+1
3.插入删除
插入:insert()
删除:erase()
erase(num);//在set中删除num的全部元素,假如有2个num,都被删除
erase(up/down.find(num));//在set中删除一个num的全部元素,假如有2个num,都被删除
#include<iostream>
#include<algorithm>
#include<stack>
#include<cstring>
#include<set>
using namespace std;
stack<int> st;
multiset<int> up,down;
void adjust(){
while(up.size()>down.size()){
down.insert(*up.begin());
up.erase(up.begin());
}
while(down.size()>up.size()+1){
auto it=down.end();
it--;
up.insert(*it);
down.erase(it);
}
}
int main(){
int N,index=0,num;
char op[20];
scanf("%d",&N);
while(N--){
scanf("%s",&op);
if(strcmp(op,"Push")==0){
scanf("%d",&num);
st.push(num);
if(up.empty()||num<*up.begin()){
down.insert(num);
}else{
up.insert(num);
}
adjust();
}else if(strcmp(op,"PeekMedian")==0){
if(st.empty()){
printf("Invalid\n");
}else{
auto it=down.end();
it--;
printf("%d\n",*it);
}
}else if(strcmp(op,"Pop")==0){
if(st.empty()){
printf("Invalid\n");
}else{
num=st.top();
st.pop();
printf("%d\n",num);
auto it=down.end();
it--;
if(num<=*it){
down.erase(down.find(num));//加了find函数,只删除其中一个值,不是整个数删除
}else{
up.erase(up.find(num));
}
adjust();
}
}
}
return 0;
}
1044 Shopping in Mars 火星购物
利用了前缀和
还有控制变量求最短且符合条件的区间
#include<iostream>
using namespace std;
#define MaxN 100010
#define INF 1e9
int N,M;
int S[MaxN];//前缀和
int main(){
scanf("%d%d",&N,&M);
for(int i=1;i<=N;i++){
scanf("%d",&S[i]);
S[i]+=S[i-1];
}
int res=INF;
for(int i=1,j=0;i<=N;i++){
while(S[i]-S[j+1]>=M)
j++;
if(S[i]-S[j]>=M){
res=min(res,S[i]-S[j]);
}
}
bool first=true;
for(int i=1,j=0;i<=N;i++){
while(S[i]-S[j+1]>=M)
j++;
if(S[i]-S[j]==res){
if(!first){
printf("\n");
}else{
first=false;
}
printf("%d-%d",j+1,i);
}
}
return 0;
}
1040 Longest Symmetric String 最长回文数
两种情况:奇数回文数,偶数回文数,向两边发展
注意字符串有空格,用getline(cin,str)输入
#include<iostream>
#include<cstring>
using namespace std;
int main(){
string str;
int maxnum=-1;
getline(cin,str);
for(int i=0;i<str.size();i++){
int l=i-1,r=i+1;//奇数 以i为中心
while(l>=0&&r<str.size()&&str[l]==str[r]){
l--;r++;
}
maxnum=max(maxnum,r-l-1);
l=i,r=i+1;//偶数 以i,i+1为中心
while(l>=0&&r<str.size()&&str[l]==str[r]){
l--;r++;
}
maxnum=max(maxnum,r-l-1);
}
printf("%d\n",maxnum);
return 0;
}
并查集
1013 Battle Over Cities 战争中的城市
find函数
,注意N和M的关系,范围不一样,M是边的最大数量,题目没有明确给出但是与N不同并且和N有紧密联系
find函数的背默
int find(int x){
if(P[x]!=x){
P[x]=find(P[x]);
}
return P[x];
}
联通集的问题,去掉结点A则找除去A(不包含A的结点有多少个联通集),一开始有N-1个联通集,要联通起来只需要联通集个数-1
#include<iostream>
#define MaxN 1010
#define MaxM MaxN*MaxN
using namespace std;
int N,M,K;
int P[MaxN];
struct Node{
int a,b;
}Edge[MaxM];
int find(int x){
if(P[x]!=x){
P[x]=find(P[x]);
}
return P[x];
}
int main(){
scanf("%d%d%d",&N,&M,&K);
for(int i=0;i<M;i++){
scanf("%d%d",&Edge[i].a,&Edge[i].b);
}
for(int j=0;j<K;j++){
int target,cnt=N-1;//最开始有N-1个联通集
scanf("%d",&target);
for(int i=1;i<=N;i++){
P[i]=i;
}
for(int i=0;i<M;i++){
int a=Edge[i].a;
int b=Edge[i].b;
if(a!=target&&b!=target){
int pa=find(a);
int pb=find(b);
if(pa!=pb){
P[pa]=pb;
cnt--;//多一个联通
}
}
}
printf("%d\n",cnt-1);
}
return 0;
}