最大連續乘積子串
題目描述:給一個浮點數序列,取最大乘積連續子串的值,例如-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;
}