
2025-09-30:最大化交错和为 K 的子序列乘积。用go语言,给出一个整数数组 nums 和两个整数 k、limit,要求从 nums 中选出一个非空的子序列(从原数组中挑选若干元素且保留它们的相对顺序),满足以下两点:
在所有满足上述条件的子序列中,选择乘积最大的那个,并返回其乘积值;如果不存在任何满足条件的子序列,则返回 -1。
1 <= nums.length <= 150。
0 <= nums[i] <= 12。
-100000 <= k <= 100000。
1 <= limit <= 5000。
输入: nums = [1,2,3], k = 2, limit = 10。
输出: 6。
解释:
交错和为 2 的子序列有:
[1, 2, 3]
交错和:1 - 2 + 3 = 2
乘积:1 * 2 * 3 = 6
[2]
交错和:2
乘积:2
在 limit 内的最大乘积是 6。
题目来自力扣3509。
这是一个动态规划思路,但状态设计比较特殊。
我们考虑逐步处理 nums 的每个元素,维护两个字典(哈希表):
oddS:键是交错和 s,值是另一个集合,存储以奇数长度结尾的子序列的乘积值。evenS:键是交错和 s,值是另一个集合,存储以偶数长度结尾的子序列的乘积值。为什么分奇偶长度? 因为交错和的符号取决于该元素在子序列中的位置(偶数下标加,奇数下标减),而位置奇偶性由子序列长度决定:
oddS 和 evenS 初始为空。total 先算出来,如果 |k| > total,说明不可能有解,直接返回 -1(因为交错和最大绝对值就是总和)。对 nums 中每个元素 x:
oddS 生成新的偶数长度子序列当前 oddS 里的子序列长度是奇数,如果加入 x,新子序列长度变为偶数,那么 x 在奇数下标,所以交错和变化是 -x,乘积是原来的乘积乘以 x(如果不超过 limit)。
遍历 oddS 的每个 (s, 乘积集合):
s - xx(如果超过 limit 则忽略)(新和, 新乘积) 暂存到 newEvenS 中(因为不能立即更新 evenS,否则会重复计算)。evenS 生成新的奇数长度子序列当前 evenS 里的子序列长度是偶数,如果加入 x,新子序列长度变为奇数,那么 x 在偶数下标,所以交错和变化是 +x,乘积是原来的乘积乘以 x(如果不超过 limit)。
遍历 evenS 的每个 (s, 乘积集合):
s + xx(如果超过 limit 则忽略)oddS[新和] 的乘积集合中。x 单独作为一个子序列长度为 1(奇数长度),交错和 = x,乘积 = x(如果 x <= limit),加入 oddS[x]。
x = 0 的特殊情况如果 x = 0,乘积会变成 0(且不超过 limit),需要单独考虑:
evenS 到 oddS 时,即使乘积超过 limit,但 0 总是允许的,所以加一个乘积 0。oddS 到 evenS 时同理。newEvenS 到 evenS把之前暂存的 newEvenS 合并到 evenS 中。
如果 oddS[k] 或 evenS[k] 的乘积集合中有 limit,说明已经找到乘积等于 limit 的解,可以直接返回 limit(因为这是可能的最大值)。
处理完所有元素后:
oddS[k] 中的最大乘积值。evenS[k] 中的最大乘积值。n(数组长度)。[-total, total],其中 total <= n * max(nums[i]) = 150 * 12 = 1800,所以范围约 3601 个可能值。limit = 5000,所以每个和的乘积集合最多约 5000 个不同值。O(n * (total * limit)) 太大,但实际剪枝(乘积超过 limit 就丢弃)会大幅减少状态。oddS 和 evenS,键的数量最多约 2 * total + 1,每个键对应的乘积集合大小最多 limit。O(total * limit),即约 1800 * 5000 量级(900 万),但实际不会满,因为乘积不会同时取满所有值。最终答案(题目给的例子):
nums = [1,2,3], k=2, limit=10[1,2,3] 交错和 = 1 - 2 + 3 = 2,乘积 = 6,满足条件且最大,所以输出 6。.
package main
import (
"fmt"
)
func maxProduct(nums []int, k, limit int)int {
total := 0
for _, x := range nums {
total += x
}
if total < abs(k) { // |k| 太大
return-1
}
// s -> {m}
oddS := map[int]map[int]struct{}{}
evenS := map[int]map[int]struct{}{}
add := func(m map[int]map[int]struct{}, key, val int) {
if _, ok := m[key]; !ok {
m[key] = map[int]struct{}{}
}
m[key][val] = struct{}{}
}
for _, x := range nums {
// 长为偶数的子序列的计算结果 newEvenS
newEvenS := map[int]map[int]struct{}{}
for s, set := range oddS {
newEvenS[s-x] = map[int]struct{}{}
for m := range set {
if m*x <= limit {
newEvenS[s-x][m*x] = struct{}{}
}
}
}
// 长为奇数的子序列的计算结果 oddS
for s, set := range evenS {
if _, ok := oddS[s+x]; !ok {
oddS[s+x] = map[int]struct{}{}
}
for m := range set {
if m*x <= limit {
oddS[s+x][m*x] = struct{}{}
}
}
if x == 0 {
add(oddS, s, 0)
}
}
// 用 newEvenS 更新 evenS
for s, set := range newEvenS {
if eSet, ok := evenS[s]; ok {
for m := range set {
eSet[m] = struct{}{}
}
} else {
evenS[s] = set
}
if x == 0 {
add(evenS, s, 0)
}
}
// 子序列只有一个数的情况
if x <= limit {
add(oddS, x, x)
}
if set, ok := oddS[k]; ok {
if _, ok := set[limit]; ok {
return limit // 提前返回
}
}
if set, ok := evenS[k]; ok {
if _, ok := set[limit]; ok {
return limit // 提前返回
}
}
}
calcMax := func(m map[int]struct{})int {
maxVal := -1
if m != nil {
for v := range m {
maxVal = max(maxVal, v)
}
}
return maxVal
}
return max(calcMax(oddS[k]), calcMax(evenS[k]))
}
func abs(x int)int {
if x < 0 {
return -x
}
return x
}
func main() {
nums := []int{1, 2, 3}
k := 2
limit := 10
result := maxProduct(nums, k, limit)
fmt.Println(result)
}

