算法学习(十二)最大连续乘积子串、字符串编辑距离
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; }
相关文章推荐
- mysql 事务级别
- Getting or Setting Pixels
- CentOS6.5加域
- Python中的__new__和__init__
- 字符串函数番外篇
- 6.1文件和文件系统
- 剑指offer剖析__空格替换字符串问题
- [SCU 4498] RunningPhoton's Nightmare (BFS预处理+SPFA)
- ARM地址总线与可寻址空间的一些疑问
- android选取本地图片及关于图片压缩上传问题
- javax.crypto.BadPaddingException: Given final block not properly padded
- 五步搞定Android开发环境部署——非常详细的Android开发环境搭建教程
- Xcode使用
- 从多地商户抵制团购 看巨头“联盟小船”为何说翻就翻?
- android 屏幕适配
- 分水岭算法的原理、改进及matlab实现
- R语言学习笔记——用ggplot2作图
- a标签加入单击事件 屏蔽href跳转页面
- 南邮OJ 1005 多项式加法(二)
- ubuntu kylin 14.04 下载,编译,安装android内核源码