您的位置:首页 > 其它

算法学习(十二)最大连续乘积子串、字符串编辑距离

2016-05-10 22:19 549 查看

最大连续乘积子串

题目描述:给一个浮点数序列,取最大乘积连续子串的值,例如-2.5,4,0,3,0.5,8,-1,则取出的最大乘积子串为3,0.5,8。也就是说,上述数组中,3,0.5,8这3个数的乘积3*0.5*8 = 12是最大的,而且是连续的。

分析:

注意子串和字序列的区别。

子串:是串的连续的部分。

子序列:是串中不改变顺序,但是是去掉个别元素的到新的序列。

1,连续数的乘积,最简单的就是穷举法,就是区间[i…j]之间的数的乘积,和最大值max比较,最后输出max。但是时间复杂度很大几乎为O(N^2)。

2,其实这个有点类似最大子数组和问题,求最大子数组和时,遍历时,如果sum <0,sum = data[i]。

不过在求乘积的时候,还是有区别的,因为在这一时刻乘积为负,在下一个时刻乘积就又变为正,所以单纯的判断<0就舍去的方法行不通,我们可以声明两个变量,一个表示乘积最大,一个表示乘积最小,两者都是动态变化的,乘积最大的可能会再乘以某个数后变为最小,乘积最小的可能变为最大。

3,可以使用动态规划的方法,假设数组为a[],Max表示以a结尾的最大连续子串的乘积值,Min表示以a结尾的最小的子串的乘积值:

Max = max{a,Max[i-1]*a,Min[i-1]*a};

Min = min{a,Max[i-1]*a,Min[i-1]*a};

初始状态:Max[1] = Min[1] = a[0];

1,穷举法

#include <iostream>
using namespace std;

double max_product(double * data,int N)
{
double max = 0;
int start,end;
int i,j;
double result;
for(i = 0;i< N;i++)
{
result = data[i];
for(j = i+1;j<N;j++)
{
result*= data[j];
if(result > max)
{
max = result;
start = i;
end =j;
}
}
}
return max;   //区间就是[start,end]
}


方法二:

double max_prod(double *data,int N)
{
int i;
double maxcurrent = 1;  //当前的最大乘积
double maxprod = 1;      //保存的最大乘积
double mincurrent = 1;
double minprod = 1;
for(i = 0;i< N;i++)
{
maxcurrent *= data[i];
mincurrent *=data[i];
if(mincurrent > maxprod)
maxprod = mincurrent;
if(maxcurrent > maxprod)
maxprod = maxcurrent;
if(mincurrent < minprod)
minprod = mincurrent;
if(maxcurrent < minprod)
minprod = maxcurrent;
if(mincurrent > maxcurrent)
swap(mincurrent,maxcurrent);
if(maxcurrent < 1)   //关键点,初始化为1,如果最大值比1小,就重置为1,有点类似最大子数组和。
maxcurrent = 1;
}
return maxprod;
}


方法三: 动态规划

double func(double * data,int N)
{
double *maxA = new double
;
double *minA = new double
;
maxA[0] = minA[0] = data[0];
double Max = maxA[0];
int i;
for(i = 1;i< N;i++)
{
maxA[i] = max( data[i],maxA[i-1]*data[i],minA[i-1]*data[i]);
minA[i] = min(data[i],maxA[i-1]*data[i],minA[i-1]*data[i]);
Max = max(Max,maxA[i]);
}
return Max;
}


扩展:最大n-1个数组合中乘积最大的值

题目描述:

给定一个长度为N的整数数组,只允许用乘法,计算任意个(N-1)个数的组合中乘积最大的值。

如:a[] = {-1,2,3,4};最大乘积为2*3*4 = 24。

分析:

实际上就是计算(N-1)个数的组合乘积,假设第i个元素被排除在乘积之外,剩余的元素乘积。我们可以把这N-1个数的组合找出来,分别计算他们的乘积,并比较大小,总共有N个(N-1)组合,总的时间复杂度为O(N^2),这种时间复杂度太高。

