问题描述
小R手上有一个长度为 n 的数组 (n > 0),数组中的元素分别来自集合 [0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]。小R想从这个数组中选取一段连续的区间,得到可能的最大乘积。
你需要帮助小R找到最大乘积的区间,并输出这个区间的起始位置 x 和结束位置 y (x ≤ y)。如果存在多个区间乘积相同的情况,优先选择 x 更小的区间;如果 x 相同,选择 y 更小的区间。
注意:数组的起始位置为 1,结束位置为 n。
测试样例
样例1:
输入:
n = 5, arr = [1, 2, 4, 0, 8]
输出:[1, 3]
样例2:
输入:
n = 7, arr = [1, 2, 4, 8, 0, 256, 0]
输出:[6, 6]
样例3:
输入:
n = 8, arr = [1, 2, 4, 8, 0, 256, 512, 0]
输出:[6, 7]
解题思路
使用队列和暴力求解的方法来寻找最大乘积的子数组
-
数据结构初始化:
vector<int> res: 用来存储最终的结果,即最大乘积子数组的起始和结束索引。queue<int> q: 用来存储数组中 0 的位置。0 元素作为子数组的分隔符,分割了数据。queue<PII> qp: 用来存储最大乘积子数组的起始和结束位置。PII是一个pair<int, int>类型,表示子数组的开始和结束位置。
-
循环查找 0 的位置:
- 在
for循环中,遍历data数组,将所有值为 0 的索引位置推入queue<int> q中。 - 这些 0 的位置将成为子数组的“分隔点”。
- 在
-
遍历每个分隔点:
-
设置
start = 0,表示从数组的第一个元素开始。 -
max = -1e9是初始化的最大乘积值,用于比较各个子数组的乘积。 -
while (!q.empty())循环遍历所有的 0 分隔符,处理每个子数组的乘积。- 从
start到当前end = q.front()之间的子数组被认为是一个独立的子数组(不包括当前的 0)。 - 计算该子数组的乘积
mul。 - 如果当前子数组的乘积
mul大于当前的最大乘积max,则更新最大乘积,并将子数组的起始和结束位置start和end记录到qp队列中。
- 从
-
-
处理最后一个子数组:
- 在
while循环结束后,判断end < n-1,即是否存在一个在最后没有被 0 分隔的子数组。此时我们计算最后一个子数组的乘积,并更新最大乘积。 - 如果计算的乘积大于当前的最大值
max,则将该子数组的起始和结束位置end和n推入qp中。
- 在
-
获取最大乘积子数组的起始和结束位置:
- 在所有的子数组中,只有一个最大乘积的子数组会被保留在
qp中。为了保证我们只得到一个结果,使用while (qp.size() > 1)来删除队列中多余的元素。 - 然后,取出队列中的唯一元素,即最大乘积子数组的起始和结束位置,并将其加入到
res中。
- 在所有的子数组中,只有一个最大乘积的子数组会被保留在
-
返回结果:
- 返回的是一个包含最大乘积子数组的起始和结束位置的数组
res,位置是以 1 为起始的索引。
- 返回的是一个包含最大乘积子数组的起始和结束位置的数组
代码示例
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
typedef pair<int,int> PII;
vector<int> solution(int n, vector<int> data) {
// Edit your code here
vector<int> res;
queue<int> q;
queue<PII> qp;
for(int i = 0; i < data.size(); i ++)
{
if(data[i] == 0) q.push(i);
}
int start = 0, max = -1e9, end;
while(!q.empty())
{
end = q.front();
q.pop();
int mul = 1;
for(int i = start; i < end; i ++)
{
mul *= data[i];
}
// cout << "mul = " << mul << endl;
if(mul > max)
{
max = mul;
qp.push({start,end});
}
start = end+1;
}
if(end < n-1)
{
int mul = 1;
for(int i = end+1; i < n; i ++) mul *= data[i];
if(mul > max)qp.push({end, n});
}
while(qp.size() > 1) qp.pop();
auto t = qp.front();
res.push_back(t.first+1),res.push_back(t.second);
return res;
}
代码中存在的问题:
- 乘积溢出:数组元素的乘积可能会非常大,可能导致整数溢出。为了避免溢出,通常我们应该考虑使用
long long类型或避免直接计算乘积。