`

编程之美-子数组的最大乘积

 
阅读更多

public class MaxProduct {

	/**
	 * 编程之美 子数组的最大乘积
	 * 题目: 给定一个长度为N的整数数组,只允许使用乘法,不能用除法,计算任意N-1个数的组合中乘积中最大的一组,并写出算法的时间复杂度。
	 * 以下程序对应书上两种方法,求得“乘积中最大的一组”的乘积——都是有溢出的可能的。
	 * 但按题目的意思,是要求得这个子数组,而不是这个子数组的乘积。
	 * 实际应用中,返回去掉的那一个元素的下标更合理。
	 */

	private boolean invalidInput = false;

	public static void main(String[] args) {
		int[][] aa = { 
						{ 0, 0, 1, 2 }, 
						{ 0, 1, 2 }, 
						{ 0, -1, 2 },
						{ -1, -2, -3 }, 
						{ 1, 2, 3 }, 
					};
		for (int[] a : aa) {
			MaxProduct m = new MaxProduct();
			int result = m.maxProductA(a);
			int result2 = m.maxProductB(a);
			if (m.invalidInput) {
				System.out.println("invalid input!");
			} else {
				System.out.println(result + "," + result2);
			}
		}
	}

	// 对应书上的解法1.空间换时间
	public int maxProductA(int[] a) {
		if (a == null || a.length == 0) {
			invalidInput = true;
			return 0;
		}
		int n = a.length;
		int[] s = new int[n];
		s[0] = 1;
		for (int i = 1; i <= n - 1; i++) {
			s[i] = s[i - 1] * a[i - 1];
		}
		int[] t = new int[n];
		t[n - 1] = 1;
		for (int i = n - 2; i >= 0; i--) {
			t[i] = t[i + 1] * a[i + 1];
		}
		int p = Integer.MIN_VALUE;
		for (int i = 0; i < n; i++) {
			int pi = s[i] * t[i];
			if (pi > p) {
				p = pi;
			}
		}
		return p;
	}

	/*
	 对应书上的解法2。对乘积作分类讨论。书上的分析如下:
	 计算N个数的乘积为P,然后分P的正负性讨论如下:
     1,P==0
             说明P中必定至少含有一个0。假设将这个0去掉后得到N-1个元素的乘积为Q。
           1.1 Q==0
                  返回0。说明N个元素中必有至少两个0,所以不管去掉什么元素,N-1个乘积必为0。
           1.2 Q为正
                  返回Q。说明其中再无0了,若之前去掉的不是0,则剩余的N-1个的乘积必为0。小于现在的Q。
           1.3 Q为负
                  返回0,。说明其中再无0了,若之前去掉的不是0,则剩余的N-1个的乘积必为0。大于现在的Q,取大者,所以之前应该保留0。
    2,P为负
          说明这N个数中无0,并且至少有一个负数。所以只有去掉一个绝对值最小的负数才获得最大乘积Q。并且这个负数必定是存在的。
    3,P为正
          由于可能负负得正,所以现在应该考虑到应该去掉一个绝对值最小的正数,但是这个正数不一定存在,比如数组-1,-1。所以如果该正数不存在,就应该去掉一个绝对值最大的负数。
		 同时注意,为了避免乘积溢出,建议只统计符号,计算0,正,负的个数 。  
	 */
	public int maxProductB(int[] a) {
		if (a == null || a.length == 0) {
			invalidInput = true;
			return 0;
		}
		int n = a.length;
		int zeroCount = 0;
		int negativeCount = 0;
		int positiveCount = 0;
		int maxNegative = Integer.MIN_VALUE; // 最大的负整数是-1,初始化应该设为最小的负整数
		int minNegative = -1; // 最小的负整数是Integer.MIN_VALUE.,初始化应该设为最大的负整数
		int minPositive = Integer.MAX_VALUE; // 最小的正整数,初始化为最大的正整数

		for (int i : a) {
			if (i == 0) {
				zeroCount++;
			}
			if (i > 0) {
				positiveCount++;
				if (minPositive > i) {
					minPositive = i;
				}
			}
			if (i < 0) {
				negativeCount++;
				if (maxNegative < i) {
					maxNegative = i;
				}
				if (minNegative > i) {
					minNegative = i;
				}
			}
		}

		// 设P为数组所有元素的乘积。Q为除去一个0元素之外其他元素的乘积。
		int p = 1;
		int excludeItem = 0;
		// P=0
		if (zeroCount >= 2) { // 有两个或两个以上的0
			p = 0;
		} else if (zeroCount == 1) { // 有一个0
			if (negativeCount % 2 == 0) { // Q>0
				excludeItem = 0;
			} else { // Q<0
				p = 0;
			}
		} else {
			// P>0
			if (negativeCount % 2 == 0) {
				if (positiveCount > 0) {
					excludeItem = minPositive;
				} else {
					excludeItem = minNegative;
				}
				//P<0
			} else {
				excludeItem = maxNegative;
			}
		}
		if (p != 0) {
			for (int i = 0; i < n; i++) {
				if (excludeItem != a[i]) {
					p *= a[i];
				}
			}
		}

		return p;
	}

}
分享到:
评论

相关推荐

    最大子数组乘积

    对于最大子数组乘积问题,我们可以定义两个状态变量,一个是当前子数组的最大乘积(max_product),另一个是最小乘积(min_product)。最小乘积在这里的作用是处理负数的情况,因为负数乘以最大乘积可能会变成新的...

    Java-Leetcode-乘积最大子数组.zip

    这个名为"Java-Leetcode-乘积最大子数组.zip"的压缩包很可能包含了某个开发者解决LeetCode上的一道问题——“乘积最大子数组”(Max Product Subarray)的Java实现代码。这道问题是关于数组处理和动态规划的经典实例...

    DP-LeetCode152. 乘积最大子数组(Python)

    在LeetCode的第152题“乘积最大子数组”中,目标是找到一个整数数组中的连续子数组,使得这个子数组的乘积最大。这个问题可以通过动态规划(Dynamic Programming, DP)来解决,主要考察了数组处理和优化算法的能力。...

    03-python-数组属性方法总结-数组与字符串的转换-生成数组的函数-矩阵

    在Python编程语言中,数组是一种非常重要的数据结构,它用于存储和操作一组相同类型的数据。在本篇Python学习笔记中,我们将深入探讨四个关键主题:数组的属性和方法、数组与字符串之间的转换、生成数组的函数以及...

    数组解决乘积超出数据范围

    根据给定文件的信息,我们可以总结出以下关于“数组解决乘积超出数据范围”的知识点: ### 一、问题背景 在计算机编程中,处理大整数运算时常常会遇到超出基本数据类型(如 `int`, `long` 等)所能表示的范围的...

    python-leetcode面试题解之第152题乘积最大子数组-题解.zip

    在本压缩包中,我们关注的是一个Python编程与算法相关的面试题目,具体是LeetCode的第152题——“乘积最大子数组”。这道题目是数据结构和算法领域中的经典问题,常出现在程序员求职面试中,尤其对于Python开发者来...

    php-leetcode题解之乘积最大子序列.zip

    在本压缩包“php-leetcode题解之乘积最大子序列.zip”中,主要涵盖了使用PHP语言解决LeetCode上的一个问题——找到数组中的乘积最大子序列。LeetCode是一个在线平台,提供各种编程挑战,帮助开发者提升算法技能和...

    javascript-leetcode面试题解动态规划问题之第152题乘积最大子数组-题解.zip

    第152题,即“乘积最大子数组”,是LeetCode中的一道经典动态规划题目,它要求我们找出数组中乘积最大的连续子数组。 动态规划是一种将复杂问题分解成更小、更简单的子问题的方法,通过构建一个表格或状态来存储子...

    java-leetcode面试题解双指针之第713题乘积小于k的子数组.zip

    这是因为当前子数组的乘积已超过`k`,我们需要找到下一个乘积小于`k`的子数组,因此左指针向右移动,缩小子数组的范围。 - 如果`product`仍小于`k`,则`count`加1,表示找到了一个满足条件的子数组。 - 然后将右...

    js代码-200530-构建乘积数组

    在JavaScript编程中,"构建乘积数组"是一个常见的任务,特别是在处理数组的数学运算和算法设计时。这个任务要求我们创建一个新的数组,其中每个元素是原数组中对应位置的元素与所有其他元素的乘积。例如,对于数组[1...

    python入门-leetcode面试题解之第238题除自身以外数组的乘积.zip

    这个压缩包特别聚焦于第238题,该题目的目标是计算数组中每个元素除自身以外所有元素的乘积。 题目描述:给定一个整数数组`nums`,你需要找出数组中每个元素除自身以外的乘积。返回一个数组`output`,其中`output[i...

    算法-最大K乘积问题

    首先,我们要理解问题的核心:给定一个整数数组nums和一个正整数k,我们需要找到数组中乘积最大的k个数。这里的关键点在于,单纯的排序并不能直接解决这个问题,因为乘积的大小受到正负数的影响,而且我们不仅要找出...

    【华为OD机试真题2023JAVA&JS】几何平均值最大子数组

    题目要求在给定的正数数组`numbers`中找到长度至少为`L`的子数组,使得这个子数组的几何平均值最大,并输出该子数组的起始位置和长度。如果存在多个几何平均值最大的子数组,应优先选择长度最短的,若长度相同,则...

    蓝桥杯c++-蓝桥杯竞赛练习之算法提高题最大乘积.zip

    描述中提到的“蓝桥杯c++_蓝桥杯竞赛练习之算法提高题最大乘积”进一步确认了这是一个与蓝桥杯竞赛相关的C++编程练习,特别关注算法的提升和优化,目标是解决找到数组中连续子数组的最大乘积的问题。这个问题在实际...

    Leetcode最大乘积和19.10.3_leetcode_C++_

    描述中的“找出数组中连续相乘后能得出最大乘积的一组数字,算法十分精妙”揭示了我们需要解决的核心问题:在给定的整数数组中找到一个子数组,使得这些元素相乘得到的最大乘积。 这个问题属于数组和动态规划的范畴...

    gasstationleetcode-leetcode-solution:该存储库包含LeetCode编程问题的解决方案

    最大乘积子阵列(中) - 除自身以外的数组的乘积(中) - 查找数组中的所有重复项(中) - 移零(简单) - 数组的度数(简单) - 两和(简单) - 最大子阵列(简单) - 买卖股票的最佳时机(简单) - 包含重复(简单...

    C#二维数组乘法算法

    在C#编程中,二维数组是一种非常常见的数据结构,它被广泛用于表示表格或矩阵类的数据。本主题将深入探讨如何实现两个二维数组的乘法算法。在数学中,两个矩阵相乘是一种基本运算,其规则是:如果第一个矩阵是m×n,...

    数据结构-数组.zip

    数组作为最基础的数据结构之一,它的理解与应用至关重要。在这个"数据结构-数组.zip"压缩包中,包含三个核心知识点:多项式操作、稀疏矩阵处理以及字符串匹配的KMP算法。 首先,我们来看多项式。在数学中,多项式是...

Global site tag (gtag.js) - Google Analytics