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

题目描述:给一个浮点数序列,取最大乘积连续子串的值,例如 -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]结尾的最大连续子序列和,则状态转移方程为:

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

and

有了状态转移方程,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
子序列
最大连续子序列乘积、c语言矩阵乘积、c语言计算1到n的乘积、c语言求奇数的乘积、c语言乘积函数,以便于您获取更多的相关知识。

时间: 2025-01-21 19:25:09

利用C语言来求最大连续子序列乘积的方法_C 语言的相关文章

C语言查找数组里数字重复次数的方法_C 语言

本文实例讲述了C语言查找数组里数字重复次数的方法.分享给大家供大家参考.具体如下: #include "stdafx.h" #include<stdio.h> #include <iostream> using namespace std; int main() { int myarray[10]={4,3,7,4,8,7,9,4,3,6}; printf("输入你想查询的数:"); int number=0; cin>>numb

C语言连接并操作Sedna XML数据库的方法_C 语言

本文实例讲述了C语言连接并操作Sedna XML数据库的方法.分享给大家供大家参考.具体如下: #include "libsedna.h" #include "stdio.h" int handle_error(SednaConnection* conn, const char* op, int close_connection) { printf("%s failed: \n%s\n", op, SEgetLastErrorMsg(conn))

求数组中最长递增子序列的解决方法_C 语言

存储扩展算法n2编程c 写一个时间复杂度尽可能低的程序,求一个一维数组(N个元素)中的最长递增子序列的长度.例如:在序列1,-1,2,-3,4,-5,6,-7中,其最长的递增子序列为1,2,4,6 或者 -1,2,4,6.(编程之美P198-202)分析与解法根据题目的要求,求一维数组中的最长递增子序列,也就是找一个标号的序列b[0],b[1],-,b[m](0 <= b[0] < b[1] < - < b[m] < N),使得array[b[0]]<array[b[1

c语言求1+2+...+n的解决方法_C 语言

题目:求1+2+-+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字以及条件判断语句(A?B:C). 分析:这道题没有多少实际意义,因为在软件开发中不会有这么变态的限制.但这道题却能有效地考查发散思维能力,而发散思维能力能反映出对编程相关技术理解的深刻程度.通常求1+2+-+n 除了用公式n(n+1)/2之外,无外乎循环和递归两种思路.由于已经明确限制for和while的使用,循环已经不能再用了.同样,递归函数也需要用if语句或者条件判断语句来判断是继续

C语言实现返回字符串函数的四种方法_C 语言

前言 C语言返回字符串函数共有四种方式,分别如下:       使用堆空间,返回申请的堆地址,注意释放       函数参数传递指针,返回该指针       返回函数内定义的静态变量(共享)       返回全局变量 下面来看看详细的介绍 其实就是要返回一个有效的指针,尾部变量退出后就无效了. 使用分配的内存,地址是有效 char *fun() { char* s = (char*)calloc(100, sizeof(char*) ); if (s) strcpy ( s , "abc &qu

c语言中用字符串数组显示菜单的解决方法_C 语言

以前写菜单方面东西时往往重复, 发现这个方法还可以, 用一个指针的指针解决遍历问题.代码如下所示: 复制代码 代码如下: #include <stdio.h>static char *menu[] = {  "1 --- push one item./n",  "2 --- pop one item./n",  "3 --- quit./n",  NULL};void Show_menu();int main(){ Show_menu

c语言中十六进制转二进制显示的实现方法_C 语言

复制代码 代码如下: //====================================== //输出格式: hex2bin 5e. //得到: 0101 1110 //====================================== #include <stdio.h>#include <limits.h> char *bitstr(char *, void const *, size_t); int main(int argc, char **argv){

C语言求连续最大子数组和的方法_C 语言

本文实例讲述了C语言求连续最大子数组和的方法,是非常实用的技巧.分享给大家供大家参考. 具体实现方法如下: #include <iostream> using namespace std; int array[] = {1, -2, 3, 10, -4, 7, 2, -5}; //int array[] = {-10, -1, -2, -3, -4, -5}; const int size = sizeof array / sizeof *array; int maxSubArray(int

排列和组合算法的实现方法_C语言经典案例_C 语言

排列和组合算法是考查递归的常见算法,这两种算法能用递归简洁地实现. 本人在经过多次摸索和思考之后,总结如下,以供参考. 程序代码如下: #include <stdio.h> #include <stdlib.h> char array[] = "abcd"; #define N 4 #define M 3 int queue[N] = {0}; int top = 0; int flag[N] = {0}; void perm(int s, int n) { i