i have a list of elements (let’s say integers), and i need to make all possible 2-pair comparisons. my approach is O(n^2), and i am wondering if there is a faster way. here is my implementation in java.
public class Pair {
public int x, y;
public Pair(int x, int y) {
this.x = x;
this.y = y;
}
}
public List<Pair> getAllPairs(List<Integer> numbers) {
List<Pair> pairs = new ArrayList<Pair>();
int total = numbers.size();
for(int i=0; i < total; i++) {
int num1 = numbers.get(i).intValue();
for(int j=i+1; j < total; j++) {
int num2 = numbers.get(j).intValue();
pairs.add(new Pair(num1,num2));
}
}
return pairs;
}
please note that i don’t allow self-pairing, so there should be ((n(n+1))/2) – n possible pairs. what i have currently works, but as n increases, it is taking me an unbearable long amount of time to get the pairs. is there any way to turn the O(n^2) algorithm above to something sub-quadratic? any help is appreciated.
by the way, i also tried the algorithm below, but when i benchmark, empirically, it performs worst than what i had above. i had thought that by avoiding an inner loop this would speed things up. shouldn’t this algorithm below be faster? i would think that it’s O(n)? if not, please explain and let me know. thanks.
public List<Pair> getAllPairs(List<Integer> numbers) {
int n = list.size();
int i = 0;
int j = i + 1;
while(true) {
int num1 = list.get(i);
int num2 = list.get(j);
pairs.add(new Pair(num1,num2));
j++;
if(j >= n) {
i++;
j = i + 1;
}
if(i >= n - 1) {
break;
}
}
}
You cannot make it sub-quadric, because as you said – the output is itself quadric – and to create it, you need at least
#elements_in_outputops.However, you could do some “cheating” create your list on the fly:
You can create a class
CombinationsGetterthat implementsIterable<Pair>, and implement itsIterator<Pair>. This way, you will be able to iterate on the elements on the fly, without creating the list first, which might decrease latency for your application.Note: It will still be quadric! The time to generate the list on the fly will just be distributed between more operations.
EDIT:
Another solution, which is faster then the naive approach – is multithreading.
Create a few threads, each will get his “slice” of the data – and generate relevant pairs, and create its own partial list.
Later – you can use
ArrayList.addAll()to convert those different lists into one.Note: though complexity is stiil
O(n^2), it is likely to be much faster – since the creation of pairs is done in parallel, andArrayList.addAll()is implemented much more effieciently then the trivial insert one by one elements.EDIT2:
Your second code is still
O(n^2), even though it is a “single loop” – the loop itself will repeatO(n^2)times. Have a look at your variablei. It increases only whenj==n, and it decreasesjback toi+1when it does it. So, it will result inn + (n-1) + ... + 1iterations, and this is sum of arithmetic progression, and gets us back toO(n^2)as expected.We cannot get better then O(n^2), because we are trying to create O(n^2) distinct
Pairobjects.