首页 > 其他分享 ># 87双周赛

# 87双周赛

时间:2022-09-18 22:00:05浏览次数:74  
标签:val nums int 双周 ++ vector ans 87

这次只做出了三道题

6184. 统计共同度过的日子数

  1. 不熟悉api,没用过sscanf,在处理日期字符串的时候耽误了很多时间,最后用的substr()stoi(stoi还是现场在网上搜的,哈哈哈)
  2. 没有及时把重复代码提取出去,多写了很多行
class Solution {
public:
    int month[32] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int getDays(string date){
        int mon, day;
        sscanf(date.c_str(), "%d-%d", &mon, &day);
        for(int i = 1; i < mon; i++)
            day += month[i];
        return day;
    }
    
    int countDaysTogether(string as, string ae, string bs, string be){
        int ast = getDays(as), aed = getDays(ae), 
                  bst = getDays(bs), bed = getDays(be);
        if(aed < bst || ast > bed) return 0;
        return min(aed, bed) - max(ast, bst) + 1;
    }
};

6185. 运动员和训练师的最大匹配数

这道题做的很快,3分钟就出来了,就是一个很简单的贪心问题,这里给出证明

经过排序后进行的选择一定是最优解,假设某个解不是按照顺序进行选择的,比如说,能力为2的运动员训练师能力为8,而能力为4的运动员训练师能力为6,此时可以把他们的训练师对换且结果不会发生变化,因此得证,

这是很经典的贪心证明方法

class Solution {
public:
    int matchPlayersAndTrainers(vector<int>& a, vector<int>& b) {
        sort(a.begin(), a.end());
        sort(b.begin(), b.end());
        int i = 0, j = 0, ans = 0;
        for(; i < a.size() && j < b.size(); j++)
            if(a[i] <= b[j]) i++, ans++;
        return ans;
    }
};

6186. 按位或最大的最小子数组长度

这个题我用的方法比较复杂

//我的垃圾代码
class Solution {
public:
    vector<int> smallestSubarrays(vector<int>& nums) {
        vector<int> save(32); //save数组存储每个位置1的个数
        int n = nums.size();
        vector<int> ans(n);
        int max = 0, tmp = 0;
        for(int i = 0; i < n; i++) max |= nums[i];
        for(int i = 0, j = -1; i < n - 1; i++){
            if(i){	 //从1位置开始,每次都要删除前一个位置的数
                int val = nums[i - 1];
                for(int k = 0; val; k++, val >>= 1) //把要删除数的1去掉,
                    if(val & 1) {
                        --save[k];
                        if (!save[k]) //如果去掉后对应位置1个数变为0,那就异或掉这个数
                            tmp ^= 1 << k;
                    }
            }
            int ss = j, st = tmp;
            while(j < n - 1 && tmp < max){ //每次向后移动 或 一个新的数时
                int val = nums[++j];
                tmp |= val;
                if(tmp > st)
                    ss = j, st = tmp;
                for(int k = 0; val; k++, val >>= 1)  //把这个数每个有1的位置加到save数组中
                    if(val & 1)
                        save[k]++;
            }
            for(int u = ss + 1; u <= j; u++){
                int val = nums[u];
                for(int k = 0; val; k++, val >>= 1)
                    if(val & 1)
                        --save[k];
            }
            if(i > ss) ss = i;
            j = ss;
            ans[i] = j - i + 1;
        }
        ans[n - 1] = 1;
        return ans;
    }
};

然后看了大神的题解,就...很简洁,

(位运算) \(O(nlogS)\)

独立每一位看,每个位置的最短子数组就是寻找其位置之后第一个出现 1 的位置,如果其之后没有出现 1 的位置,则当前位置的最短子数组就是自身。
这样可以从后向前维护一个指针 p(初始位置可以为 0),记录出现 1 时最靠前的位置,每次用当前位置的值来更新 p。
拓展到更多位也同理,相当于寻找所有位中,出现 1 且最靠后的位置作为最短子数组的结束点。

时间复杂度

遍历数组一次,每个位置需要 \(O(log⁡S)\) 的时间遍历所有位,故总时间复杂度为 \(O(nlog⁡S)\)。

空间复杂度

需要 \(O(n+logS)\) 的额外空间存储答案和 p 数组。

