算法题:乘积最大子序列
写一个函数找出一个序列中乘积最大的连续子序列,其中序列中至少包含一个数)。
格式:
第一行输入一个数组,最后依次输出最大乘积的子序列及其乘积的大小。
样例输入
[ 2,3,-2,4 ]
样例输出
[ 2,3 ]
写一个函数找出一个序列中乘积最大的连续子序列,其中序列中至少包含一个数)。
格式:
第一行输入一个数组,最后依次输出最大乘积的子序列及其乘积的大小。
样例输入
[ 2,3,-2,4 ]
样例输出
[ 2,3 ]
6
java版本的代码实现:
package cn.cat.algorithm;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MaxProductSubSequence {
/**
* 分析:拆分数组,然后分别计算各数组的乘积,乘积最大的数组即为乘积最大子序列。
* 拆分规则:
* 1、先根据0进行拆分。
* 2、然后判断负数的元素个数,如果个数为偶数,则无须再拆分(因为偶数个负数相乘必定为正数)。
* 3、如果负数个数为奇数,则需要细分为两种情况:
* 情况一:负数只有一个,则直接以负数为中点,把数组拆分为三个。
* 情况二:负数个数大于1,也是将数组分为两个 :
* 第一个数组范围为 数组最前端 至 倒数第二个负数索引
* 第二个数组范围为 第二个负数 索引至 数组最末端。
* @Description:
* @author gwj
* @Created 2018年4月16日 下午2:05:30
* @param args
*/
public static void main(String[] args) {
int[] data = new int[]{ 2, 3, -2, 4 };
//统计0的个数和负数个数
int countZero = 0;
for (int ele : data) {
if (ele == 0 ) {
countZero ++;
}
}
//1、按零进行分割
List<ArrRang> segmentsByZero = new ArrayList<ArrRang>(countZero + 1);
if (countZero == 0) {
segmentsByZero.add(newArrRang(0, data.length - 1));
} else {
//被拆分的数组元素起始索引
int startDataIndex = 0;
for (int i = 0; i < data.length; i++) {
if (data[i] == 0) {
//0被单独分割是一组
segmentsByZero.add(newArrRang(i, i));
//0前面的所有非0元素被分割为一组。
if (i > 0) {
segmentsByZero.add(newArrRang(startDataIndex, i - 1));
}
startDataIndex = i + 1;
}
}
//0后面的元素被分割为一组
if (startDataIndex < data.length) {
segmentsByZero.add(newArrRang(startDataIndex, data.length - 1));
}
}
//2、按负数进行分割
List<ArrRang> segmentsByNegative = new ArrayList<ArrRang>();
for (ArrRang arrRang : segmentsByZero) {
int countNegative = 0;
for (int i = arrRang.startIndex; i <= arrRang.endIndex; i++) {
if (data[i] < 0) {
countNegative ++;
}
}
if (countNegative == 0 || countNegative % 2 == 0) {
//没有负数,或负数个数为偶数,则不用再分割
segmentsByNegative.add(arrRang);
} else if (countNegative == 1) {
//负数个数为1个,以负数中心,将数组拆分为三段。
for (int i = arrRang.startIndex; i <= arrRang.endIndex; i++) {
if (data[i] < 0) {
//负数单独为一组
segmentsByNegative.add(newArrRang(i, i));
//负数左边为一组
if (i > arrRang.startIndex) {
segmentsByNegative.add(newArrRang(arrRang.startIndex, i - 1));
}
//负数右边为一组
if (i < arrRang.endIndex) {
segmentsByNegative.add(newArrRang(i + 1, arrRang.endIndex));
}
}
}
} else {
//奇数个负数,且个数大于1,需要分割为左右两段数组。
//第二个负数的索引
int secondNegativeIndex = -1;
//倒数第二个负数的索引
int reverseSecondNegativeIndex = -1;
int newCountNegative = 0;
for (int i = arrRang.startIndex; i <= arrRang.endIndex; i++) {
if (data[i] < 0) {
newCountNegative ++;
}
if (newCountNegative == 2 && secondNegativeIndex == -1) {
secondNegativeIndex = i;
}
if (newCountNegative + 1 == countNegative) {
reverseSecondNegativeIndex = i;
}
}
segmentsByNegative.add(newArrRang(0, reverseSecondNegativeIndex));
segmentsByNegative.add(newArrRang(secondNegativeIndex, data.length - 1));
}
}
int maxProduct = Integer.MIN_VALUE;
ArrRang maxArrRang = null;
for (ArrRang arrRang : segmentsByNegative) {
int product = 1;
for (int i = arrRang.startIndex; i <= arrRang.endIndex; i++) {
product *= data[i];
}
if (maxProduct < product) {
maxProduct = product;
maxArrRang = arrRang;
}
}
int[] maxSequence = Arrays.copyOfRange(data, maxArrRang.startIndex, maxArrRang.endIndex + 1);
System.out.println("原数组为:" + Arrays.toString(data));
System.out.println("最大乘积的子序列为:" + Arrays.toString(maxSequence) + " , 乘积为:"+ maxProduct);
}
/**
* 创建表示数组范围的对象。
*/
static ArrRang newArrRang(int startIndex, int endIndex) {
return new ArrRang(startIndex, endIndex);
}
/**
* 数组范围类。标识下标的起点和终点。
*/
static class ArrRang{
int startIndex;
int endIndex;
public ArrRang(int startIndex, int endIndex) {
this.startIndex = startIndex;
this.endIndex = endIndex;
}
}
}