152乘積最大子數組(動態規劃、貪心)

1、題目描述

給你一個整數數組 nums ,請你找出數組中乘積最大的連續子數組(該子數組中至少包含一個數字),並返回該子數組所對應的乘積。

2、示例

輸入: [2,3,-2,4]
輸出: 6
解釋: 子數組 [2,3] 有最大乘積 6。

3、題解

解法一:

基本思想:動態規劃,維護兩個動態方程,nums[0:i]的最大子數組的乘積Fmax和最小子數組的乘積Fmin

  • Fmax[i]=max{Fmax[i - 1] * nums[i], nums[i], Fmin[i - 1] * nums[i]}
  • Fmin[i]=min{Fmin[i - 1] * nums[i], nums[i], Fmax[i - 1] * nums[i]}

動態規劃優化空間,根據滾動數組思想,我們可以只用兩個變量來維護i-1時刻的狀態。

解法二:

基本思想:貪心,negative記錄當前以0爲邊界區間的負數位置

  • 如果negative爲偶數,當前區間的最大值就是所有數的乘積
  • 如果negative爲奇數,當前區間的最大值就是去掉第一個負數或者去掉最後一個負數之間所有數的乘積

貪心優化空間,最大值是在以0爲邊界區間的所有數之和或者去掉第一個負數之和或者去掉最後一個負數之和,所以從頭到尾乘積找一遍最大值,然後從尾到頭找一遍最大值即可。

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
class Solution {
public:
	int maxProduct(vector<int>& nums) {
		//基本思想:動態規劃,維護兩個動態方程,nums[0:i]的最大子數組的乘積Fmax和最小子數組的乘積Fmin
		//Fmax[i]=max{Fmax[i - 1] * nums[i], nums[i], Fmin[i - 1] * nums[i]};
		//Fmin[i]=min{Fmin[i - 1] * nums[i], nums[i], Fmax[i - 1] * nums[i]};
		vector <int> Fmax(nums), Fmin(nums);
		for (int i = 1; i < nums.size(); ++i) {
			Fmax[i] = max(Fmax[i - 1] * nums[i], max(nums[i], Fmin[i - 1] * nums[i]));
			Fmin[i] = min(Fmin[i - 1] * nums[i], min(nums[i], Fmax[i - 1] * nums[i]));
		}
		return *max_element(Fmax.begin(), Fmax.end());
	}
};
class Solution1 {
public:
	int maxProduct(vector<int>& nums) {
		//動態規劃優化空間,根據滾動數組思想,我們可以只用兩個變量來維護i-1時刻的狀態
		int res = nums[0], Fmax = nums[0], Fmin = nums[0];
		for (int i = 1; i < nums.size(); i++)
		{
			int fmax = Fmax, fmin = Fmin;
			Fmax = max(fmax * nums[i], max(fmin * nums[i], nums[i]));
			Fmin = min(fmin * nums[i], min(fmax * nums[i], nums[i]));
			res = max(res, Fmax);
		}
		return res;
	}
};
class Solution2 {
public:
	int maxProduct(vector<int>& nums) {
		//基本思想:貪心,negative記錄當前以0爲邊界區間的負數位置
		//如果negative爲偶數,當前區間的最大值就是所有數的乘積
		//如果negative爲奇數,當前區間的最大值就是去掉第一個負數或者去掉最後一個負數之間所有數的乘積
		if (nums.size() == 1)
			return nums[0];
		vector<int> negative;
		int res = 0, start = 0, cur, ans;
		for (int i = 0; i <= nums.size(); i++)
		{
			if (i < nums.size() && nums[i] < 0)
				negative.push_back(i);
			else if (i==nums.size() || nums[i] == 0)
			{
				if (negative.size() % 2 == 0)
				{
					cur = 1;
					ans = 0;
					for (int j = start; j < i; j++)
					{
						cur *= nums[j];
						ans = cur;
					}
					res = max(res, ans);
				}
				else
				{
					cur = 1;
					ans = 0;
					for (int j = start; j < negative[negative.size() - 1]; j++)
					{
						cur *= nums[j];
						ans = cur;
					}
					res = max(res, ans);
					cur = 1;
					ans = 0;
					for (int j = negative[0] + 1; j < i; j++)
					{
						cur *= nums[j];
						ans = cur;
					}
					res = max(res, ans);
				}
				start = i + 1;
				negative.clear();
			}
		}
		return res;
	}
};
class Solution3 {
public:
	int maxProduct(vector<int>& nums) {
		//貪心優化空間,最大值是在以0爲邊界區間的所有數之和或者去掉第一個負數之和或者去掉最後一個負數之和
		//所以從頭到尾乘積找一遍最大值,然後從尾到頭找一遍最大值即可
		int res = nums[0], cur = 1;
		for (int i = 0; i < nums.size(); i++)
		{
			cur *= nums[i];
			res = max(res, cur);
			if (nums[i] == 0)
				cur = 1;
		}
		cur = 1;
		for (int i = nums.size()-1; i >= 0; i--)
		{
			cur *= nums[i];
			res = max(res, cur);
			if (nums[i] == 0)
				cur = 1;	
		}
		return res;
	}
};
int main()
{
	Solution3 solute;
	vector<int> nums = { 2,3,2,4 };
	cout << solute.maxProduct(nums) << endl;
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章