周赛补题(力扣,acwing)

AcWing第63场周赛

第一题:4503. 数对数量 - AcWing题库

思路:两层循环暴力枚举。

代码

#include <bits/stdc++.h>

using namespace std;

int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int  cnt = 0;
    int a, b, n;
    cin >> a >> b >> n;
    for(int i = 0; i <= a; i ++)
    {
        for(int j = 0; j <= b; j ++)
            if(i + j == n)
                cnt ++;
    }
    cout << cnt << endl;
    return 0;
}

第二题:4504. 字符串消除 - AcWing题库

思路:用栈来模拟。当前元素和栈顶元素相同就将栈顶元素压出栈,否则就入栈,统计出栈的次数数,如果为奇数就是先手胜利,否则后手胜利。

代码

#include <bits/stdc++.h>

using namespace std;

int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    stack<char> s;
    string str;
    cin >> str;
    int cnt = 0;
    for(int i = 0; i < str.size(); i ++)
    {
        if(s.size() && s.top() == str[i])
        {
            s.pop();
            cnt ++;
        }
        else s.push(str[i]);
    }
    // cout << cnt << endl;
    if(cnt & 1) cout << "Yes" << endl;
    else cout << "No" << endl;
    return 0;
}

力扣第84场周赛

第一题:6141. 合并相似的物品 - 力扣(LeetCode)

思路:用map<int, int>来存储物品和其价值。分别将两个数组中的数据加入到map中。

代码

class Solution {
public:
    vector<vector<int>> mergeSimilarItems(vector<vector<int>>& items1, vector<vector<int>>& items2) {
        map<int, int> mp;
        for(auto i : items1)
        {
            int a = i[0], b = i[1];
            mp[a] += b;
        }
        for(auto i : items2)
        {
            int a = i[0], b = i[1];
            mp[a] += b;
        }
        vector<vector<int>> ans;
        for(auto [x, y] : mp) ans.push_back({x, y});
        return ans;
    }
};

第二题:6142. 统计坏数对的数目 - 力扣(LeetCode)

思路:统计不是坏数对个总数目n,用所有的数组减去n就是坏数对的数目。

坏数对   j - i != nums[j] - nums[i]

不是坏数对  j - i == nums[j] - nums[i]  将等式变换一下   nums[j] - j == nums[i] - i;

通过上面变换的等式我们可以将数组中的元素都减去其下标,再用map来存储数组元素相同的个数。每个数组元素相同表示从中任选两个都可以变成一个不是坏数对。

总数目和不是坏数对都是同一个数目(假设数目为m)中选择两个不行同下标:m * (m - 1) / 2

代码

class Solution {
public:
    long long countBadPairs(vector<int>& nums) {
        for(int i = 0; i < nums.size(); i ++) nums[i] -= i;
        map<int, int> mp;
        for(auto i : nums) mp[i] ++;
        int n = nums.size();
        long long ans = (long long)(n - 1) * n / 2;
        for(auto [x, y] : mp)
            ans -= (long long)y * (y - 1) / 2;
        return ans;
    }
};

第三题:6174. 任务调度器 II - 力扣(LeetCode)

思路:用map来模拟。map<int, int> 表示任务的完成时是第几天。

代码

class Solution {
public:
    long long taskSchedulerII(vector<int>& t, int space) {
        long long ans = 0;
        map<int, long long> mp;
        for(int i = 0; i < t.size(); i ++)
        {
            if(!mp.count(t[i]))
            {
                ans ++;
                mp[t[i]] = ans;
            }
            else
            {
                ans ++;
                if(ans - mp[t[i]] <= space) ans = mp[t[i]] + space + 1;
                mp[t[i]] = ans;
            }
            // cout << ans << " ";
        }
        return ans;
    }
};

第四题:6144. 将数组排序的最少替换次数 - 力扣(LeetCode)

思路:对数组从后向前遍历,用一个数ans来表示最小值,如果当前数大于ans,就将该数分为几个数都小于等于ans,注意每次都更新一下ans。

代码

class Solution {
public:
    long long minimumReplacement(vector<int>& nums) {
        long long ans = 0;
        int n = nums.size();
        int m = nums[n - 1];
        for(int i = n - 1; i >= 0; i --)
        {
            if(nums[i] <= m) m = nums[i];
            else
            {
                int t = nums[i] / m;
                ans += t;
                int a = nums[i] % m;
                if(!a) ans --;
                else
                {
                    t ++;
                    m = nums[i] / t;
                }
            }
        }
        return ans;
    }
};

力扣第305场周赛

第一题:2367. 算术三元组的数目 - 力扣(LeetCode)

思路:因为数据不大,可以直接暴力枚举。如果数据大一点就要将第三层替换为二分查找。

代码

朴素版(时间复杂度O(n^3))

