LeetCode 2588: 统计美丽子数组数目

LeetCode 2588: 统计美丽子数组数目

题目描述

给你一个下标从 0 开始的整数数组 nums。每次操作中,你可以:

  • 选择两个满足 0 <= i, j < nums.length 的不同下标 i 和 j。
  • 选择一个非负整数 k,满足 nums[i] 和 nums[j] 在二进制下的第 k 位(下标编号从 0 开始)是 1。
  • 将 nums[i] 和 nums[j] 都减去 2^k。

如果一个子数组内执行上述操作若干次后,该子数组可以变成一个全为 0 的数组,那么我们称它是一个 美丽子数组。

请你返回数组 nums 中 美丽子数组 的数目。

示例 1:

python 复制代码
输入: nums = [4,3,1,2,4]
输出: 2

示例 2:

python 复制代码
输入: nums = [1,10,4]
输出: 0

解题思路

本题的核心在于:如果一个子数组是美丽的,那么它的所有元素异或后的结果必然为 0。

我们可以利用 前缀异或和 + 哈希表 来高效计算满足条件的子数组数量。

前缀异或的思路

  1. 设 preXor[i] 表示从数组起点到索引 i 的前缀异或和。
  2. 如果某一段子数组 nums[l..r] 异或和为 0,那么它满足美丽子数组的条件。
  3. 由于 preXor[i] = preXor[j] 表示 nums[j+1..i] 这段子数组的异或和为 0,因此我们可以使用哈希表 cnt 统计 preXor 出现的次数。
  4. 每次计算当前 preXor[i] 时,累加 cnt[preXor[i]] 到答案中。

代码实现

python 复制代码
from collections import defaultdict

class Solution:
    def beautifulSubarrays(self, nums: List[int]) -> int:
        dict1 = defaultdict(int)  # 存储前缀异或和出现次数
        ans, cur = 0, 0
        dict1[0] = 1  # 处理从索引 0 开始就是美丽子数组的情况
        
        for num in nums:
            cur ^= num  # 计算当前的前缀异或和
            ans += dict1[cur]  # 统计当前前缀异或和已出现的次数
            dict1[cur] += 1  # 记录当前异或和出现的次数
        
        return ans

代码解析

  • cur:记录当前前缀异或和。
  • dict1[cur]:记录前缀异或和 cur 出现的次数。
  • dict1[0] = 1:表示当 cur == 0 时,说明从 0 到 i 的子数组本身是美丽子数组。
  • 遍历 nums,每次更新 cur ^= num 计算当前前缀异或和。
  • ans += dict1[cur] 统计 cur 之前出现的次数,这些都是满足异或和为 0 的子数组。
  • 最后更新 dict1[cur] 以记录当前 cur 的次数。

时间复杂度分析

  • 时间复杂度 :O(n),遍历 nums 一次,每次操作均为 O(1)。
  • 空间复杂度 :O(n),哈希表 dict1 最坏情况下存储 n 个不同的前缀异或和。

示例分析

示例 1

python 复制代码
nums = [4,3,1,2,4]

计算前缀异或和并统计 dict1:

i numsi cur (前缀异或) dict1 计数 ans (累计美丽子数组)
0 4 4 {0:1, 4:1} 0
1 3 7 {0:1, 4:1, 7:1} 0
2 1 6 {0:1, 4:1, 7:1, 6:1} 0
3 2 4 {0:1, 4:2, 7:1, 6:1} 1
4 4 0 {0:2, 4:2, 7:1, 6:1} 2

最终答案 ans = 2,表示 nums 中存在两个美丽子数组。

示例 2

python 复制代码
nums = [1,10,4]
  • 计算前缀异或和 cur 依次为 [1, 11, 15],它们都没有重复出现,因此 ans = 0。

总结

  • 核心思想 :利用前缀异或和的性质,判断某个子数组是否异或和为 0。
  • 哈希表优化 :利用 dict1 记录 cur 出现的次数,实现 O(n) 复杂度计算。
  • 适用范围 :适用于寻找连续子数组异或和特定值 的问题,比如 560. 和为 K 的子数组。

这道题的解法很巧妙,是 前缀异或 + 哈希表 的经典应用,值得深入理解!

相关推荐
Dream it possible!4 小时前
LeetCode 面试经典 150_多维动态规划_交错字符串(97_C++_中等)
算法·leetcode·面试·动态规划
心抵鹊4 小时前
算法之双指针系列(一)
算法·leetcode
十二4 小时前
【洛谷题解】P1083 [NOIP 2012 提高组] 借教室(二分答案 + 差分)
数据结构·c++·算法·蓝桥杯
小此方5 小时前
[算法实战论:动态规划]回文串问题的dp解法,回文串问题的母题,以及以此为基础的派生题
算法·动态规划
Pniubi6 小时前
力扣560.和为k的子数组
算法·leetcode·职场和发展
D e re k ZH6 小时前
C++ 从零入门(一):基础语法与程序结构
数据结构·c++·算法
Pniubi7 小时前
力扣438.找到字符串中所有字母异位词
算法·leetcode·职场和发展
東隅已逝,桑榆非晚9 小时前
算法6. 双指针法-查找总价格为目标的两个商品
c++·学习·算法
Eyfcom9 小时前
〖物联网终端实战 01〗UWB 室内高精度定位:仓储 AGV 与人员的厘米级轨迹追踪
物联网·算法·物流系统·快递系统·跨境物流快递系统·物联网终端实战
bro_Java66610 小时前
《排序的底层逻辑:比较、交换与分治》
java·算法·排序算法