.
# -*-coding:utf-8-*-
def max_product(nums, k, limit):
total = sum(nums)
if total < abs(k): # |k| 太大
return-1
# s -> set(products)
oddS = {} # 长为奇数的子序列:交替和 s -> {product}
evenS = {} # 长为偶数的子序列:交替和 s -> {product}
def add(m, key, val):
if key not in m:
m[key] = set()
m[key].add(val)
for x in nums:
# 由 oddS 扩展得到的新 evenS
newEvenS = {}
for s, prod_set in list(oddS.items()):
ns = s - x
if ns not in newEvenS:
newEvenS[ns] = set()
for m in prod_set:
prod = m * x
if prod <= limit:
newEvenS[ns].add(prod)
# 由 evenS 扩展得到的 oddS 更新
for s, prod_set in list(evenS.items()):
ns = s + x
if ns not in oddS:
oddS[ns] = set()
for m in prod_set:
prod = m * x
if prod <= limit:
oddS[ns].add(prod)
if x == 0:
# 当加入 0 时,产生乘积为 0 的情况
add(oddS, s, 0)
# 用 newEvenS 更新 evenS
for s, prod_set in newEvenS.items():
if s in evenS:
evenS[s].update(prod_set)
else:
evenS[s] = set(prod_set)
if x == 0:
add(evenS, s, 0)
# 只有一个数的子序列
if x <= limit:
add(oddS, x, x)
# 提前返回的判断(达到上界 limit)
if k in oddS and limit in oddS[k]:
return limit
if k in evenS and limit in evenS[k]:
return limit
def calc_max(sset):
if not sset:
return-1
return max(sset)
return max(calc_max(oddS.get(k)), calc_max(evenS.get(k)))
if __name__ == "__main__":
nums = [1, 2, 3]
k = 2
limit = 10
print(max_product(nums, k, limit))
我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。 欢迎关注“福大大架构师每日一题”,发消息可获得面试资料,让AI助力您的未来发展。