最大乘积子串-----输出子串和乘积

本文探讨如何解决最大乘积子串问题,包括处理负数的影响,通过设置maxv、positive和negative变量,以及在遍历数组过程中更新坐标。重点在于逻辑梳理,特别是遇到0和负数时的操作策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

鉴于最近碰到此问题,可网上却全部是只找到最大的乘积,并没有输出子串序列的。

首先,解释下定义。

子串(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");
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值