周赛补题(AcWing、力扣)

AcWing第65场周赛

第一题:4603. 最大价值 - AcWing题库

思路:我是真的傻,看错题目了两次(第一次看成前缀和,第二次看成求和,后来发现是最大值)。双指针求最大值。

代码

#include <bits/stdc++.h>

using namespace std;

int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int t; cin >> t;
    while(t --)
    {
        int n;
        string s;
        cin >> n >> s;
        int ans = 0;
        for(int i = 0; i < n; i ++)
        {
            if(s[i] == 'A')
            {
                int j = i + 1;
                while(j < n && s[j] == 'P') j ++;
                ans = max(ans, j - i - 1);
            }
        }
        cout << ans << endl;
    }
    return 0;
}

第二题:4604. 集合询问 - AcWing题库

思路:第一次是向用哈希表来存储每个数和这个数的次数,然后来枚举,后来超时了。因为字符串的最大值为18,所以每次将字符串长度扩展为18(长度不足18的补上前导0),用哈希表来存储这些字符串,所以每次插入、删除、询问的时间复杂度都是18,所以总时间复杂度最大为18*100000是可以过的。

代码

#include <bits/stdc++.h>

using namespace std;

unordered_map<string, int> mp;

string get(string s)
{
    string res;
    for(int i = 0; i < s.size(); i ++)
        if((s[i] - '0') & 1) res.push_back('1');
        else res.push_back('0');
    while(res.size() < 18) res = "0" + res;
    // cout << res << endl;
    return res;
}

int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int t; cin >> t;
    while(t --)
    {
        char op;
        string a;
        cin >> op >> a;
        if(op == '+')
            mp[get(a)] ++;
        else if(op == '-')
            mp[get(a)] --;
        else
            cout << mp[get(a)] << endl;
    }
    return 0;
}

力扣第85场双周赛

第一题:2379. 得到 K 个黑块的最少涂色次数 - 力扣(LeetCode)

思路:定长滑动窗口求最小值。直接两层循环(一层枚举起点,另一层枚举终点(长度不能大于窗口的长度)),找出白色个数的最小值。

代码

class Solution {
public:
    int minimumRecolors(string b, int k) {
        int ans = k;
        int n = b.size();
        for(int i = 0; i <= n - k; i ++)
        {
            int cnt = 0;
            for(int j = 0; j < k; j ++)
            {
                if(b[i + j] == 'W')
                    cnt ++;
            }
            ans = min(ans, cnt);
        }
        return ans;
                
    }
};

第二题:2380. 二进制字符串重新安排顺序需要的时间 - 力扣(LeetCode)

思路:我原本还以为是找规律,找了半天(wa了两次,还是没有过),后来看了一下通过人数觉得可能是模拟,用模拟写了一下过了,我是**。将01变为10,在这其中1和0的个数都没有发生改变,并且最后会变成111...10....0这样的形式(因为最后不能存在01),每次对字符串进行变形(将01变为10),直到最后是111..10...0的形式。

代码

class Solution {
public:
    int secondsToRemoveOccurrences(string s) {
        int cnt = 0, n = s.size();
        for(auto i : s) if(i == '1') cnt ++;
        string t;
        for(int i = 0; i < n; i ++)
        {
            if(i + 1 <= cnt) t += "1";
            else t += "0";
        }
        int ans = 0;
        while(1)
        {
            if(s == t) break;
            for(int i = 0; i < n; i ++)
            {
                if(s[i] == '0' && i + 1 < n && s[i + 1] == '1')
                {
                    swap(s[i], s[i + 1]);
                    i ++;
                }
            }
            ans ++;
        }
        return ans;
    }
};

第三题:2381. 字母移位 II - 力扣(LeetCode)

思路:差分。连续的区间并且想前变化和想后变化所以就想到了差分。向后移+1,向前移-1,最后用前缀和求出每个位置需要向一个方向(整数向后移动,负数向前移动)移动多少位(注意这个要对26取模,因为是a-z循环)。

代码

