1393 0和1相等串(O(N)求值相等的最远距离+易错:偏移量)

题目描述:

1393 0和1相等串

 

给定一个0-1串,请找到一个尽可能长的子串,其中包含的0与1的个数相等。

 

输入

一个字符串,只包含01,长度不超过1000000。

输出

一行一个整数,最长的0与1的个数相等的子串的长度。

输入样例

1011

输出样例

2

思路:

       统计出前i个数中0/1的个数,然后对于个数相等的区间满足sum1[y]-sum1[x-1]==sum0[y]-sum0[x-1];
    即sum1[y]-sum0[y]==sum1[x-1]-sum0[x-1],求出每项i的sum1-sum0,然后排个序找距离最远的相等值即可,

复杂度O(NlogN)。

       O(N)的算法,首先,该类题目为了方便处理,可以将0转换为-1,前缀和,然后即求相等值的最大距离,

求相等值的最大距离这里可以用桶的思想,记录1~1e6每个值的最小下标和最大下表。

代码实现:O(NlogN)

#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#include<cstdio>
#include<algorithm>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=1e6+100;
int arr[N],mak[N];
int sum1[N],sum0[N];
pair<int,int> sum[N];
int main() {
	freopen("E:\\io.txt","r",stdin);
    string str;
    cin>>str;
    int n=str.length();

    for(int i=1; i<=n; i++) {
        if(str[i-1]=='1')sum1[i]=1;
        else sum0[i]=1;
    }
    for(int i=1; i<=n; i++) {
        sum1[i]=sum1[i-1]+sum1[i];
        sum0[i]=sum0[i-1]+sum0[i];
    }
    //sum1[y]-sum1[x-1]==sum0[y]-sum0[x-1];
    //sum1[y]-sum0[y]==sum1[x-1]-sum0[x-1];
    for(int i=1; i<=n; i++)sum[i].first=sum1[i]-sum0[i],sum[i].second=i;
    stable_sort(sum,sum+1+n);
    int ans=0;
    for(int i=0; i<n; i++) {
        int pos=i;
        int l=i,r=n;
        while(l<=r) {
            int mid=(l+r)/2;
            if(sum[mid].first<sum[i].first)l=mid+1;
            else if(sum[mid].first==sum[i].first) {
                l=mid+1;
                pos=mid;
            } else r=mid-1;
        }
        ans=max(ans,sum[pos].second-sum[i].second);
    }
    cout<<ans<<endl;
    return 0;
}

O(N)解法:

几个易错点:直接映射的化映射值可能为负数,要加一个偏移量,然后 原来的 0 现在变成

1e6。

#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#include<cstdio>
#include<algorithm>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e6+100;
int arr[N],mak[N];
int sum[N];
pair<int,int> c[N];
int main() {
	//freopen("E:\\io.txt","r",stdin);
	for(int i=0;i<=2000000;i++)c[i].second=-INF,c[i].first=INF;
    string str;
    cin>>str;
    int n=str.length();
	for(int i=1;i<=n;i++){
		if(str[i-1]=='0')arr[i]=-1;
		else arr[i]=1;
	}
	for(int i=1;i<=n;i++)sum[i]=sum[i-1]+arr[i];
	for(int i=1;i<=n;i++)sum[i]+=1e6;
	c[1000000].first=0;
	for(int i=1;i<=n;i++){
		if(i<c[sum[i]].first)c[sum[i]].first=i;
		if(i>c[sum[i]].second)c[sum[i]].second=i;
	}
	int ans=0;
	for(int i=0;i<=2e6;i++)ans=max(ans,c[i].second-c[i].first);
	cout<<ans<<endl;
    return 0;
}

The end

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值