牛客春招刷题训练营 - 3.21题解 | C++

活动地址: 牛客春招刷题训练营 - 编程打卡活动

简单题:字符串加密

【模拟】【set】

“去重”一般使用STL的set比较方便,出现过了就插入集合。

然后按照题目要求模拟即可。

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

int main() {
    string s, t;
    cin >> s >> t;
    string p = "";
    set<char> vis;
    for(char c: s) {
        if(vis.count(c)) continue;
        vis.insert(c);
        p += c;
    }
    for(char c='a'; c<='z'; c++) {
        if(!vis.count(c)) {
            p += c;
        }
    }
    for(char c: t) {
        cout << p[c-'a'];
    }
    return 0;
}

中等题:从单向链表中删除指定值的节点

【链表】

链表模版题,其实虽然我个人写链表都是直接上来就写双向链表,因为双向的功能比单向要全面。

不过这道题的标题里就要求用“单向链表”,那就讲一下单向链表的做法。

首先观察到这道题插入数值的范围是1e4,那就不需要离散化了,直接开个1e4的数组就好。

然后因为考虑到题给的头结点h也是可能被删除的,所以为了方便起见,我手动引入了一个头结点,值为0(肯定不会和插入的节点重复)。最后按普遍习惯,把-1作尾结点。

然后其实就是比较基础的单向链表的模板,就不赘述了。不熟悉的小伙伴请自行去补充知识点。

#include <iostream>
#include <vector>
using namespace std;
const int N = 1e4+5;
int nxt[N];
int main() {
    int n;
    cin >> n;
    int h;
    cin >> h;
    nxt[0] = h;
    nxt[h] = -1;
    for(int i=1; i<n; i++) {
        int a, b;
        cin >> a >> b;
        nxt[a] = nxt[b];
        nxt[b] = a;
    }
    int k;
    cin >> k;
    for(int i=0; i!=-1; i=nxt[i]) {
        if(nxt[i] == k) {
            nxt[i] = nxt[k];
            break;
        }
    }
    for(int i=0; i!=-1; i=nxt[i]) {
        if(i != 0) cout << i << " ";
    }
    return 0;
}

困难题:走方格的方案数

【dp】【组合数学】

这道题一看数据范围只有8,有点离谱。

那应该瞎搞都能暴力做出来。不过这其实是比较典的题,也算是dp经典过河卒模型的基础版。

先来dp写一下吧,复杂度是O(N^2)。

状态转移为:一个点的方案始终等于到上一个点的可能方案之和。由于只能向下或者向右,所以一个点(i, j)的上一个点要么是(i-1, j),(i, j-1),所以dp[i][j] = dp[i][j-1] + dp[i-1][j];。

#include <iostream>
#include <vector>
using namespace std;
int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> dp(n+5, vector<int>(m+5));
    for(int i=0; i<=n; i++) {
        dp[i][0] = 1;
    }
    for(int j=0; j<=m; j++) {
        dp[0][j] = 1;
    }
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=m; j++) {
            dp[i][j] = dp[i][j-1] + dp[i-1][j];
        }
    }
    cout << dp[n][m] << endl;
    return 0;
}

不过这道题最优解是O(N)的做法,也是一个比较典的思想。

不难想到,从起点走到终点一定是n次向下+m次向右。

不妨将其转化为一个模型:n个0和m个1组成01序列有多少种组合方法。每种01序列其实就对应着唯一一条路径。

而对于“n个0和m个1组成01序列有多少种组合方法”的解其实就是C(n+m, n)或者C(n+m, m)。所以组合数公式套一下就行了。

fac[i]表示i的阶乘,因为i最大可能到16,所以要开long long。

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

int main() {
    int n, m;
    cin >> n >> m;
    vector<long long> fac(n+m+1);
    fac[0] = 1;
    for(int i=1; i<=n+m; i++)
        fac[i] = fac[i-1] * i;
    // C(n+m, n)
    cout << fac[n+m]/(fac[n]*fac[m]) << endl;
    return 0;
}

#牛客春招刷题训练营#
全部评论

相关推荐

Cherrycola01:0实习 0项目 约等于啥也没有啊 哥们儿这简历认真的吗
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务