思路:
题目的主要信息:
两个长度相同的数组a与b,长度都为n
统计数对出现的次数,其中:
相当于是相同的下标,a数组中的区间求和等于b数组中两端相加。
方法一:暴力法
具体做法:
一个慢指针遍历a数组中的每个元素,另一个快指针遍历a数组中后面的所有元素,并累加快慢指针之间的和,并每次与快慢指针下标在b数组中对应两个元素的和作比较,若是相等则计数加一。
class Solution { public: int countLR(vector<int>& a, vector<int>& b) { int count = 0; //计数 for(int i = 0; i < a.size(); i++){ int sum = 0; for(int j = i; j < a.size(); j++){ //遍历之后的相加 sum += a[j]; if(sum == b[i] + b[j]) //比较首尾 count++; } } return count; } };
复杂度分析:
- 时间复杂度:,两层循环遍历
- 空间复杂度:,无额外空间
方法二:前缀和+哈希表
具体做法:
对于这个公式:,我们可以看到在方法一中,我们并非每次都从头加到尾,而是在前缀的基础上加上当前元素,我们可以用表示前i个元素的前缀和。因此这个公式我们还可以变化一下:(下标从1开始)
寻找左右两个前缀和之间的关系,就为:
因此我们可以在遍历的时候将放入一个哈希表中,每次检查是否在哈希表中有存在,若是有则加上哈希表中的计数。
class Solution { public: int countLR(vector<int>& a, vector<int>& b) { int count = 0; //计数 vector<int> dp; //记录前缀和,dp[i]表示前面项加起来的和 unordered_map<int, int> mp; int sum = 0; for(int i = 0; i < a.size(); i++){ //求前缀和 sum += a[i]; dp.push_back(sum); } mp[b[0] + dp[0] - a[0]] = 1; //第0个元素 for(int i = 1; i < a.size(); i++){ mp[b[i] + dp[i] - a[i]]++; if(mp.find(dp[i] - b[i]) != mp.end()) //在哈希表中查找 count += mp[dp[i] - b[i]]; } return count; } };
复杂度分析:
- 时间复杂度:,两次遍历都是单循环,unordered_map的查找为
- 空间复杂度:,哈希表与记录前缀和的辅助数组dp