最大连续乘积子串

题目描述

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

解法一:暴力求解

/**
	 * 暴力求解:时间复杂度为O(n^2)
	 * 
	 * @param arr
	 * @param length
	 * @return
	 */
	public static double getMaxSubstring(double[] arr) {
		if (arr == null || arr.length < 1) {
			return -1.0;
		}
		double max = arr[0];
		for (int i = 0; i < arr.length; i++) {
			double x = 1;
			for (int j = i; j < arr.length; j++) {
				x *= arr[j];
				if (x > max)
					max = x;
			}
		}
		return max;
	}

解法二:动态规划

考虑到乘积子序列中有正有负也还可能有0,我们可以把问题简化成这样:数组中找一个子序列,使得它的乘积最大;同时找一个子序列,使得它的乘积最小(负数的情况)。因为虽然我们只要一个最大积,但由于负数的存在,我们同时找这两个乘积做起来反而方便。也就是说,不但记录最大乘积,也要记录最小乘积。

假设数组为a[],直接利用动态规划来求解,考虑到可能存在负数的情况,我们用maxend来表示以a[i]结尾的最大连续子串的乘积值,用minend表示以a[i]结尾的最小的子串的乘积值,那么状态转移方程为:

  maxend = max(max(maxend * a[i], minend * a[i]), a[i]);
  minend = min(min(maxend * a[i], minend * a[i]), a[i]);

初始状态为maxend = minend = a[0]。

+

参考代码如下:


/**
	 * 假设数组为a[],直接利用动态规划来求解,考虑到可能存在负数的情况,<br>
	 * 我们用maxend来表示以a[i]结尾的最大连续子串的乘积值,<br>
	 * 用minend表示以a[i]结尾的最小的子串的乘积值,<br>
	 * 那么状态转移方程为:<br>
	 * maxend = max(max(maxend * a[i], minend * a[i]), a[i]);<br>
	 * minend = min(min(maxend * a[i], minend * a[i]), a[i]);
	 * 
	 * @param arr
	 * @return
	 */
	public static double getMaxSubString1(double[] arr) {
		double maxEnd = arr[0];
		double minEnd = arr[0];
		double maxResult = arr[0];
		for (int i = 1; i < arr.length; i++) {
			double end1 = maxEnd * arr[i];
			double end2 = minEnd * arr[i];
			maxEnd = Math.max(Math.max(end1, end2), arr[i]);
			minEnd = Math.min(Math.min(end1, end2), arr[i]);
			maxResult = Math.max(maxResult, maxEnd);
		}
		return maxResult;
	}


猜你喜欢

转载自blog.csdn.net/u013230189/article/details/80896882