day1
Q1 难度⭐⭐
小易的升级之路_牛客题霸_牛客网 (nowcoder.com)
题目:
小易经常沉迷于网络游戏.有一次,他在玩一个打怪升级的游戏,他的角色的初始能力值为 a.在接下来的一段时间内,他将会依次遇见n个怪物,每个怪物的防御力为b1,b2,b3...bn. 如果遇到的怪物防御力bi小于等于小易的当前能力值c,那么他就能轻松打败怪物,并 且使得自己的能力值增加bi;如果bi大于c,那他也能打败怪物,但他的能力值只能增加bi 与c的最大公约数.那么问题来了,在一系列的锻炼后,小易的最终能力值为多少?
输入描述:第一行输入两个正整数n和,代表怪物的数量、小易输初始的战斗力。
第二行输入n个正整数a,代表每个怪物的战斗力。,
输出描述:1个正整数,代表小易最终的战斗力。
思路:
遍历判断,辗转相除
#include <cstddef>
#include <iostream>
using namespace std;
int GCD(int a, int b)
{
while(a != 0 && b != 0)
{
int t = b;
b = a % b;
a = t;
}
return a;
}
int main()
{
long long n, x;
cin >> n >> x;
for(int i = 0; i < n; i ++)
{
int t;
cin >> t;
if(t <= x) x += t;
else x += GCD(t, x);
}
cout << x << endl;
return 0;
}
Q2 难度⭐⭐
礼物的最大价值_牛客题霸_牛客网 (nowcoder.com)
题目:
在一个𝑚×𝑛的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
如输入这样的一个二维数组,
[
[1,3,1],
[1,5,1],
[4,2,1]
]
那么路径 1→3→5→2→1 可以拿到最多价值的礼物,价值为12
思路:
动态规划
状态转移方程:dp[x][y] = max(dp[x - 1][y], dp[x][y - 1]) + grid[i][j]
class Solution
{
public:
int maxValue(vector<vector<int> >& grid)
{
int dp[205][205];
dp[1][1] = grid[0][0];
for(int i = 0; i < grid.size(); i ++)
for(int j = 0; j < grid[0].size(); j ++)
{
int x = i + 1, y = j + 1;
dp[x][y] = max(dp[x - 1][y], dp[x][y - 1]) + grid[i][j];
}
return dp[grid.size()][grid[0].size()];
}
};
Q3 难度⭐⭐
对称之美 (nowcoder.com)
题目:
给出n个字符串,从第1个字符串一直到第n个字符串每个串取一个字母来构成一个新字符串,新字符串的第i个字母只能从第i行的字符串中选出,这样就得到了一个新的长度为n的字符串,请问这个字符串是否有可能为回文字符串?
输入描述:第一行一个数字 t,,代表测试数据的组数 每组测试数据先给出一个数字 n,然后接下来n行每行一个只由小写字母组成的字符串 si,,
输出描述:在一行中输出 “Yes” or “No”
思路:
双指针
#include <iostream>
using namespace std;
char s[105][55];
int aba(char a[], char b[])
{
for(int i = 0; a[i]; i ++)
for(int j = 0; b[j]; j ++)
if(a[i] == b[j]) return 1;
return 0;
}
int main()
{
int t;
cin >> t;
while(t --)
{
int n, k = 1;
cin >> n;
for(int i = 1; i <= n; i ++)
cin >> s[i];
int l = 1, r = n;
while(l < r)
{
if(aba(s[l], s[r]) == 0) k = 0;
l ++;
r --;
}
if(!k) cout << "No" << endl;
else cout << "Yes" << endl;
}
return 0;
}
day2
Q1 难度⭐
经此一役小红所向无敌_牛客小白月赛37 (nowcoder.com)
题目:
经过重重困难,对立和光终于来到魔王城,和最终的大魔王——小红进行决战。
已知小红的血量是 。
对立的攻击力是 a ,血量是 h 。
光的攻击力是 b ,血量是 k 。
每回合光先对小红发起攻击,然后对立对小红发起攻击,然后小红展开幻术,令光和对立同时互相攻击。每次攻击后,受击者的血量会减掉攻击者的攻击力。
当光和对立其中一人死亡后,另一人会悲痛欲绝,对小红发出自己攻击力*10的伤害的大招,然后自杀。(若两人同时死亡,则两人都无法发出大招)
小红想知道,弱小的光和对立,她们能对自己造成多少点伤害?
输入描述:一行 4 个正整数 a , h , b , k ,用空格隔开。
输出描述:一个正整数,代表小红受到的伤害。
思路:
计算题
#include <iostream>
using namespace std;
typedef long long LL;
int main()
{
LL a, b, h, k, sum, t1 = 0, t2 = 0;
cin >> a >> h >> b >> k;
t1 = h / b;
t2 = k / a;
if(h % b) t1 ++;
if(k % a) t2 ++;
sum = min(t1, t2) * (a + b);
if(t1 < t2) sum += b * 10;
if(t1 > t2) sum += a * 10;
cout << sum;
return 0;
}
Q2 难度⭐⭐
连续子数组最大和_牛客题霸_牛客网 (nowcoder.com)
题目:
给定一个长度为 𝑛 n 的数组,数组中的数为整数。
请你选择一个非空连续子数组,使该子数组所有数之和尽可能大,子数组最小长度为1。求这个最大值。
思路:
遍历更新最大值(给a先分配空间,不然会段错误)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;
int n;
vector<LL> a;
int main()
{
cin >> n;
a.resize(n); // 预先分配空间
for(int i = 0; i < n; i ++)
cin >> a[i];
LL max_ans = a[0], ans = a[0];
for(int i = 1; i < n; i ++)
{
ans = max(ans + a[i], a[i]);
max_ans = max(ans, max_ans);
}
cout << max_ans << endl;
return 0;
}
Q3 难度⭐⭐⭐
非对称之美 (nowcoder.com)
题目:
给出一个字符串,求最长非回文子字符串的长度
思路1:
暴力解法 O(n^3)-------------超时
#include <iostream>
#include <string>
using namespace std;
string s;
bool aba(const string& s, int start, int end)
{
while (start < end)
{
if (s[start] != s[end]) return false;
start++;
end--;
}
return true;
}
int main()
{
cin >> s;
int n = s.size();
int ans = 0;
for(int i = 0; i < n; i ++)
for(int j = i; j < n; j ++)
if(!aba(s, i, j))
ans = max(ans, j - i + 1);
cout << ans << endl;
return 0;
}
思路2:
先判断字符串是否都是同一字符,再equal函数判断是否回文 O(n)
#include<iostream>
#include<string>
using namespace std;
string s;
bool isSame(string s)
{
return s.find_first_not_of(s[0]) == string::npos;
}
int main()
{
cin >> s;
int n = s.size();
if (isSame(s))
{
cout << 0 << endl;
return 0;
}
bool is_palindrome = equal(s.begin(), s.begin() + n/2, s.rbegin());
cout << (is_palindrome ? n - 1 : n) << endl;
return 0;
}
day3
Q1 难度⭐
爱丽丝的人偶 (nowcoder.com)
题目:
爱丽丝有n 个人偶,每个人偶的身高依次是1、2、3……n
现在她要将这n 个人偶摆成一排。
但是人偶被设置了魔法。假设对一个非两端的(不在队首也不在队尾)人偶x 而言,她相邻的两个人偶,一个比x 高、一个比x 矮,那么x 就会爆炸。
爱丽丝想找到一种摆法,使得所有人偶都不会爆炸。你能帮帮她吗?
思路:
旋转着输出,注意n的奇偶
#include <iostream>
using namespace std;
int main()
{
int n;
cin >> n;
int l = 1, r = n;
while(l < r)
{
cout << l << ' '<< r << ' ';
l ++;
r --;
}
if(n % 2 != 0) cout << l << endl;
return 0;
}
Q2 难度⭐
集合_牛客题霸_牛客网 (nowcoder.com)
题目:
给你两个集合,要求{A} + {B}。 注:同一个集合中不会有两个相同的元素。
输出时按数字升序输出。
思路:
STL::set
#include <iostream>
#include <set>
using namespace std;
int main()
{
int n, m;
cin >> n >> m;
set<int> val;
for (int i = 0; i < n + m; ++i)
{
int x;
cin >> x;
val.insert(x);
}
for (const auto& z : val)
{
cout << z << ' ';
}
cout << endl;
return 0;
}
Q3 难度⭐⭐
最长回文子序列_牛客题霸_牛客网 (nowcoder.com)
题目:
给定一个字符串,找到其中最长的回文子序列,并返回该序列的长度。
注:回文序列是指这个序列无论从左读还是从右读都是一样的。
本题中子序列字符串任意位置删除k(len(s)>=k>=0)个字符后留下的子串。
思路:
二维dp
状态转移方程为:dp[i][j] = max(dp[i][j-1],dp[i+1][j])
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
string s;
cin >> s;
vector<vector<int> > dp(s.size(), vector<int> (s.size(), 0));
for(int i = 0;i < s.size(); i ++)
dp[i][i] = 1;
for(int i = s.size() - 1;i >= 0; i --)
for(int j = i+1; j < s.size(); j ++)
{
if(s[i] == s[j]) dp[i][j] = dp[i + 1][j - 1] + 2;
else dp[i][j] = max(dp[i][j - 1], dp[i + 1][j]);
}
cout << dp[0][s.size() - 1] << endl;
return 0;
}
day4
Q1 难度⭐⭐
添加字符_牛客笔试题_牛客网 (nowcoder.com)
题目:
牛牛手里有一个字符串A,羊羊的手里有一个字符串B,B的长度大于等于A,所以牛牛想把A串变得和B串一样长,这样羊羊就愿意和牛牛一起玩了。
而且A的长度增加到和B串一样长的时候,对应的每一位相等的越多,羊羊就越喜欢。比如"abc"和"abd"对应相等的位数为2,为前两位。
牛牛可以在A的开头或者结尾添加任意字符,使得长度和B一样。现在问牛牛对A串添加完字符之后,不相等的位数最少有多少位?
思路:
遍历并比较两个字符串的最小差异
#include <iostream>
using namespace std;
int main()
{
string a, b;
cin >> a >> b;
int n = a.size();
int m = b.size();
int z = n;
for(int i = 0 ; i <= m - n; i ++)
{
int k = 0;
for(int j = 0; j < n; j ++)
{
if(a[j] != b[i + j])
k ++;
}
z = min(k, z);
}
cout << z << endl;
return 0;
}
Q2 难度⭐
数组变换__牛客网 (nowcoder.com)
题目:
牛牛有一个数组,里面的数可能不相等,现在他想把数组变为:所有的数都相等。问是否可行。
牛牛可以进行的操作是:将数组中的任意一个数改为这个数的两倍。
这个操作的使用次数不限,也可以不使用,并且可以对同一个位置使用多次。
输入描述:输入一个正整数N (N <= 50) 接下来一行输入N个正整数,每个数均小于等于1e9.
输出描述:假如经过若干次操作可以使得N个数都相等,那么输出"YES", 否则输出"NO"
思路:
将数组每一位偶数一直除2直到变为奇数,再遍历数组判断每一位是否相同
#include <iostream>
using namespace std;
int main()
{
int n;
cin >> n;
int a[50];
for (int i = 0; i < n; i++)
{
cin >> a[i];
while (a[i] % 2 == 0)
a[i] /= 2;
}
int flag = 1;
for (int i = 1; i < n; i++)
{
if (a[i] != a[i - 1])
{
flag = 0;
break;
}
}
printf("%s\n", flag ? "YES" : "NO");
return 0;
}
Q3 难度⭐⭐⭐
[NOIP2001]装箱问题 (nowcoder.com)
题目:
有一个箱子容量为V(正整数,0 ≤ V ≤ 20000),同时有n个物品(0<n ≤ 30),每个物品有一个体积(正整数)。
要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。
输入描述:1个整数,表示箱子容量1个整数,表示有n个物品
接下来n行,分别表示这n个物品的各自体积
输出描述:1个整数,表示箱子剩余空间。
思路:
01背包
状态转移方程为:dp[j] = max(dp[j], dp[j - a[i]] + a[i]);
#include<iostream>
using namespace std;
int v, n;
int a[40];
int dp[20010];
int main()
{
cin >> v >> n;
for(int i = 1; i <= n; i ++)
cin >> a[i];
dp[0] = 0;
for(int i = 1; i <= n; i ++ )
for(int j = v; j >= a[i]; j --)
dp[j] = max(dp[j], dp[j - a[i]] + a[i]);
for(int j = v; j >= 0; j --)
{
if(dp[j] > 0)
{
cout << v - dp[j] << endl;
break;
}
}
return 0;
}
day5
Q1 难度⭐⭐
打怪_牛客练习赛61 (nowcoder.com)
题目:
你是一个勇士,现在你准备去森林刷毛球怪,你有两个属性(血量,攻击力),毛球怪也有这两个属性。当你遭遇一只毛球怪时你们会进入战斗,然后你和毛球怪轮流攻击(你先手),每次使对方的血量减去自己攻击力的数值,当一方的血量小于等于 0 时死亡。现在你想知道在自己活着的前提下最多杀死几只毛球怪。
输入描述:第一行一个正整数t,代表测试数据组数。
第二行四个正整数h,a,H,A,代表你的血量和攻击力以及毛球怪的血量和攻击力。
所有整数大小不超过1000。
输出描述: 共 t 行,每行一个整数x,代表最多能杀死多少毛球怪。如果能杀死无数只,输出-1。
思路:
判断是否秒杀怪或被秒杀,再计算次数
#include <iostream>
using namespace std;
int main()
{
int t;
cin >> t;
while(t--)
{
int h, a, H, A;
cin >> h >> a >> H >> A;
if(a >= H)
cout << -1 << endl;
else if(h <= A)
cout << 0 << endl;
else
{
int k = (h - 1) / (((H - 1) / a) * A);
cout << k << endl;
}
}
return 0;
}
Q2 难度⭐
字符串分类_牛客笔试题_牛客网 (nowcoder.com)
题目:
牛牛有N个字符串,他想将这些字符串分类,他认为两个字符串A和B属于同一类需要满足以下条件:A中交换任意位置的两个字符,最终可以得到B,交换的次数不限。
比如:abc与bca就是同一类字符串。
现在牛牛想知道这N个字符串可以分成几类。
输入描述:首先输入一个正整数N(1 <= N <= 50),接下来输入N个字符串,每个字符串长度不超过50。
输出描述:输出一个整数表示分类的个数。
思路:
STL::map
#include <iostream>
#include <string>
#include <map>
#include <algorithm>
using namespace std;
int main()
{
int N;
cin >> N;
map<string, int> ss;
for(int i = 0; i < N; i ++)
{
string s;
cin >> s;
sort(s.begin(), s.end());
ss[s] ++;
}
cout << ss.size() << endl;
return 0;
}
Q3 难度⭐⭐⭐
城市群数量_牛客题霸_牛客网 (nowcoder.com)
题目:
给定一个 n 个节点的邻接矩阵 m。 节点定义为城市,如果 a 城市与 b 城市相连, b 与 c 城市相连,尽管 a 与 c 并不直接相连,但可以认为 a 与 c 相连,定义 a,b,c 是一个城市群。
矩阵 m[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,否则表示不相连。
请你找出共有多少个城市群。
数据范围: 1≤𝑛≤200 , 矩阵中只包含 0 和1
思路:
朴素并查集:并查集-CSDN博客
class Solution
{
public:
int find(int x, int p[])
{
if (p[x] != x) p[x] = find(p[x], p);
return p[x];
}
int citys(vector<vector<int>>& m)
{
int n = m.size();
int p[n];
for (int i = 0; i < n; i++)
{
p[i] = i;
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (m[i][j] == 1 && i != j)
{
int rootI = find(i, p);
int rootJ = find(j, p);
if (rootI != rootJ)
{
p[rootI] = rootJ;
}
}
}
}
int count = 0;
for (int i = 0; i < n; i++)
{
if (p[i] == i) count++;
}
return count;
}
};
day6
Q1 难度⭐⭐
判断是不是平衡二叉树_牛客题霸_牛客网 (nowcoder.com)
题目:
输入一棵节点数为 n 二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
思路:
判断左右子树高度差
class Solution
{
public:
// 辅助函数,用于计算树的高度
int treeHeight(TreeNode* root)
{
if (root == nullptr) return 0;
int leftHeight = treeHeight(root->left);
int rightHeight = treeHeight(root->right);
// 如果发现左右子树高度差大于1,直接返回-1表示不是平衡树
if (leftHeight == -1 || rightHeight == -1 || abs(leftHeight - rightHeight) > 1)
return -1;
return max(leftHeight, rightHeight) + 1;
}
bool IsBalanced_Solution(TreeNode* pRoot)
{
// 如果树的高度计算结果不是-1,则树是平衡的
return treeHeight(pRoot) != -1;
}
};
Q2 难度⭐⭐⭐⭐
最大子矩阵_牛客题霸_牛客网 (nowcoder.com)
题目:
已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵。
输入描述:
输入是一个N * N的矩阵。输入的第一行给出N (0 < N <= 100)。 再后面的若干行中,依次(首先从左到右给出第一行的N个整数,再从左到右给出第二行的N个整数……)给出矩阵中的N2个整数,整数之间由空白字符分隔(空格或者空行)。 已知矩阵中整数的范围都在[-127, 127]。
输出描述:输出最大子矩阵的大小。
思路:
先累加每行,再将行和累加
状态转移方程:dp[i] = max(dp[i-1], 0) + arr[i];
#include<iostream>
using namespace std;
int n;
int dp[110];
int sums[110][110][110];
int getMax(int arr[110], int n)
{
int res = dp[0] = arr[0];
for(int i = 1; i < n; ++i)
{
dp[i] = max(dp[i-1], 0) + arr[i];
res = max(res, dp[i]);
}
return res;
}
int main()
{
int val;
int ans = -0x3f3f3f;
cin >> n;
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
cin >> val;
for(int k = 0; k <= i; ++k)
if(k == 0)
sums[i][k][j] = val;
else
sums[i][k][j] = sums[i-1][k-1][j] + val;
}
}
for(int i = 0; i < n; ++i)
for(int k = 0; k <= i; ++k)
ans = max(ans, getMax(sums[i][k], n));
cout << ans;
return 0;
}
Q3 难度⭐⭐⭐
小葱的01串_牛客挑战赛54 (nowcoder.com)
题目:
给定一个长度为偶数的环形 01 字符串。(环形指,第一个字符和最后一个字符是相邻的)
字符串初始每个字符都是白色。小葱想把一段连续区间染成红色,使得红色的字符'0'数量等于白色的字符'0'数量,红色的字符'1'数量等于白色的字符'1'数量。问有多少种不同的染色方法?
两个方案不同当且仅当存在一个某字符,在一个方案是染成红色,在另一个方案为白色。
输入描述:
第一行输入一个正整数 n,代表字符串长度。 第二行输入一个长度为 n 的 01 字符串(仅由字符'0'和字符'1'组成的字符串)
数据范围: 2≤n≤300000。保证 n 是偶数。
输出描述:合法的染色方案数。
思路:
前缀和,拼接字符串并跳跃判断0,1个数
#include<iosdtream>
using namespace std;
int a[600008],b[600008];
int main()
{
int n;
string s;
cin >> n >> s;
s += s;
for(int i = 1; i <= 2 * n; i ++)
{
if(s[i - 1] == '1')
a[i] ++;
else
b[i] ++;
a[i] += a[i - 1];
b[i] += b[i - 1];
}
int ans = 0;
for(int i = 1; i <= n; i ++)
{
if(a[i + n / 2 - 1] - a[i - 1] == a[n] / 2 && b[i + n / 2 - 1] - b[i - 1] == b[n] / 2)
ans ++;
}
cout << ans << endl;
return 0;
}