最大子序列乘积----DP求解

  问题起源于《数据结构与算法分析-C语言描述》一书中的习题2.12。

  存在序列A(a1,a2,......,a),(在此仅讨论序列A中元素均为整数的情况)

  问:给出有效的算法求解最大子序列乘积。

  一看此题,容易想到的是穷举所有的可能的子序列,求乘积后去最大值,代码如下。

 1 int  MaxProduct(int a[], int len)
 2 {
 3       int Max = a[0];
 4       for(int i = 0; i < len; ++i)
 5       {
 6               int   thisMax = 1;
 7               for(int j = i;  j < len; ++j)
 8               {
 9                       thisMax *= a[j];
10                       Max = Max<thisMax ? thisMax:Max;
11                }
12         }
13
14         return Max;
15 }                    

  此算法的复杂度容易计算得O(n2)。

  根据书中对最大子序列和问题的线性算法求解,进一步探索对该问题的线性求解得可能性。

  同样的,从问题的最终解的形式出发,假设序列A最大乘积的子序列为(ai,ai+1,....aj)。

  由此假设P(k)为以ak结尾的子序列的最大乘积,N(k)为以ak结尾的子序列的最小乘积。

  定义递推公式如下:

          若 ak > 0;  P(k) = ak * P(k-1),  N(k) = ak * N(k-1);

            ak = 0;  P(k) = N(k) = 0;

            ak < 0;  P(k) = ak * N(k-1),  N(k) = ak * P(k-1);

  代码实现如下:

 1 int MaxProduct(int a[], int len)
 2 {
 3     int Max = a[0];
 4     int ThisMax = 0, ThisMin = 0;
 5
 6     for(int i = 0; i < len; ++i)
 7     {
 8         if(0 == a[i])
 9         {
10             ThisMax = 0;
11             ThisMin = 0;
12
13         }
14         else if(a[i] > 0)
15         {
16             ThisMax = ThisMax ? ThisMax*a[i] : a[i];
17             ThisMin = ThisMin ? ThisMin*a[i] : ThisMin;
18         }
19         else if(a[i] < 0)
20         {
21             int tmp = ThisMax;
22             ThisMax = ThisMin ? ThisMin*a[i] : 0;
23             ThisMin = tmp ? a[i]*tmp : a[i];
24         }
25
26          Max = Max>ThisMax?Max:ThisMax;
27     }
28
29     return Max;
30 }

  容易计算得到该算法计算复杂度为O(n)。

时间: 2024-10-13 01:03:05

最大子序列乘积----DP求解的相关文章

dp求解各种子串子序列

目录 概念 最长上升子序列 最长连续子串 最长公共子序列 最长公共上升子序列 注:dp可能并不是求解该这些问题的最优算法,这里只是做一个dp 算法的简介. 概念 定义:假设现有一个 string = abcdefghijklmn 最长连续子串:要求在原序列中连续,比如 str = abcd.fghijklm都是valid substring 最长连续子序列:相对顺序在原序列中不变即可:比如 str = afgh.dfkn等等都是valid subsequence 说完了上面的定义:下面来说一说怎

动态规划:最大连续子序列乘积

题目描述: 给定一个浮点数序列(可能有正数.0和负数),求出一个最大的连续子序列乘积. 分析:若暴力求解,需要O(n^3)时间,太低效,故使用动态规划. 设data[i]:第i个数据,dp[i]:以第i个数结尾的连续子序列最大乘积, 若题目要求的是最大连续子序列和,则易确定状态转移方程为: dp[i]=max(data[i],dp[i-1]+data[i])(dp[i]为以第i个数结尾的连续子序列最大和) 但乘积存在负负得正的问题,即原本很小的负数成了一个负数反而变大了,(负数逆袭了), 故不能

最大子序列和,最小子序列和,最小正子序列和,最大子序列乘积

来自:<数据结构与算法分析——C语言描述>练习2.12 一. 最大子序列和 1.穷举法,O(N3) 1 int maxSequenceSum1(const int A[], int N) 2 { 3 int i, j, k, maxSum, thisSum; 4 5 maxSum = 0; 6 for (i = 0; i < N; i++) 7 { 8 for (j = i; j < N; j++) 9 { 10 thisSum = 0; 11 for (k = i; k <

最大连续子序列乘积

问题描述 给定一个整数序列(可能有正数,0和负数),求它的一个最大连续子序列乘积.比如给定数组a={3, -4, -5, 6, -2},则最大连续子序列乘积为360,即3*(-4)*(-5)*6=360. 分析 求最大连续子序列乘积与最大连续子序列和问题有所不同,因为其中有正有负还有可能有0. 假设数组为a[],直接利用动归来求解,考虑到可能存在负数的情况,我们用Max[i]来表示以a[i]结尾的最大连续子序列的乘积值,用Min[i]表示以a[i]结尾的最小的连续子序列的乘积值,那么状态转移方程

分治法应用----最大子序列和与最大子序列乘积

分治法,采用一种"分治(divide-and-conquer)"的策略.其想法是把问题分成两个大致相等的子问题,然后递归地对他们求解,这是"分"的含义."治"阶段将两个子问题修补到一起并外加少量附加工作,最后得到整个问题的答案.分治法的思想其实是递归. [求最大子序列和]在最大子序列和问题中,最大子序列和可能出现在三处.可能是整个数组的左半部,可能是整个数组的右半部,也有可能是跨越中间元素从而位于左右两部分之间.前面两种情况很容易使用递归来求解,

HDU 1231 最大连续子序列 --- 入门DP

HDU 1231 题目大意以及解题思路见: HDU 1003题解,此题和HDU 1003只是记录的信息不同,处理完全相同. /* HDU 1231 最大连续子序列 --- 入门DP */ #include <cstdio> #include <cstring> int dp[10005]; int main() { #ifdef _LOCAL freopen("D:\\input.txt", "r", stdin); #endif int n

最长上升子序列--经典dp

最长上升子序列 Time Limit: 3000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的.对于给定的一个序列(a1, a2, ..., aN),我们可以得到一些上升的子序列(ai1, ai2, ..., aiK),这里1<= i1 < i2 < ... < iK <= N.比如,对于序列(1, 7, 3, 5, 9, 4, 8)

最大连续子序列之和,最大连续子序列乘积

最大连续子序列之和问题描述为:数组中里有正数也有负数,连续的一个或多个整数组成一个子数组,每个子数组都有一个和,求所有子数组的和的最大值.分析,对数组a进行一遍扫描,sum[i] 为前i个元素中,包含第i个元素且和最大的连续子数组,MaxSum保存当前子数组中最大和,对于a[i+1]来说,sum[i+1] = sum[i]+a[i+1],此时如果sum[i+1]<0,那么sum需要重新赋0,从i+1之后开始累加,如果sum[i+1]>0,那么MaxSum = max(MaxSum, Sum[i

LeetCode OJ 322. Coin Change DP求解

题目链接:https://leetcode.com/problems/coin-change/ 322. Coin Change My Submissions Question Total Accepted: 15289 Total Submissions: 62250 Difficulty: Medium You are given coins of different denominations and a total amount of money amount. Write a func