力扣第312场周赛

第一题:按身高排序

思路:开一个索引数组存按身高排序后的下标即可

代码

class Solution {
public:
    vector<string> sortPeople(vector<string>& names, vector<int>& heights) {
        vector<string> ans;
        int n=names.size();
        vector<int> idx(n);
        iota(idx.begin(),idx.end(),0);
        sort(idx.begin(),idx.end(),[&](int a,int b){
             return heights[a]>heights[b];
        });
        for(int i=0;i<n;i++){
            ans.push_back(names[idx[i]]);
        }
        return ans;
    }
};

第二题:按位与最大的最长子数组

思路:题意是在保证最大的基础上最长,一个数与其他数按位与运算所得到的值一定是小于等于其中较大的那一个数,所以要想保证最大就要只看最大的数,看数组中最大的数出现的最大连续长度

代码

class Solution {
public:
    int longestSubarray(vector<int>& nums) {
        int n=nums.size();
        int maxm=*max_element(nums.begin(),nums.end());
        int ans=0;
        for(int i=0;i<n;i++){
            int j=i;
            while(j<n&&nums[j]==maxm){
                j++;
            }
            ans=max(ans,j-i);
            i=j;
        }
        return ans; //双指针模板
    }
};

第三题:找到所有好下标

思路:动态规划 相当于正向逆向求两次非递增子序列的长度 (需要注意的是该题得出来的i不一定是极小值,因为其只是对i的左右两边做了要求,但i本身没有,nums[i]可能比nums[i-1]和nums[i+1]都要大)

代码

class Solution {
public:
    vector<int> goodIndices(vector<int>& nums, int k) {
        int n=nums.size();
        vector<int> f(n),g(n);
        for(int i=0;i<n;i++){
            f[i]=1;
            if(i&&nums[i-1]>=nums[i]) f[i]=f[i-1]+1;
        }

        for(int i=n-1;i>=0;i--){
            g[i]=1;
            if(i+1<n&&nums[i]<=nums[i+1]) g[i]=g[i+1]+1;
        } //要把长度叠加到i上 所以逆向求非递增当作正向非递减

        vector<int> res;
        for(int i=k;i<n-k;i++){
            if(f[i-1]>=k&&g[i+1]>=k) res.push_back(i);
        } //只要i的左右两边同时满足条件则加入答案数组 因为是按顺序遍历所以不用排序
        return res;
    }
};

第四题:好路径的数目

思路:先排序,然后把权值相同的点分块,相同连通块的点才能组成一条路径

代码

class Solution {
public:
    vector<int> p;

    int find(int x){
        if(p[x]!=x) p[x]=find(p[x]);
        return p[x];
    }
    int numberOfGoodPaths(vector<int>& vals, vector<vector<int>>& edges) {
        int n=vals.size();
        vector<vector<int>> g(n); //存图

        for(auto &e:edges){
            g[e[0]].push_back(e[1]);
            g[e[1]].push_back(e[0]);
        }

        vector<int> q(n); //排序后的索引数组
        p.resize(n);
        for(int i=0;i<n;i++) p[i]=q[i]=i; //初始化索引和并查集
        sort(q.begin(),q.end(),[&](int a,int b){
            return vals[a]<vals[b];  //让索引按照点权值大小排序
        });
        //q中存的是按权值排序好的各点
        int res=0;


        for(int i=0;i<n;i++){
            int j=i+1;
            while(j<n&&vals[q[i]]==vals[q[j]]) j++;

            for(int k=i;k<j;k++){ //[i,j)都是权值相同的点
                int x=q[k]; //找到点
                for(int y:g[x]){ //遍历该点能到达的且权值比自己小的点
                    if(vals[x]>=vals[y]){
                        p[find(x)]=find(y); //把该点加入到x的连通块中
                    }
                }
            }

            unordered_map<int,int> mp;
            for(int k=i;k<j;k++) mp[find(q[k])]++; //权值相同的点分块  相同连通块权值相同的点才能练成路径

            for(auto &[u,v]:mp) res+=v*(v+1)/2; //单独一个点也算一条路径 n*(n-1)/2+n=n*(n+1)/2

            i=j-1; //前面是j=i+1  这里对应

        }
        return res;
    }
};

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值