算法专练:前缀和

1.1480. 一维数组的动态和

原题链接


        给你一个数组 nums 。
        数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i]) 。

        请返回 nums 的动态和

        示例 1:

        输入:nums = [1,2,3,4]

        输出:[1,3,6,10]

        解释:动态和计算过程为 [1, 1+2, 1+2+3, 1+2+3+4] 。

        示例 2:

        输入:nums = [1,1,1,1,1]

        输出:[1,2,3,4,5]

        解释:动态和计算过程为 [1, 1+1, 1+1+1, 1+1+1+1, 1+1+1+1+1] 。

        示例 3:

        输入:nums = [3,1,2,10,1]

        输出:[3,4,6,16,17]

        提示:

        1 <= nums.length <= 1000

        -10^6 <= nums[i] <= 10^6

前缀和模板题,单纯的求一下前缀和即可。

class Solution {
public:
    vector<int> runningSum(vector<int>& nums) {
        vector<int>ans;
        for(int i=0;i<nums.size();++i){
            if(!i){
                ans.push_back(nums[i]);
            }else ans.push_back(nums[i]+ans[i-1]);
        }
        return ans;
    }
};

2.1588. 所有奇数长度子数组的和

原题链接


        给你一个正整数数组 arr ,请你计算所有可能的奇数长度子数组的和。

        子数组 定义为原数组中的一个连续子序列。

        请你返回 arr 中 所有奇数长度子数组的和 。

示例 1:

输入:arr = [1,4,2,5,3]

输出:58

示例 2:

输入:arr = [1,2]

输出:3。

示例 3:

输入:arr = [10,11,12]

输出:66

提示:

1 <= arr.length <= 100

1 <= arr[i] <= 1000

也十分简单,先求出原数组的前缀和,然后枚举所有不超过数组长度的奇数,统计他们的和即可。

class Solution {
public:
    int sumOddLengthSubarrays(vector<int>& arr) {
        int n=arr.size();
        int*sum=new int[n+1];
        for(int i=1;i<=n;i++)
        sum[i]=sum[i-1]+arr[i-1];
        int ans=0;
        for(int len=1;len<=n;len+=2)
        {
            for(int l=0;l+len-1<n;l++)
            {
                int r=l+len-1;
                ans+=sum[r+1]-sum[l];
            }
        }
        return ans;
    }
};

3.1442. 形成两个异或相等数组的三元组数目

原题链接


        给你一个整数数组 arr 。

        现从数组中取三个下标 i、j 和 k ,其中 (0 <= i < j <= k < arr.length) 。

        a 和 b 定义如下:

        a = arr[i] ^ arr[i + 1] ^ … ^ arr[j - 1]

        b = arr[j] ^ arr[j + 1] ^ … ^ arr[k]

        注意:^ 表示 按位异或 操作。

        请返回能够令 a == b 成立的三元组 (i, j , k) 的数目。

        示例 1:

        输入:arr = [2,3,1,6,7]

        输出:4

        解释:满足题意的三元组分别是 (0,1,2), (0,2,2), (2,3,4) 以及 (2,4,4)

        示例 2:

        输入:arr = [1,1,1,1,1]

        输出:10

        示例 3:

        输入:arr = [2,3]

        输出:0

        示例 4:

        输入:arr = [1,3,5,7,9]

        输出:3

        示例 5:

        输入:arr = [7,11,12,9,5,2,7,17,22]

        输出:8

        提示:

        1 <= arr.length <= 300

        1 <= arr[i] <= 10^8

利用异或的性质,0与任何数异或都是他本身,任何数和自己异或都是0可以求出来某段区间的异或和。所以我们先求出来数组的前缀和,然后枚举所有的i,j,k去寻找相等的某些区间即可。这里利用了哈希表使得查找的时间复杂度降了下来。

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

4.1094. 拼车

原题链接


        车上最初有 capacity 个空座位。车 只能 向一个方向行驶(也就是说,不允许掉头或改变方向)

        给定整数 capacity 和一个数组 trips , trip[i] = [numPassengersi, fromi, toi] 表示第 i 次旅行有 numPassengersi 乘客,接他们和放他们的位置分别是 fromi 和 toi 。这些位置是从汽车的初始位置向东的公里数。

        当且仅当你可以在所有给定的行程中接送所有乘客时,返回 true,否则请返回 false。

        示例 1:

        输入:trips = [[2,1,5],[3,3,7]], capacity = 4

        输出:false

        示例 2:

        输入:trips = [[2,1,5],[3,3,7]], capacity = 5

        输出:true

        提示:

        1 <= trips.length <= 1000

        trips[i].length == 3

        1 <= numPassengersi <= 100

        0 <= fromi < toi <= 1000

        1 <= capacity <= 10^5

这道题与其说是前缀和不如说是差分数组,但是思想类似。对于每个trips[i],我们对从0到fron的区间加上trips[i][0],从0到to-1减去trips[i][0],来计算出车上每个时刻的人数。最后在统计所有时间内车上的乘客人数,如果超过了车容量就返回false,如果全部模拟玩仍然没有超过就最终返回true.
具体到什么是差分数组,就是我们对某个区间内要做将区间内的所有元素都加上或减去某个数字,并进行查找。最容易想到的方式就是遍历区间内每个元素进行加或减。但是当操作次数太大的时候这种方法太浪费时间了,于是我们现在考虑如何快速查找到修改后的数字。
现在我们定义数组d[i]他的定义是d[i]=arr[i]-arr[i-1],当我们想得到修改后的某个元素,应该如何做?很简单arr[i]=arr[i-1]+d[i].回归到本题上来,那么修改呢?也很简单,对某个区间[l,r],要加上某个数字num,考虑差分数组d[i]的定义,我们发现修改后该区间内的数字d[i]不变,但是d[l]却比d[l-1]多了num,d[r+1]比d[r]小了num.
如下图所示:
在这里插入图片描述

现在回到本题,构造差分数字就很简单了,对[from,to-1]的区间加上上车人数就对cnt[from]加上cnt即可,同时由于这些乘客在to的时候下车了,所以cnt[to]要减去cnt。(这里这样处理只是为了之后好算,因为差分数组要求下标从1开始这里当作从0开始了,所以直接对cnt[from],cnt[to]进行操作了,也是为了方便处理.)最后统计车上人数即可。

class Solution {
public:
    bool carPooling(vector<vector<int>>& trips, int capacity) {
        int cnt[1005];
        memset(cnt,0,sizeof(cnt));
        for(int i=0;i<trips.size();++i){
            int num=trips[i][0];
            int from=trips[i][1];
            int to=trips[i][2];
            cnt[from]+=num;
            cnt[to]-=num;//这里在to上减去人数也可以,因为是先下车再有人上车
        }
        int cur=0;
        for(int i=0;i<=1000;i++){
            cur+=cnt[i];
            if(cur>capacity){
                return false;
            }
        }
        return true;
    }
};
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值