|
| 1 | +## 题目地址(1770. 执行乘法运算的最大分数) |
| 2 | + |
| 3 | +https://leetcode.cn/problems/maximum-score-from-performing-multiplication-operations/ |
| 4 | + |
| 5 | +## 题目描述 |
| 6 | + |
| 7 | +``` |
| 8 | +给你两个长度分别 n 和 m 的整数数组 nums 和 multipliers ,其中 n >= m ,数组下标 从 1 开始 计数。 |
| 9 | +
|
| 10 | +初始时,你的分数为 0 。你需要执行恰好 m 步操作。在第 i 步操作(从 1 开始 计数)中,需要: |
| 11 | +
|
| 12 | +选择数组 nums 开头处或者末尾处 的整数 x 。 |
| 13 | +你获得 multipliers[i] * x 分,并累加到你的分数中。 |
| 14 | +将 x 从数组 nums 中移除。 |
| 15 | +
|
| 16 | +在执行 m 步操作后,返回 最大 分数。 |
| 17 | +
|
| 18 | + |
| 19 | +
|
| 20 | +示例 1: |
| 21 | +
|
| 22 | +输入:nums = [1,2,3], multipliers = [3,2,1] |
| 23 | +输出:14 |
| 24 | +解释:一种最优解决方案如下: |
| 25 | +- 选择末尾处的整数 3 ,[1,2,3] ,得 3 * 3 = 9 分,累加到分数中。 |
| 26 | +- 选择末尾处的整数 2 ,[1,2] ,得 2 * 2 = 4 分,累加到分数中。 |
| 27 | +- 选择末尾处的整数 1 ,[1] ,得 1 * 1 = 1 分,累加到分数中。 |
| 28 | +总分数为 9 + 4 + 1 = 14 。 |
| 29 | +
|
| 30 | +示例 2: |
| 31 | +
|
| 32 | +输入:nums = [-5,-3,-3,-2,7,1], multipliers = [-10,-5,3,4,6] |
| 33 | +输出:102 |
| 34 | +解释:一种最优解决方案如下: |
| 35 | +- 选择开头处的整数 -5 ,[-5,-3,-3,-2,7,1] ,得 -5 * -10 = 50 分,累加到分数中。 |
| 36 | +- 选择开头处的整数 -3 ,[-3,-3,-2,7,1] ,得 -3 * -5 = 15 分,累加到分数中。 |
| 37 | +- 选择开头处的整数 -3 ,[-3,-2,7,1] ,得 -3 * 3 = -9 分,累加到分数中。 |
| 38 | +- 选择末尾处的整数 1 ,[-2,7,1] ,得 1 * 4 = 4 分,累加到分数中。 |
| 39 | +- 选择末尾处的整数 7 ,[-2,7] ,得 7 * 6 = 42 分,累加到分数中。 |
| 40 | +总分数为 50 + 15 - 9 + 4 + 42 = 102 。 |
| 41 | +
|
| 42 | +
|
| 43 | + |
| 44 | +
|
| 45 | +提示: |
| 46 | +
|
| 47 | +n == nums.length |
| 48 | +m == multipliers.length |
| 49 | +1 <= m <= 103 |
| 50 | +m <= n <= 105 |
| 51 | +-1000 <= nums[i], multipliers[i] <= 1000 |
| 52 | +``` |
| 53 | + |
| 54 | +## 前置知识 |
| 55 | + |
| 56 | +- 动态规划 |
| 57 | +- 区间动态规划 |
| 58 | + |
| 59 | +## 公司 |
| 60 | + |
| 61 | +- 暂无 |
| 62 | + |
| 63 | +## 思路 |
| 64 | + |
| 65 | +这是一个典型的区间 DP 问题。 |
| 66 | + |
| 67 | +直接套用区间 DP 的公,定义 DP[i][j] 为考虑区间 nums[i:j] 的情况下, 所能获得的最大分数。 |
| 68 | + |
| 69 | +那么我们有两个选择, 取左端点或者取右端点,这两种选择取最大值即可。同时需要一个变量记录当前是第几步操作, 以便知道要乘以多少。 |
| 70 | + |
| 71 | +这样 dp[i][j][steps] 就表示考虑区间 nums[i:j] 的情况下当前是第 steps 步, 所能获得的最大分数。 |
| 72 | + |
| 73 | +```py |
| 74 | +class Solution: |
| 75 | + def maximumScore(self, nums: List[int], multipliers: List[int]) -> int: |
| 76 | + @cache |
| 77 | + def dp(i, j, steps): |
| 78 | + if steps == len(multipliers): return 0 |
| 79 | + return max(dp(i + 1, j, steps + 1) + multipliers[steps] * nums[i], dp(i, j - 1, steps + 1) + multipliers[steps] * nums[j]) |
| 80 | + return dp(0, len(nums) - 1, 0) |
| 81 | +``` |
| 82 | + |
| 83 | +上面代码非常好写,复杂度为 $O(m*n^2)$但是会严重超时。代入题目中的数据 m 为 10^3, n 为 10 ^ 5,那么整体就是 $10^13$, 远远大于 $10^7$ 这个临界值。 |
| 84 | + |
| 85 | +注意到 steps 其实可以根据 i 和 j 推导出来。因为每一步我们必定要选择一次,这是关键。那么我们当前选择了多少就可以根据 i 和 j 推导出来, 这样就可以降低到二维 dp[i][j]。代码: |
| 86 | + |
| 87 | +```py |
| 88 | +class Solution: |
| 89 | + def maximumScore(self, nums: List[int], multipliers: List[int]) -> int: |
| 90 | + @cache |
| 91 | + def dp(i, j): |
| 92 | + steps = len(nums) - (j - i + 1) |
| 93 | + if steps == len(multipliers): return 0 |
| 94 | + return max(dp(i + 1, j) + multipliers[steps] * nums[i], dp(i, j - 1,) + multipliers[steps] * nums[j]) |
| 95 | + return dp(0, len(nums) - 1) |
| 96 | +``` |
| 97 | + |
| 98 | +不过代入后还是远远大于 $10^7$ 这个临界值。 |
| 99 | + |
| 100 | +小技巧,下面的代码可以通过,不过也不推荐。 |
| 101 | + |
| 102 | +```py |
| 103 | +class Solution: |
| 104 | + def maximumScore(self, nums: List[int], multipliers: List[int]) -> int: |
| 105 | + @cache |
| 106 | + def dp(i, j): |
| 107 | + steps = len(nums) - (j - i + 1) |
| 108 | + if steps == len(multipliers): return 0 |
| 109 | + return max(dp(i + 1, j) + multipliers[steps] * nums[i], dp(i, j - 1,) + multipliers[steps] * nums[j]) |
| 110 | + ans = dp(0, len(nums) - 1) |
| 111 | + dp.cache_clear() |
| 112 | + return ans |
| 113 | +``` |
| 114 | + |
| 115 | +这里要使用到一种技巧 - 维度选择。 |
| 116 | + |
| 117 | +我们可以换一种状态定义方式,即思考 mutlipiers, 因为它的数据量小(题目给的是 10 ^ 3)。 |
| 118 | + |
| 119 | +实际上,我们可以定义 dp[i][j] 为选择 nums 前 i 项目和 nums 后 j 项目可以获得的最大分数(题目限制了只能取左右两端)。但是注意到 i 和 j 一定是要小于 m 的, 因为不妨直接枚举到 m 即可, 而不需要枚举到 n。 |
| 120 | + |
| 121 | +显然这种方式枚举的时间复杂度为 $O(m^2)$,代入题目大概是 $10^6$ , 小于临界值 $10^7$。 |
| 122 | + |
| 123 | +## 关键点 |
| 124 | + |
| 125 | +- 维度选择 |
| 126 | +- 降维 |
| 127 | + |
| 128 | +## 代码 |
| 129 | + |
| 130 | +- 语言支持:Python3 |
| 131 | + |
| 132 | +Python3 Code: |
| 133 | + |
| 134 | +```python |
| 135 | + |
| 136 | +class Solution: |
| 137 | + def maximumScore(self, nums: List[int], multipliers: List[int]) -> int: |
| 138 | + n,m=len(nums),len(multipliers) |
| 139 | + dp=[[float('-inf')]*(m+1) for _ in range(m+1)] |
| 140 | + dp[0][0]=0 |
| 141 | + ans=float('-inf') |
| 142 | + for i in range(1,m+1): # 枚举长度 |
| 143 | + for l in range(i+1): # 枚举左侧取了 l 个 |
| 144 | + r = i - l # 右侧取的就是总数 - 左边取的 |
| 145 | + dp[l][r]=max(dp[l][r],dp[l-1][r]+nums[l-1]*multipliers[i-1], dp[l][r-1]+nums[-r]*multipliers[i-1]) |
| 146 | + if i == m: ans=max(ans,dp[l][r]) |
| 147 | + return ans |
| 148 | + |
| 149 | + |
| 150 | +``` |
| 151 | + |
| 152 | +**复杂度分析** |
| 153 | + |
| 154 | +令 n 为数组长度。 |
| 155 | + |
| 156 | +- 时间复杂度:$O(n^2)$ |
| 157 | +- 空间复杂度:$O(n^2)$ |
| 158 | + |
| 159 | +> 此题解由 [力扣刷题插件](https://leetcode-pp.github.io/leetcode-cheat/?tab=solution-template) 自动生成。 |
| 160 | +
|
| 161 | +力扣的小伙伴可以[关注我](https://leetcode-cn.com/u/fe-lucifer/),这样就会第一时间收到我的动态啦~ |
| 162 | + |
| 163 | +以上就是本文的全部内容了。大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 40K star 啦。大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。 |
| 164 | + |
| 165 | +关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。 |
| 166 | + |
| 167 | + |
| 168 | + |
| 169 | +## 其他 |
| 170 | + |
| 171 | +大家也可以看下[力扣国际站的官方题解](https://leetcode.com/problems/maximum-score-from-performing-multiplication-operations/solution/) |
0 commit comments