《五月集训》(第八天)——前缀和

本文探讨了如何使用前缀和与哈希表解决数组操作中的四个问题:一维数组的动态和、奇数长度子数组的和、异或相等数组的三元组数目以及拼车问题。通过详细阐述算法思路和源码解析,展示了在编程中应用这些数据结构和技巧的重要性。
摘要由CSDN通过智能技术生成

前言

        欢迎大家积极在评论区留言发表自己的看法,知无不言,言无不尽,养成每天刷题的习惯,也可以自己发布优质的解题报告,供社区一同鉴赏,吸引一波自己的核心粉丝。
        今天是五月集训第八天:前缀和

一、练习题目

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

二、算法思路

  • 1、1480.一维数组的动态和:就利用前缀和。
  • 2、1588.所有奇数长度子数组的和:这个题目感觉对我来说并不是一道简单题,想了很久才逐渐理清了思路。我能理解的思考写法在下面源码剖析中。
      具体过程:
        1.拿[1,4,2,5,3]举例,用一个sum数组表示前缀和,sum求出来是[0,1,5,7,12,15]
        2.定义i扫描原数组,定义j从i+1开始,每次j += 2,意图是找i开始奇数长度度的子数组,看上面的例子,j就是+1,+3,+5往后走;
        3.我们提前算好了前缀和,那比如我i = 0j = i + 1就是从i开始1长度的奇数数组[1],刚好也是sum[j] - sum[i] = 1,然后j = i + 3就是i开始长度为3的奇数数组[1,4,2],刚好也是sum[j] - sum[i] = 7,后面就依次类推就行了,可以草稿纸复现一下。
  • 3、1442. 形成两个异或相等数组的三元组数目:前缀和+哈希表。
  • 4、1094.拼车:巧妙的前缀和。

三、源码剖析

// 1480.一维数组的动态和
class Solution {
public:
    vector<int> runningSum(vector<int>& nums) {
        int n = nums.size();
        for (int i = 1; i < n; i++)
        {
            nums[i] += nums[i - 1]; //(1)
        }
        return nums;
    }
  • 1、利用前缀和直接在原数组操作。
// 1588.所有奇数长度子数组的和
class Solution {
public:
    int sumOddLengthSubarrays(vector<int>& arr) {
        int n = arr.size(), ans = 0;
        vector<int> sum(n + 1);
        for(int i = 0; i < n; i++) {
            sum[i + 1] = sum[i] + arr[i]; // (1)
        }

        for(int i = 0; i < n; i++) {
            for(int j = i + 1; j <= n; j += 2) { //(2)
                ans += sum[j] - sum[i]; //(3)
            }
        }

        return ans;

    }
};
  • 1、用一个sum数组表示前缀和;
  • 2、定义i扫描原数组,定义j从i+1开始,每次j += 2,意图是找i开始奇数长度度的子数组,j就是+1,+3,+5,……+奇数往后走;
  • 3、加到ans里面。
// 1442. 形成两个异或相等数组的三元组数目
class Solution {
    unordered_map<int, int> hash;
public:
    int countTriplets(vector<int>& arr) {
        int pre, ans = 0, n = arr.size();
        for(int i = 1; i < n; i++) {
            arr[i] = arr[i - 1] ^ arr[i]; //(1)
        }

        for(int j = 1; j < n; ++j) {
            hash.clear();
            for(int i = 0; i < j; ++i) { //(2)
                if(i == 0) {
                    pre = 0;
                } else {
                    pre = arr[i - 1];
                }
                ++hash[arr[j - 1] ^ pre];
            }

            for(int k = j; k < n; ++k) { //(3)
                ans += hash[arr[k] ^ arr[j - 1]];
            }
        }
        return ans;
    }
};
  • 1、计算前缀和
  • 2、枚举一个j,再枚举一个i将异或和[i,j-1]塞入哈希表;
  • 3、再去枚举k,去哈希表中查找[j,k]的异或和并累加。
// 1094. 拼车
class Solution {
public:
    bool carPooling(vector<vector<int>>& trips, int capacity) {
        int n = trips.size(), numPassengers[1001];
        memset(numPassengers, 0, sizeof(numPassengers));
        for(int i = 0; i < n; ++i) {
            int cnt = trips[i][0];
            int l = trips[i][1];
            int r = trips[i][2];
            numPassengers[l] += cnt;
            numPassengers[r] -= cnt; 
        } //(1)
        int sum = 0;
        for(int i = 0; i < 1000; i++) {
            sum += numPassengers[i];
            if(sum > capacity) { //(2)
                return false;
            }
        }
        return true;
    }
};
  • 1、用一个数组来标记上下车的情况,线性扫描置上标记;
  • 2、累加标记,当前时间点列车上的人数,如果超过给定值,返回false,否则true。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值