算法笔记(一)

将单词逆序输出
cin--空格和回车键表示输入结束
gets()---回车键表示结束


int main(){
    char str[90];
    gets(str);   //回车表示输入结束
   long len=strlen(str);
    long r=0,h=0;
    char ans[90][90];
    for(long i=0;i<len;i++){
        if(str[i]!=' ')
        {
            ans[r][h++]=str[i];
        }
        else{
            ans[r][h]='\0';
            r++;
            h=0;
        }
    }
    
    for(long j=r;j>=0;j--){
        printf("%s",ans[j]);
        if(j>0) printf(" ");
    }
    return 0;
}
sort()排序(6.9.6)
  • sort(首元素地址,尾元素地址的下一个地址,比较函数(非必填))
  • 比较函数不填时,默认按照从小到大的顺序排序
  • 使用sort时 必须头文件"#include"和"using namespace std"
比较函数cmp(基本数据类型、结构体类型、STL容器进行自定义规则排序时的写法)
  
--基本数据类型:int double char --
#include<cstdio>
#include <algorithm>
using namespace std;

bool cmp(int a,int b){
    return a>b;
}

int main(){
    int a[5]={3,1,4,2};
    sort(a,a+4,cmp);
    for(int i=0;i<4;i++)
        printf("%d",a[i]);
    return 0;
}

----结构体类型
bool cmp(node a,node b){
if(a.x!=b.x) return a.x>b.x;
else return a.y<b.y;
}

---容器的排序
在STL容器中,只有vector,string,deque是可以使用sort的。 map,set这种容器元素本身有序,是通过红黑树实现的。
字符串hash
#include<cstdio>
const int maxn=100;
char s[maxn][5],temp[5];
int hashtable[26*26*26+10];//全局变量自动初始化为0

int hasnfunc(char s[],int len){
    int id=0;
    for(int i=0;i<len;i++){
        id=id*26+(s[i]-'A');
    }
    return id;
}


int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++){
        scanf("%s",s[i]);
        int id=hasnfunc(s[i], 3);
        hashtable[id]++;
    }
    
    for(int i=0;i<m;i++){
        scanf("%s",temp);
        int id=hasnfunc(temp, 3);
        printf("%d",hashtable[id]);
    }
    return 0;
}


全排列
#include<cstdio>
const int maxn=11;
//p为当前排列,hastable记录当前的x是否已经在p中
int n,p[maxn],hastable[maxn]={false};

void generatep(int index){
    if(index==n+1){  //递归边界,以及处理完排列的1~n位
        for(int i=1;i<=n;i++){
            printf("%d",p[i]);
        }
        printf("\n");
        return;
    }
    
    for(int x=1;x<=n;x++){ //枚举1~n,试图将x填入p[index]
        if(hastable[x]==false){
            p[index]=x;
            hastable[x]=true;
            generatep(index+1);
            hastable[x]=false;    //已经处理完p[index]为x的子问题,还原状态
        }
    }
}

int main(){
    n=3;
    generatep(1);
    return 0;
}


----n皇后问题----------
  
  #include<cstdio>
#include <cmath>
const int maxn=11;
//p为当前排列,hastable记录当前的x是否已经在p中
int n,p[maxn],hastable[maxn]={false};
int count=0;
void generatep(int index){
    if(index==n+1){  //递归边界,以及处理完排列的1~n位
        count++;
        return;
    }
    
    for(int x=1;x<=n;x++){ //枚举1~n,试图将x填入p[index]
        if(hastable[x]==false){
            bool flag=true;   //表示当前皇后不会和之前的皇后冲突
            for(int pre=1;pre<index;pre++){
                if(fabs((index-pre)) == fabs(x-p[pre])){
                    flag=false;
                break;
            }
            }
            if(flag)
            {
            p[index]=x;
            hastable[x]=true;
            generatep(index+1);
                hastable[x]=false;    //已经处理完p[index]为x的子问题,还原状态
            }
        }
    }
}

int main(){
    n=6;
    generatep(1);
    printf("%d",count);
    printf("\n");
    return 0;
}


贪心
----//算法笔记120页--
  --月饼---
#include<cstdio>
#include <algorithm>
using namespace std;
struct mooncake{
    double store; //库存量
    double sell;  //总售价
    double price; //月饼单价
}cake[1010];
bool cmp(mooncake a,mooncake b){
    return a.price>b.price;
}
int main(){
    int n; //月饼的种类
    double d;//最大需求量
    scanf("%d %lf",&n,&d);
    for(int i=0;i<n;i++){
        scanf("%lf",&cake[i].store);
    }
    for(int i=0;i<n;i++){
        scanf("%lf",&cake[i].sell);
        cake[i].price=cake[i].sell/cake[i].store;
    }
    
    sort(cake,cake+n,cmp);
    
    double ans=0;
    for(int i=0;i<n;i++){
        if(cake[i].store<d){
            d-=cake[i].store;
            ans+=cake[i].sell;
        }
        else{
            ans+=cake[i].price*d;
            break;
        }
    }
    printf("%.2f",ans);
    printf("\n");
    return  0;
}

随机快排
int randparttion(int A[],int left,int right){
    //生成[left,right]内的随机数p  round()四舍五入-math.h文件里面  RAND_MAX是stdlib.h中的一个常数
    int p=(round(1.0*rand()/RAND_MAX*(right-left)+left));
    
    swap(A[p],A[left]);
    int temp=A[left];
    while(left<right){
        while(left<right && temp<A[right] )
            right--;
        A[left]=A[right];
        while(left<right && temp>=A[left])
            left++;
        A[right]=A[left];
    }
    A[left]=temp;
    return left;
}

void  quicksort(int A[],int left,int right){
    if(left<right){
    int p=randparttion(A, left, right);
    quicksort(A, left, p-1);
    quicksort(A, p+1, right);
    }
}
有几个PAT(PAT B1040/A1093)

思想:

  • 对于一个确定位置的A来说,以它形成的PAT的个数=它左边的P的个数*它右边的T的个数;
  • 问题转换为->对字符串中的每个A,计算它左边的P的个数和它右边的T的个数,然后把所有A的这个乘积相加
#include <iostream>
#include <cstring>
using namespace std;

