五月集训 (第08天) —— 前缀和

Posted 英雄哪里出来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了五月集训 (第08天) —— 前缀和相关的知识,希望对你有一定的参考价值。

文章目录

前言

        此为《英雄算法联盟:算法集训》的内容,具体内容详见:知识星球:英雄算法联盟。加入星球后,即可享用星主 CSDN付费专栏 免费阅读 的权益。
        欢迎大家积极在评论区留言发表自己的看法,知无不言,言无不尽,养成每天刷题的习惯,也可以自己发布优质的解题报告,供社区一同鉴赏,吸引一波自己的核心粉丝。
        希望大家先自己思考,如果实在没有想法,再看下面的算法思路,如果有思路但是写不出来,可以参考朋友圈中其他人的代码,总有一款是适合你的,关注一下他,取其之长,补给之短。
        今天集训的内容是:前缀和
        前两题较为简单,第三题用C++会非常方便,第四题比较巧妙,如果暂时写不出来,可以先记录下,后续再来做。

一、练习题目

题目链接难度
1480. 一维数组的动态和★☆☆☆☆
1588. 所有奇数长度子数组的和★☆☆☆☆
1442. 形成两个异或相等数组的三元组数目★★☆☆☆
1094. 拼车★★☆☆☆

二、算法思路

1、一维数组的动态和

        (1)定义一个用于返回的数组 ret
        (2)遍历原数组,如果是第 0 个元素,则直接将它插入待返回的数组;
        (3)否则,则将待返回的数组的最后一个元素和当前第 i 个元素加和后插入;
        (4)当然,也可以直接在原数组操作,如下:

class Solution 
public:
    vector<int> runningSum(vector<int>& nums) 
        for(int i = 1; i < nums.size(); ++i) 
            nums[i] += nums[i-1];
        
        return nums;
    
;

2、所有奇数长度子数组的和

        (1)首先,定义前缀和 sum
        (2)枚举一个长度 i,枚举一个结束为止 j,利用差分就能得到 sum[j-i+1, j] 的元素和;
        (3)统计加和所有 i 为奇数的元素和即可;

class Solution 
public:
    int sumOddLengthSubarrays(vector<int>& arr) 
        int i, j, pre, ans = 0;
        for(i = 1; i < arr.size(); ++i) 
            arr[i] += arr[i-1];
        
        for(i = 1; i <= arr.size(); i += 2) 
            for(j = i-1; j < arr.size(); ++j) 
                // 以第 j 个数结尾并且长度为 i 的子数组
                if(j - i == -1) 
                    pre = 0;
                else 
                    pre = arr[j-i];
                
                ans += arr[j] - pre;  // arr[j] - arr[j-i]
            
        
        return ans;
    
;

3、形成两个异或相等数组的三元组数目

        (1)计算前缀和;
        (2)枚举一个 j,再枚举 i 将异或和 [i,j-1] 塞入哈希表;
        (3)再枚举 k,去哈希表中查找 [j, k] 的异或和并且累加;
        (4)时间复杂度可以做到 O(n*n)

class Solution 
    unordered_map<int, int> hash;
public:
    int countTriplets(vector<int>& arr) 
        int i, j, k, pre, ans = 0;
        for(i = 1; i < arr.size(); ++i) 
            arr[i] = arr[i-1] ^ arr[i];
        
        for(j = 1; j < arr.size(); ++j) 
            hash.clear();
            for(i = 0; i < j; ++i) 
                if(i == 0) 
                    pre = 0;
                else 
                    pre = arr[i-1];
                
                ++hash[ arr[j-1] ^ pre ];
            
            for(k = j; k < arr.size(); ++k) 
                ans += hash[ arr[k] ^ arr[j-1] ];
            
        
        return ans;

    
;

4、拼车

        (1)用一个数组来标记上下车的情况;
        (2)一次线性扫描置上标记
        (3)然后再累加标记,就是当前时间点列车上的人数,如果某个时间点人数超过了给定值,返回 false;一直没有超过,返回 true

class Solution 
public:
    bool carPooling(vector<vector<int>>& trips, int capacity) 
        int i, numPassengers[1002];
        memset(numPassengers, 0, sizeof(numPassengers));
        for(i = 0; i < trips.size(); ++i) 
            int cnt = trips[i][0];
            int l = trips[i][1];
            int r = trips[i][2];
            numPassengers[l] += cnt;
            numPassengers[r] -= cnt;
        
        int sum = 0;
        for(i = 0; i <= 1000; ++i) 
            sum += numPassengers[i];
            if(sum > capacity) 
                return false;
            
        
        return true;
    
;

以上是关于五月集训 (第08天) —— 前缀和的主要内容,如果未能解决你的问题,请参考以下文章

五月集训(第31天) —— 状态压缩

七月集训(第08天) —— 前缀和

六月集训(第08天) —— 前缀和

五月集训(第25天) —— 树状数组

五月集训(第28天) —— 动态规划

五月集训(第22天) —— 有序集合