leetcode 第 31 场双周赛

A 在区间范围内统计奇数数目

水题

class Solution {
public:
    int countOdds(int low, int high) {
        if(low%2==0 && high%2==0)
            return (high-low)/2;
            return (high-low)/2+1;
    }
};

B 和为奇数的子数组数目

算一下前缀和遍历一遍就好了,水题

long long mod = 1e9 + 7;
class Solution {
public:
    long long numOfSubarrays(vector<int>& arr) {
        int n = arr.size();
        vector<long long> sum(n+1);
        sum[0] = arr[0];
        for(int i=1;i<n;++i)
            sum[i] = sum[i-1]+arr[i];
        int js=0;
        long long ans = 0;
        int os = 0;
        for(int i=0;i<n;++i)
        {
            if(sum[i]&1)
            {
                ans=(ans+i-js+mod+1ll)%mod;
                js++;
            }
            else
                ans=(ans+js)%mod;
            //cout<<ans<<endl;
        }
        return ans;
    }
};

C 字符串的好分割数目

维护一个前缀,维护一个后缀然后遍历一下就好,水题

int l[100010],r[100010];
        int zm[30];
class Solution {
public:
    int numSplits(string s) {
        for(int i=0;i<s.length()+3;++i)
            l[i]=r[i]=0;
        for(int i=0;i<30;++i)
            zm[i] = 0;
        for(int i=0;i<s.length();++i)
            if(zm[s[i]-'a']==0)
            {
                l[i+1] = l[i]+1;
                zm[s[i]-'a']=1;
            }
            else
                l[i+1]=l[i];
        for(int i=0;i<30;++i)
            zm[i] = 0;
        for(int i=s.length()-1;i>=0;--i)
            if(zm[s[i]-'a']==0)
            {
                r[i+1] = r[i+2]+1;
                zm[s[i]-'a']=1;
            }
            else
                r[i+1] = r[i+2];
        int ans = 0;
        for(int i=1;i<s.length();++i)
            if(l[i]==r[i+1])
                ans++;
        return ans;
    }
};

D 形成目标数组的子数组最少增加次数

一眼就想用线段树了
思路:遍历数组,每次删除尽可能长的区间
我的写法:维护一个线段树,遍历数组每次寻找连续的最小的数的位置(连续指两个数之间没有0),然后这个连续区间整体减掉这个数字。
然后我写了个憨批有问题的代码,交了发现对了,然后就有了一个其他思路。
憨批代码:

const int N = 1e5+10;
class Solution {
public:
    
    int segm[N<<3];
    int arr[N];
    int lazy[N<<3];
    void build(int pos,int l,int r)
    {
        if(l==r)
        {
            segm[pos] = arr[l];
            return;
        }
        int mid = l+r>>1;
        build(pos<<1,l,mid);
        build(pos<<1|1,mid+1,r);
        segm[pos] = min(segm[pos<<1],segm[pos<<1|1]);
    }
    void pushdown(int pos)
    {
        segm[pos<<1] -= lazy[pos];
        segm[pos<<1|1] -= lazy[pos];
        lazy[pos<<1] += lazy[pos];
        lazy[pos<<1|1] += lazy[pos];
        lazy[pos] = 0;
    }
    void md(int pos,int l,int r,int d)
    {
        if(lazy[pos])
            pushdown(pos);
        if(l==r)
        {
            segm[pos] = (1<<30);
            return;
        }
        int mid = l+r>>1;
        if(d<=mid)
            md(pos<<1,l,mid,d);
        else 
            md(pos<<1|1,mid+1,r,d);
        segm[pos] = min(segm[pos<<1],segm[pos<<1|1]);
    }
    void mdq(int pos,int l,int r,int L,int R,int x)
    {
        //cout<<pos<<" "<<l<<" "<<r<<endl;
        if(lazy[pos])
            pushdown(pos);
        if(L<=l && r<=R)
        {
            segm[pos]-=x;
            lazy[pos]+=x;
            return;
        }
        int mid = (l+r)>>1;
        if(L<=mid)
            mdq(pos<<1,l,mid,L,R,x);
        if(mid<R)
            mdq(pos<<1|1,mid+1,r,L,R,x);
        segm[pos] = min(segm[pos<<1],segm[pos<<1|1]);
    }
    int find(int pos,int l,int r,int &dd)
    {
        if(lazy[pos])
            pushdown(pos);
        if(l==r)
        {
            dd = segm[pos];
            return l;
        }
        int mid = l+r>>1;
        //cout<<segm[pos<<1]<<" "<<segm[pos<<1|1]<<endl;
        if(segm[pos<<1]<=segm[pos<<1|1])
            return find(pos<<1,l,mid,dd);
        else
            return find(pos<<1|1,mid+1,r,dd);
        segm[pos] = min(segm[pos<<1],segm[pos<<1|1]);
    }
    int findd(int pos,int l,int r,int d)
    {
        //cout<<pos<<" "<<l<<" "<<r<<" "<<d<<endl;
        if(lazy[pos])
            pushdown(pos);
        if(l==r)
            return segm[pos];
        int mid = (l+r)>>1;
        if(d<=mid)
            return findd(pos<<1,l,mid,d);
        else
            return findd(pos<<1|1,mid+1,r,d);
        segm[pos] = min(segm[pos<<1],segm[pos<<1|1]);
    }
    int minNumberOperations(vector<int>& target) {
        for(int i=0;i<target.size();++i)
            arr[i+1] = target[i];
        int n = target.size();
        build(1,1,n);
        int ans = 0;
        for(int i=1;i<=n;++i)
        {
            while(1)
            {
                int dd;
                int xb = find(1,1,n,dd);

                if(dd==0)
                {
                    if(xb==i)
                        break;
                    xb--;
                    int e = findd(1,1,n,xb);
                    ans += e;
                    mdq(1,1,n,i,xb,e);
                }
                else
                {
                        ans += dd;
                        mdq(1,1,n,i,n,dd);
                }
            }
            md(1,1,n,i);
        }
        return ans;
    }
};

真正的解法
递增的就作差加上贡献,递减的不用管

class Solution {
public:
    int minNumberOperations(vector<int>& target) {
        int ans = 0;
        int d = 0;
        for(int i:target)
        {
            int c = i-d;
            if(c>=0)
            {
                ans+=c;
                d+=c;
            }
            else
            {
                d = i;
            }
        }
        return ans;
    }
};

这个也写的很憨,其实可以这么写

class Solution {
public:
    int minNumberOperations(vector<int>& target) {
        int ans = target[0], n = target.size();;
        for(int i=1;i<n;i++)
            if(target[i] > target[i-1])
            	ans += target[i] - target[i-1];
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值