数据结构与算法分析——c语言描述 练习2.12(c) 答案
这道题有两个难点,第一是需要考虑值为0的时候,第二是需要考虑值为负的时候.
说下我的思路,用联机算法,只需要从头到尾遍历一遍就行了.
第一个问题很好解决,每次遇到值为0的时候,就分成一段,算出这一段的最大子序列乘积,输出答案时只需要比较每一段的最大值就好了.
第二个问题可以拆成当这一段有偶数个负数和有奇数个负数这两种情况.有偶数个负数时可以不用管,因为这一段中的所有数相乘的结果必然是最大的.而奇数个负数可以拆成偶数个负数加上一个负数,再复杂的情况也能化简为"a,b","b,a","a,b,a"这三种情况(a代指正数,b代指负数).因此将每一段拆成三部分,开头的部分到第一个负值结束(注意:包含第一个负值),结尾的部分从最后一个负值开始(注意:包含最后一个负值).
从头开始遍历的时候,将一段中的每个数字都累乘起来,这个乘积如果除以开头部分的所有乘积就是后半部分,这个乘积如果除以结尾部分的所有乘积就是前半部分,比较一下就是答案了.
当每一段只有一个值的时候也需要注意一下,因为不加特殊限制,负值会被运算成1.
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
int MaxM(vector<int>&nums) {
int Spart = 1, Endpart = 1,f_max=0,t=0,Fmax=INT_MIN,start=0,all=1;
for (int i = 0; i <= nums.size(); i++) {
if (i==nums.size()||nums[i] == 0) {
if (i!=nums.size()&&nums[i]==0) Fmax=max(0,Fmax);
if (i-start<=1){
if (start==nums.size()) break;
Fmax=max(Fmax,nums[start]);
}
else if (all>0) Fmax=max(Fmax,all);
else if (all<0) Fmax = max(Fmax,max(all / Spart, all / Endpart));
t = 0,Spart = 1,Endpart = 1,f_max = 0,all = 1,start=i+1;
continue;
}
all *= nums[i];
if (t == 0) Spart *= nums[i];
if (nums[i] < 0) {
t = 1;
Endpart = nums[i];
}
if (nums[i] > 0 && t == 1) Endpart *= nums[i];
}
return Fmax;
}
int main() {
int num;
vector<int>nums;
while (scanf("%d", &num)) nums.push_back(num);
int MaxProduct=MaxM(nums);
cout << MaxProduct << endl;
return 0;
}