每日一练22&&23——小易的升级之路&&找出字符串中第一个只出现一次的字符&&微信红包&&计算字符串的编辑距离(难)


小易的升级之路

题目链接:

思路:

本题的能力值的累加分两种情况,一种是直接相加bi,一种是累加当前能力值于bi的最大公约数。最大公约数可以通过碾转相除法求得:a与b的最大公约数相当于b与a,b余数的最大公约数。如果求余结果为0, 则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 gcd(int a, int ev) {
    int min = a > ev ? ev : a;
    int gcd;
    for (int i = min; i >= 1; i--) {
        if (a % i == 0 && ev % i == 0) {
            gcd = i;
            break;
        }
    }
    return gcd;
}

int main() {
    int n, a;
    while (cin >> n >> a) {
        vector<int> v(n);
        for (int i = 0; i < n; i++) {
            cin >> v[i];
        }
        for (auto ev : v) {
            if (ev <= a) {
                a += ev;
            } else {
                a += gcd(a, ev);
            }
        }
        cout << a << endl;
    }
    return 0;
}

找出字符串中第一个只出现一次的字符

题目链接:

思路:

  • 用一个数组的每一个位置表示对应的位置。对应的字符位置存放字符出现的次数。统计完之后,遍历输入字符,遇到第一个只出现一次的字符就停止。
  • 也可以用一个map来记录字符串中字符出现的次数,然后遍历字符串,直到找到第一个只出现一次的字符为止。

代码:

#include<iostream>
#include<string>
#include<map>
using namespace std;
int main() {
    string str;
    cin >> str;
    map<char, int> countmap;
    for (auto& s : str) {
        countmap[s]++;
    }
    int flag = 1;
    for (auto& s : str) {
        if (countmap[s] == 1) {
            cout << s;
            flag = 0;
            return 0;
        }
    }
    cout << -1;
    return 0;
}

微信红包

题目链接:

思路:

本题两种思路,第一种排序思路,如果一个数出现次数超过一半了,排序过后,必然排在中间,则最后遍历整个数组查看是否符合即可。第二种思路可以用map统计每个数字出现的次数,最后判断有没有超过一半的数字。

代码:

class Gift {
  public:
    int getValue(vector<int> gifts, int n) {
// write code here
        map<int, int> countMap;
        for (auto v : gifts) {
            countMap[v]++;
        }
        int ret = 0;
        for (auto m : countMap) {
            if ((m.second * 2) > n) {
                ret = m.first;
            }
        }
        return ret;
    }
};

计算字符串的编辑距离

题目链接:

思路:

状态:
子状态:word1的前1,2,3,…m个字符转换成word2的前1,2,3,…n个字符需要的编辑距离
F(i,j):word1的前i个字符于word2的前j个字符的编辑距离
状态递推: F(i,j) = min { F(i-1,j)+1, F(i,j-1) +1, F(i-1,j-1) +(w1[i]==w2[j]?0:1) } 上式表示从删除,增加和替换操作中选择一个最小操作数
F(i-1,j): w1[1,…,i-1]于w2[1,…,j]的编辑距离,删除w1[i]的字符—>F(i,j)
F(i,j-1): w1[1,…,i]于w2[1,…,j-1]的编辑距离,增加一个字符—>F(i,j)
F(i-1,j-1): w1[1,…,i-1]于w2[1,…,j-1]的编辑距离,如果w1[i]与w2[j]相同, 不做任何操作,编辑距离不变,如果w1[i]与w2[j]不同,替换w1[i]的字符为w2[j]—>F(i,j)
初始化: 初始化一定要是确定的值,如果这里不加入空串,初始值无法确定 F(i,0) = i :word与空串的编辑距离,删除操作
F(0,i) = i :空串与word的编辑距离,增加操作
返回结果:F(m,n)


其实自己看这些东西也很是头大,那么直接通俗来说解题步骤吧。

  • 先初始化一个二维数组,注意这里行和列都需要多开一个,
    在这里插入图片描述

  • 然后把第0行和0列,依次从0开始往后赋值

在这里插入图片描述

  • 然后根据递推方程,依次计算两个字符串相差的距离,其实对角线的最后一个就是所求结果。
    在这里插入图片描述

代码:

#include<iostream>
#include<string>
#include<vector>

using namespace std;
int main() {
    string str1, str2;
    getline(cin, str1);
    getline(cin, str2);
    int size1 = str1.size();
    int size2 = str2.size();
	//行和列都多开一个空间
    vector<vector<int>> vv(size1 + 1, vector<int>(size2 + 1, 0));

    //s1初始化
    for (int i = 1; i <= size1; i++) {
        vv[i][0] = i;
    }
    //s2初始化
    for (int j = 1; j <= size2; j++) {
        vv[0][j] = j;
    }

    for (int i = 1; i <= size1; i++) {
        for (int j = 1; j <= size2; j++) {
            if (str1[i-1] != str2[j-1]) {
                vv[i][j] = 1 + min(vv[i - 1][j], vv[i][j - 1]);
                vv[i][j] = min(vv[i][j], 1 + vv[i - 1][j - 1]);
            } else {
                vv[i][j] = 1 + min(vv[i - 1][j], vv[i][j - 1]);
                vv[i][j] = min(vv[i][j], vv[i - 1][j - 1]);
            }
        }
    }

    cout<<vv[size1][size2];
    return 0;
}

end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

有效的放假者

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

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

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

打赏作者

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

抵扣说明:

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

余额充值