第102场双周赛

Posted 929code

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第102场双周赛相关的知识,希望对你有一定的参考价值。

1. 查询网格每一列宽度

送分题
class Solution 
public:
    vector<int> findColumnWidth(vector<vector<int>>& grid) 
        vector<int> res;
        int m = grid.size(); int n = grid[0].size();
        for(int j=0;j<n;j++)
            int len = 0;
            for(int i=0;i<m;i++)
            len = max(len,judge(grid[i][j]));
        
            res.push_back(len);
        
        return res;
    
    int judge(int num)
        int len = 0;
        if(num==0) return 1;
        if(num<0)len++;num=-1*num;
        while(num!=0)
            num/=10;
            len++;
        
        return len;
    
;

2. 一个数组所有前缀的分数

送分题
class Solution 
public:
    vector<long long> findPrefixScore(vector<int>& nums) 
        int n = nums.size();
        vector<int> premax(n);
        vector<long long> convert(n);
        int cur = INT_MIN;
        for(int i=0;i<n;i++)
            if(nums[i]>cur)
                cur = nums[i];
            premax[i]=cur;
            convert[i] = nums[i]+premax[i];
        
        for(int i=1;i<n;i++)
            convert[i] = convert[i-1]+convert[i];
        return convert;
    
;

3. 二叉树的堂兄弟节点 II

层次遍历+先序遍历
class Solution 
public:
    TreeNode* replaceValueInTree(TreeNode* root) 
        if(!root) return root;
        queue<TreeNode*> q;
        q.push(root);
        vector<int> cursum;
        while(!q.empty())
            int sum =0;//当前层的和
            int n = q.size();
            for(int i=0;i<n;i++)
                TreeNode* temp = q.front();
                q.pop();
                if(temp==nullptr) continue;
                sum+= temp->val;
                if(temp->left) q.push(temp->left);
                if(temp->right) q.push(temp->right);
             
            cursum.push_back(sum);
    
         visit(root,0,cursum,root->val);
         return root;
    
        void visit(TreeNode* root,int deep,vector<int> &cursum,int sub)
            if(!root) return;
            int left = root->left?root->left->val:0;
            int right = root->right?root->right->val:0;
            
            root->val = cursum[deep]-sub;
            visit(root->left,deep+1,cursum,left+right);
            visit(root->right,deep+1,cursum,left+right);
            
        
    
;

4. 设计可以求最短路径的图类

领接矩阵+迪杰斯特拉算法
class Graph 
public:
    vector<vector<int>> graph;
    Graph(int n, vector<vector<int>>& edges) 
        graph.resize(n);
        for(auto &point:graph)
            point.resize(n,INT_MAX);//初始赋无穷远距离
        for(int i=0;i<edges.size();i++)
            int from = edges[i][0];
            int to = edges[i][1];
            int cost = edges[i][2];
            graph[from][to] = cost;
             
    
    
    void addEdge(vector<int> edge) 
            int from = edge[0];
            int to = edge[1];
            int cost = edge[2];
            graph[from][to] = cost;
    
    
    int shortestPath(int node1, int node2) 
        if(node1==node2) return 0;
        int n =graph.size();
        vector<int> dis(n);//记录到各点的距离
        vector<bool> mark(n);//标记访问情况
        mark[node1] = true;//加入源点
        for(int i=0;i<n;i++)
            dis[i] = graph[node1][i];//初始化源点到各点距离
        
        for(int count=1;count<n;count++)//更新n-1次
            int minpath = INT_MAX;//记录最小距离
            int nextpoint = -1;//下一个邻近节点
            for(int i=0;i<n;i++)//贪心找下一个最近节点
            
                if(mark[i]==0&&dis[i]<minpath)
                    minpath = dis[i];
                    nextpoint = i;
                
            
            if(nextpoint==node2) return dis[node2];
            //如果没有下一个邻近节点
            if(nextpoint==-1) return -1;
            
            mark[nextpoint] = true;//将节点加入访问集合
            for(int i=0;i<n;i++)//根据新加入的节点更新所有节点离源点的距离
                if(graph[nextpoint][i]<INT_MAX&&mark[i]==false)//该点到新加入节点有边
                    if(dis[i]>dis[nextpoint]+graph[nextpoint][i])
                        dis[i]=dis[nextpoint]+graph[nextpoint][i];//更新该点到源点距离
                    
                
    
        
        return dis[node2]==INT_MAX?-1:dis[node2];
    
