2025-04-18:求出数组中最大序列值。用go语言,给定一个整数数组 nums 和一个正整数 k。 定义一个长度为 2*k 的子序列 seq 的值为:
1.将 seq 的前 k 个元素依次做按位或运算,得到一个值;
2.将 seq 的后 k 个元素依次做按位或运算,得到另一个值;
3.然后将这两个结果做按位异或(XOR),得到 seq 的最终值。
任务是从 nums 中的所有长度为 2*k 的连续子序列中,找出使上述计算值最大的那个,并返回该最大值。
2 <= nums.length <= 400。
1 <= nums[i] < 128。
1 <= k <= nums.length / 2。
输入:nums = [2,6,7], k = 1。
输出:5。
解释:
子序列 [2, 7] 的值最大,为 2 XOR 7 = 5 。
题目来自leetcode3287。
nums
和一个正整数 k
。nums
中,寻找所有长度为 2*k
的连续子序列。k
个元素的“按位或”值(即从第一个到第k个元素的或)。k
个元素的“按位或”值(即从第k+1个到第2*k个元素的或)。k
的连续子序列的按位或结果。k
的子序列,计算按位或。如果直接暴力计算,时间复杂度会较高(O(nkn))。findORs(nums, k)
,其目的是:nums
,对于每个前缀位置 i
,计算所有以 i
结尾的长度为 k
子序列的按位或结果集合。dp
结构是一个数组,dp[i]
存储所有以 nums[i]
结尾的长度为 k
子序列的按位或结果(用map[int]bool
表示set结构,记录不同的按位或值)。prev[j]
表示选择了 j
个元素时,所有能够得到的按位或值集合。prev[0]
包含0(未选择元素)。j = min(k-1, i+1)
到0遍历,prev[j+1]
。prev[k]
中包含了所有长度为 k
的子序列的按位或结果的集合。prev[k]
拷贝到对应的dp
位置,表示以当前元素结尾的长度为k
子序列的按位或集合。findORs
计算数组从左向右的所有长度为 k 子序列的按位或结果,保存在 A
。nums
数组,再调用 findORs
,得到从右向左的所有长度为 k 子序列的按位或结果集合,保存在 B
。i
从 k-1
到 len(nums)-k-1
遍历:i
表示左边长度为 k 子序列的结尾索引,下一个索引开始为右边长度 k 子序列的起点(连续且不重叠)。A[i]
中所有按位或结果 a
,和 B[len(nums)-i-2]
中所有结果 b
。a XOR b
,更新最大值 mx
。n
,子序列长度为 k
。findORs
函数中,核心循环最多遍历 n
个元素,每个元素对 k
个子序列长度进行更新。prev[j]
集合中存储按位或结果的数量:由于 nums[i] < 128
,按位或的最大范围是 7 位二进制,总共最多 2^7=128
个不同的按位或值。prev[j]
集合大小最多为 128。k * 128
次,整体为 O(n * k * 128)
,可简写为 O(n * k)
。findORs
各执行一次,总共 O(2 * n * k)
,即 O(n * k)
。A[i]
和 B[j]
集合大小均为最多约 128,因此这部分为 O(n * 128 * 128)
≈ O(n)
,常数因子较大但与128无关的情况下视作常数。dp
向量大小为 n,每个元素是一个 map/set,大小约为 128。A
和B
)都存储相同大小。A
和 B
占据,为 O(n * 128 * 2)
≈ O(n)
。prev
同理,大小为 k+1
,每个元素也是大小上限128的集合。复杂度项 | 具体说明 | 估算 |
---|---|---|
时间复杂度 | 两次DP更新(遍历n,k,和集合大小最多128) + 枚举切分点异或计算 | O(n * k) (k ≤ n) |
空间复杂度 | 两边DP存储 2 * n * 128大小的字典 | O(n) |
以上为该算法的详细实现思路及复杂度分析。
package main
import (
"fmt"
)
func maxValue(nums []int, k int)int {
findORs := func(nums []int, k int) []map[int]bool {
dp := make([]map[int]bool, 0)
prev := make([]map[int]bool, k+1)
for i := 0; i <= k; i++ {
prev[i] = make(map[int]bool)
}
prev[0][0] = true
for i := 0; i < len(nums); i++ {
for j := min(k-1, i+1); j >= 0; j-- {
for x := range prev[j] {
prev[j+1][x|nums[i]] = true
}
}
current := make(map[int]bool)
for key := range prev[k] {
current[key] = true
}
dp = append(dp, current)
}
return dp
}
A := findORs(nums, k)
reverse(nums)
B := findORs(nums, k)
mx := 0
for i := k - 1; i < len(nums)-k; i++ {
for a := range A[i] {
for b := range B[len(nums)-i-2] {
if a^b > mx {
mx = a ^ b
}
}
}
}
return mx
}
func reverse(nums []int) {
for i, j := 0, len(nums)-1; i < j; i, j = i+1, j-1 {
nums[i], nums[j] = nums[j], nums[i]
}
}
func main() {
nums := []int{2, 6, 7}
k := 1
results := maxValue(nums, k)
fmt.Println(results)
}
# -*-coding:utf-8-*-
from typing importList
defmax_value(nums: List[int], k: int) -> int:
deffind_ors(nums: List[int], k: int) -> List[set]:
dp = []
prev = [set() for _ inrange(k+1)]
prev[0].add(0)
for i inrange(len(nums)):
for j inrange(min(k-1, i) , -1, -1):
for x in prev[j]:
prev[j+1].add(x | nums[i])
current = set(prev[k])
dp.append(current)
return dp
defreverse(nums: List[int]) -> None:
nums.reverse()
A = find_ors(nums, k)
reverse(nums)
B = find_ors(nums, k)
mx = 0
n = len(nums)
for i inrange(k-1, n - k):
for a in A[i]:
for b in B[n - i - 2]:
mx = max(mx, a ^ b)
return mx
if __name__ == "__main__":
nums = [2, 6, 7]
k = 1
print(max_value(nums, k))