Suppose that a music site wants to compare your song preferences to those of a friend. One approach is to have you and your friend each rank a set of n songs and count the number of pairs of songs (i, j) for which you prefer i to j but your friend prefers j to i. When the count is low, the preferences are similar.
More generally, given an array of integers, a pair of elements a[i] and a[j] are inverted if i < j and a[i] > a[j]. For example, the array a[ ] has 1 inversion and the array b[ ] has 4 inversions.
Write a program Inversions.java that implements the following API:
public class Inversions {
// Return the number of inversions in the permutation a[].
public static long count(int[] a)
// Return a permutation of length n with exactly k inversions.
public static int[] generate(int n, long k)
// Takes an integer n and a long k as command-line arguments,
// and prints a permutation of length n with exactly k inversions.
public static void main(String[] args)
}
Here is some more information about the required behavior:
Here are a few sample executions:
~/Desktop/performance> java Inversions 10 0
0 1 2 3 4 5 6 7 8 9
~/Desktop/performance> java Inversions 10 1
0 1 2 3 4 5 6 7 9 8
~/Desktop/performance> java Inversions 10 45
9 8 7 6 5 4 3 2 1 0
~/Desktop/performance> java Inversions 10 20
9 8 0 1 2 3 7 4 5 6
Counting inversions arise in a number of applications, including sorting, voting theory, collaborative filtering, rank aggregation, and non-parametric statistics.
public class Inversions {
// Return the number of inversions in the permutation a[].
// Max time complexity = O(n2)
public static long count(int[] a) {
long count = 0;
for (int i = 0; i < a.length; i++) {
for (int j = i + 1; j < a.length; j++) {
if (a[i] > a[j]) {
count++;
}
}
}
return count;
}
// Return a permutation of length n with exactly k inversions.
// Max time complexity = O(n)
public static int[] generate(int n, long k) {
// generate starting sequence of length n with no inversions
final int[] a = new int[n];
for (int i = 0; i < n; i++) {
a[i] = i;
}
// nothing to do
if (k == 0) {
return a;
}
/**
* Example:
*
* n = 6
*
* 0 1 2 3 4 5 -> 5 0 1 2 3 4 == 5 inversions (1 swap)
* 5 0 1 2 3 4 -> 5 4 0 1 2 3 == 9 inversions (2 swaps)
* 5 4 0 1 2 3 -> 5 4 3 0 1 2 == 12 inversions (3 swaps)
* 5 4 3 0 1 2 -> 5 4 3 2 0 1 == 14 inversions (4 swaps)
* 5 4 3 2 0 1 -> 5 4 3 2 1 0 == 15 inversions (5 swaps)
*/
// compute the number of swaps (as shown above example)
int minSwap = 0;
int inversionCount = 0;
for (int i = 1; i < n; i++) {
final int newInversions = (n - i);
if ((inversionCount + newInversions) <= k) {
minSwap++;
inversionCount += newInversions;
} else {
break;
}
}
// perform min swaps (bulk inversions)
for (int i = 0; i < minSwap; i++) {
a[i] = (n - 1) - i;
}
// fill in remaining numbers
for (int i = 0; i < (n - minSwap); i++) {
a[minSwap + i] = i;
}
// do remining individual inversions
for (int i = 0; (i < (n - minSwap)) && (inversionCount < k); i++) {
for (int j = i + 1; (j < (n - minSwap)) && (inversionCount < k); j++) {
// swap to create inversion
final int temp = a[minSwap + i];
a[minSwap + i] = a[minSwap + j];
a[minSwap + j] = temp;
inversionCount++;
}
}
return a;
}
// Takes an integer n and a long k as command-line arguments,
// and prints a permutation of length n with exactly k inversions.
public static void main(String[] args) {
final int n = Integer.parseInt(args[0]);
final long k = Long.parseLong(args[1]);
final int[] a = generate(n, k);
for (int i = 0; i < a.length; i++) {
StdOut.print(a[i] + " ");
}
}
}
Link To: Java Source Code