
2026-02-14:含上限元素的子序列和。用go语言,给你一个长度为 n 的整数数组 nums 和一个正整数 k。对于每个整数 x(1 ≤ x ≤ n),先把数组中大于 x 的数都缩小到 x,得到一个新的数组。然后在这个新数组中,是否能够取出一个非空的、保持原来相对顺序的子序列,使其元素之和恰好等于 k?
将对每个 x(按 x=1 到 n 顺序)的可行性用一个长度为 n 的布尔数组 answer 表示,其中 answer[i](下标从 0 开始)表示当 x = i+1 时是否存在这样的子序列。
1 <= n == nums.length <= 4000。
1 <= nums[i] <= n。
1 <= k <= 4000。
输入: nums = [4,3,2,4], k = 5。
输出: [false,false,true,true]。
解释:
对于 x = 1,限制后的数组为 [1, 1, 1, 1]。可能的和为 1, 2, 3, 4,因此无法选出和为 5 的子序列。
对于 x = 2,限制后的数组为 [2, 2, 2, 2]。可能的和为 2, 4, 6, 8,因此无法选出和为 5 的子序列。
对于 x = 3,限制后的数组为 [3, 3, 2, 3]。可以选择子序列 [2, 3],其和为 5,能选出满足要求的子序列。
对于 x = 4,限制后的数组为 [4, 3, 2, 4]。可以选择子序列 [3, 2],其和为 5,能选出满足要求的子序列。
题目来自力扣3685。
算法采用增量构造 + 二进制状态压缩动态规划的思想:
步骤1:排序
步骤2:初始化
步骤3:枚举 x 从 1 到 n
步骤4:输出结果
nums = [4,3,2,4], k = 5
排序后:[2,3,4,4]
注意:big.Int 内部存储二进制位所需空间为 O(k/wordsize),k ≤ 4000,所以约 4000 位 ≈ 63 个 64位字,可视为常数空间。
package main
import (
"fmt"
"math/big"
"slices"
)
func subsequenceSumAfterCapping(nums []int, k int) []bool {
slices.Sort(nums)
n := len(nums)
ans := make([]bool, n)
f := big.NewInt(1)
u := new(big.Int).Lsh(big.NewInt(1), uint(k+1))
u.Sub(u, big.NewInt(1))
i := 0
for x := 1; x <= n; x++ {
// 增量地考虑所有恰好等于 x 的数
for i < n && nums[i] == x {
shifted := new(big.Int).Lsh(f, uint(nums[i]))
f.Or(f, shifted).And(f, u) // And(f, u) 保证 f 的二进制长度 <= k+1
i++
}
// 枚举(从大于 x 的数中)选了 j 个 x
for j := range min(n-i, k/x) + 1 {
if f.Bit(k-j*x) > 0 {
ans[x-1] = true
break
}
}
}
return ans
}
func main() {
nums := []int{4, 3, 2, 4}
k := 5
result := subsequenceSumAfterCapping(nums, k)
fmt.Println(result)
}

.
# -*-coding:utf-8-*-
def subsequence_sum_after_capping(nums, k):
nums.sort()
n = len(nums)
ans = [False] * n
# 使用位掩码,f 的第 b 位为 1 表示存在和为 b 的子序列
f = 1
# 只需要保留到 2^(k+1) - 1
mask = (1 << (k + 1)) - 1
i = 0
for x in range(1, n + 1):
# 增量地考虑所有恰好等于 x 的数
while i < n and nums[i] == x:
# f = f | (f << nums[i]),并截断到 mask
f = (f | (f << nums[i])) & mask
i += 1
# 枚举(从大于 x 的数中)选了 j 个 x
for j in range(min(n - i, k // x) + 1):
if f >> (k - j * x) & 1:
ans[x - 1] = True
break
return ans
def main():
nums = [4, 3, 2, 4]
k = 5
result = subsequence_sum_after_capping(nums, k)
print(result)
if __name__ == "__main__":
main()
.
#include <vector>
#include <algorithm>
#include <iostream>
#include <bitset>
#include <climits>
std::vector<bool> subsequenceSumAfterCapping(std::vector<int> nums, int k) {
std::sort(nums.begin(), nums.end());
int n = nums.size();
std::vector<bool> ans(n, false);
// 使用bitset来存储可达和的状态
// 只需要考虑和不超过k的状态
std::bitset<100001> f; // 假设k最大为100000,可以根据需要调整
f[0] = 1;
int i = 0;
for (int x = 1; x <= n; x++) {
// 增量地考虑所有恰好等于x的数
while (i < n && nums[i] == x) {
f = f | (f << nums[i]);
i++;
}
// 枚举(从大于x的数中)选了j个x
int max_j = std::min(n - i, k / x);
for (int j = 0; j <= max_j; j++) {
if (k - j * x >= 0 && f.test(k - j * x)) {
ans[x - 1] = true;
break;
}
}
}
return ans;
}
int main() {
std::vector<int> nums = {4, 3, 2, 4};
int k = 5;
std::vector<bool> result = subsequenceSumAfterCapping(nums, k);
// 打印结果
std::cout << "[";
for (size_t i = 0; i < result.size(); i++) {
std::cout << (result[i] ? "true" : "false");
if (i < result.size() - 1) {
std::cout << ", ";
}
}
std::cout << "]" << std::endl;
return0;
}

·
我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。 欢迎关注“福大大架构师每日一题”,发消息可获得面试资料,让AI助力您的未来发展。
·