最长的含有相同数目的01子串 & 括号匹配问题


题目:给定一个字符串,字符串中只包含‘0’和‘1’。请找到一个最长的子串,使得其中0和1的数量是相同的

例1:“10101010” 结果就是其本身

例2:“0011110”结果是“0011”


扩展:给定一个字符串,字符串只包含‘(’和‘)’,请找出一个最长的子串,使得该子串满足括号匹配法则。

例1:“(()())()()”结果为自身

例2:“())()()(”结果为“()()"


错误的解法:(没考虑仔细)

解:扩展后题目要求更严格一点,但解题思路是一样的:

用栈保存字符,扫描字符串,如果

1)当前字符与栈顶匹配(‘0’和‘1’相互匹配,‘)’与‘(’匹配),删除栈顶,计算长度,遍历下一个字符。

2)当前字符与栈顶不匹配,当前字符入栈,遍历下一个字符。

代码1:与讲解稍有不同,栈内存的是下标不是字符,这样方便计算长度。

时间复杂度:O(n),空间复杂度:最坏为O(n)

#include 
#include 
#include 
using namespace std;

void longestSubsequence(const string &str, int &s, int &t){
	stack q;
	int maxLen = 0;
	for(int i = 0; i

PS:此代码与”柱状图中找最大矩形 &  矩阵中找最大的仅含相同值的矩形区域”的代码有点相似。


此解法总是尽量向左匹配,错误!例子:0011110000100 结果不正确。



============================割=========================================

正确的解法:

解法I:直观的动态规划解法:

f[i] = f[j] + (i - j), 其中j为max{ j | j < i,并且 串"i+1, i+2,...,j"为合法串(0、1个数相等,或者 满足括弧法则)}

若找不到满足条件的j,则f[i] = 0;

最后的结果为 max{ f[i] }。

此算法时间复杂度为O(n^2),空间复杂度O(n),同时适用原问题和扩展问题。


解法II:对解法I进行优化:

由于解法I需要遍历找j,所以时间复杂度比较高。

实际上,可以根据01串的特点,在O(1)的时间确定出j。

扫描字符串,将扫描到的0的个数与1的个数的差,记录在A数组中,则A[i]值在区间[-n, n],n为总的字符个数。

状态转移方程可改写为:

f[i] = f[j] + (i - j), 其中j为max{ j |  j < i,并且 A[j] == A[i] }。

如果在算f的时候,同时记录数组B,B[k]表示差值为k的最后出现的位置,注意此处k理论上可以为负值,那么状态转移方程可以改写为:

f[i] = f[j] + (i - j), 其中j=B[A[i]]

此算法,时间复杂度O(n),空间复杂度3 * O(n)。 仅适用于原问题。


解法III:对解法II进行 简化:

仔细观察会发现,f[i]的值等于:差值A[i]最早出现的位置,与i的距离。所以可以对解法II进行简化,见代码2

此算法,时间复杂度与解法II一样,同为O(n),空间复杂度同为O(n),但系数变小了2 * O(n)。 仅适用于原问题。

代码2:

#include 
#include 
#include 
#include 
using namespace std;

void longestSubsequence(const string &str, int &s, int &t){
	int strLen = str.size();
	vector v(strLen * 2 + 1, -1);
	int maxLen = 0;
	int diff = 0;
	for(int i = 0; i



你可能感兴趣的:(Algorithms,★★★★,C++)