蓝桥杯训练day5

这篇具有很好参考价值的文章主要介绍了蓝桥杯训练day5。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.kmp算法

(1)831. KMP字符串

蓝桥杯训练day5

p是模式串,s是主串

第一步:算出p的最长前后缀,用两个p来求
第二部:算出p在s中的位置,用p和s来求

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=1e6+10;

char s[N],p[N];

int ne[N];


int n,m;


int main()
{
    cin>>n;
    scanf("%s",p+1);
    cin>>m;
    scanf("%s",s+1);
    
    for(int i=2,j=0;i<=n;i++)
    {
        while(j&&p[i]!=p[j+1])j=ne[j];
        if(p[i]==p[j+1])j++;
        ne[i]=j;
    }
    
    for(int i=1,j=0;i<=m;i++)
    {
        while(j&&s[i]!=p[j+1])j=ne[j];
        if(s[i]==p[j+1])j++;
        if(j==n)
        {
            cout<<i-n<<" ";
            j=ne[j];
        }
    }
    
    return 0;
}

2.单调栈

(1)830. 单调栈

蓝桥杯训练day5

单调栈模板题
思路:
整理了一下:
求左边第一个小的数,等价于求右边第一个小的数(将答案倒过来即可),从左往右使用单调递增的栈
求左边第一个大的数,等价于求右边第一个大的数(将答案倒过来即可),从左往右使用单调递减的栈

#include<iostream>
#include<stack>
using namespace std;

const int N=1e5+10;
int a[N];
int ans[N];

stack<int>st;

int n;

int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>a[i];
        
    for(int i=0;i<n;i++)  //保证栈单调递增
    {
        while(!st.empty()&&a[st.top()]>=a[i])st.pop();
        if(st.empty())ans[i]=-1;  //表示第i个元素左边没有比他小的数
        else ans[i]=a[st.top()];
        st.push(i);
    }
    
    for(int i=0;i<n;i++)
        cout<<ans[i]<<" ";
    return 0;
    
}



3.单调队列

(1)154. 滑动窗口

蓝桥杯训练day5

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;


const int N=1e6+10;

int a[N];
deque<int>q;


int n,k;


int main()
{
    cin>>n>>k;
    for(int i=0;i<n;i++)
        cin>>a[i];
    
    for(int i=0;i<n;i++)  //保证递增(从队头到队尾)
    {
        if(!q.empty()&&q.front()<i-k+1)q.pop_front();
        while(!q.empty()&&a[q.back()]>=a[i])q.pop_back();
        q.push_back(i);
        if(i-k+1>=0)
            cout<<a[q.front()]<<" ";
    }
    cout<<endl;
    q.clear();
    for(int i=0;i<n;i++)  //保证递减
    {
        if(!q.empty()&&q.front()<i-k+1)q.pop_front();
        while(!q.empty()&&a[q.back()]<=a[i])q.pop_back();
        q.push_back(i);
        if(i-k+1>=0)
            cout<<a[q.front()]<<" ";
    }
    return 0;
}

(2)135. 最大子序和

蓝桥杯训练day5

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;


const int N=3*1e6+10;

int n,m;

int a[N];
int s[N];

deque<int>q;

int ans;

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>a[i];
        
    for(int i=1;i<=n;i++)
        s[i]=s[i-1]+a[i];
    
    ans=-0x3f3f3f3f;
    q.push_back(0);
    for(int i=1;i<=n;i++)
    {
        if(!q.empty()&&q.front()<i-m)  //为什么是i-m,模拟一下
            q.pop_front();
        if(!q.empty())
            ans=max(ans,s[i]-s[q.front()]);
        while(!q.empty()&&s[q.back()]>=s[i])q.pop_back();
        q.push_back(i);
    }
    cout<<ans;
    return 0;
}

(3)1089. 烽火传递

蓝桥杯训练day5

首先,可以敏锐的发现这是一道动态规划的题目,如果没有察觉,说明题目做少了。

定义:
f [ i ] 表示前 1 到 i − 1 座烽火塔点燃的最小价值 + 第 i 座烽火一定点燃的价值 f[i]表示前1到i-1座烽火塔点燃的最小价值+第i座烽火一定点燃的价值 f[i]表示前1i1座烽火塔点燃的最小价值+i座烽火一定点燃的价值
f [ i ] = m i n ( f [ i − 1 ] , f [ i − 2 ] , f [ i − 3 ] . . . f [ i − m ] ) + v a l u e [ i ] f[i]=min(f[i-1],f[i-2],f[i-3]...f[i-m])+value[i] f[i]=min(f[i1],f[i2],f[i3]...f[im])+value[i]