//int 所占字节数:4    最大值:2147483647    最小值:-2147483648
const int maxn=100010;
const int mod=1000000007;
char str[maxn];
int leftnump[maxn]={0};  //记录每一位左边P的个数(包括当前位)
int main(){
    gets(str);  //gets(str) 以enter键结束
    int len=strlen(str);
    for(int i=0;i<len;i++){
        if(i>0){
            leftnump[i]=leftnump[i-1];
        }
        if(str[i]=='P')
            leftnump[i]++;
    }
    //rightnumt记录当前累计右边T的个数
    int ans=0,rightnumt=0;
    for(int j=len-1;j>=0;j--){
        if(str[j]=='T')
            rightnumt++;
        else if(str[j]=='A')
            ans=(ans+leftnump[j]*rightnumt)%mod;
    }
    cout<<ans<<'\n';
    return 0;
}

随机选择算法

从一个无序数组中,选择第k大的数,采用随机选择算法,对任何的输入都可以达到o(n)的期望复杂度,最坏时间复杂度是o(n*n)

#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <time.h>
#include <cmath>
using namespace std;

int randparttion(int A[],int left,int right){
    //生成[left,right]内的随机数p  round()四舍五入-math.h文件里面  RAND_MAX是stdlib.h中的一个常数
    int p=(round(1.0*rand()/RAND_MAX*(right-left)+left));
    
    swap(A[p],A[left]);
    int temp=A[left];
    while(left<right){
        while(left<right && temp<A[right] )
            right--;
        A[left]=A[right];
        while(left<right && temp>=A[left])
            left++;
        A[right]=A[left];
    }
    A[left]=temp;
    return left;
}

//找无序数组中d第k大的数
int randselect(int A[],int left,int right,int k){
    if(left==right) return A[left]; //边界
    //划分后主元位置为A[p]
    int p=randparttion(A, left, right);
    int m=p-left+1; //A[p]是A[left,right]中的第m大的数
    if(m==k) return A[p];
    if(k<m) { return randselect(A, left, p-1, k);}
    else
    {
        return randselect(A, p+1, right, k-m);
    }
    
    
}

int main(){
    int randselect(int A[],int left,int right,int k);
    srand((unsigned)time(NULL));
    int array[100010];
    int num;
    int n=0;
    do{
        cin>>num;
        array[n++]=num;
    }while(getchar()!='\n');
    int k;
    cin>>k;
    int val=randselect(array, 0, n-1, k);
    cout<<val<<'\n';
    return 0;
}

第五章

数字黑洞(PAT B1019/A1069)
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
bool cmp(int a,int b)
{
    return a>b;
}

void to_array(int n,int num[]){ //将n的每一位存到数组中
    for(int i=0;i<4;i++){
        num[i]=n%10;  //每次把最后一个数字取出来
        n=n/10;
    }
}

int to_number(int num[]){
    int sum=0;
    for(int i=0;i<4;i++)
        sum=sum*10+num[i];
    return sum;
}

int main(){
    int n,maxn,minn;
    cin>>n;
    int num[5];
    while(1){
    to_array(n, num);
    sort(num,num+4);
    minn=to_number(num);
    sort(num,num+4,cmp);
    maxn=to_number(num);
    n=maxn-minn;
    cout<<maxn<<"-"<<minn<<"="<<n<<'\n';
        if(n==0 || n==6174) break;
    }
    return 0;
}




-------自己做的------------

#include <iostream>
#include <cmath>
using namespace std;
const int kaprekar=6174;

int numheidong(int num){
    int a[4];
    for(int i=1;i<4;i++){
        a[i-1]=num/pow(10,4-i);
        num=num-a[i-1]*pow(10,4-i);
    }
    a[3]=num%10;
    int t1,t2;
    for(int i=1;i<4;i++){
        int temp=a[i];
        int j=i-1;
        while(j>=0 && a[j]<temp){
            a[j+1]=a[j];
            j--;
        }
        a[j+1]=temp;
    }
    t1=a[0]*1000+a[1]*100+a[2]*10+a[3];
    t2=a[3]*1000+a[2]*100+a[1]*10+a[0];
    num=t1-t2;
    cout<<t1<<"-"<<t2<<"="<<num<<'\n';
    return num;
}

int main(){
    int num;
    cin>>num;
    int p=numheidong(num);
    while(p!=kaprekar){
        p=numheidong(p);
    }
    return 0;
}

最大公约数(辗转相除法)/最小公倍数

最小公倍数在最大公约数d的基础上,为ab/d,防止ab溢出,写为a/d*b;

#include <iostream>
using namespace std;

int gcd(int a,int b)
{
    if(b==0) return a;
    else return gcd(b,a%b);
}
int lcm(int a,int b){
    int num=gcd(a, b);
    num=a/num*b;
    return num;
}
int main(){
    int n,m;
    while(cin>>n>>m){
        cout<<gcd(n,m)<<"   "<<lcm(n,m);
    }
    return 0;
}



分数的四则运算
#include <iostream>
using namespace std;

int gcd(int a,int b){
    if(b==0) return a;
    else return gcd(b,a%b);
}
/*
 分数的制定需满足三项规则:
1.使down为非负数。如果分数为负数,则令分子为负数;
2.如果该分数恰好为0,则令down=1;
3.分子和分母没有除了1之外的公约数
 */

struct Fraction{
    int up,down;
};
//分数的化简:约分,且满足三项规则
Fraction reduction(Fraction result){
    if(result.down<0){
        result.up=-result.up;
        result.down=-result.down;
    }
    if(result.up==0){
        result.down=1;
    }
    else{
        int d=gcd(abs(result.up),abs(result.down));
        result.up=result.up/d;
        result.down=result.down/d;
    }
    return result;
}

Fraction add(Fraction f1,Fraction f2){
    Fraction result;
    result.up=f1.up*f2.down+f2.up*f1.down;
    result.down=f1.down*f2.down;
    result=reduction(result);
    return result;
}

int main(){
    Fraction f1;
    cin>>f1.up>>f1.down;
    f1=reduction(f1);
    
    Fraction f2;
    cin>>f2.up>>f2.down;
    f2=reduction(f2);
    
    Fraction f=add(f1, f2);
    if(f.down==1)
        cout<<f.up<<'\n';
    else
    cout<<f.up<<"/"<<f.down<<'\n';
    return 0;
}

素数
判断是否为素数
bool isPrime(int n){
    if(n<=1) return false;
    int sqr=(int)sqrt(1.0*n);
    for(int i=2;i<=sqr;i++){
        if(n%i==0)
            return false;
    }
    return true;
}

