周赛补题(AcWing,力扣)

AcWing第59场周赛

第一题:4491. 数组操作 - AcWing题库

思路:前缀和

代码

#include <bits/stdc++.h>

using namespace std;

const int N = 110;
int a[N];
int n;

int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin >> n;
    int ans = 0;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    for(int i = 1; i <= n; i ++)
    {
        a[i] += a[i - 1];
        ans = min(ans, a[i]);
    }
    cout << a[n ] -ans;
    return 0;
}

 第二题:4492. 减法操作 - AcWing题库

思路:这题。。。。本以为只是找到一个最小的质因数然后相除得到的结果就是答案,当时一直以为是正确的,然后没有做出来。后来看了题解后直到一个数减去它的最小质因子后为偶数,2位最小的质因子。这题的数据最大为10^10,会爆int,所以数据要用long long(或者long)来存储。

代码

#include<bits/stdc++.h>

using namespace std;

int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    long long n;
    cin >> n;
    long long ans = 0;
    bool st = 0;
    for(long long i = 2; i * i <= n; i ++)
    {
        if(n % i == 0)
        {
            n -= i;
            ans ++;
            st = 1;
            break;
        }
    }
    if(!st) n = 0, ans ++;
    ans += n / 2;
    cout << ans;
    return 0;
}

 力扣第301场周赛

第一题:6112. 装满杯子需要的最短总时长 - 力扣(LeetCode)

思路:模拟,每次将最多的两个减去1,直到只有一个数大于0。

代码

class Solution {
public:
    int fillCups(vector<int>& amount) {
        priority_queue<int> q;
        for(auto i : amount)
        {
            if(i > 0)   q.push(i);
        }
        int ans = 0;
        while(q.size() > 1)
        {
            int a = q.top(); q.pop();
            int b = q.top(); q.pop();
            a --, b --;
            ans ++;
            if(a > 0)   q.push(a);
            if(b > 0)   q.push(b);
        }
        if(q.size() == 1) ans += q.top();
        return ans;
    }
};

 第二题:6113. 无限集中的最小数字 - 力扣(LeetCode)

思路:用set来存储,set是从小到到排列的,所以每次返回最小值并移除可以直接返回并移除set的第一个元素。

代码

class SmallestInfiniteSet {
public:
    set<int> s;
    SmallestInfiniteSet() {
        for(int i = 1; i <= 1000; i ++) s.insert(i);
    }
    
    int popSmallest() {
        int it = *s.begin();
        s.erase(s.begin());
        return it;
    }
    
    void addBack(int num) {
        s.insert(num);
    }
};

/**
 * Your SmallestInfiniteSet object will be instantiated and called as such:
 * SmallestInfiniteSet* obj = new SmallestInfiniteSet();
 * int param_1 = obj->popSmallest();
 * obj->addBack(num);
 */

第三题:6114. 移动片段得到字符串 - 力扣(LeetCode)

思路:将两个字符串(只比较L和R)进行比较,如果两个字符相同且都为L,那么start的L的位置一定要大于等于target中L的位置,否则无法从start到target,如果两个字符相同且都为R,那么start中R的位置一定要小于等于target中R的位置,否则无法从start到target。将start和target中的字符(L和R)逐一比较。

代码

class Solution {
public:
    bool canChange(string start, string target) {
        int n = start.size(), m = target.size();
        int i, j;
        for(i = 0, j = 0; i < n && j < m; i ++, j ++)
        {
            int a = i, b = j;
            while(a < n && start[a] == '_') a ++;
            while(b < m && target[b] == '_')    b ++;
            if(a == n && b == m)    return true;
            if(start[a] == 'L' && target[b] == 'L' && a >= b)   i = a, j = b;
            else if(start[a] == 'R' && target[b] == 'R' && a <= b)  i = a, j = b;
            else return false;
        }
        while(i < n && start[i] == '_') i ++;
        while(j < n && target[j] == '_') j ++;
        return (i == n) && (j == m);
    }
};

力扣第82场双周赛

第一题:6116. 计算布尔二叉树的值 - 力扣(LeetCode)

思路:递归

代码

/**
 * 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) {}
 * };
 */
class Solution {
public:
    bool evaluateTree(TreeNode* root) {
        if(root->val == 2)  return evaluateTree(root->left) || evaluateTree(root->right);
        else if(root->val == 3) return evaluateTree(root->left) && evaluateTree(root->right);
        return root->val;
    }
};

第二题:6117. 坐上公交的最晚时间 - 力扣(LeetCode)

思路:模拟。我在写这题的时候是用的指针模拟的,用指针模拟的话要很多的判定条件(这个我当时真的快要崩溃了,wa了13次,整个人都不好了)。后来看了别人的代码,用数组和队列模拟的,这个最后判断的条件比指针少很多。

