Medium
题目描述
给你一个整数数组 nums。
特殊三元组定义为满足以下条件的三元组索引 (i, j, k):
0 <= i < j < k < n,其中n = nums.lengthnums[i] == nums[j] * 2nums[k] == nums[j] * 2
返回数组中特殊三元组的总数。
由于答案可能很大,请返回对 10^9 + 7 取模的结果。
示例 1:
输入:nums = [6,3,6]
输出:1
解释:
唯一的特殊三元组是 (i, j, k) = (0, 1, 2),其中:
- nums[0] = 6, nums[1] = 3, nums[2] = 6
- nums[0] = nums[1] * 2 = 3 * 2 = 6
- nums[2] = nums[1] * 2 = 3 * 2 = 6
示例 2:
输入:nums = [0,1,0,0]
输出:1
解释:
唯一的特殊三元组是 (i, j, k) = (0, 2, 3),其中:
- nums[0] = 0, nums[2] = 0, nums[3] = 0
- nums[0] = nums[2] * 2 = 0 * 2 = 0
- nums[3] = nums[2] * 2 = 0 * 2 = 0
示例 3:
输入:nums = [8,4,2,8,4]
输出:2
解释:
恰好有两个特殊三元组:
- (i, j, k) = (0, 1, 3)
- (i, j, k) = (1, 2, 4)
提示:
3 <= n == nums.length <= 10^50 <= nums[i] <= 10^5
解题思路
这道题要求找到满足条件的三元组 (i, j, k),其中 nums[i] == nums[j] * 2 且 nums[k] == nums[j] * 2。
核心思路:
对于每个位置 j,我们需要统计在它之前有多少个元素等于 nums[j] * 2,以及在它之后有多少个元素等于 nums[j] * 2。这两个数量的乘积就是以位置 j 为中心的特殊三元组数量。
优化策略: 使用频率数组来动态维护前缀和后缀的元素频率:
- 初始化时,将所有元素的频率存储在
freqNext中 - 遍历数组,对于每个位置
j:- 从
freqNext中移除当前元素 - 计算当前位置作为中间元素时的贡献:
freqPrev[nums[j] * 2] * freqNext[nums[j] * 2] - 将当前元素添加到
freqPrev中
- 从
这种方法避免了三重循环,时间复杂度降为 O(n),是最优解法。
需要注意的是,当 nums[j] * 2 超出数组范围时要特别处理,以及结果需要对 10^9 + 7 取模。
代码实现
class Solution {
public:
int specialTriplets(vector<int>& nums) {
const int MOD = 1e9 + 7;
const int MAX_VAL = 1e5;
int n = nums.size();
vector<int> freqPrev(MAX_VAL + 1, 0);
vector<int> freqNext(MAX_VAL + 1, 0);
// 初始化freqNext
for (int num : nums) {
freqNext[num]++;
}
long long result = 0;
for (int j = 0; j < n; j++) {
freqNext[nums[j]]--;
// 检查nums[j] * 2是否在有效范围内
if (nums[j] <= MAX_VAL / 2) {
int target = nums[j] * 2;
long long count = (long long)freqPrev[target] * freqNext[target];
result = (result + count) % MOD;
}
freqPrev[nums[j]]++;
}
return result;
}
};
class Solution:
def specialTriplets(self, nums: List[int]) -> int:
MOD = 10**9 + 7
MAX_VAL = 10**5
n = len(nums)
freq_prev = [0] * (MAX_VAL + 1)
freq_next = [0] * (MAX_VAL + 1)
# 初始化freq_next
for num in nums:
freq_next[num] += 1
result = 0
for j in range(n):
freq_next[nums[j]] -= 1
# 检查nums[j] * 2是否在有效范围内
if nums[j] <= MAX_VAL // 2:
target = nums[j] * 2
count = freq_prev[target] * freq_next[target]
result = (result + count) % MOD
freq_prev[nums[j]] += 1
return result
public class Solution {
public int SpecialTriplets(int[] nums) {
const int MOD = 1000000007;
const int MAX_VAL = 100000;
int n = nums.Length;
int[] freqPrev = new int[MAX_VAL + 1];
int[] freqNext = new int[MAX_VAL + 1];
// 初始化freqNext
foreach (int num in nums) {
freqNext[num]++;
}
long result = 0;
for (int j = 0; j < n; j++) {
freqNext[nums[j]]--;
// 检查nums[j] * 2是否在有效范围内
if (nums[j] <= MAX_VAL / 2) {
int target = nums[j] * 2;
long count = (long)freqPrev[target] * freqNext[target];
result = (result + count) % MOD;
}
freqPrev[nums[j]]++;
}
return (int)result;
}
}
var specialTriplets = function(nums) {
const MOD = 1e9 + 7;
const MAX_VAL = 1e5;
const n = nums.length;
const freqPrev = new Array(MAX_VAL + 1).fill(0);
const freqNext = new Array(MAX_VAL + 1).fill(0);
// 初始化freqNext
for (const num of nums) {
freqNext[num]++;
}
let result = 0;
for (let j = 0; j < n; j++) {
freqNext[nums[j]]--;
// 检查nums[j] * 2是否在有效范围内
if (nums[j] <= Math.floor(MAX_VAL / 2)) {
const target = nums[j] * 2;
const count = freqPrev[target] * freqNext[target];
result = (result + count) % MOD;
}
freqPrev[nums[j]]++;
}
return result;
};
复杂度分析
| 复杂度类型 | 分析 |
|---|---|
| 时间复杂度 | O(n),其中 n 是数组长度。只需要遍历数组一次,每次操作都是 O(1) |
| 空间复杂度 | O(MAX_VAL),使用了两个大小为 MAX_VAL + 1 的频率数组,其中 MAX_VAL = 10^5 |