;

LeetCode第82场双周赛

第82场双周赛

黑暗后是黎明!

6116. 计算布尔二叉树的值

思路:

递归,就是对二叉树的递归遍历,判断非叶子节点是2还是3来进行与/并叶子的计算。

/**
 * 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) 
        //题目明确说了树中节点数目在 [1, 1000] 之间。所以不可能为空
        //完整二叉树,无左孩子一定无有孩子,考虑一边就行
        if(!root->left)return root->val;
        auto l =evaluateTree(root->left);
        auto r=evaluateTree(root->right);
        if(root->val==2) return l||r;
        return l&&r;
    
;

6117. 坐上公交的最晚时间

思路:

来源灵佬https://www.bilibili.com/video/BV1Le4y1R7xu/?spm_id_from=333.788&vd_source=11a40407ca73e76119d9f9b789cc7ff2、

排序后,模拟乘客上车的过程。

模拟结束后:

如果最后一班公交还有空位,我们可以在发车时到达公交站,如果此刻有人,我们可以顺着他往前找到没人到达的时刻;
如果最后一班公交没有空位,我们可以找到上一个上车的乘客,顺着他往前找到一个没人到达的时刻。

作者:endlesscheng
链接:https://leetcode.cn/problems/the-latest-time-to-catch-a-bus/solution/pai-xu-by-endlesscheng-h9w9/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class Solution 
public:
    int latestTimeCatchTheBus(vector<int>& buses, vector<int>& passengers, int capacity) 
         sort(buses.begin(), buses.end());
        sort(passengers.begin(), passengers.end());
        //j代表上车的人数,c代表当前的容量剩余
        int j=0,c;
        for(int t:buses)
            //此时容量有剩余且当前的人数未到达全部乘客的人数,乘客来的比公交早
            for(c=capacity;c&&j<passengers.size()&&passengers[j]<= t;j++)
                c--;
            
        
        j--;//代表最后一个上车的乘客
        //顺着最后一个人往前找,找到即答案
         int ans = c ? buses.back() : passengers[j];
         while (j >= 0 && passengers[j--] == ans) --ans; // 往前找没人到达的时刻
         return ans;
    
;

6118. 最小差值平方和

贪心 + 二分查找

参考:

https://leetcode.cn/problems/minimum-sum-of-squared-difference/solution/c-by-lao-hang-n-a2sg/

class Solution 
    bool check(vector<int> diff, int mid, int cnt)
         long long sum = 0;      // sum注意要为long long,不然int类型存不下100000*100000
        for(int i: diff) 
            sum += (max(i, mid) - mid);
        
        return sum<=cnt; // 操作数小于k1+k2说明大值都可以缩小到mid
    
public:
    long long minSumSquareDiff(vector<int>& nums1, vector<int>& nums2, int k1, int k2) 
        int n = nums1.size();
        long long  sum=0;
        vector<int> diff(n);
        for(int i=0;i<n;i++)
            diff[i]=abs(nums1[i]-nums2[i]);
            sum+= diff[i];
        
    if(sum<=k1+k2) return 0;
    //二分求目标值
        int target, left = 0, right = 100001;   
    while(left<=right)
        int mid = left +(right-left)/2;
        if(check(diff,mid,k1+k2))
            target = mid;
            right=mid-1;
        else
            left = mid+1;
        
    
    //
    int res=k1+k2;
    // 将所有大于target的值变为target
        for(int i = 0; i < n; ++i) 
            if(diff[i]>target)
                res-=(diff[i]-target); // 减去将该值变为target所需的操作数
                diff[i]=target; // 更新该值为target
            
        
        // 如果剩余操作数大于0,说明还可以继续操作差值数组
        // 继续对大值们进行修改,此时数组中的大值均为target,那么就为target的项就减去1,操作数也减1
for(int i=0;i<n &&res>0;++i)
    if(diff[i]==target)
        --diff[i];
        --res;
    

 long long ans=0;
for(int i:diff)
    ans+=1ll*i*i;

return ans;
    
;

6119 元素值大于变化阈值的子数组

思路:

本题我的思路是,每次给一个子数组的长度,然后再遍历该长度下的子数组中所有元素是否能够全部符合题目条件,如果符合就把当前长度加入到一个set当中,最后遍历set的值即可。(好像不对,题目只要求有一个符合的即可)

别人的思路:

目前弄懂了单调栈的解法,还有并查集的方法目前还没有弄懂

 /*
        单调栈的应用:
        不妨枚举nums[i]并假设某包含nums[i]的子段是长度为k的某段中最小的数字
        在该段中其余数字都大于nums[i],只要nums[i]>threshold/k,那么段内的所有元素均大于threshold/k
        我们只需要求出有没有这样的nums[i]就可以知道是否有符合题意的k
        怎样维护某个nums[i]在某个段内是最小的数字?我们只需要找到nums[i]左边和右边首个严格小于nums[i]的索引
        那么索引之间就是nums[i]这段的波及范围
        快速求nums[i]左边和右边首个小于nums[i]的元素属于Next Greater问题,可以用单调栈解决
        时间复杂度:O(N) 空间复杂度:O(N)
         */
