题目描述:
给你一个长度为 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() ;
}
};