我们可以使用空间换时间的思想,以元素i为分割点,将原数组分成两部分,构建数组s[i]来表示数组前i个元素的乘积,t[i]表示数组后(N-i)个元素的乘积,t[i] = t[i+1]* a[i];

设数组 p[i]为数组除第i个元素外,其他N-1个元素的乘积,

p[i] = s[i-1]*t[i+1]。

需要从头到尾,再从尾到头扫描数组两次来得到数组s[] 和t[],进而线性时间得到p[],然后遍历p[],得到最大值。

#include <iostream>
using namespace std;

int max_prod(int * a,int N)
{
int i;
int prod1 ,prod2;
prod1 = prod2 = 1;
int Max = 0;
int *s = new int(N);
int * t = new int (N);
int *p = new int(N);
for(i = 0;i< N;i++)  //得到s[i]
{
prod1 *= a[i];
s[i] = prod1;
}
for(i = N-1;i>=0;i--)
{
prod2 *= a[i];
t[i] = prod2;
}
for(i= 0;i< N;i++)
{
p[i] = s[i-1]*t[i+1];
if(p[i]>Max)
Max = p[i];
}
delete[]s;  //释放内存
delete[]t;
delete[]p;
return Max;
}
int main()
{
int data[5]= {1,2,-3,1,3};
cout << "max is" << max_prod(data,5) << endl;
return 0;
}


字符串编辑距离

题目描述:给定一个源串和目标串,能够对源串进行如下操作:

1,在给定位置上插入一个字符

1,替换任意字符

3,删除任意字符

写一个程序,返回最小操作数,使得对源串进行这些操作后等于目标串,源串和目标串的长度都小于2000。

分析:

就是从源串变为目标串,做的最少的操作,操作包括三种,没一次可以从中选一个。

s[0…i]表示源串

t[0…j]表示目标串。

f[i,j]表示从s[0…i]到t[0…j]的最小编辑距离。

可以使用动态规划思想:操作就是三种,添加,删除,替换

f[i,j] = min { f[i-1,j]+1 ,f[i,j-1]+1 ,f[i-1][j-1]+(s[i]== t[i]?0:1)}

f[i-1,j]+1 :表示的是删除一个数,f[i-1,j]表示s[0…i-1]到t[0…j]的最小编辑距离,这个时候源串已经能够变为目标串,于是就可以删除多余的s[i]。

f[i,j-1]+1:表示的是添加一个数,f[i,j-1]表示的是s[0…i]到t[0…j-1]的最小编辑距离,还没有转化为目标串,还少一个t[i],进行添加操作。

f[i-1,j-1]+(s[i]==t[i] ?0:1) :表示替换操作,f[i-1,j-1]表示的是s[0…i-1]到t[0…i-1]的最小编辑距离,此时还未转化为目标串,而且源串有剩余,关键点就是s[i]和t[i]是否相等,如果相等,说明已经完成转化操作,[f[i-1,j-1]就是要求得,如果不相等,需要对源串进行一次替换,需要f[i-1,j-1]+1次操作。

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
int min(int a,int b,int c)
{
if(a > b)
{
if(b > c)
return c;
else
return b;

}
else
{
if(a > c)
return c;
else
return a;
}
}
int min_change(char * src,int n,char * dest,int m)
{
if(src == NULL || dest == NULL || n< 0 || m< 0)
return 0;
static int f[2000][2000];  //栈内存有限,注意加static
int i,j;
for(i = 1;i< n;i++)
{
if(src[0] == dest[0])
f[0][0] = 0;
else
f[0][0] =1;
if(src[i]== dest[0])
f[i][0] =i;
else
f[i][0] =i+1;
}
for(i = 1;i< m;i++)
{
if(dest[i] == src[0])
f[0][i] =i;
else
f[0][i] =i+1;
}
int result;
for(i = 1;i<n;i++)
{
for(j= 1;j<m;j++)
{
f[i][j] = min(f[i-1][j]+1,f[i][j-1]+1,f[i-1][j-1]+(src[i]==dest[j]?0:1));
result = f[i][j];
}
}
return result;

}
int main()
{
char a[10] = "bcefg";
char b[10] = "abedg";
cout << "the cout is " << min_change(a,5,b,5) << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: