目录
- [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];
}
};