多多的特殊三元组(C++/Py/Java /Js/Go)题解
拼多多技术岗 5月17号笔试 第二题
题目内容
在多多王国的数字世界里,多多和我们遇到了一个有趣的数值问题。给定一个整数数组 numsnumsnums,需要找出所有满足特定条件的特殊三元组。
问题描述:
特殊三元组定义为满足以下条件的三元组 (i,j,k)(i, j, k)(i,j,k): 0≤i<j<k<len(nums)0 ≤ i < j < k < len(nums)0≤i<j<k<len(nums),其中 n=len(nums)n = len(nums)n=len(nums),满足: numsi=numsk=numsj∗2numsi = numsk = numsj * 2numsi=numsk=numsj∗2
由于答案可能非常大,请返回结果对 109+710^9 + 7109+7 取余数后的值。
输入描述
第一行:包含一个整数 TTT,表示测试用例的数量。 每个测试用例的输入如下:
- 第一行:一个整数 nnn,表示数组 numsnumsnums 的长度(0≤n≤3000000 ≤ n ≤ 3000000≤n≤300000)
- 第二行:包含 nnn 个整数,表示数组 numsnumsnums 的元素(−1000000000≤numsi≤1000000000-1000000000 ≤ numsi ≤ 1000000000−1000000000≤numsi≤1000000000)
输出描述
对于每个测试用例,输出一个整数,表示满足条件的特殊三元组的数量(对 109+710^9 + 7109+7 取模)。
样例1
输入
1
4
0 1 0 0
输出
1
样例2
输入
1
3
6 3 6
输出
1
样例3
输入
1
5
8 4 2 8 4
输出
2
题解
思路
逻辑分析
- 从前往后枚举
j, 那么该j可以组成的三元组数量等于j左侧值等于num[j]*2 的数量 * j右侧值等于num[j]*2 的数量。 - 按照1的逻辑,题目难点主要变成如何快速求出左右侧值=numsj * 2的数量,这部分可以通过使用两个哈希表动态追踪各个值的数量。
这部分逻辑可参照下面代码。 - 代码总体时间复杂度为
O(n)
C++
cpp
#include<bits/stdc++.h>
using namespace std;
const long MOD = 1e9+7;
long solve(int n, vector<long>& nums) {
// 动态右侧指定数数量
unordered_map<long, int> rightCount;
for (auto& num : nums) {
rightCount[num]++;
}
long res = 0;
// 动态追踪左侧指定数数目
unordered_map<long, int> leftCount;
for (auto& num : nums) {
rightCount[num]--;
int l = leftCount[2 * num];
int r = rightCount[2 * num];
res = (res + (l * r) % MOD) % MOD;
leftCount[num]++;
}
return res;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<long> nums(n);
for (int i = 0; i < n; i++) {
cin >> nums[i];
}
cout << solve(n, nums) << endl;
}
}
java
java
import java.io.*;
import java.util.*;
public class Main {
static final long MOD = 1000000007L;
static long solve(int n, long[] nums) {
// 动态右侧指定数数量
HashMap<Long, Integer> rightCount = new HashMap<>();
for (long num : nums) {
rightCount.put(num, rightCount.getOrDefault(num, 0) + 1);
}
long res = 0;
// 动态追踪左侧指定数数目
HashMap<Long, Integer> leftCount = new HashMap<>();
for (long num : nums) {
rightCount.put(num, rightCount.get(num) - 1);
int l = leftCount.getOrDefault(2 * num, 0);
int r = rightCount.getOrDefault(2 * num, 0);
res = (res + (long) l * r % MOD) % MOD;
leftCount.put(num, leftCount.getOrDefault(num, 0) + 1);
}
return res;
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int T = Integer.parseInt(br.readLine());
while (T-- > 0) {
int n = Integer.parseInt(br.readLine());
String[] strs = br.readLine().split(" ");
long[] nums = new long[n];
for (int i = 0; i < n; i++) {
nums[i] = Long.parseLong(strs[i]);
}
System.out.println(solve(n, nums));
}
}
}
python
python
MOD = 10 ** 9 + 7
def solve(n, nums):
# 动态右侧指定数数量
right_count = {}
for num in nums:
right_count[num] = right_count.get(num, 0) + 1
res = 0
# 动态追踪左侧指定数数目
left_count = {}
for num in nums:
right_count[num] -= 1
l = left_count.get(2 * num, 0)
r = right_count.get(2 * num, 0)
res = (res + l * r) % MOD
left_count[num] = left_count.get(num, 0) + 1
return res
T = int(input())
for _ in range(T):
n = int(input())
nums = list(map(int, input().split()))
print(solve(n, nums))
javascript
js
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const input = [];
rl.on("line", line => {
input.push(line);
});
rl.on("close", () => {
const MOD = 1000000007n;
function solve(n, nums) {
// 动态右侧指定数数量
const rightCount = new Map();
for (const num of nums) {
rightCount.set(num, (rightCount.get(num) || 0) + 1);
}
let res = 0n;
// 动态追踪左侧指定数数目
const leftCount = new Map();
for (const num of nums) {
rightCount.set(num, rightCount.get(num) - 1);
const l = leftCount.get(num * 2) || 0;
const r = rightCount.get(num * 2) || 0;
res = (res + BigInt(l) * BigInt(r)) % MOD;
leftCount.set(num, (leftCount.get(num) || 0) + 1);
}
return res;
}
let idx = 0;
const T = parseInt(input[idx++]);
const ans = [];
for (let t = 0; t < T; t++) {
const n = parseInt(input[idx++]);
const nums = input[idx++].split(" ").map(Number);
ans.push(solve(n, nums).toString());
}
console.log(ans.join("\n"));
});
Go
go
package main
import (
"bufio"
"fmt"
"os"
)
const MOD int64 = 1000000007
func solve(n int, nums []int64) int64 {
// 动态右侧指定数数量
rightCount := make(map[int64]int)
for _, num := range nums {
rightCount[num]++
}
var res int64 = 0
// 动态追踪左侧指定数数目
leftCount := make(map[int64]int)
for _, num := range nums {
rightCount[num]--
l := leftCount[2*num]
r := rightCount[2*num]
res = (res + int64(l)*int64(r)%MOD) % MOD
leftCount[num]++
}
return res
}
func main() {
in := bufio.NewReader(os.Stdin)
var T int
fmt.Fscan(in, &T)
for ; T > 0; T-- {
var n int
fmt.Fscan(in, &n)
nums := make([]int64, n)
for i := 0; i < n; i++ {
fmt.Fscan(in, &nums[i])
}
fmt.Println(solve(n, nums))
}
}