class Solution 
public:
    int validSubarraySize(vector<int>& nums, int threshold) 
        int n=nums.size();
        stack<int> s;
        int left[n];// left[i] 为左侧小于 nums[i] 的最近元素位置(不存在时为 -1)
        for(int i=0;i<n;i++)
                // 遇到nums[i]<=nums[栈顶索引] -> 弹出栈顶索引直至nums[i]>nums[栈顶索引]
            // 此时nums[栈顶索引]就是nums[i]左边首个严格小于nums[i]的数字
            // 被弹出的那些栈顶元素是不可能成为后面left[i]有效取值的,因为会优先取到当前的nums[i]
            // e.g. nums[st1]=[1,2,4,5] nums[i]=3 显然4与5不符合题意弹出 3才是符合题意的 加入后面有个6进来了
            // 必然会优先取到3而不会取更前面的4与5
            while(!s.empty() &&nums[s.top()] >=nums[i])
                s.pop();
            
            left[i]=s.empty() ?-1:s.top();  // 栈顶的必定1严格小于nums[i]并且是最近的(-1表示取全部)
            s.push(i);
        
 int right[n];
 s = stack<int>();
        for(int i=n-1;i>=0;i--)
            while(!s.empty() &&nums[s.top()] >=nums[i])
                s.pop();
            
            right[i]=s.empty() ?n:s.top();
            s.push(i);
        
// 枚举nums[i]根据其波及范围确定到k,再判断k是否合法
        for(int i=0;i<n;i++)
            int k = right[i]-left[i]-1;
           // cout<<k;
            if(nums[i]>threshold/k)return k;
        
        return -1;
    
;

总结:
本次LeetCode周赛看了评论,普遍说难度大。对我来说也是,哈哈。很自闭,赛后看解析都很费力。
本次的题目的类型分别为 1.二叉树的应用(还行)2.脑筋急转弯 3.贪心+二分 4.并查集/单调栈
本次需要补的内容有:单调栈的内容,并查集的的内容以及类型的题目。重新回顾一下 3/4两题的解题方法。
在下周的时候重点学习一下相关欠缺的内容,绝不忙不刷题。

以上是关于第102场双周赛的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode第82场双周赛

LeetCode第82场双周赛

LeetCode第82场双周赛

LeetCode 第 55 场双周赛 / 第 247 场周赛

LeetCode 第 14 场双周赛

LeetCode第69场双周赛