1,求最长回文子串
中心法应该是最为普通的办法,时间复杂度O(n^2)。当然用后缀树或者后缀数组也可以降低时间复杂度,不过这个我不熟就不写了。输入字符串假设为”abcdedc";从左到右依次考虑以a为中心最长回文是多少,以ab中间的空为中心最长回文是多少,以b为中心最长回文是多少.......
代码如下:
int LPS(char *str, int n)
{
assert(str != NULL);
int len = 0;
int i, temp;
int l,r;
for (i=0; i<n; i++)
{
l = i-1;
r = i+1;
temp = 1;
while (l>=0 && r<n && str[l]==str[r])
{
l--;
r++;
temp = temp + 2;
}
if (temp > len)
len = temp;
l=i;
r=i+1;
temp = 0;
while (l>=0 && r<n && str[l]==str[r])
{
l--;
r++;
temp = temp + 2;
}
if (temp > len)
len = temp;
}
return len;
}
2,求最长回文子序列
这道题可以用递归来解决。对于一个输入的数组,首尾下标分别为begin,end,函数原型为int LPS(int a[], int begin, int end);我们可以分为下列几种情况来讨论:
1,begin>end;直接返回0;2,begin == end;只有一个元素,天然就是回文,返回1;
3,begin<end时分两种情况讨论
1) a[begin] == a[mid];应该返回 LPS(a, begin+1, end-1) + 2;两边向中间收拢。
2) a[begin] != a[mid];这时有两种情况,应该返回较大值,即max(LPS(a,begin+1,end), LPS(a,begin,end-1))
根据上述思路形成递归代码:
int LPS(char *s, int begin, int end)
{
assert(s != NULL);
if (begin > end)
return 0;
if (begin == end)
return 1;
else
{
if (s[begin] == s[end])
return LPS(s, begin+1, end-1) + 2;
else
{
return max(LPS(s,begin+1,end), LPS(s,begin,end-1));
}
}
}
3,求最长公共子串
int LCS2( char *str1, char *str2)
{
int len1 = strlen(str1);
int len2 = strlen(str2);
int *cl = new int[len2+1];
int max = 0;
int i, j;
int start, end;
for (i=0; i<=len2; i++)
{
cl[i]=0;
}
for (i=0; i<len1; i++)
{
for (j=len2-1; j>=0; j--)
{
if (str1[i] == str2[j])
{
cl[j+1] = cl[j] + 1;
if (cl[j+1] > max)
{
max = cl[j+1];
end = j;
}
}
else
{
cl[j+1] = 0;
}
}
}
start = end - max + 1;
for (i=start; i<=end; i++)
{
cout << str2[i] << " " ;
}
return max;
}
4,求最长公共子序列
int LCS(char str1[], int astart, int aend, char str2[], int bstart, int bend)
{
if (astart > aend || bstart > bend)
return 0;
if (str1[astart] == str2[bstart])
{
return LCS(str1,astart+1,aend,str2,bstart+1,bend) + 1;
}
else
{
return max(LCS(str1,astart+1,aend,str2,bstart,bend), LCS(str1,astart,aend,str2,bstart+1,bend));
}
}
5,求最长连续递增子串
比如输入”abcd12345ed125ss123456789“,最长的为”123456789“,所以返回9。这个题比较简单,顺序遍历即可,时间复杂度O(n)。
代码:
int LIS(char *str)
{
assert (str != NULL);
int len = strlen(str);
int cur = 1, max = 0;
int start, end, temp = 0;
for (int i = 1; i < len; i++)
{
if (str[i] == str[i-1] + 1)
{
cur++;
}
else //不满足连续递增了,立即更新一些状态
{
if (cur > max)
{
max = cur;
start = temp;
end = i-1;
}
temp = i;
cur = 1;
}
if (i == len-1) //这里是特殊处理,针对处于整个字符串末尾的最长字符串
{
if (cur > max)
{
max = cur;
start = temp;
end = i;
}
}
}
for (i = start; i <= end; i++)
cout << str[i];
cout << endl;
return max;
}
6,求最长递增子序列
输入一个字符串str { "a d e f e g“},其最长递增子序列为 "a d f g“ 或者 ”a e f g “ 。该如何实现这个算法呢?我们定义一个数组lis[N]表示以下标 i 结尾的元素的最长递增子序列长度。lis[i]初始时为1,此时只有本身一个元素,但是下标i之前的元素可能大于str[i];所以要遍历从0到i-1的元素,检查是否有元素str[j]值大于str[i],若有且满足lis[j]+1>lis[i],lis[i]=lis[j]+1;最后扫描lis[N]求出最大值即可。这种方法整个时间复杂度O(n^2)。
代码:
int LIS(char *str)
{
assert(str != NULL);
int len = strlen(str);
int i, j, max = 0;
int *lis = new int[len];
for (i=0; i<len; i++)
{
lis[i] = 1;
for (j=0; j<i; j++)
{
if (str[j] < str[i] && lis[j] + 1 > lis[i])
{
lis[i] = lis[j] + 1;
}
}
}
for (i=0; i<len; i++)
{
if (lis[i] > max)
max = lis[i];
}
return max;
}
这个问题还可以优化到O(nlgn),以后补充。
7,求最大子串和
这是最经典最常见的一道题,这里直接给出代码,代码中加了两个变量来标记最大子串的起始位置。
int SubMaxSum(int a[], int n) //子数组最大和
{
int sum=0;
int max=0;
int begin, end;
int temp = 0;
for (int i=0; i<n; i++)
{
if (sum + a[i] < 0)
{
sum = 0;
temp = i+1;
}
else
{
sum += a[i];
if (sum > max)
{
max = sum;
begin = temp;
end = i;
}
}
}
for (i=begin; i<=end; i++)
cout << a[i] << " ";
cout << endl;
return max;
}
8,求最大子串积
见这篇博文: http://blog.youkuaiyun.com/cl512976287/article/details/21337185