素数表的获取
  • “筛法”,即Eratosthenes筛法,复杂度o(nloglogn),更优的欧拉筛法,可以达到o(n)
-------筛法----------
#include <iostream>
#include <cmath>
using namespace std;
const int maxn=101; //表长
int prime[maxn];   //prime数组存放所有素数,pnum存放素数个数
int pnum=0;
bool p[maxn]={0};  //如果i为素数,则p[i]为false;否则为p[i]为true

void Find_prime(){
    for(int i=2;i<maxn;i++){
        if(p[i]==false){
            prime[pnum++]=i;
            for(int j=i+i;j<maxn;j+=i){
                p[j]=true;
            }
        }
    }
}

int main(){
    Find_prime();
    for(int i=0;i<pnum;i++){
        cout<<prime[i]<<" ";
    }
    
    return 0;
}

数素数
#include <iostream>
#include <cmath>
using namespace std;
const int maxn=100001; //表长
int prime[maxn];   //prime数组存放所有素数,pnum存放素数个数
int pnum=0;
bool p[maxn]={0};  //如果i为素数,则p[i]为false;否则为p[i]为true
void Find_prime(int n){
    for(int i=2;i<maxn;i++){
        if(p[i]==false){
            prime[pnum++]=i;
            if(pnum>=n) break;  //控制素数个数
            for(int j=i+i;j<maxn;j+=i){
                p[j]=true;
            }
        }
    }
}

int main(){
    int m,n;
    cin>>m>>n;
    Find_prime(n);
    int count=0;
    for(int i=m-1;i<n;i++){
        count++;
        cout<<prime[i];
        if(count%10!=0)
          cout<<" ";
        else
            cout<<'\n';
    }
    cout<<'\n';
    return 0;
}
质因子分解

前提:得到素数表

  • 1.枚举1~sqr=sqrt(n)范围内的所有质因子p,判断p是否是n的因子
  • 2.如果上述步骤后n>1,说明n有且仅有一个大于sqr的质因子(有可能是n本身)
#include <iostream>
#include <cmath>
using namespace std;
const int maxn=10001;
int prime[maxn];
int pnum=0;
bool is_prime(int n){
    if(n==1) return false;
    int sqr=(int)sqrt(1.0*n);
    for(int i=2;i<=sqr;i++){
        if(n%i!=0) return false;
    }
    return true;
}

void Find_prime() //求素数表
{
    for(int i=1;i<maxn;i++)
    {
        if(is_prime(i)==true)
            prime[pnum++]=i;
            }
}

struct factor{
    int x,cnt;  //x是质因子,cnt是它的个数
}fac[10];

int main(){
    int n,num=0;//num为n的不同质因子的个数
    cin>>n;
    Find_prime();
    if(n==1) cout<<"1=1"<<'\n';
    else{
        cout<<n<<"=";
        int sqr=(int)sqrt(1.0*n);
        for(int i=0;i<pnum && prime[i]<=sqr;i++){
            if(n%prime[i]==0){
                fac[num].x=prime[i];
                fac[num].cnt=0;  //记录该因子
                while(n%prime[i]==0){ //计算质因子prime[i]的个数
                    fac[num].cnt++;
                    n/=prime[i];
                }
                num++;
            }
            if(n==1) break;//及时推出循环,节省时间
        }
        //如果无法被sqr以内的质因子除尽,那么一定有一个大于sqr的质因子,即为除了剩下的n
        if(n!=1){  
            fac[num].x=n;
            fac[num++].cnt=1;
        }
        
        for(int i=0;i<num;i++){
            if(i>0) cout<<"*";
            cout<<fac[i].x;
            if(fac[i].cnt>1)
                cout<<"^"<<fac[i].cnt;
        }
    }
    cout<<'\n';
    return 0;
}

大整数四则运算
#include <iostream>
#include <cmath>
#include <string>
using namespace std;

struct bign{
    int d[1000];
    int len;
    bign(){
        memset(d,0,sizeof(d));
        len=0;
    }
};

bign change(char str[]){
    bign a;
    a.len=strlen(str);
    for(int i=0;i<a.len;i++){
        a.d[i]=str[a.len-1-i]-'0';
    }
    return a;
}

int compare(bign a,bign b){//比较ab的大小,a大:1,ab相等:0,a小:-1
    if(a.len>b.len) return 1;
    else if(a.len<b.len) return -1;
    else {
        for(int i=a.len-1;i>=0;i--){
            if(a.d[i]>b.d[i]) return 1;
            else if(a.d[i]<b.d[i]) return -1;
        }
        return 0;
    }
}
bign add(bign a,bign b){//高精度a+b
    bign c;
    int carry=0; //carry是进位
    for(int i=0;i<a.len || i<b.len;i++){//以较长的为界限
        int temp=a.d[i]+b.d[i]+carry;
        c.d[c.len++]=temp%10;
        carry=temp/10;
    }
    if(carry!=0)
        c.d[c.len++]=carry;
    return c;
}

//使用sub函数前需要比较两个数的大小,如果被减数小于减数,需要交换两个变量的位置,输出负号,再使用sub函数
void show(bign a){
    for(int i=a.len-1;i>=0;i--){
        cout<<a.d[i];
    }
}

bign sub(bign a,bign b){
    bign c;
    for(int i=0;i<a.len || i<b.len;i++){
        if(a.d[i]<b.d[i]){
            a.d[i+1]--;
            a.d[i]+=10;
        }
        c.d[c.len++]=a.d[i]-b.d[i];
    }
    
    while(c.len-1>=1 && c.d[c.len-1]==0)
        c.len--;  //去除高位的0,同时至少保留一位最低位
    
    return c;
}
int main(){
    char str1[1000],str2[1000];
    cin>>str1>>str2;
    bign a=change(str1);
    bign b=change(str2);
  //  show(add(a,b));
    show(sub(a,b));
    cout<<'\n';
    return 0;
}

栈的应用

#include <iostream>
#include<string>
#include <queue>
#include <stack>
#include <map>

using namespace std;

struct node{
    double num;  //操作数
    char op;     //操作符
    bool flag; //true表示操作数,false表示操作符
};

string str;
stack<node> s;    //操作符栈
queue<node> q;  //后缀表达式序列
map<char, int> op;


