1. 最大和
1.1 一维最大和
思路:动态规划、贪心
用变量dp
维护最大和。当要加一个数时(无论正负),如果最大和小于0,将其reset为0(相当于转换为从当前数开始加)
leetcode题解上有更多思路与讲解
时间复杂度 O ( N ) O(N) O(N) ,空间复杂度 O ( 1 ) O(1) O(1)
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
dp = 0
ans = -inf
for num in nums:
if dp < 0:
dp = 0
dp += num
ans = max(ans, dp)
return ans
1.2 二维路径最大和
建议看这个题解:
思路:动态规划。当前的最大值可以由上边或左边转移过来
时间复杂度 O ( M N ) O(MN) O(MN) ,空间复杂度 O ( M N ) O(MN) O(MN)
按照题解的思路(下方代码也是按照这个思路),可以复用grid二维数组,而不用自己开dp二维数组,达到空间复杂度压缩为 O ( 1 ) O(1) O(1)的效果。
class Solution:
def maxValue(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
for j in range(1, n): # 初始化第一行
grid[0][j] += grid[0][j - 1]
for i in range(1, m): # 初始化第一列
grid[i][0] += grid[i - 1][0]
for i in range(1, m):
for j in range(1, n):
grid[i][j] += max(grid[i][j - 1], grid[i - 1][j])
return grid[-1][-1]
2. 最大乘积
2.1 一维最大乘积
这题的思路部分可以直接看题解
时间复杂度 O ( N ) O(N) O(N) ,空间复杂度 O ( N ) O(N) O(N)
class Solution:
def maxProduct(self, nums: List[int]) -> int:
minF = nums.copy()
maxF = nums.copy()
n = len(nums)
ans = maxF[0]
for i in range(1, n):
num = nums[i]
minF[i] = min(minF[i - 1] * num, maxF[i - 1] * num, num)
maxF[i] = max(minF[i - 1] * num, maxF[i - 1] * num, num)
ans = max(ans, maxF[i])
return ans
可以用【滚动数组】思想对空间复杂度进行优化
时间复杂度 O ( N ) O(N) O(N) ,空间复杂度 O ( 1 ) O(1) O(1)
class Solution:
def maxProduct(self, nums: List[int]) -> int:
minF = nums[0]
maxF = nums[0]
n = len(nums)
ans = maxF
for i in range(1, n):
num = nums[i]
cur_minF = min(minF * num, maxF * num, num)
cur_maxF = max(minF * num, maxF * num, num)
minF = cur_minF
maxF = cur_maxF
ans = max(ans, maxF)
return ans
2.2 二维路径最大乘积
结合2.1和1.2的思路,我们可以先对左边(
d
p
[
i
]
[
0
]
,
i
=
1
,
⋯
,
m
−
1
dp[i][0],i=1,\cdots ,m-1
dp[i][0],i=1,⋯,m−1)和上边(
d
p
[
0
]
[
j
]
,
j
=
1
,
⋯
,
n
−
1
dp[0][j],j=1,\cdots ,n-1
dp[0][j],j=1,⋯,n−1)进行初始化,然后再用maxF
和minF
分别维护各个坐标能取到的最大值和最小值,再从上边和左边转移。
时间复杂度 O ( M N ) O(MN) O(MN) ,空间复杂度 O ( M N ) O(MN) O(MN)
P.S. 这题是腾讯机器学习岗4-4的笔试题
class Solution:
def maxProductPath(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
maxF = [[0] * n for _ in range(m)]
minF = [[0] * n for _ in range(m)]
# 对顶点进行初始化
maxF[0][0] = minF[0][0] = grid[0][0]
# 对左边进行初始化
# P.S. 对单边初始化时不涉及转移,所以直接赋值就好了,没有min-max选择的操作
for i in range(1, m):
maxF[i][0] = minF[i][0] = maxF[i - 1][0] * grid[i][0]
# 对上边进行初始化
for j in range(1, n):
maxF[0][j] = minF[0][j] = maxF[0][j - 1] * grid[0][j]
# 状态转移
for i in range(1, m):
for j in range(1, n):
num = grid[i][j]
maxF[i][j] = max(
maxF[i - 1][j] * num,
maxF[i][j - 1] * num,
minF[i - 1][j] * num,
minF[i][j - 1] * num,
)
minF[i][j] = min(
maxF[i - 1][j] * num,
maxF[i][j - 1] * num,
minF[i - 1][j] * num,
minF[i][j - 1] * num,
)
ans = maxF[-1][-1]
if ans < 0:
return -1
else:
return ans % int(1e9 + 7)