代码

class Solution {
public:
    int latestTimeCatchTheBus(vector<int>& buses, vector<int>& passengers, int capacity) {
        queue<int> q;
        set<int> s;
        sort(buses.begin(), buses.end());
        sort(passengers.begin(), passengers.end());
        int n = buses.size();
        vector<vector<int>> d(n);
        for(auto i : passengers)    q.push(i), s.insert(i);
        for(int i = 0; i < n; i ++)
        {
            while(d[i].size() < capacity && q.size() && q.front() <= buses[i])
            {
                d[i].push_back(q.front());
                q.pop();
            }
        }
        int ans;
        if(d[n - 1].size() < capacity) ans = buses[n - 1];
        else ans = d[n - 1][capacity - 1];
        while(1)
        {
            if(!s.count(ans))   break;
            ans --;
        }
        return ans;
    }
};

第三题:2333. 最小差值平方和 - 力扣(LeetCode)

思路:根据题目意思,可以看作用一个数组来存储nums1与nums2每个元素的差的绝对值,然后对这个数组中的数做多可以进行k1  + k2次减1操作,进行操作之后得到的数组的每个数的平方和的最小值是多少。为了得到最小值肯定是从最大的值开始减。首先我先想到的就是用大根堆来存储,每次将第一个元素减1,如果减1后 如果大于0就存入大根堆。然后这样超时了。这个需要做一些优化,因为有一些相同的数,所以可以用大根堆来存储数和数的个数。

 类似于这样的一座山砍掉面积为k1 + k2。

代码

class Solution {
public:
    typedef long long LL;
    long long minSumSquareDiff(vector<int>& nums1, vector<int>& nums2, int k1, int k2) {
        unordered_map<int, int> mp;
        for(int i = 0; i < nums1.size(); i ++)
        {
            int a = abs(nums1[i] - nums2[i]);
            if(a)   mp[a] ++;
        }
        priority_queue<pair<int, int>> q;
        for(auto [x, y] : mp)   q.push({x, y}), cout << x << " " << y << endl;
        int cnt = k1 + k2;
        while(q.size() && cnt)
        {
            auto [x, y] = q.top(); q.pop();
            if(q.size())
            {
                auto [xx, yy] = q.top(); q.pop();
                int a = x - xx, b = y;
                if(a * b <= cnt)
                {
                    cnt -= a * b;
                    q.push({xx, yy + y});
                }
                else
                {
                    int aa = cnt / b;
                    int bb = cnt - aa * b;
                    
                    cnt = 0;
                    q.push({xx, yy});
                    q.push({x - aa, y - bb});
                    q.push({x - aa - 1, bb});
                }
            }
            else
            {
                if(x * y <= cnt) break;
                int a = cnt / y;
                int b = cnt - a * y;
                cnt = 0;
                x -= a;
                q.push({x, y - b});
                if(x - 1) q.push({x - 1, b});
            }
        }
        LL ans = 0;
        while(q.size())
        {
            auto [x, y] = q.top(); q.pop();
            cout << x << " " << y << endl;
            ans += (LL)x * x * y;
        }
        return ans;
    }
};

这个的时间复杂度有点高,后来看了一下y总的力扣单周赛讲解发现这个可以二分。

代码

class Solution {
public:
    bool check(int mid, vector<int> & nums1, int cnt)
    {
        long long sum = 0;
        for(auto i : nums1)
        {
            if(i >= mid)    sum += i - mid;
        }
        return sum <= cnt;
    }
    long long minSumSquareDiff(vector<int>& nums1, vector<int>& nums2, int k1, int k2) {
        long long sum = 0;
        for(int i = 0; i < nums1.size(); i ++)
        {
            nums1[i] = abs(nums1[i] - nums2[i]);
            sum += nums1[i];
        }
        int cnt = k1 + k2;
        if(sum <= cnt)  return 0;
        sort(nums1.begin(), nums1.end());
        reverse(nums1.begin(), nums1.end());
        int l = 0, r = nums1[0];
        while(l < r)
        {
            int mid = (l + r ) >> 1;
            if(check(mid, nums1, cnt)) r = mid;
            else    l = mid + 1;
        }
        int a = 0;
        for(auto i : nums1)
        {
            if(i >= l) a += i - l;   
        }
        a = cnt - a;
        long long ans = 0;
        for(auto i : nums1)
        {
            if(i >= l)
            {
                if(a) ans += (long long)pow(l - 1, 2), a --;
                else ans += (long long)pow(l, 2);
            }
            else    ans += (long long)pow(i, 2);
        }
        return ans;
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值