数组求和统计
问题描述:牛牛有两个长度为$n$的数组$a$,$b$,牛牛希望统计有多少数对$(l,r)$满足:
示例
输入:[1,2,3,4],[2,1,4,5]
返回值:4
说明:满足条件的数对有$(0,1),(0,2),(1,1),(1,2)$,即存在这样四个等式:
方法一
思路分析
此题我们可以直接使用暴力搜索的办法,即设置内外两层循环,也可理解为快慢指针,循环计算数组$a$中$i(i<n)$位置到$j$位置$(i<=j<=n-1)$之间的元素的和,并计算数组$b$中$b[i]+b[j]$的和,判断两者是否相等,如果相等那么统计数对的变量加一。图解
输入:[1,2,3,4],[2,1,4,5]
其中,内外两层循环暴力搜索。
$i=0$ | ||||
$j$ | 0 | 1 | 2 | 3 |
$sum$ | 1 | 3 | 6 | 10 |
$b[i]+b[j]$ | 4 | 3 | 6 | 7 |
$ans$ | | $ans++$ | $ans++$ | |
数对 | | $(0,1)$ | $(0,2)$ | |
$i=1$ | |||
$j$ | 1 | 2 | 3 |
$sum$ | 2 | 5 | 9 |
$b[i]+b[j]$ | 2 | 5 | 6 |
$ans$ | $ans++$ | $ans++$ | |
数对 | $(1,1)$ | $(1,2)$ | |
$i=2$ | ||
$j$ | 2 | 3 |
$sum$ | 3 | 7 |
$b[i]+b[j]$ | 8 | 9 |
$ans$ | | |
数对 | | |
$i=3$ | |
$j$ | 3 |
$sum$ | 4 |
$b[i]+b[j]$ | 10 |
$ans$ | |
数对 | |
C++核心代码
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 计算有多少对符合条件的数对 * @param a int整型vector 数组a * @param b int整型vector 数组b * @return int整型 */ int countLR(vector<int>& a, vector<int>& b) { // write code here int n=a.size(); int sum; int res=0; for(int i=0;i<n;i++) { sum=0; for(int j=i;j<n;j++) { sum+=a[j];//数组a中[i,j]之间元素的和 if(sum==(b[i]+b[j]))//数组a中[i,j]之间元素的和是否与数组下标为i和j的元素和相同 res++; } } return res; } };
复杂度分析
- 时间复杂度:内外两层循环,循环次数为$1+2+3+...+n=n*(n+1)/2$,因此时间复杂度为$O(n^2)$
- 空间复杂度:借助于两个变量,因此空间复杂度为$O(1)$
方法二
思路分析
注意到方法一中时间消耗在了计算数组$a$中$i,(i<n)$i位置到$j$位置$(i<=j<n)$之间的元素的和上面,因此方法二中先将数组$a$的前缀和计算并将其存储在数组$a$中,那么就有然后利用下面的公式推导。
因此循环遍历数组$b$,设置map对象计算$(4)$右边的值的数量,即作为键值,键值对应的数量。
C++核心代码
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 计算有多少对符合条件的数对 * @param a int整型vector 数组a * @param b int整型vector 数组b * @return int整型 */ int countLR(vector<int>& a, vector<int>& b) { // write code here for(int i = 1; i < a.size(); i++) a[i] += a[i-1];//计算数组a的前缀和并存储在数组a中节省空间 int ans = 0; map<int, int> count; count[b[0]] = 1; for(int i = 1; i < b.size(); i++) { count[b[i]+a[i-1]]++;//等式左边 ans += count[a[i]-b[i]];//计数等式右边 } return ans; } };
复杂度分析
- 时间复杂度:首先对数组$a$求前缀和,时间复杂度为$O(n)$,接着求取等式$(4)$遍历次数$n$,因此总的时间复杂度为$O(n)$
- 空间复杂度:借助于一个map对象,因此总的空间复杂度为$O(n)$