乘积最大子数组

147 阅读1分钟

题目

动态规划

public class Main {


    public static void main(String[] args) {

        Main main = new Main();
        int [] nums = new int[] {2, 3, -2, 4};
        main.maxProduct(nums);
    }

    public int maxProduct(int[] nums) {
        if (nums.length == 1) {
            return nums[0];
        }

        // 因为数组中存在负数, 所以当前位置i的最大连续子数组乘积的结果不能直接由dp[i - 1] * nums[i]得到
        // 因此需要维护两个dp数组, 一个数组用来存储每个位置的最大连续乘积, 一个数组用来存储最小连续乘积

        int [] dpMax = new int[nums.length];
        int [] dpMin = new int[nums.length];
        int max = Integer.MIN_VALUE;
        for(int i = 0; i < nums.length; i ++) {
            if (i == 0) {
                dpMax[i] = nums[i];
                dpMin[i] = nums[i];
            } else {
                dpMax[i] = Math.max(nums[i], Math.max(nums[i] * dpMax[i - 1], nums[i] * dpMin[i - 1]));
                dpMin[i] = Math.min(nums[i], Math.min(nums[i] * dpMax[i - 1], nums[i] * dpMin[i - 1]));
            }
            max = Math.max(dpMax[i], max);
        }
        return max;
    }
}

基本思路

  1. 首先数组只有整数, 不存在小数, 因此对于正数来说, 乘的越多越好.

  2. 数组中存在负数, 如果当前位置是负数的话, 那么之前存在的连续乘积中, 最小的那个和负数相乘才是最大的数字. 因此需要一个dpMin来维护每个位置的最小连续乘积

  3. 对于当前是正数的来说, 就需要维护一个dpMax来记录每个位置的最大连续乘积.

  4. 因此每个位置的最大值和最小值, 需要比较三个元素nums[i], dpMax[i - 1] * nums[i] 和dpMin[i - 1] * nums[i];