Maximum product of “subarray” or “subsequence”

字节面试原题⁉️

「子数组」乘积最大值:152. 乘积最大子数组

给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续 子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

1
2
3
输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6
1
2
3
输入: nums = [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int maxProduct(vector<int>& nums) {
int n = nums.size();
vector<long> mx(nums.begin(), nums.end()), mn(nums.begin(), nums.end());
for (int i = 1; i < n; i++) {
mx[i] = max({mx[i - 1] * nums[i], (long)nums[i], mn[i - 1] * nums[i]});
mn[i] = min({mn[i - 1] * nums[i], (long)nums[i], mx[i - 1] * nums[i]});
}
return *max_element(mx.begin(), mx.end());
}
};

「子序列」乘积最大值:2708. 一个小组的最大实力值

给你一个下标从 0 开始的整数数组 nums ,它表示一个班级中所有学生在一次考试中的成绩。老师想选出一部分同学组成一个 非空 小组,且这个小组的 实力值 最大,如果这个小组里的学生下标为 i0, i1, i2, … , ik ,那么这个小组的实力值定义为 nums[i0] * nums[i1] * nums[i2] * ... * nums[ik]

请你返回老师创建的小组能得到的最大实力值为多少。

1
2
3
输入:nums = [3,-1,-5,2,5,-9]
输出:1350
解释:一种构成最大实力值小组的方案是选择下标为 [0,2,3,4,5] 的学生。实力值为 3 * (-5) * 2 * 5 * (-9) = 1350 ,这是可以得到的最大实力值。
1
2
3
输入:nums = [-4,-5,-4]
输出:20
解释:选择下标为 [0, 1] 的学生。得到的实力值为 20 。我们没法得到更大的实力值。
1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
long long maxStrength(vector<int>& nums) {
long long mn = nums[0], mx = mn;
for (int i = 1; i < nums.size(); i++) {
long long x = nums[i];
long long tmp = mn;
mn = min({mn, x, mn * x, mx * x});
mx = max({mx, x, tmp * x, mx * x});
}
return mx;
}
};

「三维子数组」乘积最大值:1594. 矩阵的最大非负积

给你一个大小为 m x n 的矩阵 grid 。最初,你位于左上角 (0, 0) ,每一步,你可以在矩阵中 向右向下 移动。

在从左上角 (0, 0) 开始到右下角 (m - 1, n - 1) 结束的所有路径中,找出具有 最大非负积 的路径。路径的积是沿路径访问的单元格中所有整数的乘积。

返回 最大非负积10^9 + 7 取余 的结果。如果最大积为 负数 ,则返回 -1

注意,取余是在得到最大积之后执行的。

示例 1:

img

1
2
3
输入:grid = [[-1,-2,-3],[-2,-3,-3],[-3,-3,-2]]
输出:-1
解释:从 (0, 0) 到 (2, 2) 的路径中无法得到非负积,所以返回 -1

示例 2:

img

1
2
3
输入:grid = [[1,-2,1],[1,-2,1],[3,-4,1]]
输出:8
解释:最大非负积对应的路径如图所示 (1 * 1 * -2 * -4 * 1 = 8)

✅ 本题为「鹅厂」与「字节」面试算法题,也是「152. 乘积最大子数组 」的升维算法题

1️⃣ 三维数组

第三维度记录 min 与 max,需要单独初始化第一行和第一列。

由于过程中无法确定最大值的由来,那么需要「左」和「上」的最大最小值来乘于当前值 grid[i][j],与「乘积最大子数组」思路一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public:
int maxProductPath(vector<vector<int>>& grid) {
const int MOD = 1e9 + 7;
int m = grid.size(), n = grid[0].size();
// [0]: min; [1]: max
vector f(m, vector(n, vector(2, 0LL)));
f[0][0] = {grid[0][0], grid[0][0]};
for (int j = 1; j < n; j++) {
f[0][j][0] = f[0][j - 1][0] * grid[0][j];
f[0][j][1] = f[0][j - 1][1] * grid[0][j];
}
for (int i = 1; i < m; i++) {
f[i][0][0] = f[i - 1][0][0] * grid[i][0];
f[i][0][1] = f[i - 1][0][1] * grid[i][0];
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
int x = grid[i][j];
f[i][j][0] = min({f[i - 1][j][0] * x, f[i - 1][j][1] * x,
f[i][j - 1][0] * x, f[i][j - 1][1] * x});
f[i][j][1] = max({f[i - 1][j][0] * x, f[i - 1][j][1] * x,
f[i][j - 1][0] * x, f[i][j - 1][1] * x});
}
}
return f[m - 1][n - 1][1] >= 0 ? f[m - 1][n - 1][1] % MOD : -1;
}
};

2️⃣ 两个二维数组

相当于将方法一三维数组的第三维度拆分成两个二维数组,与「乘积最大子数组」思路一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
int maxProductPath(vector<vector<int>>& grid) {
const int MOD = 1e9 + 7;
int m = grid.size(), n = grid[0].size();
vector<vector<long long>> mx(m, vector<long long>(n));
vector<vector<long long>> mn(m, vector<long long>(n));
mx[0][0] = mn[0][0] = grid[0][0];
for (int j = 1; j < n; j++)
mx[0][j] = mn[0][j] = mx[0][j - 1] * grid[0][j];
for (int i = 1; i < m; i++)
mx[i][0] = mn[i][0] = mx[i - 1][0] * grid[i][0];
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
int x = grid[i][j];
mx[i][j] = max({mx[i - 1][j] * x, mn[i - 1][j] * x,
mx[i][j - 1] * x, mn[i][j - 1] * x});
mn[i][j] = min({mx[i - 1][j] * x, mn[i - 1][j] * x,
mx[i][j - 1] * x, mn[i][j - 1] * x});
}
}
return mx[m - 1][n - 1] >= 0 ? mx[m - 1][n - 1] % MOD : -1;
}
};

✍️ Yikun Wu 已发表了 69 篇文章 · 总计 293k 字,采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处

🌀 本站总访问量