动态规划-最长平衡子串(2018北邮机试真题)

题目:

最长平衡串
给定只含0、1的字符串,找出最长平衡子串的长度(平衡串:包含0和1的个数相同)
输入包含两行:
    第一行输入串长n(1=<n<=100000)
    第二行输入字符串
Example:
Input:
8
11011011
Output:
4

[思路分析]:

        看到题目想到了动态规划中前缀和的思想。定义dp[i]表示前i项和,但是发现,0和1的前i项和并没找到什么规律。
将字符串s中的0看成-1,这样的话,前i项若相等(dp[j]=dp[k],其中k>j),那么,对应下标之间的字符串中0和1的个数相等(即s[j],...s[k-1]中0与1个数相等),只需找到dp[i]相等时,坐标之差的最大值
         得到状态转移方程:
         dp[0]=0;
          i>=1时,
         s[i-1]=0, dp[i]=dp[i-1]-1
         s[i-1]=1,dp[i]=dp[i-1]+1
         接下来,如何寻找前缀和相等时的下标呢?如何找到最大值?起初想到放到数组里面,记录每个dp[i]的位置,dp[i]相等时,计算位置之差,但是,字符串最长10万,数组开辟空间太大(dp[i]取值-10万到10万),而且,基本上用不到,最好是遍历一遍,若某个dp[i]有记录最起始位置begin,则算长度i-begin,没有的话,就记作起始位置begin=i;
            再用一个变量max_substr进行最大值的记录。可以用map,进行dp[i]与其最起始位置的映射。

有关map的简单使用,可参考:https://blog.csdn.net/lady_killer9/article/details/79283548

手算模拟:

例子模拟
下标i012345678
字符串s11011011 
转换串c11-111-111 
前缀和dp[i]012123234
最起始位置begin012125258

其中,转换串没有必要在代码中体现,判断一下s[i]是0还是1即可,此处是为了读者看着方便。dp[i]要往后多算一个,才能在算最长平衡子串时,包括最后一个。可以看出,dp[i]=0与dp[i]=4时,没有对应平衡串。dp[i]=1时,最长平衡串为10;dp[i]=2时,最长平衡串为0110;dp[i]=3时,最长平衡串为01。综上,最长平衡串长度为4,即0110。

代码:


/*
Project:
Date:    2019/01/07
Author:  Frank Yu
题目:最长平衡串
给定只含0、1的字符串,找出最长平衡子串的长度(平衡串:包含0和1的个数相同)
输入包含两行:
	第一行输入串长n(1=<n<=100000)
	第二行输入字符串
Example:
Input:
8
11011011
Output:
4
Project:
Date:    2019/01/07
Author:  Frank Yu
[思路分析]:看到题目想到了动态规划中前缀和的思想。定义dp[i]表示前i项和,但是发现,0和1的前i项和并没找到什么规律。
			将字符串s中的0看成-1,这样的话前i项若相等(dp[j]=dp[k],其中k>j),那么,对应下标之间的字符串中0和1的
			个数相等(即s[j],...s[k-1]中0与1个数相等)
			得到状态转移方程:
            dp[0]=0;
			i>=1时,
		    s[i-1]=0, dp[i]=dp[i-1]-1
		    s[i-1]=1,dp[i]=dp[i-1]+1
			接下来,如何寻找前缀和相等时的下标呢?如何找到最大值?起初想到放到数组里面,记录每个dp[i]的位置,
			dp[i]相等时,计算位置之差,但是,字符串最长10万,数组开辟空间太大(dp[i]取值-10万到10万),而且,
			基本上用不到,最好是遍历一遍,若某个dp[i]有记录最起始位置begin,则算长度i-begin,没有的话,就记作起始位置begin=i;
			再用一个变量max_substr进行最大值的记录。可以用map,进行dp[i]与其最起始位置的映射。
*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<set>
#include<list>
#include<vector>
#include<map>
#include<iterator>
#include<algorithm>
#include<iostream>
#define Maxsize 100000
using namespace std;
int main()
{
	int len=0;int dp[Maxsize];
	int start = 0;
	int begin = 0;
	int max_substr = 0;	
	map<int, int> mymap;//映射dp[i]与其对应的最起始位置
	string s="";
	memset(dp,0,sizeof(dp));
	cin >> len >> s;
	dp[0] = 0;
	//cout << "dp[0]=" << dp[0] << endl;
	for (int i=1;i<=len;i++)//注意等于,dp[i]的下标多一个,因为要算前缀和,最后一个也要算
	{
		if('0'==s[i-1]) dp[i] = dp[i - 1] - 1;
		else dp[i] = dp[i - 1] + 1;
		//cout << "dp[" << i << "]=" << dp[i]<<endl;
	}
	//利用map记录每个dp[i]的最起始位置
	for (int i=1;i<=len;i++)
	{
		//得到dp[i]对应的起点
		begin = mymap[dp[i]];
		//cout << "begin:" << begin << endl;
		if (begin == 0 && dp[i] != 0) {    //除去第一个已记录的dp[i]与begin
			mymap[dp[i]] = i;              //记录dp[i]最起始位置
			//cout << mymap[dp[i]] <<endl;
		}
		else {
			//更新当前dp[i]最大子串
			if (i - begin > max_substr) {
				max_substr = i - begin;
				start = begin;
				//cout << "start:"<< start<<endl;
			}
		}
	}
	cout<< max_substr<<endl;
	/*输出最长子串(若长度相等,输出起始下标最小的)
	cout << s.substr(start,max_substr);*/
	return 0;
}

结果截图:

结果截图

代码中有调试时的一些输出,读者可以复制代码,输出看一下。

更多数据结构与算法实现:数据结构(严蔚敏版)与算法的实现(含全部代码)

有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lady_killer9

感谢您的打赏,我会加倍努力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值