void Change(){  //将中缀表达式转为后缀表达式
    node temp;
    for(int i=0;i<str.length();){
        if(str[i]>='0' && str[i]<='9')
        {
            temp.flag=true; //标记是数字
            temp.num=str[i++]-'0';
            while(i<str.length() && str[i]>='0' && str[i]<='9'){
                temp.num=temp.num*10+str[i]-'0';
                i++;
            }
            q.push(temp);
            
        }
        else{
            while(!s.empty() && op[str[i]]<=op[s.top().op]){
                q.push(s.top());
                s.pop();
            }
            temp.flag=false;
            temp.op=str[i];
            s.push(temp);
            i++;
        }
}
    while(!s.empty()){
        q.push(s.top());
        s.pop();
    }
}

double cal(){
    double temp1,temp2;
    node cur,temp;
    while(!q.empty()){
        cur=q.front();
        q.pop();
        if(cur.flag==true) s.push(cur);
        else{
            temp2=s.top().num;
            s.pop();
            temp1=s.top().num;
            s.pop();
            temp.flag=true;
            if(cur.op=='+') temp.num=temp1+temp2;
            else if(cur.op=='-') temp.num=temp1-temp2;
            else if(cur.op=='*') temp.num=temp1*temp2;
            else if(cur.op=='/') temp.num=temp1/temp2;
            s.push(temp);
        }
    }
    return s.top().num;
}

int main(int argc, const char * argv[]) {
    op['+']=op['-']=1;
    op['*']=op['/']=2;
    while(getline(cin,str),str!="0"){
        for(string::iterator it=str.end();it!=str.begin();it--){
            if(*it==' ') str.erase(it);   //把表达式中的空格都擦掉
        }
        while(!s.empty()) s.pop(); //初始化栈
        Change();
        cout<<cal()<<'\n';
    }
    return 0;
}

第八章

深度优先搜索(背包问题)

背包问题:有n件物品,每件物品重量为w[i],价值为c[i].现在需要选出若干物品放入一个容器为V的背包中,使得在选入背包的物品重量和不超过容量v的前提下,让背包中物品的价值之和最大,求最大价值。

深度优先搜索:递归实现

  • "岔道口“(递归式):每件物品都有选或不选两种选择
  • "死胡同“(递归边界):选择物品重量总和超过V
#include<iostream>
using namespace std;
const int maxn=30;
int n,V,maxValue=0;
int w[maxn],c[maxn];

void DFS(int index,int sumW,int sumC){
    if(index==n){
        if(sumW<=V && maxValue<sumC){
            maxValue=sumC;
        }
        return;
    }
    DFS(index+1, sumW,  sumC);
    DFS(index+1, sumW+w[index], sumC+c[index]);
}

int main(){
    cin>>n>>V;
    for(int i=0;i<n;i++){
        cin>>w[i];
    }
    for(int i=0;i<n;i++){
        cin>>c[i];
    }
    
    DFS(0, 0, 0);
    cout<<maxValue<<'\n';
    return 0;
}

广度优先搜索BFS(迷宫问题 连通块)

广度优先搜索:队列实现

给出一个n*m的矩阵,矩阵中的元素为0或1。称位置(x,y)与其上下左右四个位置(x,y+1),(x,y-1),(x+1,y),(x-1,y)是相邻的。如果矩阵中有若干个1是相邻的(不必两两相邻),那么称这些1构成了一个"块"。求给定的矩阵中"块"的个数。

#include<iostream>
#include <queue>
using namespace std;
const int maxn=100;
struct node{
    int x,y;
}Node;

int n,m;
int matrix[maxn][maxn];
bool inq[maxn][maxn]={false}; //记录是否入队
int X[4]={0,0,1,-1};
int Y[4]={1,-1,0,0};

bool judge(int x,int y){ //判断该元素是否越界
    if(x>=n || x<0 || y>=m || y<0)
        return false;
    if(matrix[x][y]==0 || inq[x][y]==true) return false;
    return true;
}

void BFS(int x,int y){
    queue<node> q;
    Node.x=x;
    Node.y=y;
    q.push(Node);
    inq[x][y]=true;
    while(!q.empty()){
        node top=q.front();
        q.pop();
        for(int i=0;i<4;i++){
            int newx=top.x+X[i];
            int newy=top.y+Y[i];
            if(judge(newx,newy)){
                Node.x=newx;
                Node.y=newy;
                q.push(Node);
                inq[newx][newy]=true;
            }
        }
    }
}

int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
            cin>>matrix[i][j];
    }
    int ans=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(matrix[i][j]==1 && inq[i][j]==false){
                ans++;
                BFS(i, j);
            }
        }
    }
    cout<<ans<<'\n';
    return 0;
}

第九章

二叉树:链表存储

中序序列可以与先序序列、后序序列、层次序列中的任意一个序列来构建一个二叉树,二后三者两两搭配或是三个一起上都无法构建唯一的二叉树。原因是先序、后序、层序均是提供根结点,作用是相同的,都必须由中序序列来区分左右子树。

链表二叉树
//已知中序、后序 求层序
#include<iostream>
#include <queue>
#include <vector>
using namespace std;
vector<int> postorder;
vector<int> inorder;
struct node{
    int data;
    node* lchild;
    node* rchild;
    node(int d):data(d),lchild(NULL),rchild(NULL){};
};

node* createleveltree(int posl,int posr,int inl,int inr){
    if(posr<posl)
        return NULL;
    node* nownode=new node(postorder[posr]);
    
    int k;
    for(k=inl;k<=inr;k++){
        if(inorder[k]==postorder[posr])
            break;
    }
    
    int numlen=k-inl;
    
    nownode->lchild=createleveltree(posl, posl+numlen-1, inl, k-1);
    nownode->rchild=createleveltree(posl+numlen, posr-1, k+1, inr);
    
    return nownode;
}


int main(){
    int n;
   
    cin>>n;
    int temp;
    for(int i=0;i<n;i++){
        cin>>temp;
        postorder.push_back(temp);    //向vector里面加数据用push_back(value)函数,vector[i]适合访问数据
        
    }
    for(int i=0;i<n;i++){
        cin>>temp;
        inorder.push_back(temp);
    }
    
    queue<node*> inq;  //队列存放的是地址
    node* rootnode=createleveltree(0, n-1, 0, n-1);
    inq.push(rootnode);
    while(!inq.empty()){
        node nod=*inq.front();
        cout<<nod.data<<" ";
        
        if(nod.lchild!=NULL) inq.push(nod.lchild);
        if(nod.rchild!=NULL) inq.push(nod.rchild);
            inq.pop();
    }
    cout<<endl;
    return 0;
}


