利用C语言来求最大连续子序列乘积的方法

   2015-08-12 0
核心提示:这篇文章主要介绍了利用C语言来求最大连续子序列乘积的方法,基本的思路以外文中还附有相关ACM题目,需要的朋友可以参考下

题目描述:给一个浮点数序列,取最大乘积连续子串的值,例如 -2.5,4,0,3,0.5,8,-1,则取出的最大乘积连续子串为3,0.5,8。也就是说,上述数组中,3 0.5 8这3个数的乘积3*0.5*8=12是最大的,而且是连续的。

提醒:此最大乘积连续子串与最大乘积子序列不同,请勿混淆,前者子串要求连续,后者子序列不要求连续。也就是说:最长公共子串(Longest CommonSubstring)和最长公共子序列(LongestCommon Subsequence,LCS)的区别:


    子串(Substring)是串的一个连续的部分,子序列(Subsequence)则是从不改变序列的顺序,而从序列中去掉任意的元素而获得的新序列;
    更简略地说,前者(子串)的字符的位置必须连续,后者(子序列LCS)则不必。比如字符串“ acdfg ”同“ akdfc ”的最长公共子串为“ df ”,而它们的最长公共子序列LCS是“ adf ”,LCS可以使用动态规划法解决。

解答:

    解法一、穷举,所有的计算组合:
    或许,读者初看此题,自然会想到最大乘积子序列问题类似于最大子数组和问题:http://blog.csdn.net/v_JULY_v/article/details/6444021,可能立马会想到用最简单粗暴的方式:两个for循环直接轮询。

    解法二、虽说类似于最大子数组和问题,但实际上具体处理起来诸多不同。为什么呢,因为乘积子序列中有正有负也还可能有0。我们可以把问题简化成这样:数组中找一个子序列,使得它的乘积最大;同时找一个子序列,使得它的乘积最小(负数的情况)。因为虽然我们只要一个最大积,但由于负数的存在,我们同时找这两个乘积做起来反而方便。也就是说,不但记录最大乘积,也要记录最小乘积。So,我们让maxCurrent表示当前最大乘积的candidate,minCurrent反之,表示当前最小乘积的candidate,而maxProduct则记录到目前为止所有最大乘积candidates的最大值。(以上用candidate这个词是因为只是可能成为新一轮的最大/最小乘积)由于空集的乘积定义为1,在搜索数组前,maxCurrent,minCurrent,maxProduct都赋为1。
假设在任何时刻你已经有了maxCurrent和minCurrent这两个最大/最小乘积的candidates,新读入数组的元素x(i)后,新的最大乘积candidate只可能是maxCurrent或者minCurrent与x(i)的乘积中的较大者,如果x(i)<0导致maxCurrent<minCurrent,需要交换这两个candidates的值。当任何时候maxCurrent<1,由于1(空集)是比maxCurrent更好的candidate,所以更新maxCurrent为1,类似的可以更新minCurrent。任何时候maxCurrent如果比最好的maxProduct大,更新maxProduct。

    解法三、本题除了上述类似最大子数组和的解法,也可以直接用动态规划求解(其实,上述的解法一本质上也是动态规划,只是解题所表现出来的具体形式与接下来的解法二不同罢了。这个不同就在于下面的解法二会写出动态规划问题中经典常见的DP方程,而解法一是直接求解)。具体解法如下:
    假设数组为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[1]。


下面来看一道具体的ACM题目
 题目

    题目描述: 
    给定一个浮点数序列(可能有正数、0和负数),求出一个最大的连续子序列乘积。 
    输入: 
    输入可能包含多个测试样例。 
    每个测试样例的第一行仅包含正整数 n(n<=100000),表示浮点数序列的个数。 
    第二行输入n个浮点数用空格分隔。 
    输入数据保证所有数字乘积在双精度浮点数表示的范围内。 
    输出: 
    对应每个测试案例,输出序列中最大的连续子序列乘积,若乘积为浮点数请保留2位小数,如果最大乘积为负数,输出-1。 
    样例输入:  

  7 
  -2.5 4 0 3 0.5 8 -1 
  5 
  -3.2 5 -1.6 1 2.5 
  5 
  -1.1 2.2 -1.1 3.3 -1.1 

    样例输出:  

  12 
  64 
  8.78 


思路
最大连续子序列乘积和最大连续子序列和不同,这里先回忆一下最大连续子序列和的最优解结构:

最大连续子序列和
我们用sum[i]来表示以arr[i]结尾的最大连续子序列和,则状态转移方程为:

利用C语言来求最大连续子序列乘积的方法

最大连续子序列乘积
考虑存在负数的情况(ps:负负会得正),因此我们用两个辅助数组,max[i]和min[i],max[i]来表示以arr[i]结尾的最大连续子序列乘积,min[i]来表示以arr[i]结尾的最小连续子序列乘积,因此状态转移方程为:

利用C语言来求最大连续子序列乘积的方法

and

利用C语言来求最大连续子序列乘积的方法

有了状态转移方程,dp代码就很容易实现了,看到这里还不理解的同学,我建议你多花点时间用在算法学习上吧!