class Solution {
public:
    int arithmeticTriplets(vector<int>& nums, int diff) {
        int cnt = 0, n = nums.size();
        for(int i = 0; i < n; i ++)
        {
            for(int j = i + 1; j < n; j ++)
            {
                if(nums[j] - nums[i] == diff)
                {
                    for(int k = j + 1; k < n; k ++)
                    {
                        if(nums[k] - nums[j] == diff)
                            cnt ++;
                    }
                }
            }
        }
        return cnt;
    }
};

二分版(时间复杂度O(n^2logn))

代码

class Solution {
public:
    int arithmeticTriplets(vector<int>& nums, int diff) {
        int cnt = 0, n = nums.size();
        for(int i = 0; i < n; i ++)
        {
            for(int j = i + 1; j < n; j ++)
            {
                if(nums[j] - nums[i] == diff)
                {
                    int l = j + 1, r = n - 1;
                    while(l < r)
                    {
                        int mid = l + r >> 1;
                        if(nums[mid] - nums[j] >= diff) r = mid;
                        else l = mid + 1;
                    }
                    if(l < n && nums[l] - nums[j] == diff) cnt ++;
                }
            }
        }
        return cnt;
    }
};

第二题:6139. 受限条件下可到达节点的数目 - 力扣(LeetCode)

思路:dfs。用dfs(u)来统计以u为根节点的子树的节点总数(节点不在受限制节点数组里)。

代码

const int N = 100010, M = 200010;
class Solution {
public:
    int h[N], e[M], ne[M], idx;
    bool st[N];
    unordered_set<int> s;
    void add(int a, int b)
    {
        e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
    }
    
    int dfs(int u)
    {
        int sum = 1;
        st[u] = 1;
        for(int i = h[u]; i != -1; i = ne[i])
        {
            int j = e[i];
            if(!s.count(j) && !st[j]) sum += dfs(j);
        }
        return sum;
    }
    
    int reachableNodes(int n, vector<vector<int>>& edges, vector<int>& r) {
        memset(h, -1, sizeof h);
        memset(st, 0, sizeof st);
        for(auto i : edges)
        {
            int a = i[0], b = i[1];
            add(a, b), add(b, a);
        }
        // for(int i = h[0]; i != -1; i = ne[i]) cout << e[i] << " ";
        for(auto i : r) s.insert(i);
        // for(auto i : )
        int ans = 0;
        ans = dfs(0);
        return ans;
    }
};

第三题:2369. 检查数组是否存在有效划分 - 力扣(LeetCode)

思路:动态规划。f[i] 表示从nums[0]到nums[i - 1]是否可以有效划分。

对f[i + 1]进行讨论

第一种情况:第i个数为相等元素的第二个   i >= 1 && f[i - 1] && nums[i - 1] == nums[i]

第二种情况:第i个数为相等元素的第三个   i >= 2 && f[i - 2] && nums[i] == nums[i - 1] && nums[i - 1] == nums[i - 2]

第三种情况:第i个数为递增元素的最后一个    i >= 2 && f[i - 2] && nums[i] == nums[i - 1] + 1 && nums[i - 1] == nums[i - 2] + 1

只要满足三种情况中任意一种nums[0]到nums[i]都可以有效划分,即f[i + 1] = 1。

代码

class Solution {
public:
    bool validPartition(vector<int>& nums) {
        int n = nums.size();
        vector<int> f(n + 1, 0);
        f[0] = 1;
        for(int i = 1; i < n; i ++)
        {
            if((f[i - 1] && nums[i] == nums[i - 1]) || (i - 2 >= 0 && f[i - 2] && nums[i] == nums[i - 1] && nums[i - 1] == nums[i - 2]) || (i - 2 >= 0 && f[i - 2] && nums[i] == nums[i - 1] + 1 && nums[i - 2] + 1 == nums[i - 1]))
                f[i + 1] = 1;
        }
        return f[n];
    }
};

第四题:2370. 最长理想子序列 - 力扣(LeetCode)

思路:动态规划。f[i]表示以i + 'a'结尾的理想字符串的最大长度。

f[i] = max(f[i], f[t] + 1)   t表示在字母表中与i的绝对值位次差小于等于k。

代码

const int N = 100010;
class Solution {
public:
    int f[26];
    int longestIdealString(string s, int k) {
        for(int i = 0; i < s.size(); i ++)
        {
            int u = s[i] - 'a';
            f[u] = f[u] + 1;
            for(int j = -k; j <= k; j ++)
            {
                if(!j) continue;
                int t = u + j;
                if(t < 0 || t >= 26) continue;
                f[u] = max(f[u], f[t] + 1);
            }
        }
        int ans = 0, m = 0;
        for(int i = 0; i < 26; i ++)    ans = max(ans, f[i]);

        return ans;
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值