静态二叉树
#include<iostream>
#include <queue>
using namespace std;
const int maxn=30;
int inpos=0;
/*struct 结构体类型名
 {
 类型名 成员名;
 类型名 成员名;
 ……
 };
 
 先声明结构体类型,再定义结构体变量名
 声明结构体类型,不分配空间
 定义结构体类型变量,就要分配内存空间*/
struct node{
    int data;
    int lchild;
    int rchild;
}Node[maxn];


int newnode(int v){
    Node[inpos].data=v;
    Node[inpos].lchild=-1;
    Node[inpos].rchild=-1;
    return inpos++;
}//创建新的结点

void search(int root,int x,int newdata){
    if(root==-1)
        return;
    if(Node[root].data==x)
        Node[root].data=newdata;
    
    search( Node[root].lchild, x, newdata); //往左子树搜索
    search( Node[root].rchild, x, newdata);
}

void insert(int &root,int x){
    if(root==-1){  //当插入的是空树时
        root=newnode(x);
        return;
    }
      if(Node[root].lchild==-1)
        insert(Node[root].lchild, x);
       else
        insert(Node[root].rchild, x);
}

int create(int data[],int n){
    int root=-1;
    for(int i=0;i<n;i++){
        insert(root, data[i]);
    }
    return root;
}
//先序遍历
void preorder(int root){
    if(root==-1)
        return;
    cout<<Node[root].data<<" ";
    preorder(Node[root].lchild);
    preorder(Node[root].rchild);
}
//中序遍历
void inorder(int root){
    if(root==-1)
        return;
    inorder(Node[root].lchild);
    cout<<Node[root].data<<" ";
    inorder(Node[root].rchild);
}
//后序遍历
void postorder(int root){
    if(root==-1)
        return;
    postorder(Node[root].lchild);
    postorder(Node[root].rchild);
    cout<<Node[root].data<<" ";
}
//层序遍历
void layerorder(int root){
    queue<int> q;
    q.push(root);
    while(!q.empty()){
        int now=q.front();
        q.pop();
        cout<<Node[now].data<<" ";
        if(Node[now].lchild!=-1)
            q.push(Node[now].lchild);
        if(Node[now].rchild!=-1)
            q.push(Node[now].rchild);
    }
}

int main(){
    int n;
    int data[maxn];
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>data[i];
    }
    int root=create(data, n);
    preorder(root);
    cout<<'\n';
    inorder(root);
    cout<<'\n';
    postorder(root);
    cout<<'\n';
    layerorder(root);
    cout<<'\n';
    
    cout<<"输入要替换的数据:"<<'\n';
    int x,newdata;
    cin>>x>>newdata;
    search(root,x,newdata);
    preorder(root);
    return 0;
}


求根结点到叶子结点的权值和为某一值s的所有路径

给定一棵树和每个节点的权值,求所有从根结点到叶子结点的路径,使得每条路径上的结点的权值之和等于给定的常数s.如果有多条这样的路径,则按路径非递增顺序输出。

#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
const int MAXN=110;
struct node{
    int weight;
    vector<int> child;
}Node[MAXN];

bool cmp(int a,int b){
    return Node[a].weight>Node[b].weight;//按结点域从大到小排序
}

int n,m,s;//结点树、非叶子结点数、给定的和
int path[MAXN];
//当前访问结点为index.numNode为当前路径path上的结点个数
//sum为当前的结点点权和
void DFS(int index,int numNode,int sum){
    if(sum>s) return;
    if(sum==s){
        if(Node[index].child.size()!=0) return; //非叶子结点
        //到达叶子结点,此时path[]中存放了一条完整的路径,输出它
        for(int i=0;i<numNode;i++)
        {
            cout<<Node[path[i]].weight;
            if(i<numNode-1) cout<<" ";
            else cout<<'\n';
        }
        return;
    }     for(int i=0;i<Node[index].child.size();i++){
        int child=Node[index].child[i];
        path[numNode]=child;
        DFS(child, numNode+1, sum+Node[child].weight);
    }
    
}
int main(){
    cin>>n>>m>>s;
    for(int i=0;i<n;i++)
        cin>>Node[i].weight;
    int id,k,child;
    for(int i=0;i<m;i++){
        cin>>id>>k;
        for(int j=0;j<k;j++){
            cin>>child;
            Node[i].child.push_back(child);
        }
        sort(Node[id].child.begin(), Node[id].child.end(), cmp); //排序
    }
    path[0]=0;
    DFS(0, 1, Node[0].weight);
    return 0;
}
----------
input:
20 9 24
10 2 4 3 5 10 2 18 9 7 2 2 1 3 12 1 8 6 2 2
0 4 1 2 3 4
2 1 5
4 2 6 7
3 3 11 12 13
6 1 9
7 2 8 10
16 1 15
13 3 14 16 17
17 2 18 19

output:
10 5 2 7
10 4 10
10 3 3 6 2
10 3 3 6 2
Program ended with exit code: 0

第十章

图的存储

两种方式:邻接矩阵和邻接表(可用vector实现)

图的遍历
采用深度优先搜素(DFS)遍历图
  • 连通分量:在无向图中,如果两个顶点之间可以相互到达(可以是通过一定路径间接到达),那么就称这两个顶点连通
  • 强连通分量:在有向图中,如果两个顶点可用各自通过一条有向路径到达另一个顶点,就称这两个顶点强连通

连通块:连通分量和强连通分量

DFS遍历图的思路:将经过的顶点设置为已访问,在下次递归碰到这个顶点时就不再去处理,直到整个图的顶点都被标记已访问

DFS(u){
  vis[u]=true; //设置u已被访问
  for(从u出发能到达的所有顶点v){
    if(vis[v]==false){
      DFS(v);  //递归访问v
    }
  }
}

DFSTrave(G) {//遍历图G
  
  
}



#include<iostream>
#include<string>
#include<map>
using namespace std;
const int maxn=2010; //总人数
const int INF=100000000; //无穷大

