一、LeetCode单周赛 314 场
1、6200.处理用时最长的那个任务的员工
(1)原题链接:力扣https://leetcode.cn/problems/the-employee-that-worked-on-the-longest-task/
(2)解题思路:
1、用pair数组保存每个id以及对应的任务的完成时间。
2、按完成时间所花费的大小顺序排序。
3、遍历数组,找到时间的最大值,若存在相同值,返回id较小的即可。
(3)参考代码:
class Solution {
public:
int hardestWorker(int n, vector<vector<int>>& logs) {
vector<pair<int, int>> a;
a.push_back({logs[0][1], logs[0][0]});
for(int i = 1; i < logs.size(); i ++ ) {
int t = logs[i][1] - logs[i - 1][1];
a.push_back({t, logs[i][0]});
}
sort(a.begin(), a.end());
int res = 0;
for(int i = a.size() - 1; i > 0; i --) {
if(a[i].first > a[i - 1].first) {
res = a[i].second;
break;
}
if(a[i].first == a[i - 1].first) {
res = min(a[i].second, a[i - 1].second);
}
}
return res;
}
};
2、6201.找出前缀异或的原始数组
(1)原题链接:力扣https://leetcode.cn/problems/find-the-original-array-of-prefix-xor/
(2)解题思路:
这题就是前缀和的逆运算。具体思路如下:
(3)参考代码:
class Solution {
public:
vector<int> findArray(vector<int>& pref) {
int n = pref.size();
vector<int> res(n);
res[0] = pref[0];
for (int i = 1; i < n; i ++ )
res[i] = pref[i] ^ pref[i - 1];
return res;
}
};
3、6202.使用机器人打印字典序最小的字符串
(1)原题链接:力扣https://leetcode.cn/problems/using-a-robot-to-print-the-lexicographically-smallest-string/
(2)解题思路:
1、遍历s串,找到所有的a,然后加入到t中,若加入时当前字母是 'a' 则直接输出,若不是则暂时加入到t中。
2、再遍历一遍s串,找到所有的b,但是要先将t中小于等于b的字典序的字母输出,当遍历到t中的某个字母大于b了,则开始类似的重复第一步。以此类推,处理26个字母。
3、最后再将t中剩余的元素输出即可。
(3)参考代码:
class Solution {
public:
string robotWithString(string s) {
string res, t;
//保存每个字母最后出现的位置
vector<int> pos(26, -1);
for(int i = 0; i < s.size(); i ++ )
pos[s[i] - 'a'] = i;
for(int i = 0, k = 0; i < 26 && k < s.size(); i ++ ) {
char c = i + 'a';
while(t.size() && t.back() <= c) {
res += t.back();
t.pop_back();
}
while(k <= pos[i]){
if(s[k] == c) res += c;
else t += s[k];
k ++;
}
}
reverse(t.begin(), t.end());
return res + t;
}
};
二、AcWing周赛 72
1、4624.最小值
(1)原题链接:4624. 最小值 - AcWing题库
(2)解题思路:
小学数学题,思路见代码。
(3)参考代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int main()
{
int t;
cin >> t;
while(t --) {
int a, b;
cin >> a >> b;
int c = (a + b) / 3;
int res = min(min(a, b), c);
cout << res << endl;
}
return 0;
}
2、4625.压缩文件
(1)原题链接:4625. 压缩文件 - AcWing题库
(2)解题思路:
1、先保存文件未被压缩时的所占空间大小总和。
2、用一个数组维护文件压缩前后的大小的差值,并排序。
3、从大到小依次减去差值,直到所占空间小于等于优盘的空间,减去的差值个数就是我们需要压缩的最少的文件数量。
(注意用long long保存当前文件所占空间,题目数据过大容易爆int)
(3)参考代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
typedef long long LL;
int main()
{
int n, m;
cin >> n >> m;
vector<int> tmp;
LL sum = 0;
for(int i = 0; i < n; i ++ ) {
int a, b;
cin >> a >> b;
sum += a;
tmp.push_back((a - b));
}
sort(tmp.rbegin(), tmp.rend());
if(sum <= m) {
cout << "0";
return 0;
}
else {
int res = 0;
for(int i = 0; i < n; i ++ ) {
sum -= tmp[i];
res ++;
if(sum <= m) {
cout << res;
return 0;
}
}
}
cout << "-1";
return 0;
}
3、4626.最小移动距离
(1)原题链接:4626. 最小移动距离 - AcWing题库
(2)解题思路:
1、本题的本质是一个基环树。
2、存不存在答案只需要判断是否每个点的入度都是 1,若存在不为 1 的点, 那么就不存在答案。
3、利用并查集,求出每个连通块的节点个数的最小公倍数即为答案。
(3)参考代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 110;
int n;
//d存入度,p存并查集,s存每个并查集大小
int d[N], p[N], s[N];
int find(int x)
{
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
int work()
{
for(int i = 1; i <= n; i ++ ) {
if(d[i] != 1) return -1;
}
int res = 1;
for(int i = 1; i <= n; i ++ ) {
if(i == p[i]){
int len = s[i];
if(len % 2 == 0) len /= 2;
res = res * (len / gcd(res, len));
}
}
return res;
}
int main()
{
cin >> n;
//初始化并查集
for(int i = 1; i <= n; i ++ ) p[i] = i, s[i] = 1;
for(int i = 1; i <= n; i ++ ) {
int x;
cin >> x;
d[x] ++;
int a = find(i), b = find(x);
//若两个点不在一个连通块中,则合并这两个点
if(a != b) {
s[b] += s[a];
p[a] = b;
}
}
cout << work() << endl;
return 0;
}