掌握LeetCode 152:乘积最大子数组,解锁动态编程制胜之道
2023-12-22 07:55:40
动态编程的魅力:揭开 LeetCode 152 乘积最大子数组的奥秘
简介
在计算机科学领域,我们经常遇到看似棘手的问题,仅凭直觉很难解决。在这种情况下,一种称为动态编程的技术就会成为我们的救命稻草。本文将通过剖析 LeetCode 上经典的 152 题:乘积最大子数组,带你领略动态编程的魅力。
动态编程:分步求解的艺术
动态编程是一种解决复杂问题的策略,它将问题分解为一系列更小的子问题,并逐步求解。其核心思想是存储子问题的解,避免重复计算。这有点像爬楼梯,我们逐级攀登,每一步都依赖于之前走过的台阶。
LeetCode 152:乘积最大子数组
在 LeetCode 152 中,我们的目标是找出给定数组中乘积最大的连续子数组。例如,对于数组 [-2, 0, -1],乘积最大的子数组是 [-2, -1],其乘积为 2。
子问题的定义
为了应用动态编程,我们首先需要定义子问题。我们定义 dp[i][j]
为以索引 i
结尾、长度为 j+1
的子数组的乘积最大值。
子问题的求解
接下来,我们需要确定如何求解子问题。当 j=0
时,dp[i][0] = nums[i]
,即子数组只有一个元素。当 j>0
时,我们有两种情况:
- 如果
nums[i]
为正数,那么dp[i][j] = dp[i-1][j-1] * nums[i]
,因为正数相乘会使乘积更大。 - 如果
nums[i]
为负数,那么dp[i][j] = dp[i-1][j-1] / nums[i]
,因为负数相乘会使乘积更小,但除以一个负数会使结果变为正数。
初始化
我们从 dp[0][0] = nums[0]
开始初始化。
最终解
最终,最大乘积子数组的乘积为 max(dp[0][n-1], dp[1][n-1], ..., dp[n-1][n-1])
,其中 n
是数组的长度。
代码实现
public int maxProduct(int[] nums) {
int n = nums.length;
int[][] dp = new int[n][n];
for (int i = 0; i < n; i++) {
dp[i][0] = nums[i];
}
int max = nums[0];
for (int j = 1; j < n; j++) {
for (int i = 0; i < n-j; i++) {
int p = dp[i][j-1];
if (nums[i+j] > 0) {
dp[i][j] = p * nums[i+j];
} else if (nums[i+j] < 0) {
dp[i][j] = p / nums[i+j];
} else {
dp[i][j] = 0;
}
max = Math.max(max, dp[i][j]);
}
}
return max;
}
总结
动态编程为解决复杂问题提供了有效的途径。通过将问题分解成更小的子问题,并逐步求解,我们可以轻松地找到最佳解。LeetCode 152:乘积最大子数组就是动态编程的一个经典应用,它完美诠释了这种方法的强大之处。
常见问题解答
-
什么是动态编程?
动态编程是一种解决复杂问题的分步求解策略,通过存储子问题的解来避免重复计算。 -
LeetCode 152 中如何定义子问题?
dp[i][j]
定义为以索引i
结尾、长度为j+1
的子数组的乘积最大值。 -
如何求解子问题?
根据nums[i]
的正负性,子问题可以转换为dp[i][j] = dp[i-1][j-1] * nums[i]
或dp[i][j] = dp[i-1][j-1] / nums[i]
。 -
LeetCode 152 中的最终解如何求得?
最终解为所有子问题解的最大值,即max(dp[0][n-1], dp[1][n-1], ..., dp[n-1][n-1])
。 -
动态编程在其他问题中有哪些应用?
动态编程广泛应用于计算机科学,包括最长公共子序列、背包问题、网格图搜索等。