map<int,string> intToString; //编号->姓名
map<string,int>stringToInt;  //姓名->编号
map<string,int>Gang; //head->人数
int G[maxn][maxn]={0},weight[maxn]={0};   //邻接矩阵G,点权weight
int n,k,numperson=0; //边数n,下限k,总人数numperson
bool vis[maxn]={false}; //标记是否被访问

//DFS函数访问单个连通块,nowvisit为当前访问编号
//head为头目,nummember为成员编号,totalvalue为连通块的总边权
void DFS(int nowvisit,int& head,int& nummember,int& totalvalue){
    nummember++;//成员人数加1
    vis[nowvisit]=true; //标记nowvisit已访问
    if(weight[nowvisit]>weight[head]){
        head=nowvisit;   //当前访问结点的点权大于头目的点权,则更新头目
    }
    
    for(int i=0;i<nummember;i++) //枚举所有人
    {
        if(G[nowvisit][i]>0){//如果从nowvisit能到达v
            totalvalue+=G[nowvisit][i];
            G[nowvisit][i]=G[i][nowvisit]=0;  //删除这条边,防止回头
            if(vis[i]==false){ //如果i未被访问,则递归访问i
                DFS(i, head, nummember, totalvalue);
                
            }
        }
    }
}

//遍历整个图,获取每个连通块的信息
void DFSTrave(){
    for(int i=0;i<numperson;i++){
        if(vis[i]==false){
            int head=i,nummember=0,totalvalue=0;//头目、成员数、总边权
            DFS(i, head, nummember, totalvalue);
            if(nummember>2 && totalvalue>k){
                //intToString[head]为头目的字符串姓名
                Gang[intToString[head]]=nummember;
            }
        }
    }
}

int change(string str){
    if(stringToInt.find(str)!=stringToInt.end()){//如果str已经出现过
        return stringToInt[str]; //返回编号
    }
    else{
        stringToInt[str]=numperson; //str的编号为numperson
        intToString[numperson]=str;
        return numperson++; //总人数加1
    }
}

int main(){
    int w;
    string str1,str2;
    //控制台输入s初始信息
    cin>>n>>k;
    for(int i=0;i<n;i++){
        cin>>str1>>str2>>w;
        int id1=change(str1);
        int id2=change(str2);
        weight[id1]+=w;
        weight[id2]+=w;
        G[id1][id2]+=w;
        G[id2][id1]+=w;
    }
    DFSTrave(); //遍历整个图,获得Gang的信息
    cout<<Gang.size()<<'\n';
    map<string,int>::iterator it;
    for(it=Gang.begin();it!=Gang.end();it++)
        cout<<it->first<<" "<<it->second<<endl;
    return 0;
}

第十一章(动态规划专题)

最大连续子列和
--复杂度o(n)--
#include<iostream>
#include <algorithm>
using namespace std;
const int maxn=10010;
int A[maxn],dp[maxn];  //状态dp[i]表示以A[i]作为末尾的连续序列的最大和
int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>A[i];
    }
    dp[0]=A[0];
    for(int i=1;i<n;i++){
        dp[i]=max(A[i], dp[i-1]+A[i]);
    }
    int k=0;
    for(int i=1;i<n;i++){
        if(dp[i]>dp[k])
            k=i;
    }
    cout<<dp[k]<<'\n';
    return 0;
}

最长不下降子列和(LIS)
#include<iostream>
#include <algorithm>
using namespace std;
const int maxn=10010;
int A[maxn],dp[maxn];  //状态dp[i]表示以A[i]作为末尾的连续序列的最大和
int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>A[i];
    }
    int ans=-1;
    for(int i=0;i<n;i++){
        dp[i]=1;
        for(int j=0;j<i;j++){
            if(A[j]<=A[i] && (dp[j]+1>dp[i]))
                dp[i]=dp[j]+1;
        }
        ans=max(ans,dp[i]);
    }
    cout<<ans<<'\n';
    return 0;
}

最长公共子序列
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
const int N=100;
char A[N],B[N];
int dp[N][N];
int main(){
    gets(A+1); //从下标1开始读入
    gets(B+1);
     int lenA=(int)strlen(A+1);
     int lenB=(int)strlen(B+1); //由于读入时从1开始读入,读取长度也从1开始
    //边界
    for(int i=0;i<=lenA;i++)
        dp[i][0]=0;
    for(int j=0;j<lenB;j++)
        dp[0][j]=0;
    //状态转移方程
    for(int i=1;i<=lenA;i++){
        for(int j=1;j<=lenB;j++){
            if(A[i]==B[j])
                dp[i][j]=dp[i-1][j-1];
            else
                dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
        }
    }
    cout<<dp[lenA][lenB]<<'\n';
    return 0;
}


最长回文子串
  • 按子串的长度和子串的初始位置进行枚举
#include<iostream>
#include <string>
using namespace std;
const int maxn=100;
char S[maxn];
int dp[maxn][maxn];//dp[i][j]表示从i到j的字串,如果是回文串,则为1,如果不是,则为0;
int main(){
    gets(S);
    int len=(int)strlen(S);
    int ans=1;
    memset(dp, 0, sizeof(dp)); //dp数组初始化为0
    //边界,将长度为1或者2的回文串的长度初始化
    for(int i=0;i<=len;i++){
        dp[i][i]=1;
        if(S[i]==S[i+1] && i<len-1)
        {  dp[i][i+1]=1;
            ans=2;//初始化时注意当前最长的回文子串
        }
    }
    
    //状态转移方程
    for(int L=3;L<=len;L++){ // L为子串的长度
        for(int i=0;i+L-1<len;i++){ //枚举子串的起始端点
            int j=i+L-1; //子串的右端点
            if(dp[i+1][j-1]==1 && S[i]==S[j])
            {
                dp[i][j]=1;
                ans=L; //更新最长回文子串
            }
        }
    }
    cout<<ans<<'\n';
    return 0;
}