AC代码

  

 #include <stdio.h> 
  #include <stdlib.h> 
    
  double maxNumInThree(double a, double b, double c) 
  { 
    double max; 
    max = (a > b)  a : b; 
    max = (max > c)  max : c; 
    
    return max; 
  } 
    
  double minNumInThree(double a, double b, double c) 
  { 
    double min; 
    min = (a < b)  a : b; 
    min = (min < c)  min : c; 
    
    return min; 
  } 
    
    
  int main(void) 
  { 
    int i, n; 
    double *arr, *max, *min, res; 
    
    while (scanf("%d", &n) != EOF) { 
      arr = (double *)malloc(sizeof(double) * n); 
      max = (double *)malloc(sizeof(double) * n); 
      min = (double *)malloc(sizeof(double) * n); 
      for (i = 0; i < n; i ++) 
        scanf("%lf", arr + i); 
    
      // 动态规划求最大连续子序列乘积 
      max[0] = min[0] = res = arr[0]; 
      for (i = 1; i < n; i ++) { 
        max[i] = maxNumInThree(arr[i], max[i - 1] * arr[i], min[i - 1] * arr[i]); 
        min[i] = minNumInThree(arr[i], max[i - 1] * arr[i], min[i - 1] * arr[i]); 
        if (max[i] > res) 
          res = max[i]; 
      } 
    
      if (res >= 0) { 
        // 判断是否为浮点数 
        if ((res - (int)res) == 0) 
          printf("%d\n", (int)res); 
        else 
          printf("%.2lf\n", res); 
      } else { 
        printf("-1\n"); 
      } 
    
      free(arr); 
    } 
    
    return 0; 
  } 

       
    /**************************************************************
        Problem: 1501
        User: wangzhengyi
        Language: C
        Result: Accepted
        Time:110 ms
        Memory:4964 kb
    ****************************************************************/ 

 
标签: C 子序列
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • 拓端tecdat|R语言VAR模型的不同类型的脉冲响应
    原文链接:http://tecdat.cn/?p=9384目录模型与数据估算值预测误差脉冲响应识别问题正交脉冲响应结构脉冲反应广义脉冲响应参考文献脉冲响应分析是采用向量自回归模型的计量经济学分析中的重要一步。它们的主要目的是描述模型变量对一个或多个变量的冲击的演化
    03-16
  • 《黑马程序员》 category分类的使用(Objective
    分类的作用:在不改变原来类的基础上,可以给类增加一些方法。使用注意 : ①  分类只能增加方法,不可以增加成员变量                ②  分类的方法在实现中可以访问成员变量,不过成员变量必须手动实现。               
    03-16
  • Windows API Reference for C#, VB.NET
    不错的.net 下用API的参考站点地址在:http://www.webtropy.com/articles/Win32-API-DllImport-art9.asp 下面摘抄分类,便于大家直接就拿来用: File, Memory, Process, Threading, Time, Console, and Comm control(kernel32.dll) _hread_hwrite_lclose_lcr
    03-16
  • 拓端tecdat|R语言代写实现向量自回归VAR模型
    原文链接:http://tecdat.cn/?p=8478 澳大利亚在2008 - 2009年全球金融危机期间发生了这种情况。澳大利亚政府发布了一揽子刺激计划,其中包括2008年12月的现金支付,恰逢圣诞节支出。因此,零售商报告销售强劲,经济受到刺激。因此,收入增加了。VAR面临的批
    03-16
  • 项目中使用TypeScript的TodoList实例详解
    项目中使用TypeScript的TodoList实例详解
    目录为什么用todolisttodolist的ts化数据到视图实现handleTodoItemreadonly分类交叉类型新增功能联合类型可选属性数据转视图总结为什么用todolist现代的框架教程目前再也不是写个hello world那么简单了,而是需要有一定基础能力能够做到数据绑定、遍历、条件
    03-16
  • 我只是想在我的 Mac 上将 Ruby 和 Rails 更新到终端中的最新版本。 .
    我只是想在我的 Mac 上将 Ruby 和 Rails 更新到
    介绍自从我尝试创建一个简单的应用程序以来已经有很长时间了,并且我尝试在创建它之前将 Ruby 和 Rails 更新到最新版本,但是我意外卡住了,所以我将它作为备忘录留下。作为版本升级1. 更新 Homebrew 和 rbenv2. 红宝石更新3. Rails 更新这就是它的感觉。让我
    03-16
  • Objective-C学习—UIScrollView控件使用
    Objective-C学习—UIScrollView控件使用
    一、知识点简单介绍1.UIScrollView控件是什么?(1)移动设备的屏幕⼤大⼩小是极其有限的,因此直接展⽰示在⽤用户眼前的内容也相当有限(2)当展⽰示的内容较多,超出⼀一个屏幕时,⽤用户可通过滚动⼿手势来查看屏幕以外的内容(3)普通的UIView不具备滚动功能
    03-16
  • SICP:复数的直角和极坐标的表示(Python实现)
    SICP:复数的直角和极坐标的表示(Python实现)
    数据抽象屏障是控制复杂性的强有力工具,然而这种类型的数据抽象还不够强大有力。从一个另一个角度看,对于一个数据对象可能存在多种有用的表示方式,且我们希望所设计的系统能够处理多种表示形式。比如,复数就可以表示为两种几乎等价的形式:直角坐标形式(
    03-16
  • 微信小程序中overflow:scroll失效的问题 微信小程序overflow设置滚动
    微信小程序中overflow:scroll失效的问题 微信小
    .common-pop-table {padding: 0 30rpx;overflow: scroll;max-height: 70%;}研究后发现,要实际的设置对应的那个维度的高度,wcss改成.common-pop-table {padding: 0 30rpx;overflow: scroll;max-height: 400px;}就恢复正常了
    03-08
  • bloom-server 基于 rust 编写的 rest api cache 中间件
    bloom-server 基于 rust 编写的 rest api cache
    bloom-server 基于 rust 编写的 rest api cache 中间件,他位于lb 与api worker 之间,使用redis 作为缓存内容存储, 我们需要做的就是配置proxy,同时他使用基于share 的概念,进行cache 的分布存储,包含了请求端口(proxy,访问数据) 以及cache 控制端口(
    03-08
点击排行