算法學習(十二)最大連續乘積子串、字符串編輯距離

最大連續乘積子串

題目描述:給一個浮點數序列,取最大乘積連續子串的值,例如-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[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 <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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章