01背包问题
  • 复杂度:o(nV)

    --dp[i][v]表示的是恰好为v的情况,所以要枚举dp[n][v](0<=v<=V),取其最大值才是最后的结果  时间复杂度为O(nV)--
    
    #include<iostream>
    #include <algorithm>
    using namespace std;
    const int maxn=100;
    const int maxv=1000;
    int w[maxn],c[maxn],dp[maxv];
    int main(){
        int n,V;
        cin>>n>>V;
        
        for(int i=1;i<=n;i++)
            cin>>w[i];
        
        for(int i=1;i<=n;i++)
            cin>>c[i];
        //边界
        for(int v=0;v<=V;v++){
            dp[v]=0;
        }
        for(int i=1;i<=n;i++){
            for(int v=V;v>=w[i];v--){
                dp[v]=max(dp[v],dp[v-w[i]]+c[i]);
            }
        }
        int maxvalue=0;
        for(int v=0;v<=V;v++){
            if(dp[v]>maxvalue)
                maxvalue=dp[v];
        }
        cout<<maxvalue<<'\n';
        return 0;
    }
    
    

十二章

字符串hash进阶
#include<iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
const int MOD=1000000007;
const int p=10000019;
vector<int> ans;
//字符串hash
long long hasfunc(string str){
    long long H=0;
    for(int i=0;i<str.length();i++){
        H=(H*p+str[i]-'a') % MOD;
    }
    return H;
}

int main(){
    string str;
    while(getline(cin,str),str!="#"){
        long long id=hasfunc(str);
        ans.push_back(id);
    }
    sort(ans.begin(),ans.end());
    int count=0;
    for(int i=0;i<ans.size();i++){
        if(i==0 || ans[i]!=ans[i-1])
            count++;
    }
    cout<<count<<'\n';
    return 0;
}


最长公共子串

输入两个长度均不超过1000的字符串,求他们的最长公共子串的长度

1.先分别对两个字符串的每个子串求出hash值(同时记录对应长度)

2.再找出两堆子串对应的hash值种相等的那些,便可以找到最大长度

时间复杂度是o(n2+m2)

#include<iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MOD=1000000007;
const int P=10000019;
const int MAXN=1010; //MAXN为字符串最大长度
//powP[i]存放P^i%MOD,H1和H2分别存放str1和str2的hash值
LL powP[MAXN],H1[MAXN]={0},H2[MAXN]={0};
//pr1存放str1的所有<子串hash值,子串长度>,ptr2同理
vector<pair<int, int>> pr1,pr2;
//init函数初始化powP函数
void init(int len){
    powP[0]=1;
    for(int i=1;i<=len;i++){
        powP[i]=(powP[i-1]*P)%MOD;
    }
}
//calH函数计算字符串str的hash值
void calH(LL H[],string &str){
    H[0]=str[0];
    for(int i=1;i<str.length();i++){
        H[i]=(H[i-1]*P+str[i])%MOD;
    }
}

//calSingleSubH计算H[i..j]
int calSingleSubH(LL H[],int i,int j){
    if(i==0) return H[j];
    return ((H[j]-H[i-1]*powP[j-i+1])%MOD+MOD)%MOD;
}
//calSubH计算所有子串的hash值,并将子串<子串hash值,子串长度>存入pr
void calSubH(LL H[],int len,vector<pair<int, int>>&pr){
    for(int i=0;i<len;i++){
        for(int j=i;j<len;j++){
            int hashvalue=calSingleSubH(H, i, j);
            pr.push_back(make_pair(hashvalue, j-i+1));
        }
    }
}
//计算pr1和pr2种相同的hash值,维护最大长度
int getMax(){
    int ans=0;
    for(int i=0;i<pr1.size();i++){
        for(int j=0;j<pr2.size();j++){
            if(pr1[i].first==pr2[j].first)
                ans=max(ans,pr1[i].second);
        }
    }
    return ans;
}
int main(){
    string str1,str2;
    getline(cin,str1);
    getline(cin,str2);
    init(max(str1.length(),str2.length()));
    calH(H1, str1);
    calH(H2, str2);
    calSubH(H1, str1.length(), pr1);
    calSubH(H2, str2.length(), pr2);
    cout<<"ans="<<getMax()<<'\n';
    return 0;
}

最长回文子串
#include<iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MOD=1000000007;
const int P=10000019;
const int MAXN=1010; //MAXN为字符串最大长度
//powP[i]存放P^i%MOD,H1和H2分别存放str1和str2的hash值
LL powP[MAXN],H1[MAXN]={0},H2[MAXN]={0};
//pr1存放str1的所有<子串hash值,子串长度>,ptr2同理
vector<pair<int, int>> pr1,pr2;
//init函数初始化powP函数
void init(int len){
    powP[0]=1;
    for(int i=1;i<=len;i++){
        powP[i]=(powP[i-1]*P)%MOD;
    }
}
//calH函数计算字符串str的hash值
void calH(LL H[],string &str){
    H[0]=str[0];
    for(int i=1;i<str.length();i++){
        H[i]=(H[i-1]*P+str[i])%MOD;
    }
}

//calSingleSubH计算H[i..j]
int calSingleSubH(LL H[],int i,int j){
    if(i==0) return H[j];
    return ((H[j]-H[i-1]*powP[j-i+1])%MOD+MOD)%MOD;
}

//对称点为i,字符串长为len,在[l,r]里二分回文半径
//寻找最后一个满足条件“hashL=hashR"的回文半径
//等价于寻找一个满足条件“hashL!=hashR”的回文半径,然后减1即可
//isEven当求奇回文时,为0,求偶回文时为1
int binarySearch(int l,int r,int len,int i,int isEven){
    while(l<r){ //当出现l==r时结束
        int mid=(l+r)/2;
        //左半子串hash值H1[H1L..H1R],右半子串hash值H2[H2L..H2R]
        int H1L=i-mid+isEven,H1R=i;
        int H2L=len-1-(i+mid),H2R=len-1-(i+isEven);
        int hasL=calSingleSubH(H1, H1L, H1R);
        int hasR=calSingleSubH(H2, H2L, H2R);
        if(hasL!=hasR) r=mid; //hash值不等,说明回文半径<mid
        else l=mid+1; //hash值相等,说明回文半径>mid
    }
    return l-1; //返回最大回文半径
}
int main(){
    string str;
    getline(cin,str);
    init(str.length()); //初始化powP
    calH(H1, str);
    reverse(str.begin(), str.end()); //反转字符串
    calH(H2, str);
    int ans=0;
    //奇回文
    for(int i=0;i<str.length();i++){
        //二分上届为分界点i的左右长度的较小值加1
        int maxLen=min(i,(int)str.length()-1-i)+1; //分界点i的回文串的半径长度,最多为一半
        int k=binarySearch(0, maxLen, str.length(), i, 0);
        ans=max(ans,k*2+1);
    }
    
    //偶回文
    for(int i=0;i<str.length();i++){
        //二分上届为分界点i的左右长度的较小值加1(注意左长为i+1)
        int maxLen=min(i+1,(int)str.length()-1-i)+1;
        int k=binarySearch(0, maxLen, str.length(), i, 1);
        ans=max(ans,k*2);
        
    }
    cout<<ans<<'\n';
    return 0;
}


