力扣——第88场双周赛

力扣——第88场双周赛

6212. 删除字符使频率相同

问题解析

可以先记录下每个字符的出现次数,然后我们分情况讨论:

  1. 是否仅有一个字符的出现次数比其它的字符要多1,如果有,返回true。如果没有或者有多个,返回false;
  2. 是否有字符的出现次数和其它字符出现次数相差不止1,如果有,返回false;
  3. 是否所有的字符出现次数都是1,如果是,返回true;
  4. 是否只有一种字符,如果是,返回true。

AC代码

class Solution {
public:
    unordered_map<char,int>mymap;
    bool equalFrequency(string word) {
        for(auto &i:word)
            mymap[i]++;
        int mn=0;
        bool flag=true,st=true;
        for(auto& i:mymap)
        {
            if(flag)mn=i.second,flag=false;
            else if(mn!=i.second)
            {
                if(!st)return false;
                else if(abs(mn-i.second)==1)
                {
                    mn=min(mn,i.second);
                    st=false;
                }
                else return false;
            }
        }
        if(st)
        {
            if(mn==1||mymap.size()==1)return true;
            else return false;
        }
        return true;
    }
};

6197. 最长上传前缀

问题解析

方便的做法:

用c++的set容器先将1~n的数都存起来,当上传哪个视频的时候,就在set中删除它。因为set自动排序的原因,最小的都在最前面,我们把set的第一个元素 - 1输出即可,如果set为空,输出n。

class LUPrefix {
public:
    set<int>st;
    int len;
    LUPrefix(int n) {
        len=n;
        for(int i=1;i<=n;i++)st.insert(i);
    }
    
    void upload(int video) {
        st.erase(video);
    }
    
    int longest() {
        if(st.empty())return len;
        return *st.begin()-1;
    }
};
复杂的做法:

用线段树,每次给位置为i的位置赋值为1,然后询问的时候,在线段树上二分,找第一个0出现的位置x,答案就是x-1.

class LUPrefix {
public:
    int f[4*100050];
    int len;
    void revise(int k,int l,int r,int x)
    {
        if(l==r)
        {
            f[k]=1;
            return;
        }
        int m=(l+r)/2;
        if(x<=m)revise(k+k,l,m,x);
        else revise(k+k+1,m+1,r,x);
        f[k]=f[k+k]+f[k+k+1];
    }
    int serch(int k,int l,int r)
    {
        if(l==r)return l;
        int m=(l+r)/2;
        if(f[k+k]!=m-l+1)return serch(k+k,l,m);
        else return serch(k+k+1,m+1,r);
    }
    LUPrefix(int n) {
        memset(f,0,sizeof f);
        len=n;
    }
    
    void upload(int video) {
        revise(1,1,len,video);
    }
    
    int longest() {
        if(f[1]==len)return len;
        return serch(1,1,len)-1;
    }
};

6213. 所有数对的异或和

首先,我们知道异或的一个性质:如果一个数被异或了偶数次,那么就相当于没异或这个数。

然后我们看两个数组,nums1的元素要先和nums2的元素各异或一次,组成新数组,在计算新数组的异或和。

那么对于nums[i]来说,在新数组中,它提供的元素就有nums1[i]nums2[0],nums1[i]nums2[1],……nums1[i]^nums2[n-1]。如果这些数进行异或运算,就可以转化成n个nums1[i]的异或和,异或上整个nums2数组的异或和。那么,如果nums2数组长度为偶数,n个nums1[i]的异或和就相当于0,结果就是nums2数组的异或和。如果nums1也是偶数长度,就相当于偶数个nums2数组的异或和,答案为0。把nums1和nums2反过来也一样。

此时我们就可以分情况讨论了:

  1. 如果nums1数组和nums2数组都是偶数长度,答案为0
  2. 如果只有nums1数组是奇数长度,答案就是nums1数组的异或和。
  3. 如果只有nums2数组是奇数长度,答案就是nums2数组的异或和。
  4. 如果都是奇数长度,答案就是nums1数组的异或和异或上nums2的异或和。

AC代码

class Solution {
public:
    int xorAllNums(vector<int>& nums1, vector<int>& nums2) {
        int n=nums1.size(),m=nums2.size();
        if(n%2==0&&m%2==0)return 0;
        else if(n%2==0)
        {
            int res=0;
            for(int i=0;i<n;i++)
            {
                res^=nums1[i];
            }
            return res;
        }
        else if(m%2==0)
        {
            int res=0;
            for(int i=0;i<m;i++)
            {
                res^=nums2[i];
            }
            return res;
        }
        int res=0;
        for(int i=0;i<n;i++)
        {
            res^=nums1[i];
        }
        for(int i=0;i<m;i++)
        {
            res^=nums2[i];
        }
        return res;
    }
};

6198. 满足不等式的数对数目

问题解析

式子nums1[i] - nums1[j] <= nums2[i] - nums2[j] + diff,可以转化成nums1[i] - nums2[i] <= nums1[j] - nums2[j] + diff

那么我们可以那nums2数组减去nums1数组来获得一个新的数组nums3,我们只要知道nums3[i]<=nums[j]+diff的个数即可。

我们可以用线段树,从左往右遍历数组,每次计算1到nums3[i]+diff的区间和,这就是这个数能提供答案。再把nums3[i]位置的值++。

要注意的是,nums3[i]可能为负数,此时这就不能直接把nums3[i]位置的值++。对此,我们可以对所有数加一个偏移量,把负数变成正数,把正数变成更大的正数。

AC代码

class Solution {
public:
    typedef long long ll;
    long long f[4*100050];
    void revise(ll k,ll l,ll r,ll x)
    {
        if(l==r)
        {
            f[k]++;
            return;
        }
        int m=(l+r)/2;
        if(x<=m)revise(k+k,l,m,x);
        else revise(k+k+1,m+1,r,x);
        f[k]=f[k+k]+f[k+k+1];
    }
    ll calc(ll k,ll l,ll r,ll x,ll y)
    {
        if(l==x&&r==y)return f[k];
        int m=(l+r)/2;
        if(y<=m)return calc(k+k,l,m,x,y);
        else 
            if(x>m)return calc(k+k+1,m+1,r,x,y);
            else return calc(k+k,l,m,x,m)+calc(k+k+1,m+1,r,m+1,y);
    }
    long long numberOfPairs(vector<int>& nums1, vector<int>& nums2, int diff) {
        memset(f,0,sizeof f);
        long long n=nums1.size(),res=0;
        for(int i=0;i<n;i++)
        {
            int x=nums1[i]-nums2[i]+diff+30050;
            res+=calc(1,1,100000,1,x);
            revise(1,1,100000,x-diff);
        }
        return res;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值