【算法札记】练习 | Week3

目录

  • [37. 牛牛冲钻五(模拟)​](#37. 牛牛冲钻五(模拟))
  • [38. 最长无重复子数组(滑动窗口)​](#38. 最长无重复子数组(滑动窗口))
  • [39. 重排字符串(贪心 + 构造)​](#39. 重排字符串(贪心 + 构造))
  • [40. 乒乓球筐(哈希)](#40. 乒乓球筐(哈希))
  • [41. 组队竞赛(贪心)](#41. 组队竞赛(贪心))
  • [42. 删除相邻数字的最大分数(动态规划 - 线性 dp)](#42. 删除相邻数字的最大分数(动态规划 - 线性 dp))
  • [43. 平方数(数学)](#43. 平方数(数学))
  • [44. 分组(枚举 + 二分)](#44. 分组(枚举 + 二分))
  • [45. 拓扑排序(拓扑排序)​](#45. 拓扑排序(拓扑排序))
  • [46. 字符串替换(模拟)](#46. 字符串替换(模拟))
  • [47. 神奇数(数学)​](#47. 神奇数(数学))
  • [48. DNA 序列(滑动窗口)​](#48. DNA 序列(滑动窗口))
  • [49. 小乐乐改数字(模拟)](#49. 小乐乐改数字(模拟))
  • [50. 十字爆破(预处理 + 模拟)](#50. 十字爆破(预处理 + 模拟))
  • [51. 比那名居的桃子(滑动窗口)​](#51. 比那名居的桃子(滑动窗口))
  • [52. 压缩字符串(一)(字符串 + 模拟)](#52. 压缩字符串(一)(字符串 + 模拟))
  • [53. chika和蜜柑(排序 / topK)](#53. chika和蜜柑(排序 / topK))
  • [54. 01 背包(动态规划 - 01背包)​](#54. 01 背包(动态规划 - 01背包))

37. 牛牛冲钻五(模拟)​

https://ac.nowcoder.com/acm/problem/227309

简单模拟题目

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        int n, k;
        cin >> n >> k;
        string s;
        cin >> s;
        int num = 0;
        int win = 0;
        for(char ch : s)
        {
            if(ch == 'L')
            {
                num--;
                win = 0;
            }
            if(ch == 'W')
            {
                win++;
                if(win >= 3)
                {
                    num += k;
                }
                else
                {
                    num++;
                }
            }
        }
        cout << num << endl;
    }
    return 0;
}

38. 最长无重复子数组(滑动窗口)​

https://www.nowcoder.com/practice/b56799ebfd684fb394bd315e89324fb4?tpId=196&tqId=37149&ru=/exam/oj

简单滑动窗口题目

cpp 复制代码
class Solution {
  public:
    int maxLength(vector<int>& arr) {
        int ret = 1;
        unordered_map<int, int> hash;
        for (int l = 0, r = 0; r < arr.size(); r++) {
            hash[arr[r]]++;
            while (hash[arr[r]] > 1) {
                hash[arr[l]]--;
                l++;
            }
            ret = max(ret, r - l + 1);
        }
        return ret;
    }
};

39. 重排字符串(贪心 + 构造)​

https://ac.nowcoder.com/acm/problem/222104

贪心,优先使用最多的字符,隔一个位置放一个。如果最多的字符数量超过了总数量的一半,就无法重排。

cpp 复制代码
#include <iostream>
#include <queue>
#include <string>
#include <vector>
#include <queue>
using namespace std;
int main()
{
    int n;
    cin >> n;
    vector<int> hash(26, 0);
    for(int i = 0; i < n; i++)
    {
        char ch;
        cin >> ch;
        hash[ch-'a']++;
    }
    using PCI = pair<char, int>;
    struct Com
    {
        bool operator()(PCI& p1, PCI& p2)
        {
            return p1.second < p2.second;
        }
    };
    priority_queue<PCI, vector<PCI>, Com> pq;
    for(int i = 0; i < 26; i++)
    {
        if(hash[i])
        {
            pq.push({'a' + i, hash[i]});
        }
    }
    
    if(pq.top().second - (n - pq.top().second) > 1)
    {
        cout << "no" << endl;
    }
    else
    {
        string ans;
        ans.resize(n);
        int curi = 0;
        while(!pq.empty())
        {
            PCI p = pq.top();
            pq.pop();
            for(int i = 0; i < p.second; i++)
            {
                ans[curi] = p.first;
                curi += 2;
                if(curi >= n) curi = 1;
            }
        }
        cout << "yes" << endl;
        cout << ans << endl;
    }
    return 0;
}

40. 乒乓球筐(哈希)

https://www.nowcoder.com/questionTerminal/bb4f1a23dbb84fd7b77be1fbe9eaaf32

简单的哈希

cpp 复制代码
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int main() {
    string s1, s2;
    while (cin >> s1 >> s2) {
        int flag = 0;
        int hash[26] = {0};
        memset(hash, 0, sizeof hash);
        for (char ch : s1) {
            hash[ch - 'A']++;
        }
        for (char ch : s2) {
            if (hash[ch - 'A'] > 0) {
                hash[ch - 'A']--;
            } else {
                flag = 1;
                cout << "No" << endl;
                break;
            }
        }
        if (flag == 0)
            cout << "Yes" << endl;
    }
    return 0;
}

41. 组队竞赛(贪心)

https://www.nowcoder.com/questionTerminal/6736cc3ffd1444a4a0057dee89be789b

贪心,最高分拿不到,只能退而求其次拿到倒数第二个人的分数。

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
    int n;
    cin >> n;
    vector<int> v(3 * n);
    for (int i = 0; i < 3 * n; i++) {
        cin >> v[i];
    }
    sort(v.begin(), v.end());
    long long sum = 0;
    for (int i = n; i < 3 * n; i += 2) {
        sum += v[i];
    }
    cout << sum << endl;
    return 0;
}

42. 删除相邻数字的最大分数(动态规划 - 线性 dp)

https://www.nowcoder.com/practice/3bcf72c738b6494bbe1ebe0ffde56152?tpId=230&tqId=40419&ru=/exam/oj

动态规划里的打家劫舍题型

cpp 复制代码
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
int main() 
{
    int n;
    cin >> n;
    int hash[10001] = {0};
    int maxnum = 0;
    memset(hash, 0, sizeof(hash));
    for (int i = 0; i < n; i++) 
    {
        int num;
        cin >> num;
        hash[num]++;
        maxnum = max(num, maxnum);
    }

    vector<vector<int>> dp(maxnum + 1, vector<int>(2, 0));
    // dp[i][0] 记录到数字i且i不算的最大值,dp[i][1] 记录到数字i且i算上的最大值
    for (int i = 1; i <= maxnum; i++) 
    {
        dp[i][0] = max(dp[i-1][0], dp[i-1][1]);
        dp[i][1] = dp[i-1][0] + hash[i] * i;
    }
    cout << max(dp[maxnum][0], dp[maxnum][1]) << endl;
    return 0;
}

43. 平方数(数学)

https://ac.nowcoder.com/acm/problem/205350

​判断一个数开根号之后左右两个数的平方,哪个最近即可。

cpp 复制代码
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
    long long x;
    cin >> x;
    long long l = sqrt(x);
    long long n1 = l*l, n2 = (l+1)*(l+1);
    long long ret = (n2-x > x-n1)? n1: n2;
    cout << ret << endl;
    return 0;
}

44. 分组(枚举 + 二分)

https://ac.nowcoder.com/acm/problem/229023

暴力枚举每个组最多的人数的情况,找出满足组数满足条件的情况。

cpp 复制代码
#include <iostream>
#include <unordered_map>
using namespace std;
int n, m;
unordered_map<int, int> cnt; // 统计每种声部的人数

bool check(int x) // 判断最多人数为 x 时,能否分成 m 组
{
    int g = 0; // 能分成多少组
    for(auto& [a, b] : cnt)
    {
        g += b / x + (b % x == 0 ? 0 : 1);
    }
    return g <= m;
}

int main()
{
    cin >> n >> m;
    int hmax = 0; // 统计声部最多的人数
    for(int i = 0; i < n; i++)
    {
        int x;
        cin >> x;
        hmax = max(hmax, ++cnt[x]);
    }
    
    int kinds = cnt.size();
    if(kinds > m)
    {
        cout << -1 << endl;
    }
    else
    {
        for(int i = 1; i <= hmax; i++)
        {
            if(check(i))
            {
                cout << i << endl;
                break;
            }
        }
    }
    return 0;
}

45. 拓扑排序(拓扑排序)​

https://www.nowcoder.com/practice/88f7e156ca7d43a1a535f619cd3f495c?tpId=308&tqId=40470&ru=/exam/oj

拓扑排序题型步骤:

  • 建图;
  • 入队为 0 的点入队;
  • 来一次层序遍历。
cpp 复制代码
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int main()
{
    int n, m;
    cin >> n >> m;
    vector<vector<int>> edges(n+1);
    vector<int> in(n+1, 0);
    for(int i = 0; i < m; i++)
    {
        int x1, x2;
        cin >> x1 >> x2;
        edges[x1].push_back(x2);
        in[x2]++;
    }

    queue<int> q;
    for(int i = 1; i <= n; i++)
    {
        if(in[i] == 0)
        { 
            q.push(i);
        }
    }
    vector<int> v;
    while (!q.empty()) 
    {
        int x = q.front();
        q.pop();
        v.push_back(x);
        for(int x2 : edges[x])
        {
            in[x2]--;
            if(in[x2] == 0)
            {
                q.push(x2);
            }
        }
    }

    if(v.size() == n)
    {
        for(int i = 0; i < n; i++)
        {
            cout << v[i];
            if(i != n-1)
            {
                cout << ' ';
            }
        }
    }
    else 
    {
        cout << -1;
    }
    return 0;
}

46. 字符串替换(模拟)

https://www.nowcoder.com/practice/f094aed769d84cf3b799033c82fc1bf6?tpId=182&tqId=34710&ru=/exam/oj

简单的模拟

cpp 复制代码
class StringFormat {
public:
    string formatString(string A, int n, vector<char> arg, int m) {
        string ret;
        int i = 0;
        int j = 0;
        while(i < n)
        {
            if(A[i] == '%')
            {
                ret += arg[j];
                j++;
                i += 2;
            }
            else 
            {
                ret += A[i];
                i++;
            }
        }
        while (j < m) 
        {
            ret += arg[j++];
        }
        return ret;
    }
};

47. 神奇数(数学)​

https://www.nowcoder.com/questionTerminal/99fa7be28d5f4a9d9aa3c98a6a5b559a

根据题意模拟

cpp 复制代码
#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;
 
int ans;
 
void check(long long n, unordered_set<int>& hash)
{
    if(n <= 10)
    {
        return;
    }
    if(hash.count(n))
    {
        ans++;
        return;
    }
    vector<int> num;
    int tmp = n;
    while (tmp)
    {
        if (tmp % 10)
            num.push_back(tmp % 10);
        tmp /= 10;
    }
    for (int i = 0; i < num.size() - 1; i++)
    {
        for (int j = i + 1; j < num.size(); j++)
        {
            int n1 = num[i] * 10 + num[j];
            int n2 = num[j] * 10 + num[i];
            if (hash.count(n1) || hash.count(n2))
            {
                ans++;
                return;
            }
        }
    }
    return;
}
 
 
int main()
{
    int a, b;
    cin >> a >> b;
    ans = 0;
    unordered_set<int> hash = {11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};
 
    for (int n = a; n <= b; n++)
    {
        check(n, hash);
 
    }
 
    cout << ans << endl;
    return 0;
}

48. DNA 序列(滑动窗口)​

https://www.nowcoder.com/practice/e8480ed7501640709354db1cc4ffd42a?tpId=37&tqId=21286&ru=/exam/oj

固定长度的滑动窗口

cpp 复制代码
#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

int main()
{
    string str;
    int n;
    cin >> str >> n;

    int begin = 0;
    int cg = 0;
    int cur = 0;
    while(cur < n)
    {
        if(str[cur] == 'C' || str[cur] == 'G')
        {
            cg++;
        }
        cur++;
    }

    int left = 0;
    int tmp = cg;
    int pos = 0;
    while(cur < str.size())
    {
        if(str[left] == 'C' || str[left] == 'G')
        {
            tmp--;
        }
        left++;
        if(str[cur] == 'C' || str[cur] == 'G')
        {
            tmp++;
        }
        cur++;      

        if(tmp > cg)
        {
            cg = tmp;
            pos = left;
        }  
    }
    cout << str.substr(pos, n) << endl;
    return 0;
}

49. 小乐乐改数字(模拟)

https://www.nowcoder.com/practice/fcd30aac9c4f4028b23919a0c649824d?tpId=290&tqId=39833&ru=/exam/oj

读取时直接按照字符串方式读,更方便

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

int main()
{
    string s;
    cin >> s;
    for(int i = 0; i < s.size(); i++)
    {
        if(s[i] % 2 == 0)
        {
            s[i] = '0';
        }
        else 
        {
            s[i] = '1';
        }
    }
    cout << stoi(s) << endl; // stoi会自动处理前导零
    return 0;
}

50. 十字爆破(预处理 + 模拟)

https://ac.nowcoder.com/acm/problem/205836

简单模拟,先把每一行每一列之和存起来

cpp 复制代码
#include <iostream>
#include <cstdio>
#include <vector>
 
using namespace std;
 
int main()
{
    int n, m;
    cin >> n >> m;
    vector<vector<long long>> nums(n, vector<long long>(m));
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < m; j++)
        {
            scanf("%lld", &nums[i][j]);
        }
    }
    vector<long long> row(n, 0), col(m, 0);
    // row[i]为第i行之和, col[j]为第j列之和
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < m; j++)
        {
            row[i] += nums[i][j];
            col[j] += nums[i][j];
        }
    }
     
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < m; j++)
        {
            printf("%lld ", row[i] + col[j] - nums[i][j]);
        }
        printf("\n");
    }
 
    return 0;
}

51. 比那名居的桃子(滑动窗口)​

https://ac.nowcoder.com/acm/problem/224679

滑动窗口思想

cpp 复制代码
#include <vector>
#include <iostream>
using namespace std;
 
int main()
{
    int n, k;
    cin >> n >> k;
    vector<int> happy(n);
    for(int i = 0; i < n; i++)
    {
        cin >> happy[i];
    }
    vector<int> shame(n);
    for(int i = 0; i < n; i++)
    {
        cin >> shame[i];
    }
 
    int l = 0, r = 0;
    int ansday = 0;
    long long curhappy = 0, curshame = 0;
    while(r < n && r < k)
    {
        curhappy += happy[r];
        curshame += shame[r];
        r++;
    }
    long long maxhappy = curhappy, minshame = curshame;
    while(r < n)
    {
        curhappy -= happy[l];
        curshame -= shame[l];
        curhappy += happy[r];
        curshame += shame[r];
        l++;
        r++;
        if(curhappy >= maxhappy)
        {
            if(curhappy > maxhappy)
            {
                maxhappy = curhappy;
                minshame = curshame;
                ansday = l;
            }
            else
            {
                if(curshame < minshame)
                {
                    ansday = l;
                    minshame = curshame;
                }
            }
        }
    }
    cout << ansday + 1 << endl;
    return 0;
}

52. 压缩字符串(一)(字符串 + 模拟)

https://www.nowcoder.com/practice/c43a0d72d29941c1b65c857d8ac9047e?tpId=196&tqId=39317&ru=/exam/oj

利用双指针模拟即可

cpp 复制代码
class Solution {
public:
    string compressString(string param)
    {
        string ret;
        int l = 0, r = 0;
        while(l < param.size())
        {
            if(param[r] == param[l])
            {
                r++;
            }
            else if(r >= param.size() || param[r] != param[l])
            {
                ret += param[l];
                if(r-l > 1) ret += to_string(r-l);
                l = r;
            }
        }
        return ret;
    }
};

53. chika和蜜柑(排序 / topK)

https://ac.nowcoder.com/acm/problem/26221

将每个橘子按照甜度由高到低排序,相同甜度的橘子按照酸度由低到高排序。吃前k个橘子即可。

cpp 复制代码
#include <climits>
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
 
using namespace std;
int n, k;

int main()
{
    cin >> n >> k;
    vector<int> sweet(n);
    vector<int> sour(n);
    for(int i = 0; i < n; i++)
    {
        cin >> sour[i];
    }
    for(int i = 0; i < n; i++)
    {
        cin >> sweet[i];
    }
    struct Com
    {
        bool operator()(pair<int, int>& p1, pair<int, int>& p2)
        {
            if(p1.first > p2.first)
            {
                return false;
            }
            else if(p1.first == p2.first)
            {
                return p1.second > p2.second;
            }
            else
            {
                return true;
            }
        }
    };
    priority_queue<pair<int, int>, vector<pair<int, int>>, Com> pq;
    for(int i = 0; i < n; i++)
    {
        pq.push({sweet[i], sour[i]});
    }
    long long anssweet = 0, anssour = 0;
    for(int i = 0; i < k; i++)
    {
        auto [a, b] = pq.top();
        pq.pop();
        anssweet += a;
        anssour += b;
    }
 
    cout << anssour << ' ' << anssweet << endl;
 
    return 0;
}

54. 01 背包(动态规划 - 01背包)​

https://www.nowcoder.com/practice/2820ea076d144b30806e72de5e5d4bbf?tpId=196&tqId=37561&ru=/exam/oj

动态规划中的背包问题

cpp 复制代码
class Solution {
    int dp[1010] = { 0 };
  public:
    int knapsack(int V, int n, vector<vector<int> >& vw) {
        for (int i = 0; i < n; i++) {
            for (int j = V; j >= vw[i][0]; j--) {
                dp[j] = max(dp[j], dp[j - vw[i][0]] + vw[i][1]);
            }
        }
        return dp[V];
    }
};
相关推荐
HackTwoHub2 小时前
网络设备基线检查AI工具、内置专业基线库批量配置合规检测、自动生成安全整改报告
人工智能·安全·web安全·网络安全·系统安全·安全架构
147API2 小时前
GPT 上线指标怎么设计:采纳率、错误率和调用成本
人工智能·gpt
沪漂阿龙2 小时前
面试题:循环神经网络(RNN)是什么?词嵌入、时序建模、梯度消失、LSTM/GRU 一文讲透
人工智能·rnn·深度学习·gru·lstm
计算机安禾2 小时前
【c++面向对象编程】第13篇:继承(三):同名隐藏与作用域覆盖
开发语言·c++·iphone
wanhengidc2 小时前
服务器机柜的功能是什么
运维·服务器·网络
恋猫de小郭2 小时前
2026 Android I/O ,全新 AI 手机、 Android PC 和自动驾驶
android·人工智能·智能手机
学海星球2 小时前
CLI-Anything:一条命令把任意软件变成 AI Agent 原生工具
人工智能
小明同学012 小时前
计算机网络编程———手写 TCP 服务器(一)搞懂网络编程核心 API
服务器·网络·计算机网络
keyipatience2 小时前
Linux进程调度与优先级机制解析
linux·运维·服务器