鉴于最近碰到此问题,可网上却全部是只找到最大的乘积,并没有输出子串序列的。
首先,解释下定义。
子串(substring):必须是连续的。
子序列(subsequence):可以不连续。
单纯的求最大乘积,自我感觉,相对于要输出子串而言,较为简单。因为博主在这里卡了很久。
题目:
int arr[arrSize] = {0 ,6 , 3 , -2 , 3 , 2 , 6 , 0 , -2 , 2 , 3 , 1 , 8 , -1 };
求最大乘积子串,输出坐标。
96
-2 , 2 , 3 , 1 , 8 , -1
这和最大子串和比较类似,不同的是这里要考虑负数。
首先我用maxv表示最终结果,positive表示正数相乘结果,negative表示有奇数个负数参与的结果。
index1 , index2 p1,p2 n1,n2 则是对应的坐标记录
首先,捋一捋逻辑。
当碰到0的时候,就是positive或者negative重新开始记录的地方。此时应该重新记录p1,n1.同时这里也是前面数据比较的交互点。
maxv , positive , negative比较,哪个大就用哪个的坐标,记录在暂时的最终结果maxv中。
当碰到负数时,这里需要考虑两种情况:(首先我们以0为分段点)一是本段中前面数据乘积为正数时,这里就需要暂时的将前面的positive值与maxv比较来重新记录。
同时重置positive值。还有一点,negative是只要不碰到0.也就是在本段内是一直进行相乘的。这是为了用来管理负数参与的乘积不遗漏。
二是本段中前面数据乘积为负数时,这里也就指马上乘上此时的arr[i]就会变成正数。(如果不考虑小数的话,此时的negative实际上是本段最大数据。当然后面还是要比较)
当碰到正数时,只是纯粹的移动positive的右坐标。
在最终循环结束时,也要比较maxv , positive , negative,重新赋予index1,index2,maxv值。
(ps:博主使用的测试用例不多,而且代码写的比较粗鄙。只是说明个思路。望大家多多指点。)
#include <iostream>
using namespace std;
//int arr[arrSize] = {0 ,6 , 3 , -2 , 3 , 2 , 6 , 0 , -2 , 2 , 3 , 1 , 8 , -1 };
//求最大乘积子串,输出坐标。
//96
//-2 , 2 , 3 , 1 , 8 , -1
#define arrSize 14
void main_of_MMS()
{
int maxv = 0;//存取最大乘积
int positive = 1 , negative = 1;//分别表示无无负数参与的乘积,有负数参与的乘积
//对应positive和negative的坐标
int p1 = 0 , p2 = 0;
int n1 = 0 , n2 = 0;
//对应max的坐标
int index1 = 0 , index2 = 0;
int arr[arrSize] = {0 ,6 , 3 , -2 , 3 , 2 , 6 , 0 , -2 , 2 , 3 , 1 , 8 , -1 };
//int arr[arrSize] = {6 , 0 , -2 , 3 , 1 , 8};
for(int i = 0;i < arrSize;++ i)
{
if(arr[i] == 0)
{
if(maxv < arr[i])
maxv = arr[i];
if((maxv < positive) && (negative < positive))
{
index1 = p1;
index2 = p2;
maxv = positive;
}
if((maxv < negative) && positive < negative)
{
index1 = n1;
index2 = n2;
maxv = negative;
}
//记录p1,n1,即起始点
p1 = i;
n1 = i;
//重新将positive,negative置为初始值
positive = 1;
negative = 1;
continue;
}
else if(arr[i] < 0)
{
//找到第一个负数
if(negative > 0)
{
//n2 = i;
//找到第一个负数的时候,如果前面记录在positive中的值较大,则放弃maxv中数据。保存positive的数据
if(maxv < positive)
{
maxv = positive;
index1 = p1;
index2 = p2;
}
positive = 1;
negative *= arr[i];
p1 = i;
continue;
}
else if(negative < 0)
{//negative为负,此时乘以arr[i]为正。需记录
//其实这里了,negative必定大于当前段的positive(不考虑小数)
//p2 = i;
n2 = i;
//找到了第二个负数,这里记录的n1,n2则即将失去作用。给了positive。
//暂时只传坐标给positive。因为negative在此判断条件内尚未乘以当前负数。
p1 = n1;
p2 = n2;
}
}
else
{//正数.纯粹只需记录positive后节点坐标
p2 = i;
}
positive *= arr[i];
negative *= arr[i];
}
//最后再次比较max positive nagative大小重新赋值给max
if((maxv < positive) && (negative < positive))
{
index1 = p1;
index2 = p2;
maxv = positive;
}
if((maxv < negative) && positive < negative)
{
index1 = n1;
index2 = n2;
maxv = negative;
}
//printf_s("max:%d\n(%d ,%d)" , maxv ,index1 , index2);
printf_s("最大乘积为:%d\n" , maxv);
printf_s("最大乘积子串为:");
for(int i = index1 + 1;i <= index2;++ i)
{
printf_s("%d " , arr[i]);
}
printf_s("\n");
}