链接:完美对_阿里巴巴笔试题_牛客网
来源:牛客网
有 n\ n n个物品,每个物品有 k\ k k个属性,第 i\ i i件物品的第 j\ j j个属性用一个正整数表示记为ai,ja_{i,j}ai,j,两个不同的物品 i,j\ i,j i,j被称为是完美对的当且仅当ai,1+aj,1=ai,2+aj,2=⋯=ai,k+aj,ka_{i,1}+a_{j,1} = a_{i,2}+a_{j,2}=\dots=a_{i,k}+a_{j,k}ai,1+aj,1=ai,2+aj,2=⋯=ai,k+aj,k,求完美对的个数。
进阶:时间复杂度O(nlogn) O(nlogn)\ O(nlogn) ,空间复杂度O(n) O(n)\ O(n)
输入描述:
第一行两个数字 n,k\ n,k n,k。 接下来 n\ n n行,第 i\ i i行 k\ k k个数字表示ai,1,ai,2,…,ai,ka_{i,1}, a_{i,2},\dots,a_{i,k}ai,1,ai,2,…,ai,k。 1≤n≤105,2≤k≤10,1≤ai≤1001 \leq n \leq 10^5, 2 \leq k \leq 10, 1 \leq a_i \leq 1001≤n≤105,2≤k≤10,1≤ai≤100
输出描述:
一行一个数字表示答案
示例1
输入
5 3 2 11 21 19 10 1 20 11 1 6 15 24 18 27 36
输出
3
思路
先找到差分和相同的行
再在差分和相同的行内找完美对
链接:完美对_阿里巴巴笔试题_牛客网
来源:牛客网
对于物品i,其属性差分和diffSum为aik-aik-1+...+ai2-ai1+ai1-ai0=aik-ai0
对于物品j,其属性差分和diffSum为ajk-ajk-1+...+aj2-aj1+aj1-aj0=ajk-aj0
对于完美对(i, j),各属性之和相等,因此将以上两式相加可以得到aik+ajk-(ai0+aj0)=0,即完美对的属性差分和互为相反数。
也就是说先满足差分和互为相反数,再满足完美对
代码
import java.util.*;
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException{
BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
String[] in = read.readLine().trim().split(" ");
int n = Integer.parseInt(in[0]),k = Integer.parseInt(in[1]);
int[][] f = new int[n][k];
Map<Integer,List<Integer>> map = new HashMap();
int count = 0;
for(int i=0;i<n;i++){
in = read.readLine().trim().split(" ");
for(int j=0;j<k;j++){
f[i][j] = Integer.parseInt(in[j]);
}
int diff = f[i][k-1]-f[i][0];
if(map.containsKey(-diff)){
List<Integer> temp = map.get(-diff);
for(int j:temp){
if(isValid(i,j,f)){
count++;
}
}
}
if(map.containsKey(diff)){
map.get(diff).add(i);
}else{
List<Integer> temp = new ArrayList();
temp.add(i);
map.put(diff,temp);
}
}
writer.write(Integer.toString(count));
writer.newLine();
writer.flush();
}
private static boolean isValid(int i,int j,int[][] f){
int[] f1 = f[i],f2 = f[j];
int val = f1[0]+f2[0];
for(int t=1;t<f1.length;t++){
if(f1[t]+f2[t]!=val)return false;
}
return true;
}
}