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

最大连续乘积子串

题目描述:给一个浮点数序列,取最大乘积连续子串的值,例如-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 
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;jif(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[N];
    double *minA = new double[N];
    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 
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 
#include 
#include 
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;ifor(j= 1;j1][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;
}

你可能感兴趣的:(算法学习)