class Solution {
public:
    string shiftingLetters(string s, vector<vector<int>>& shifts) {
        int n = s.size();
        vector<int> res(n + 1, 0);
        for(auto i : shifts)
        {
            int l = i[0], r = i[1], c = i[2];
            if(c == 0) c = -1;
            res[l] += c, res[r + 1] -= c;
        }
        for(int i = 1; i < n; i ++) res[i] += res[i - 1];
        for(int i = 0; i < n; i ++)
        {
            int t = ((s[i]  - 'a' + res[i]) % 26 + 26) % 26; //这里要先对26取模,因为负数的余数也是负数
            s[i] = t + 'a';
        }
        return s;
    }
};

力扣第 307场周赛

OS:这次的周赛前两题是我做过的最难的前两题。

第一题:2383. 赢得比赛需要的最少训练时长 - 力扣(LeetCode)

思路:因为精力每次都会减少,所以初始精力要大于所消耗的精力之和。而经验是每次相比进行比较,少了就加上少的加1,注意每次都加上经验。

代码

class Solution {
public:
    int minNumberOfHours(int t, int e, vector<int>& energy, vector<int>& x) {
        int ans = 0, sum = 0;
        int n = x.size();
        for(int i = 0; i < n; i ++)
        {
            int a = energy[i], b = x[i];
            sum += a;
            if(e <= b) ans += b + 1 - e, e += b + 1 - e;
            e += b;
        }
        if(t <= sum) ans += sum + 1 - t;
        return ans;
    }
};

第二题:2384. 最大回文数字 - 力扣(LeetCode)

思路:统计每个数字出现的次数。将每个数组从大到小进行遍历。先存储回文字符串的前一半,最后将存储的字符串翻转在加到存储的字符串的后面就是回文串了。

对于每个数字出现的次数x进存储(该数字存储x/2次),注意存储一个最大的数字的奇数次的数字op,因为是从大到小枚举的,如果存在奇数次就将一个字符变成该数字。

最后回文串为x(去掉前导0)+op(如果存在)+x'(将x翻转)。

代码

class Solution {
public:
    string largestPalindromic(string num) {
        map<int, int> mp;
        for(auto i : num) mp[i - '0'] ++;
        vector<pair<int, int>> ans;
        for(auto [x, y] : mp)
            ans.push_back({x, y});
        sort(ans.begin(), ans.end(), greater());
        string s;
        bool st = 0;
        char op;
        for(auto i : ans)
        {
            int a = i.first, b = i.second;
            if(!st && b & 1)
            {
                op = a + '0';
                st = 1;
                b --;
            }
            for(int i = 0; i < b / 2; i ++) s += to_string(a);
        }
        int i = 0;
        while(i < s.size() && s[i] == '0') i ++;
        s = s.substr(i);
        string t = s;
        reverse(t.begin(), t.end());
        if(st) s.push_back(op);
        s += t;
        if(!st && !s.size()) s = "0";       //可以num是偶数个0
        return s;
    }
};

第三题:2385. 感染二叉树需要的总时间 - 力扣(LeetCode)

思路:数的存储+bfs遍历。将该数以邻接表存储用bfs求到最远叶子节点的层数。

代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */

const int N = 100010, M = N * 2;
class Solution {
public:
    int h[N], e[M], ne[M], idx;
    bool st[N];
    void add(int a, int b)
    {
        e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
    }
    
    void build(TreeNode* root)
    {
        if(root->left != NULL)
        {
            add(root->val, root->left->val);
            add(root->left->val, root->val);
            build(root->left);
        }
        if(root->right != NULL)
        {
            add(root->val, root->right->val);
            add(root->right->val, root->val);
            build(root->right);
        }
    }
    
    int amountOfTime(TreeNode* root, int start) {
        memset(h, -1, sizeof h);
        build(root);
        queue<int> q;
        int ans = 0;
        q.push(start);
        st[start] = 1;
        while(q.size())
        {
            int n = q.size();
            while(n --)
            {
                auto p = q.front(); q.pop();
                for(int i = h[p]; i != -1; i = ne[i])
                {
                    int j = e[i];
                    if(!st[j])
                    {
                        q.push(j);
                        st[j] = 1;
                    }
                }
            }
            ans ++;
        }
        ans --;
        return ans;
    }
};

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值