声明:模板来自于灵茶山艾府的个人空间-灵茶山艾府个人主页-哔哩哔哩视频 (bilibili.com)灵神,在此进行总结学习。
问题:898. 子数组按位或操作 - 力扣(LeetCode)计算子数组按位或运算之后,统计不同结果的个数。
分析:按位或运算有两个显著特点,一个数与其他数按位或的结果中一的个数要么不变要么加一;左端点相同时,遍历右端点按位或时存在两个右端点计算结果一致,说明中间数也会得出相同结果,因此可以原地去重。
本题使用map统计结果,ors计算并保存去重结果。反向遍历nums数组,ors中第一个位置保存m个元素按位或结果,第二个位置保存m-1个元素按位或结果,以此类推。然后进行原地去重,k代表保存不重复的运算结果的右端点(从0开始),我们需要依次比较ors中其余元素(因此使用ors[1:])是否重复,不重复则计数,并将他保存在k+1的位置。去重完毕之后,切片,保留k个不重复元素。
func subarrayBitwiseORs(nums []int) int {
n := len(nums)
ors:=make([]int,0)
mp:=make(map[int]int)
for i := n - 1; i >= 0; i-- {
num := nums[i]
ors = append(ors, 0)
ors[0] |= num
mp[ors[0]]++
k := 0
for _, p := range ors[1:] {
p |= num
if ors[k] != p {
mp[p]++
k++
ors[k] = p
}
}
ors = ors[:k+1]
}
return len(mp)
}
如100271. 或值至少为 K 的最短子数组 II - 力扣(LeetCode)也是同样的思路
func minimumSubarrayLength(nums []int, k int) int {
ans := math.MaxInt
type pair struct{ or, left int }
ors := []pair{}
for i, x := range nums {
ors = append(ors, pair{0, i})
ors[0].or |= x
j := 0
for _, p := range ors[1:] {
p.or |= x
if ors[j].or == p.or {
ors[j].left = p.left
} else {
j++
ors[j] = p
}
}
ors = ors[:j+1]
for len(ors) > 0 && ors[0].or >= k {
ans = min(ans, i-ors[0].left+1)
ors = ors[1:]
}
}
if ans == math.MaxInt {
return -1
}
return ans
}