很明显,每次计算一次f[i],都要找到前面m个f的最小值,这可以想到单调队列维护最值。
那么尝试写一下代码。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=2*1e5+10;

int value[N];
int q[N];
int dp[N];
int n,m;

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>value[i];
        
    int tt=0,hh=0;   //tt是队尾,hh是队头
    dp[0]=0;
    
    for(int i=1;i<=n;i++)  //维护单调队列的递增性,每次都取队头(队列的容量是m)
    {
        if(hh<=tt&&q[hh]<i-m)hh++;  //维护单调队列的队头的范围,不能与i超过m个间隔
        dp[i]=dp[q[hh]]+value[i];
        while(hh<=tt&&dp[i]<dp[q[tt]])tt--;
        q[++tt]=i;
    }
    
    int res=0x3f3f3f3f;
    for(int i=n-m+1;i<=n;i++)  //答案在最后一段找
        res=min(res,dp[i]);
    cout<<res<<endl;
    return  0;
    
}

(4)299. 裁剪序列

蓝桥杯训练day5
国赛难度,暂时不写。

在这里插入代码片

4.trie树(字典树)

(1)835. Trie字符串统计

蓝桥杯训练day5

son[p][u]表示单前单词的下一个单词所在层数.idx++的目的是防止单词重复记录

#include<iostream>
#include<cstring>

using namespace std;

const int N=100010;

int son[N][26];
int idx;
int cnt[N];


int n;

void Insert(string &str)
{
    int p=0;
    for(int i=0;i<str.size();i++)
    {
        int u=str[i]-'a';
        if(son[p][u]==0)son[p][u]=++idx;
        p=son[p][u];
    }
    cnt[p]+=1;
    
}

int find(string &str)
{
    int p=0;
    for(int i=0;i<str.size();i++)
    {
        int u=str[i]-'a';
        if(son[p][u]==0)return 0;
        p=son[p][u];
    }
    return cnt[p];
}

int main()
{
    cin>>n;
    while(n--)
    {
        char op;
        cin>>op;
        string str;
        cin>>str;
        if(op=='I')
        {
            Insert(str);
        }
        else
        {
            cout<<find(str);
            cout<<endl;
        }
       
        
    }
    return 0;
}

(2)143. 最大异或对

蓝桥杯训练day5
首先异或运算的规则是:相同则0,相反则1

#include<iostream>
#include<cstring>
using namespace std;

const int N=1e5+10,M=31*N;

int a[N];
int son[M][2];
int idx;

int n;


void Insert(int x)   //将一个数拆分成二进制,相当于只有两种字符的字符串
{
    int p=0;
    for(int i=30;i>=0;i--)
    {
        int u=x>>i&1;  //表示x的从右往左第i+1位二进制是多少
        if(son[p][u]==0)son[p][u]=++idx;
        p=son[p][u];
    }
    
}

int find(int x)
{
    int p=0;
    int ans=0;
    for(int i=30;i>=0;i--)  //根据异或的规则,相同的为0,相反的为1,从高位到低位,尽量找到1
    {
        int u=x>>i&1;
        if(son[p][!u]==0)//没有1,只能找0了
            p=son[p][u];
        else
        {
            ans+=1<<i;
            p=son[p][!u];
        }
    }
    return ans;
}

int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>a[i];
        
    int ans=0;
    for(int i=0;i<n;i++)
        Insert(a[i]);
        
    for(int i=0;i<n;i++)
        ans=max(ans,find(a[i]));
    
    cout<<ans;
    
    return 0;
    
        
}

(3)3485. 最大异或和

蓝桥杯训练day5文章来源地址https://www.toymoban.com/news/detail-401526.html

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=31*1e5+10;
int son[N][2];
int cnt[N];
int idx;
int sum[N];



int n,m;

void insert(int x,int k)
{
    int p=0;
    for(int i=30;i>=0;i--)
    {
        int u=x>>i&1;
        if(son[p][u]==0)son[p][u]=++idx;
        p=son[p][u];
        cnt[p]+=k;   //每个节点出现的次数
    }
    
}

int find(int x)
{
    int p=0;
    int ans=0;
    for(int i=30;i>=0;i--)
    {
        int u=x>>i&1;
        if(cnt[son[p][!u]])
        {
            ans+=1<<i;
            p=son[p][!u];
        }
        else
        {
            p=son[p][u];
        }
            
    }
    return ans;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        sum[i]=sum[i-1]^x;
    }
    
    insert(sum[0],1);  //将0插入
    
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(i-m-1>=0)insert(sum[i-m-1],-1);  //删除窗口之外的数,一个数异或一个值两次会变成原样
        ans=max(ans,find(sum[i]));
        insert(sum[i],1);
    }
    cout<<ans;
    return 0;
}