class Solution {
public:
    vector<int> smallestSubarrays(vector<int>& nums) {
        vector<int> p(30);
        vector<int> ans(nums.size());
        for(int i = nums.size() - 1; i >= 0; i--){
            int ma = i, val = nums[i];
            for(int j = 0; j < 30; j++){
                if((val >> j) & 1)
                    p[j] = i;
                ma = max(ma, p[j]);
            }
            ans[i] = ma - i + 1;
        }
        return ans;
    }
};

6187. 完成所有交易的初始最少钱数

对于任一笔交易,其前序交易的交易顺序不会影响到当前这笔交易前的钱数。所以对于最坏情况,可以枚举每一笔交易都作为最后一笔交易进行测试,找到需要的最大开始钱数。

例如,样例数据[[2,1],[5,0],[4,2]]

最坏情况是[4,2]作为最后一笔交易时,需要的钱最多,前两笔交易任意顺序都不会影响结果,只要当[4,2]是最后一笔交易,就一定能得到最大亏钱结果

class Solution {
public:
    long long minimumMoney(vector<vector<int>>& a) {
        long long sum = 0, res = 0;
        for(auto &t : a)
            if(t[0] > t[1]) 
                sum += t[0] - t[1];
        
        for(auto &t : a){
            int x = t[0], y = t[1];
            auto s = sum;
            if(x > y) 
                s -= x - y;
            res = max(res, s + x);
        }
        return res;
    }
};

标签:val,nums,int,双周,++,vector,ans,87
From: https://www.cnblogs.com/INnoVationv2/p/16705966.html

相关文章

  • [leetcode 876] 链表的中间节点
    [leetcode876]链表的中间节点给定一个头结点为head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。示例1:输入:[1,2,3,4,5]输出:此列......
  • leetcode 687 最长同值路径
    给定一个二叉树的root,返回最长的路径的长度,这个路径中的每个节点具有相同值。这条路径可以经过也可以不经过根节点。做这道题的时候,我一开始想到的是直接从根节点往......
  • 687. 最长同值路径
    题目描述给定一个二叉树的 root ,返回最长的路径的长度,这个路径中的每个节点具有相同值 。这条路径可以经过也可以不经过根节点。两个节点之间的路径长度由它们之......
  • P4587 神秘数 Sol
    主席树好题。本质上是对于前缀的理解与转化。同题见牛牛的凑数游戏。实际上那场比赛T2和T3都是前缀相关的题目。这题是T3,看到很容易想到二进制拆分。稍微推广一......
  • LeetCode 1387. 按幂值对整数进行排序
    LeetCode1387.按幂值对整数进行排序剛從南湖群峰下山,原本受了現在好像又胖回去了(哭[按幂值排序整数-LeetCode整数x的幂定义为使用以下步骤将x转换为1所需的......
  • 信息学一本通 1187:统计字符数
    时间限制:1000ms      内存限制:65536KB提交数:19434   通过数:10997【题目描述】给定一个由a-z这26个字符组成的字符串,统计其中哪个字符出现的......
  • 687. 最长同值路径
    687.最长同值路径给定一个二叉树的 root ,返回 最长的路径的长度,这个路径中的 每个节点具有相同值 。这条路径可以经过也可以不经过根节点。两个节点之间的路......
  • HDU3487 Play With Chain
    题目链接  题目大意就是要我们对一个区间执行区间翻转和整体移动区间的操作。  思路:将一个区间分裂出来再移动到另一个节点的后面,可以用\(fhq-treap\)来将这一个子树......
  • [洛谷P5787] 线段树时间分治
    题目大意给\(n\)个点\(m\)条边,在\(k\)时间内,第\(i\)条边只在\([l_i+1,r_i]\)的时间范围内存在。对于每个\(i\leqk\),输出\(i\)时刻这个图是否是二分图。题......
  • 灵感宝盒新增「线上云展会」产品,「直播观赏联动」等你共建丨RTE NG-Lab 双周报
    前言哈喽各位开发者,「RTENG-Lab双周报」如期而至!近两周,我们更新了一些新的实时互动场景和产品,也举办了代码实验室的第一次线下活动,与大家一起体验了声网最新的4.0SDK......