做了下爱奇艺2018测试工程师的编程题,教开发工程师还是偏简单,特意写了个编程题合集。
题目链接:
第一场
第一题:
题目:
牛牛有一些排成一行的正方形。每个正方形已经被染成红色或者绿色。牛牛现在可以选择任意一个正方形然后用这两种颜色的任意一种进行染色,这个正方形的颜色将会被覆盖。牛牛的目标是在完成染色之后,每个红色R都比每个绿色G距离最左侧近。牛牛想知道他最少需要涂染几个正方形。
如样例所示:
s = RGRGR
我们涂染之后变成RRRGG
满足要求了,涂染的个数为2
,没有比这个更好的涂染方案。
解析:
枚举,枚举最终涂好色的状态,然后和目前的情况比较,维护一个最小值就行了。利用前缀和优化,时间复杂度 O(n) 。
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
string str;
while (cin >> str) {
int n = str.size();
vector<int> R(n + 2, 0), G(R);
for (int i = 1; i <= n; i++)
G[i] = G[i - 1] + (str[i - 1] == 'G');
for (int i = n; i > 0; i--)
R[i] = R[i + 1] + (str[i - 1] == 'R');
int ans = n;
for (int i = 0; i <= n; i++)
ans = min(ans, G[i] + R[i + 1]);
cout << ans << endl;
}
return 0;
}
第二题:
题目:
牛牛有羊羊有了属于他们自己的飞机。于是他们进行几次连续的飞行。
f[i]
表示第i
次飞行所需的燃油的升数。飞行只能按照f数组所描述的顺序进行。起初飞机里有
s
升燃油,为了正常飞行,每次飞行前飞机内燃油量应大于等于此处飞行所需要的燃油量。请帮助他们计算在不进行加油的情况下他们能进行的飞行次数。
解析:
模拟就好了,这里我用了二分去查找前缀和。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
bool cmp(const int &a, const int &b)
{
return a <= b;
}
int main()
{
int n, s;
while (cin >> n >> s) {
vector<int> sum(n + 1, 0);
for (int i = 1, x; i <= n; ++i)
sum[i] = sum[i - 1] + (cin >> x, x);
cout << lower_bound(sum.begin(), sum.end(), s, cmp) - sum.begin() - 1<< endl;
}
return 0;
}
第三题:
题目:
牛牛手中有三根木棍,长度分别是
a,b,c
。牛牛可以把任一一根木棍长度削短,牛牛的目标是让这三根木棍构成一个三角形,并且牛牛还希望这个三角形的周长越大越好。
解析:
排个序,用两较小的边之和大于第三边这个性质就可以解决了。
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector<int> arr(3);
while (cin >> arr[0] >> arr[1] >> arr[2]) {
sort(arr.begin(), arr.end());
cout << (arr[0] + arr[1] > arr[2] ? arr[0] + arr[1] + arr[2] : 2 * (arr[0] + arr[1]) - 1) << endl;
}
return 0;
}
第二场
第一题:
题目:
牛牛有一个长度为
n
的整数序列,牛牛想对这个序列进行重排为一个非严格升序序列。牛牛比较懒惰,他想移动尽量少的数就完成重排,请你帮他计算一下他最少需要移动多少个序列中的元素。(当一个元素不在它原来所在的位置,这个元素就是被移动了的)。
解析:
不要想复杂了,题干中加粗的句子就是做法。
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
vector<int> pre((cin >> n, n));
for (int i = 0; i < n; cin >> pre[i++]);
vector<int> now(pre);
sort(now.begin(), now.end());
int ans = 0;
for (int i = 0; i < n; i++)
ans += (pre[i] != now[i]);
cout << ans << endl;
return 0;
}
第二题:
题目:
牛牛参加了一场考试,考试包括
n
道判断题,每做对一道题获得1
分,牛牛考试前完全没有准备,所以考试只能看缘分了,牛牛在考试中一共猜测了t
道题目的答案是”正确”,其他的牛牛猜为”错误”。考试结束后牛牛知道实际上n
道题中有a
个题目的答案应该是”正确”,但是牛牛不知道具体是哪些题目,牛牛希望你能帮助他计算可能获得的最高的考试分数是多少。
解析:
牛牛猜测
t
道正确,n-t
道题错误;而实际上正确的题有a
道,不正确的有n-a
道,牛牛多么希望它选正确的那些题实际上也是对的,它选错的那些题实际上也是错的,这样它才能获得最多的分数。因此答案就是min(t, a) + min(n - t, n - a)
。
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n, t, a;
cin >> n >> t >> a;
cout << min(t, a) + min(n - t, n - a) << endl;
return 0;
}
第三题:
题目:
有一种有趣的字符串价值计算方式:统计字符串中每种字符出现的次数,然后求所有字符次数的平方和作为字符串的价值
例如: 字符串
"abacaba"
,里面包括4
个'a'
,2
个'b'
,1
个'c'
,于是这个字符串的价值为4 * 4 + 2 * 2 + 1 * 1 = 21
牛牛有一个字符串
s
,并且允许你从s
中移除最多k
个字符,你的目标是让得到的字符串的价值最小。
解析:
每次删除一个出现最多次数的那个字母肯定是最优的,但是这个删除是动态的,也就是说你每次删除了那个次数最多的字母,下次这个字母出现的次数可能并不是最多的了。所以每次删除过后排个序继续删除就可以了,我用的是优先队列,每次取出队头的元素使其减一,然后再插入优先队列。
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
string str;
int k;
cin >> str >> k;
map<char, int> mp;
for (auto c : str)
mp[c]++;
priority_queue<int> que;
for (auto ele : mp)
que.push(ele.second);
int ans = 0;
for (; k--; ) {
int top = que.top();
que.pop();
if (top >= 1)
que.push(top - 1);
}
while (!que.empty())
ans += que.top() * que.top(), que.pop();
cout << ans << endl;
return 0;
}
第三场
第一题:
题目:
牛牛的老师给出了一个区间的定义:对于
x <= y,[x, y]
表示x
到y
之间(包括x
和y
)的所有连续整数集合。例如[3,3] = {3}, [4,7] = {4,5,6,7}
.牛牛现在有一个长度为n
的递增序列,牛牛想知道需要多少个区间并起来等于这个序列。例如:
{1,2,3,4,5,6,7,8,9,10}
最少只需要[1,10]
这一个区间;
{1,3,5,6,7}
最少只需要[1,1],[3,3],[5,7]
这三个区间。
解析:
看一下集合中连续两个数是否在自然数上是连续的就可以了。
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
while (cin >> n) {
vector<int> arr(n);
for (int i = 0; i < n; cin >> arr[i++]);
int ans = 1;
for (int i = 1; i < n; i++)
ans += (arr[i] != arr[i - 1] + 1);
cout << ans << endl;
}
return 0;
}
第二题:
题目:
牛牛有一个由小写字母组成的字符串
s
,在s
中可能有一些字母重复出现。比如在"banana"
中,字母'a'
和字母'n'
分别出现了三次和两次。但是牛牛不喜欢重复。对于同一个字母,他只想保留第一次出现并删除掉后面出现的字母。请帮助牛牛完成对
s
的操作。
解析:
用
set
维护一下这个字符串中的字符,如果当前字符没有在set
中,就输出,然后加入到set
中;如果当前字符在set
中,就什么都不做。
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
string str;
while (cin >> str) {
set<char> st;
for (char c : str) {
if (st.end() == st.find(c)) {
cout << c;
st.insert(c);
}
}
cout << endl;
}
return 0;
}
第三题:
题目:
牛牛举办了一场数字游戏,有
n
个玩家参加这个游戏,游戏开始每个玩家选定一个数,然后将这个数写在纸上(十进制数,无前缀零),然后接下来对于每一个数字将其数位按照非递减顺序排列,得到新的数,新数的前缀零将被忽略。得到最大数字的玩家赢得这个游戏。
解析:
还是模拟,用
stringsteam
完成数字到字符串、字符串到数字的转换就行了。只不过这个题的数据有点坑,必须写成单组输入才能过。
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
stringstream sin;
cin >> n;
int ans = 0;
for (int i = 0; i < n; i++) {
string str;
cin >> str;
sort(str.begin(), str.end());
sin << str;
int tmp;
sin >> tmp;
sin.clear();
ans = max(ans, tmp);
}
cout << ans << endl;
return 0;
}