【科学刷题】最大和与最大乘积问题:从1维到2维

1. 最大和

1.1 一维最大和

53. 最大子序和

思路:动态规划、贪心

用变量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 二维路径最大和

剑指 Offer 47. 礼物的最大价值

建议看这个题解:

面试题47. 礼物的最大价值(动态规划,清晰图解)

思路:动态规划。当前的最大值可以由上边或左边转移过来

时间复杂度 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 一维最大乘积

152. 乘积最大子数组

这题的思路部分可以直接看题解

题解 - 乘积最大子数组

时间复杂度 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 二维路径最大乘积

1594. 矩阵的最大非负积

结合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,,m1)和上边( d p [ 0 ] [ j ] , j = 1 , ⋯   , n − 1 dp[0][j],j=1,\cdots ,n-1 dp[0][j],j=1,,n1)进行初始化,然后再用maxFminF分别维护各个坐标能取到的最大值和最小值,再从上边和左边转移。

时间复杂度 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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值