乘积最大子数组

一、前言

回顾前文《最大子数组》,求解的是最高点到最低点差值,后经转换为累加和最大的子数组。对这个问题再扩展一下,将加给为乘,连续乘积最大的数组怎样求解呢?

《最大子数组》https://blog.csdn.net/nie2314550441/article/details/106036517

二、题目

给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

示例 1:

输入: [2,3,-2,4]

输出: 6

解释: 子数组 [2,3] 有最大乘积 6。

 

示例 2:

输入: [-2,0,-1]

输出: 0

解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

三、思路

回顾一下《最大子数组——解法二》和 《包含min函数的栈》思路,从头到为遍历一次即可得到结果。想想能不能用这种思路解决这到题。整数有三种情况,正数、负数、零。零乘以然后数为零,零有分割重置的作用。我们只需要计算零之间的乘积即可。在两个0之间,负数可能有奇数个也可能有偶数个,只一次遍历我们无法判断后面负数个数,需要用2个数来辅助计算。一个数计算所有累乘结果,一个计算遇到第一个负数之后重置累乘结果。

(1) d1(n) = f(n) (f(n-1) = 0, 重置结果)

(2) d1(n) = d1(n-1) * f(n);

 

(3) d2(n) = f(n) (f(n-1) = 0, 重置结果)

(4) d2(n) = f(n) (f(n-1) < 0, 且从上一个0到当前遇到第一个小于0的数)

(5) d2(n) = d2(n-1) * f(n);

 

证明 max = max(d1(1..n), d2(1..n))

0可以重置后面的结果,我们只需要证明 max = max(d1(k..n), d2(k..n)) (k > 1 && f(k-1) = 0)

若 f(k...n) 有偶数个负数:

最大值为 d1(n) ,符合条件 d1(n) 包含在 d1(k..n) 或 d2(k...n) 中。

若 f(k...n) 有奇数个负数:

记负数坐标为:k1,k2...,kn 最大乘积为 max1 = f(k)*f(k+1)*...f(kn-1) 或

max2 = f(k1+1)*f(k+1)*...f(n)

max1 <=> d1(kn-1)

max2 <=> d(n) 在 (4)中第一次遇到负数会从后面开始累乘

max1,max2 包含在 d1(k..n) 或 d2(k...n) 中。

 

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

 

四、编码实现

两个解决方法,方法二为方法一的数学转换。


//==========================================================================
/**
* @file : 152_maxProduct.h
* @tilte: 乘积最大子数组
* @purpose : 给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
*
* 示例 1:
*
* 输入: [2,3,-2,4]
* 输出: 6
* 解释: 子数组 [2,3] 有最大乘积 6。
* 示例 2:
*
* 输入: [-2,0,-1]
* 输出: 0
* 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

*/
//==========================================================================

#pragma once
#include <vector>
#include <iostream>
using namespace std;

int maxProduct_solution_1(vector<int>& nums)
{
	if (nums.empty()) { return 0; }

	int max = nums[0]; //最大乘积
	int arr[2] = { nums[0] , nums[0] };		//遇到0,[0],[0]都重置; [0]: 从左往右累乘值; [1]: 从左往右累乘值若遇到第一个负数后面开始累乘; 
	int minusCount = 0;
	for (size_t i = 1; i < nums.size(); i++)
	{
		arr[0] *= nums[i];
		arr[1] *= nums[i];
		if (nums[i - 1] == 0)
		{
			// 遇到 0 就重置
			arr[0] = nums[i];
			arr[1] = nums[i];
			minusCount = 0;
		}
		else if (nums[i - 1] < 0)
		{
			++minusCount;
			if (minusCount == 1)
			{
				// 第一次遇到负数,后面数重新类似累乘
				arr[1] = nums[i];
			}
		}

		max = arr[0] > max ? arr[0] : max;
		max = arr[1] > max ? arr[1] : max;
	}

	return max;
}

// 为 maxProduct_solution_1 数学模型转换
int maxProduct_solution_2(vector<int>& nums)
{
	if (nums.empty()) { return 0; }

	int max = nums[0]; //最大乘积
	int arr[2] = { nums[0] , nums[0] };		//遇到0,[0],[0]都重置; [0]: 从左往右累乘值; [1]: 从左往右累乘值若遇到第一个负数后面开始累乘; 
	for (size_t i = 1; i < nums.size(); i++)
	{
		arr[0] *= nums[i];
		arr[1] *= nums[i];
		if (nums[i - 1] == 0)
		{
			// 遇到 0 就重置
			arr[0] = nums[i];
			arr[1] = nums[i];
		}
		else if (nums[i - 1] < 0 && ((arr[0] > 0 && arr[1] > 0) || (arr[0] < 0 && arr[1] < 0)))
		{
			arr[1] = nums[i];
		}

		max = arr[0] > max ? arr[0] : max;
		max = arr[1] > max ? arr[1] : max;
	}

	return max;
}

