202、【数组】leetcode ——2588. 统计美丽子数组数目(C++/Python版本)

题目描述

202、【数组】leetcode ——2588. 统计美丽子数组数目(C++/Python版本)_第1张图片
202、【数组】leetcode ——2588. 统计美丽子数组数目(C++/Python版本)_第2张图片
原题链接:2588. 统计美丽子数组数目

解题思路

本题的难点在于对于题意的解析与思路的转化。题中说的子数组中的美丽数,每次找两个数,其相同位减去1。相当于是这个数组中,每一个位的二进制数为1的个数偶数即可。进一步,可通过在这个子数组中所有的数进行异或运算后得到的结果是否为0来验证是否为每位为1的个数是否为偶数。(异或运算:对相同为0,相异为1,0与任何数计算该数数值保持不变)

因此,问题就转化为了找到一个一个区间内,所有的数进行异或操作后数值变为0。而想要让一段区间内异或和为0,则可以通过找到前缀和中两个相同的数,作为左右边界,则此时区间内的数异或后就为0。此时,就相当于是在求解子区间问题并找到某一区间内的结果0,而前缀和是处理子区间内数值的常用方式。

规定前缀和为异或运算后的前缀和,只要找到前缀和相同的两个位置,此时这两个位置之间的区间,异或后就一定为0。思路类似于 面试题 17.05. 字母与数字(详细解析)。

使用一个哈希表,key为前缀和,value为具有该前缀和的个数。因为是要找到所有的满足异或后为0的子区间,因此,需要的就是对相同的前缀和进行两两配对,便计算出了所有情况。同时,当出现前缀和为0时,也说明前方已经构造了异或后为1的情况,也应该加上一。

代码实现

class Solution {
public:
    long long beautifulSubarrays(vector<int>& nums) {
        int n = nums.size();
        long long res = 0;
        // 1、获取前缀和
        vector<int> s(n + 1);
        for(int i = 0; i < n; i++)      s[i + 1] = s[i] ^ nums[i];      
        // 2、构建哈希表
        unordered_map<int, int> cnt;
        // 3、记录相同前缀和的对数
        for(int x : s) {			// 这里要从包含s[0]开始遍历,从而cnt[0]++ = 1,让后续在有效区间段内出现0时,正常加上一次情况。
            res += cnt[x]++;        // 每多一个相同前缀和,就会和前方的进行两两配对,因此每次都加上cnt[x]
        }

        return res;
    }
};

Python

class Solution:
    def beautifulSubarrays(self, nums: List[int]) -> int:
        # 初始化前缀和
        s = [0]
        for i in nums:
            s.append(s[-1]^i)
        # 找到相同前缀和出现次数
        res, cnt = 0,  Counter()                
        for x in s:
            res += cnt[x]           # 出现过的x次数,就是这一段区间内可异或和为0的成对个数。
            cnt[x] += 1             # x出现过一次,则加一。            
        print(cnt)
        return res
        

代码优化
边计算前缀和,边统计

class Solution {
public:
    long long beautifulSubarrays(vector<int>& nums) {
        int n = nums.size();
        long long res = 0;
        int s = 0;      // s作为每次的前缀和
        // 注意这里是让cnt[0] = 1,因为之后的for循环是从nums[0]直接开始,所以提前就统计上出现0时,会认为出现一次目标区间,加上这次情况
        unordered_map<int, int> cnt{{s, 1}};        
        for(int x : nums) {            
            s ^= x;
            res += cnt[s]++;
        }

        return res;
    }
};

Python

class Solution:
    def beautifulSubarrays(self, nums: List[int]) -> int:
        s = 0
        res, cnt = 0, Counter({0:1})
        for i in nums:         
            s ^= i
            res += cnt[s]
            cnt[s] += 1
        return res
            


参考文章:【套路】前缀和+哈希表(Python/Java/C++/Go)

你可能感兴趣的:(数据结构与算法刷题,#,数组,#,哈希表,leetcode,c++,算法)