AcWing周赛 72 场 && LeetCode单周赛 314 场 总结

一、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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值