到了这里,关于蓝桥杯训练day5的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • LeetCode:459. 重复的子字符串 —【2、KMP算法】

    🍎道阻且长,行则将至。🍓 🌻算法,不如说它是一种思考方式🍀 算法专栏: 👉🏻123 题目描述 :给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。 来源:力扣(LeetCode) 难度: 简单 提示: 1 = s.length = 104 s 由小写英文字母组成 示例 1: 输入:

    2024年02月04日
    浏览(44)
  • 算法训练day11Leetcode20有效的括号1047删除字符串中所有相邻重复项150逆波兰表达式求值

    https://leetcode.cn/problems/valid-parentheses/description/ https://programmercarl.com/0020.%E6%9C%89%E6%95%88%E7%9A%84%E6%8B%AC%E5%8F%B7.html 判断右括号后忘记pop 括号匹配是使用栈解决的经典问题。 如果还记得编译原理的话,编译器在 词法分析的过程中处理括号、花括号等这个符号的逻辑,也是使用了栈

    2024年01月17日
    浏览(50)
  • 【数据结构】字符串匹配|BF算法|KMP算法|next数组的优化

    字符串匹配算法是在实际工程中经常遇到的问题,也是各大公司笔试面试的常考题目,本文主要介绍BF算法(最好想到的算法,也最好实现)和KMP算法(最经典的) BF算法,即暴力(Brute Force)算法,是普通的模式匹配算法,BF算法的思想就是将目标S的第一个字符与模式串T的第一

    2024年02月04日
    浏览(42)
  • 代码随想录 Leetcode459. 重复的子字符串(KMP算法)

            此解法读者需要了解什么是KMP算法以及KMP算法中next数组的具体含义才能理解         因为在KMP算法的next数组中,next[index]表示 i ndex之前的最大长度的相同前缀后缀值 ,那么要判断整个字符串中是否由重复字串构成,只需要以下两个条件:         1.next[n - 1] !=

    2024年01月19日
    浏览(54)
  • C#,字符串匹配(模式搜索)KMP算法的源代码与数据可视化

      D.E.Knuth   J.H.Morris KMP 算法(Knuth-Morris-Pratt 算法)是其中一个著名的、传统的字符串匹配算法,效率比较高。 KMP算法由 D.E.Knuth , J.H.Morris 和 V.R.Pratt 在 Brute-Force 算法的基础上提出的模式匹配的改进算法。因此人们称它为“克努特—莫里斯—普拉特算法”,简称KMP算法。K

    2024年01月25日
    浏览(41)
  • 【蓝桥杯算法题】字符串匹配算法

    这段代码实现了一个过滤字符串中非字母字符的功能,并统计字母个数。 首先,在主函数中,定义一个长度为100的字符数组str,用fgets函数从标准输入获取用户输入的字符串。 然后调用filterLetters函数,利用指针p1和p2遍历字符串中的每个字符,判断是否为字母字符, 若是,则

    2024年02月08日
    浏览(38)
  • 蓝桥杯训练day5

    p是模式串,s是主串 第一步:算出p的最长前后缀,用两个p来求 第二部:算出p在s中的位置,用p和s来求 单调栈模板题 思路: 整理了一下: 求左边第一个小的数,等价于求右边第一个小的数(将答案倒过来即可),从左往右使用单调递增的栈 求左边第一个大的数,等价于求

    2023年04月08日
    浏览(28)
  • KMP-重复子字符串

    Problem: 459. 重复的子字符串 给定一个字符串str1, 判断其是否由重复的子串构成。 例子1:输入 str1=‘ababab’ ;输出 true 例子2:输入 str1=‘ababac’ ;输出 false 重复子字符串组成的字符串,其肯定存在一个后缀和前缀是一样的,并且这个后缀其由后缀前面的字符子串组成。所以

    2024年01月25日
    浏览(36)
  • ACM - 字符串 - 基础(KMP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1711 题目大意 找出子串第一次出现的位置,找不到输出 - 1. next 数组的含义: next [ i ] 表示 :以 i 为终点,以 1 为起点,前后缀能一致的最长字串。 (在某些头文件有命名过next,所以代码里面以 ne 代表next) next [ i ] = x 表示:如果

    2024年02月04日
    浏览(47)
  • 【算法训练-字符串 三】最长公共子串、最长公共子序列

    废话不多说,喊一句号子鼓励自己:程序员永不失业,程序员走向架构!本篇Blog的主题是【】,使用【】这个基本的数据结构来实现,这个高频题的站点是: CodeTop ,筛选条件为: 目标公司+最近一年+出现频率排序 ,由高到低的去 牛客TOP101 去找,只有两个地方都出现过才做

    2024年02月09日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包