leetcode 2588. 统计美丽子数组数目

题目链接:LeetCode2588

1.题目

给你一个下标从 0 开始的整数数组nums 。每次操作中,你可以:
选择两个满足 0 <= i, j < nums.length 的不同下标 i 和 j 。
选择一个非负整数 k ,满足 nums[i] 和 nums[j] 在二进制下的第 k 位(下标编号从 0 开始)是 1 。
将 nums[i] 和 nums[j] 都减去 2k 。
如果一个子数组内执行上述操作若干次后,该子数组可以变成一个全为 0 的数组,那么我们称它是一个 美丽 的子数组。

请你返回数组 nums 中 美丽子数组 的数目。
子数组是一个数组中一段连续 非空 的元素序列。

2.示例

1)示例 1:
输入:nums = [4,3,1,2,4]
输出:2
解释:nums 中有 2 个美丽子数组:[4,3,1,2,4] 和 [4,3,1,2,4] 。

  • 按照下述步骤,我们可以将子数组 [3,1,2] 中所有元素变成 0 :
    • 选择 [3, 1, 2] 和 k = 1 。将 2 个数字都减去 21 ,子数组变成 [1, 1, 0] 。
    • 选择 [1, 1, 0] 和 k = 0 。将 2 个数字都减去 20 ,子数组变成 [0, 0, 0] 。
  • 按照下述步骤,我们可以将子数组 [4,3,1,2,4] 中所有元素变成 0 :
    • 选择 [4, 3, 1, 2, 4] 和 k = 2 。将 2 个数字都减去 22 ,子数组变成 [0, 3, 1, 2, 0] 。
    • 选择 [0, 3, 1, 2, 0] 和 k = 0 。将 2 个数字都减去 20 ,子数组变成 [0, 2, 0, 2, 0] 。
    • 选择 [0, 2, 0, 2, 0] 和 k = 1 。将 2 个数字都减去 21 ,子数组变成 [0, 0, 0, 0, 0] 。

2)示例 2:
输入:nums = [1,10,4]
输出:0
解释:nums 中没有任何美丽子数组。

3)提示:
1 <= nums.length <= 105
0 <= nums[i] <= 106

3.分析

首先题目给定的条件是“”选择一个非负整数 k ,满足 nums[i] 和 nums[j] 在二进制下的第 k 位(下标编号从 0 开始)是 1 。
将 nums[i] 和 nums[j] 都减去 2k 。
如果一个子数组内执行上述操作若干次后,该子数组可以变成一个全为 0 的数组,那么我们称它是一个 美丽 的子数组。“”
那么我们可以知道,对于每一个二进制位,上面1的个数都是偶数,这样才能达到上述条件,这样也就是转化为如果一个数组是美丽数组,那么这个数组内所有数字做异或,最后的结果为0。那么我们考虑第i个元素作为数组的右边界,如果[left,i]满足这个子数组为美丽数组,那么num[left]异或…异或num[i]=0那么[left,i-1]的异或值=nums[i]。如果遍历每个左边界的话,时间复杂度是二次的,会超时,我们可以采用哈希表+前缀异或和的思路处理数据。

4.代码

class Solution {
public:
    long long beautifulSubarrays(vector<int>& nums) {
        long long ans=0;
        map<long long,long long> map1;
        vector<long long> V(nums.size()+1);
        V[0]=0;
        for(int i=0;i<nums.size();i++)
            V[i+1]=V[i]^nums[i];
        for(int i=0;i<=nums.size();i++)
            ans+=map1[V[i]]++;
        return ans;
        
        for(int i=0;i<nums.size();i++){
            if(nums[i]==0) ans++;
            if(map1.count(nums[i])!=0) ans+=map1[nums[i]];
            map<long long,long long> map2;
            for(auto itr=map1.begin();itr!=map1.end();itr++){
                long long test=itr->first^nums[i];
                if(map2.count(test)==0) map2[test]=map1[itr->first];
                else map2[test]+=map1[itr->first];
                map1[itr->first]=0;
            }
            for(auto itr=map2.begin();itr!=map2.end();itr++)
                map1[itr->first]=map2[itr->first];
            
            // for(int j=0;j<V.size();j++){
            //     V[j]^=nums[i];
            //     if(map1.count(V[j])==0) map1[V[j]]=1;
            //     else  map1[V[j]]++;
            // }
            // V.push_back(nums[i]);
            if(map1.count(nums[i])==0) map1[nums[i]]=1;else map1[nums[i]]++;
        }
        return ans;
    }
};
  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值