// 以下为测试代码
#define NAMESPACE_MAXPRODUCT namespace NAME_MAXPRODUCT {
#define NAMESPACE_MAXPRODUCTEND }

//////////////////////////////////////////////////////////////////////
// 测试 用例 START
NAMESPACE_MAXPRODUCT

void test(const char* testName, vector<int>& data, int expect)
{
	int result1 = maxProduct_solution_1(data);
	if (result1 == expect)
	{
		cout << testName << " solution_1 passed." << endl;
	}
	else
	{
		cout << testName << " solution_1 failed." << endl;
	}

	int result2 = maxProduct_solution_2(data);
	if (result2 == expect)
	{
		cout << testName << " solution_2 passed." << endl;
	}
	else
	{
		cout << testName << " solution_2 failed." << endl;
	}
}

// 测试用例
void Test1()
{
	vector<int> data = { -1 };
	int expect = -1;

	test("Test1()", data, expect);
}

// 测试用例
void Test2()
{
	vector<int> data = { 0 };
	int expect = 0;

	test("Test2()", data, expect);
}

// 测试用例
void Test3()
{
	vector<int> data = { 10 };
	int expect = 10;

	test("Test3()", data, expect);
}

// 测试用例
void Test4()
{
	vector<int> data = { 2, 3, 4 };
	int expect = 24;

	test("Test4()", data, expect);
}

// 测试用例
void Test5()
{
	vector<int> data = { -2, -3, -4 };
	int expect = 12;

	test("Test5()", data, expect);
}

// 测试用例
void Test6()
{
	vector<int> data = { -2, -4, -3 };
	int expect = 12;

	test("Test6()", data, expect);
}

// 测试用例
void Test7()
{
	vector<int> data = { 1, -2, -4, -3 };
	int expect = 12;

	test("Test7()", data, expect);
}

// 测试用例
void Test8()
{
	vector<int> data = { -2, -4, 1, -3 };
	int expect = 12;

	test("Test8()", data, expect);
}

// 测试用例
void Test9()
{
	vector<int> data = { 2, 3 ,-1, 4, 2 };
	int expect = 8;

	test("Test9()", data, expect);
}

// 测试用例
void Test10()
{
	vector<int> data = { 2, 3, -1, 4, 2, -2 };
	int expect = 96;

	test("Test10()", data, expect);
}

// 测试用例
void Test11()
{
	vector<int> data = { 2, 3, -1, 0, 2, -2 };
	int expect = 6;

	test("Test11()", data, expect);
}

// 测试用例
void Test12()
{
	vector<int> data = { 2, 3, -2, 2, 4, -1, 6 };
	int expect = 576;

	test("Test12()", data, expect);
}

// 测试用例
void Test13()
{
	vector<int> data = { 2, 3, -2, 2, 0, -1, 6, 0, 10 };
	int expect = 10;

	test("Test13()", data, expect);
}

// 测试用例
void Test14()
{
	vector<int> data = { 15, 0, 2, 3, -2, 2, 0, -1, 6, 0, 10 };
	int expect = 15;

	test("Test14()", data, expect);
}

// 测试用例
void Test15()
{
	vector<int> data = { 15, 0, 2, 3, -2, -2, 0, -1, 6, 0, 10 };
	int expect = 24;

	test("Test15()", data, expect);
}

// 测试用例
void Test16()
{
	vector<int> data = { 15, 0, 2, 3, -2, -2, 0, -1, 6, -3, 10 };
	int expect = 180;

	test("Test16()", data, expect);
}

NAMESPACE_MAXPRODUCTEND
// 测试 用例 END
//////////////////////////////////////////////////////////////////////

void MaxProduct_Test()
{
	NAME_MAXPRODUCT::Test1();
	NAME_MAXPRODUCT::Test2();
	NAME_MAXPRODUCT::Test3();
	NAME_MAXPRODUCT::Test4();
	NAME_MAXPRODUCT::Test5();
	NAME_MAXPRODUCT::Test6();
	NAME_MAXPRODUCT::Test8();
	NAME_MAXPRODUCT::Test9();
	NAME_MAXPRODUCT::Test10();
	NAME_MAXPRODUCT::Test11();
	NAME_MAXPRODUCT::Test12();
	NAME_MAXPRODUCT::Test13();
	NAME_MAXPRODUCT::Test14();
	NAME_MAXPRODUCT::Test15();
	NAME_MAXPRODUCT::Test16();
}

执行结果:

 

 

猜你喜欢

转载自blog.csdn.net/nie2314550441/article/details/106206639
今日推荐