题目描述:
给你一个长度为 n
的 正 整数数组 nums
。
如果两个 非负 整数数组 (arr1, arr2)
满足以下条件,我们称它们是 单调 数组对:
- 两个数组的长度都是
n
。 arr1
是单调非递减 的,换句话说arr1[0] <= arr1[1] <= ... <= arr1[n - 1]
。arr2
是单调 非递增 的,换句话说arr2[0] >= arr2[1] >= ... >= arr2[n - 1]
。- 对于所有的
0 <= i <= n - 1
都有arr1[i] + arr2[i] == nums[i]
。
请你返回所有 单调 数组对的数目。
由于答案可能很大,请你将它对 109 + 7
取余 后返回。
代码思路:
代码使用了动态规划和前缀和的技巧。以下是代码的详细思路:
-
定义常量 MOD :
const int MOD = 1e9 + 7;
定义了一个常量MOD
,用于对结果进行模运算,以避免整数溢出并保持结果在一个可控的范围内。 -
类和方法 :定义了一个
Solution
类,其中包含一个countOfPairs
方法,该方法接收一个整数向量nums
并返回一个整数,表示满足条件的数对数量。 -
初始化累加数组
acc
:vector<int> acc(nums[0] + 1, 0);
初始化一个大小为nums[0] + 1
的数组acc
,所有元素初始化为 0。iota(acc.begin(), acc.end(), 1);
使用iota
函数将acc
数组填充为从 1 到nums[0]
的连续整数。这里的iota
函数来自<numeric>
头文件,用于生成一个递增序列。acc
数组用于存储到当前位置为止,所有可能的nums[i] ^ nums[j]
(其中j < i
)小于nums[i]
的数对数量。
-
遍历数组
nums
:- 使用一个迭代器
p
从nums
的第二个元素开始遍历到最后一个元素。 - 对于每个
nums[p]
,创建一个新的临时数组temp
,用于存储计算过程中的中间结果。
- 使用一个迭代器
-
计算部分和:
- 使用
partial_sum
函数计算acc
数组中部分元素的和,但只考虑那些可能对当前nums[p]
产生贡献的元素。 partial_sum
的起始范围是acc.begin()
到acc.begin() + min(*p, p[-1]) + 1
,这确保了只考虑那些异或结果可能小于nums[p]
的元素。temp.begin() + max(0, *p - p[-1])
确定了temp
数组中开始累加的位置,因为只有当nums[i] ^ nums[j]
的结果落在[0, nums[p] - 1]
范围内时,数对(i, p)
才是有效的。- 使用自定义的 lambda 函数
[](int sum, int a) { return (sum + a) % MOD; }
来计算累加和,并对结果取MOD
。
- 使用
-
更新
acc
数组:- 将
temp
数组赋值给acc
,为下一次迭代做准备。
- 将
-
返回结果:
- 最后,
acc.back()
存储了整个nums
数组遍历完成后,所有可能的nums[i] ^ nums[j]
小于nums[j]
的数对数量。
- 最后,
代码实现:
cpp
const int MOD = 1e9 + 7;
class Solution {
public:
int countOfPairs(vector<int>& nums) {
vector<int> acc(nums[0] + 1, 0);
iota(acc.begin(), acc.end(), 1);
for (auto&& p = nums.begin() + 1; p != nums.end(); p++) {
vector<int> temp(*p + 1, 0);
partial_sum(acc.begin(), acc.begin() + min(*p,p[-1]) + 1, temp.begin() + max(0,*p-p[-1]),
[](int sum, int a) { return (sum + a) % MOD; });
acc = temp;
}
return acc.back() ;
}
};