牛客竞赛每日俩题 - Day4

这篇博客涵盖了三种不同的算法应用。首先介绍了使用模拟和辗转相除法解决能力值累加问题,通过不断求最大公约数实现。接着,讲解了动态规划(DP)在分析字符串编辑距离问题中的应用,利用状态转移方程计算Levenshtein距离。最后,讨论了两种方法找出字符串中只出现一次的字符,包括线性时间和平方时间复杂度的解决方案。这些算法展示了在字符串处理和数学问题上的高效处理技巧。
摘要由CSDN通过智能技术生成

14天阅读挑战赛

目录

模拟+辗转相除法

DP作图分析状态方程

找到只出现一次的字符:


模拟+辗转相除法

小易的升级之路_牛客题霸_牛客网

 思路:

本题的能力值的累加分两种情况,一种是直接相加 bi, 一种是累加当前能力值于 bi 的最大公约数。最大公约数可以通过碾转相除法求得: a b 的最大公约数相当于 b a,b 余数的最大公约数。如果求余结果为 0 , 则 b 为所 求结果

辗转相除法

int gcd(int a,int b)
{
    int c;
    while(c=a%b){
        a=b;
        b=c;
    }
    return b;
}
#include <iostream>
#include<vector>
using namespace std;

int gcd(int a,int b)
{
    int c;
    while(c=a%b){
        a=b;
        b=c;
    }
    return b;
}

int getpw(int n,int power)
{
    vector<int> num(n);
    for(int i=0;i<n;i++)
        cin>>num[i];
    for(int i=0;i<n;i++)
    {
        if(power>=num[i]) power+=num[i];
        else power+=gcd(power,num[i]);
    }
    return power;
}

int main() {
    int n,a,power;
    while(cin>>n>>a)
    {
        power=getpw(n,a);
        cout<<power<<endl;
    }
    return 0;
}

DP作图分析状态方程

计算字符串的编辑距离_牛客题霸_牛客网

 思路:

传递公式

  1. lev[i][j]用来表示字符串a的[1...i]和字符串b[1...j]的levenshtein距离;
  2. 插入和删除操作互为逆过程:a删除指定字符变b等同于b插入指定字符变a;
  3. 如果a[i] == b[j],则说明a[i]和b[j]分别加入a,b之后不会影响levenshtein距离,lev[i][j] = lev[i-1][j-1] + 0;
  4. 如果a[i] != b[j],则需要考虑3种情况的可能:
    1. a中插入字符,即lev[i][j] = lev[i-1][j] + 1;
    2. b中插入字符,即lev[i][j] = lev[i][j-1] + 1;
    3. a[i]替换成b[j],lev[i][j] = lev[i-1][j-1] + 1;
  5. 取这4种情况的最小值。

 

  • 若两个字符相等,即str1[i-1] == str2[j-1],则在这一个位置的编辑距离和上一个字符相同,因此对应的数组dp[i][j]=dp[i-1][j-1];
  • 若两个字符不相等,可删除str1[i-1]这个字符,则dp[i][j] = 1 + dp[i-1][j];删除str2[j-1]这个字符,则dp[i][j] = 1 + dp[i][j-1];修改str1[i-1]使它与str2[i-1]相等,则dp[i][j] = 1 + dp[i-1][j-1]。

 

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

int mind(const string &s1,const string &s2)
{
    if(s1.empty()||s2.empty()) 
        return max(s1.size(),s2.size());
    int len1=s1.size();
    int len2=s2.size();
    vector<vector<int>> f(len1+1,vector<int>(len2+1,0));

    for(int i=0;i<=len1;i++) f[i][0]=i;//初始化距离
    for(int j=0;j<=len2;j++) f[0][j]=j;//表示当另一个字符串为空时,该串的距离

    for(int i=1;i<=len1;i++) 
        for(int j=1;j<=len2;j++)
        {    
            // 判断word1的第i个字符是否与word2的第j个字符相等
            if(s1[i-1]==s2[j-1])
            {
                //相同,距离不需要增加
                f[i][j]=f[i-1][j-1];
            }
            else
            {
                int x=1+min(f[i-1][j],f[i][j-1]);
                //字符不同,需要增删替换,距离+1
                f[i][j]=min(x,1+f[i-1][j-1]);
            }
        }
        return f[len1][len2];
}

int main() {
    string s1,s2;
    while(cin>>s1>>s2)
        cout<<mind(s1,s2)<<endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

找到只出现一次的字符:

时间复杂度O(n^2)

char getFirstOneChar_3(const string& str) {
    for (int i = 0; i < str.size(); ++i) {
        int index1 = str.find(str[i]);
        int index2 = str.rfind(str[i]);
        if (index1 == index2)
            return str[i];
    }
    return -1;
}

O(n)

//hash法 O(n)
char getFirstOneChar_2(const string& str) {
    int hash[256] = {0};
    for (int i = 0; i < str.size(); ++i) //统计字符的次数
        hash[str[i]]++;
    for (int i = 0; i < str.size(); ++i) {
        if (hash[str[i]] == 1)
            return str[i];
    }
    return -1;
}

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小黄同学LL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值