数组中子数组的最大乘积(Java解法)

目录

题目

[要求]

输入描述:

输出描述:

示例1

输入

输出

备注:

错误的思路分析:

错误原因:

改进后的思路:

样例推导:

代码展示:


题目

给定一个double类型的数组arr,其中的元素可正、可负、可0,返回子数组累乘的最大乘积。例如,arr=[-2.5, 4, 0, 3, 0.5, 8, -1],子数组[3, 0.5, 8]累乘可以获得最大的乘积12,所以返回12

[要求]

时间复杂度为O(N),空间复杂度为O(1)

输入描述:

第一行一个整数N。表示数组长度。 接下来一行N个浮点数表示数组内的数

输出描述:

输出一个浮点数表示答案,保留到小数点后两位

示例1

输入

7 -2.5 4 0 3 0.5 8 -1

输出

12.00

备注:

1 ≤ N ≤ Math.pow(10,5)

-100 ≤ arri ≤ 100

Math.pow(-10,22) ≤ 保证最后的答案 ≤ Math.pow(10,22)

错误的思路分析:

  1. 创建dp[n]一维数组
    1. 由于是子数组,所以dp[i]的含义是,以i结尾的子数组的最大值
  2. 初始化
    1. 如果数组长度=0,则返回1并退出
    2. 如果第一个数是负数,则dp[0]=1
    3. 如果是自然数,则dp[0]为该自然数数值
  3. 其余点:
    1. 如果当前数为0,则dp[i]=0
    2. 如果当前数为负数,
      1. 且dp[i-1]
      2. 否则dp[i] = arr[i]
    3. 如果当前数是正数
      1. 且dp[i-1]>0, dp[i] = dp[i-1]*arr[i]
      2. 否则d[i] = arr[i]
  4. 结果:
    1. dp中的最大值即为结果

错误原因:

不同于,加法,需要舍弃负数,这道题是子数组相乘。

子数组的最大累加和(java解法)

这道题看起来很简单,实则暗藏杀机,如果就按照上述方法这样写

会发现dp会将隐藏的负数宝藏给丢弃掉,也许此时负数没什么用,但也许在不久的将来,负数成负数,摇身一变,变成了最大值

就比如这个例子

arr = { 10,10,10,-1,-20}

如果按照上述思路写,答案会是(-1*10)= 20 ,但是之前的dp[4]如果为-1000,此时答案可以为20000

改进后的思路:

  1. 创建dp[n][2]二维数组,
    1. dp[i][0]的含义是,以i结尾的子数组的最大值
    2. dp[i][1]的含义是,以i结尾的子数组的最小值
  2. 初始化
    1. 如果数组长度=0,则返回1并退出
    2. dp[i][0] = dp[i][1] = arr[i]
  3. 其余点:
    1. 如果当前数为0,则dp[i][0] = dp[i][1] = 0
    2. dp[i][0] = arr[i], arr[i]*dp[i-1][0], arr[i]*dp[i-1][1] 三者中的最小值
    3. dp[i][0] = arr[i], arr[i]*dp[i-1][0], arr[i]*dp[i-1][1] 三者中的最大值
  4. 结果:
    1. dp中的最大值即为结果

样例推导:

代码展示:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main{
    public static void main(String[] args)throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(reader.readLine());
        double [] arr = new double[n];
        String[] str = reader.readLine().split(" ");
        for(int i=0;i<n;i++){
            arr[i] = Double.parseDouble(str[i]);
        }
        
        double [][] dp = new double[n][2];
        dp[0][0] = dp[0][1] = arr[0];
        double ans = 0;
        for(int i=1;i<n;i++){
            double p1 = arr[i];
            double p2 = arr[i] * dp[i-1][0];
            double p3 = arr[i] * dp[i-1][1];
            dp[i][0] = Math.max(p1, Math.max(p2, p3));
            ans = Math.max(ans, dp[i][0]);
            dp[i][1] = Math.min(p1, Math.min(p2, p3));
        }
        System.out.printf("%.2f", ans);
    }
}

空间压缩技巧:

import java.i.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main{
    public static void main(String[] args)throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(reader.readLine());
        double [] arr = new double[n];
        String[] str = reader.readLine().split(" ");
        for(int i=0;i<n;i++){
            arr[i] = Double.parseDouble(str[i]);
        }
        
        double dp00;
        double dp01;
        dp00 = dp01 = arr[0];
        double ans = 0;
        double p1,p2,p3;
        for(int i=1;i<n;i++){
            p1 = arr[i];
            p2 = arr[i] * dp00;
            p3 = arr[i] * dp01;
            dp00 = Math.max(p1, Math.max(p2, p3));
            ans = Math.max(ans, dp00);
            dp01 = Math.min(p1, Math.min(p2, p3));
        }
        System.out.printf("%.2f", ans);
    }
}

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个可能的解决方案: ```java public class MaxProductSubarray { public static void main(String[] args) { int[] nums = {2, 3, -2, 4}; int[] result = maxProductSubarray(nums); System.out.println("最大乘积为:" + result[0] + ",起始下标为:" + result[1] + ",结束下标为:" + result[2]); } public static int[] maxProductSubarray(int[] nums) { if (nums == null || nums.length == 0) { return new int[]{0, -1, -1}; } int maxProduct = nums[0]; int maxProductStartIndex = 0; int maxProductEndIndex = 0; int currentProduct = 1; int currentProductStartIndex = 0; for (int i = 0; i < nums.length; i++) { currentProduct *= nums[i]; if (currentProduct > maxProduct) { maxProduct = currentProduct; maxProductStartIndex = currentProductStartIndex; maxProductEndIndex = i; } if (currentProduct == 0) { currentProduct = 1; currentProductStartIndex = i + 1; } } return new int[]{maxProduct, maxProductStartIndex, maxProductEndIndex}; } } ``` 解释一下代码的思路: 首先判断输入数组是否为空或长度为0,如果是,则返回一个表示最大乘积为0且起始和结束下标均为-1的结果。 然后定义变量maxProduct表示最大乘积,maxProductStartIndex表示最大乘积数组的起始下标,maxProductEndIndex表示最大乘积数组的结束下标,currentProduct表示当前乘积,currentProductStartIndex表示当前乘积数组的起始下标。初始时,将maxProduct赋值为nums[0],将maxProductStartIndex和maxProductEndIndex都赋值为0,将currentProduct赋值为1,将currentProductStartIndex赋值为0。 接着使用for循环遍历数组中的每个元素。在每次循环中,将currentProduct乘上当前元素。如果currentProduct大于maxProduct,则更新maxProduct、maxProductStartIndex和maxProductEndIndex为当前值。如果currentProduct等于0,则说明当前乘积数组乘积为0,因此将currentProduct赋值为1,将currentProductStartIndex更新为当前下标加1。 最后返回一个长度为3的数组,第一个元素为最大乘积,第二个元素为最大乘积数组的起始下标,第三个元素为最大乘积数组的结束下标。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值