KMP算法

时间复杂度为O(m+n)

next数组
  • next[i]表示使子串s[0…i]的前缀s[0…k]等于后缀s[i-k…i]的最大值k
  • next[i]就是所求最长相等前后缀中前缀最后一位的下标
  • 前后缀均不是s[0…i]本身 即s[0…k]!=s[0…i] , 故next[0]=-1一定成立

next数组的求解过程:

  1. 初始化next数组,令j=next[0]=-1
  2. 让i在1~len-1的范围遍历,对每个i,执行3、4,以求解next[i]
  3. 不断令j=next[j], 直到j回退为-1,或是s[i]=s[j+1]成立
  4. 如果s[i]=s[j+1],则next[i]=j+1;否则next[i]=j
//getNext求解长度为len的字符串s的next数组
void getNext(char s[],int len){
  int j=-1;
  next[0]=-1; //初始化next数组,令j=next[0]=-1
  for(int i=1;i<len;i++){  //求解next[1]~next[len-1]
    while(j!=-1 && s[i]!=s[j+1]){
      j=next[j]; //不断令j=next[j], 直到j回退为-1,或是s[i]=s[j+1]成立
    }
    if(s[i]==s[j+1]){
       j++; //则next[i]=j+1,先令j指向这个位置
    }
      next[i]=j;  
  }
}
KMP算法

​ 此处定义一个文本串text和一个模式串pattern,然后判断模式串patterm是否是文本串text的子串,令i指向text的当前欲比较位,令j指向pattern中当前已被匹配的最后位,这样只要text[i]==pattern[j+1]成立,就说明pattern[j+1]也被成功匹配,此时让i,j加1以继续比较,直到j达到m-1时说明pattern是text的子串(m为模式串pattern的长度)

  • next数组的含义就是当j+1位失配时,j应该回退到的位置

KMP算法的一般思路

  1. 初始化j=-1,表示pattern当前已被匹配的最后位
  2. 让i遍历文本串text, 对每个i,执行3、4来试图匹配text[i]和pattern[j+1]
  3. 不断令j=next[j], 直到j回退到-1,或是text[i]=pattern[j+1]成立
  4. 如果text[i]=pattern[j+1],则令j++。如果j达到m-1,说明pattern是text子串,返回true
//KMP算法,判断pattern是否是text的子串
bool KMP(char text[],char pattern[]){
  int n=strlen(text),m=strlen(pattern); //字符串长度
  getNext(pattern,m); //计算pattern的next数组
  int j=-1;
  for(int i=0;i<n;i++){ //试图匹配text[i]
    while(j!=-1 && text[i]!=pattern[j+1]){
      j=next[j];  //不断令j=next[j], 直到j回退到-1,或是text[i]=pattern[j+1]成立
    }
    if(text[i]==pattern[j+1]){
      j++;
    }
    if(j==m-1){
      return true;
    }
  }
  return false;
}
------------------------------------------------
/*如何统计文本串text中模式串pattern出现的次数?

当j=m-1时表示pattern的一次成功完全匹配,此时令记录成功匹配次数加1,但问题在于从模式串哪个位置开始进行下一次匹配?    next[j]

next[j]代表着整个模式串pattern的最长相等前后缀,从这个位置可以让j最大,即让成功匹配的部分最长,能保证不漏解

*/
  
//KMP算法,判断pattern在text中出现的次数
int KMP(char text[],char pattern[]){
  int n=strlen(text),m=strlen(pattern); //字符串长度
  getNext(pattern,m); //计算pattern的next数组
  int j=-1;
  int ans=0;
  for(int i=0;i<n;i++){ //试图匹配text[i]
    while(j!=-1 && text[i]!=pattern[j+1]){
      j=next[j];  //不断令j=next[j], 直到j回退到-1,或是text[i]=pattern[j+1]成立
    }
    if(text[i]==pattern[j+1]){
      j++;
    }
    if(j==m-1){
      ans++;
      j=next[j]; //j回退到next[j]继续匹配
    }
  }
  return ans;
}

十三章

分块思想
实时查询序列元素第K大,即把序列元素从小到大排序后从左到右的第K个元素
  • 把有序元素划分为若干块。除最后一块外,其余每块中的元素个数都应当为(根号N-(向下取整)),块数为(根号N-(向上取整))
  • 一个统计数组block[317],其中block[i]表示第i块中的存在的元素个数
  • 一个hash数组table[100010],其中table[x]表示整数x的当前存在个数
--PAT1057----

#include<iostream>
#include <string>
#include <stack>
using namespace std;
const int maxn=100010;
const int sqrN=316; //sqrt(100010),表示块内元素个数

stack<int> st;
int block[sqrN+1]; //记录每一块中的元素个数
int table[maxn]; //hash数组,记录当前元素存在个数

void peekMedian(int K){
    int sum=0;
    int id=0;
    while(sum+block[id]<K){
        sum=sum+block[id++];
    }
    int num=id*sqrN;
    while(sum+table[num]<K){
        sum=sum+table[num++];
    }
    cout<<num<<'\n';
}

void Push(int x){
    st.push(x);
    block[x/sqrN]++;
    table[x]++;
}

void Pop(){
    int x=st.top();
    st.pop();
    block[x/sqrN]--;
    table[x]--;
    cout<<x<<'\n';
}

int main(){
    int x,query;
    memset(block, 0, sizeof(block));
    memset(table, 0, sizeof(table));
    char cmd[20];
    cin>>query;
    for(int i=0;i<query;i++){
        cin>>cmd;
        if(strcmp(cmd, "Push")==0){
            cin>>x;
            Push(x);
        }else if(strcmp(cmd, "Pop")==0){
            if(st.empty()==true){
                cout<<"Invalid\n";
            }else{
                Pop();
            }
        }else{
            if(st.empty()==true){
                cout<<"Invalid\n";
            }else{
                int k=st.size();
                if(k%2==1) k=(k+1)/2;
                else k=k/2;
                peekMedian(k);
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值