一些问题从整体上看貌似无从下手,从上到下考虑各种细节会越来越复杂。这时候就可以考虑用动态规划算法解决了,一个小的局部问题解决了后,在找到状态转移方程,通过状态转移方程解决掉所有局部问题,遍历完成后,全局问题就解决了。
关键是要找到状态转移方程。
下面先举一个例子:找到数组中sum(和)最大的子数组(maximum sum subarray)。这是个经典的问题,详细可以百度之。
用tmax表示当前局部求得的最大sum,为求得下一状态tmax值,需要tmax+A[i]和当前数组元素A[i]比较:,tmax=max(tmax+A[i],A[i])。这就是状态转移方程。所以可以写出下面程序:
// this is DPsolution int maxSum(int A[],int n) { assert(n>0); if(n<=0) return 0; if(n==1) return A[0]; int tmax= 0; int result=A[0]; for(int i=0;i<n;i++) { tmax=max(tmax+A[i],A[i]); result=max(tmax,result); } return result; }
同样用tmax表示当前局部求得的最大product。这是求状态转移方程稍微比上一例子复杂一点,考虑到数组中两个负数相乘会得到一个很大的正数。所以,还需要一个tmin来记录当前求得最小product。
下一状态的tmax值的更新,不仅需要比较tmax*A[i]和A[i],还需要比较tmin*A[i]。即tmax=max(max(tmax*A[i],A[i]),tmin*A[i])。而tmin=min(min(tmax*A[i],A[i]),tmin*A[i])。
程序如下:
// this is DP solution!!!haha int maxProduct(int A[],int n) { assert(n>0); if(n<=0) return 0; if(n==1) return A[0]; int tmax=A[0]; int tmin=A[0]; int result=A[0]; for(int i=1;i<n;i++) { int tmax_copy=tmax; tmax=max(max(tmax*A[i],A[i]),tmin*A[i]); tmin=min(min(tmax_copy*A[i],A[i]),tmin*A[i]); result=max(result,tmax); } return result; }