Calculate Permutation (nPr) in Java
Problem
A permutation counts how many ways r items can be arranged, in order, from a pool of n items — order matters here, which is exactly what separates it from a combination, where order is irrelevant.
Given n and r, calculate the number of ways to arrange r items chosen from n items, where order matters.
Java Program
public class PermutationFactorial {
static long factorial(int num) {
long result = 1;
for (int i = 2; i <= num; i++) {
result *= i; // multiply every integer from 2 up to num
}
return result;
}
public static void main(String[] args) {
int n = 6, r = 2;
long result = factorial(n) / factorial(n - r); // direct nPr formula, no factorial(r) in the denominator
System.out.println("P(" + n + ", " + r + ") = " + result);
}
}Output
Core Logic
The textbook formula for a permutation — n! divided by (n − r)! — translates directly into code once a factorial helper exists, the same way the combination formula does.
- 1
factorial(num)multiplies every integer from2up tonuminto a running product. - 2
factorial(n)andfactorial(n - r)are each computed using that helper. - 3The final result divides
factorial(n)byfactorial(n - r), matching the nPr formula exactly. - 4Unlike combination's nCr formula, there's no
factorial(r)in the denominator here — that's precisely what makes order matter for a permutation but not for a combination.
n = 6, r = 2, factorial(6) = 720 and factorial(4) = 24, so 720 / 24 = 30 — twice the combination result, since each pair of chosen items can now be arranged 2 different ways.Key Point: P(n, r) is always C(n, r) multiplied by r! — a permutation counts every ordering of each combination separately, which is why it's always at least as large as the matching combination.
Why: Computing factorial(n) costs a loop up to n, even though only the top r terms actually matter to the final answer.
Key Concepts
Approach 2: Direct Multiplication
public class PermutationDirect {
public static void main(String[] args) {
int n = 6, r = 2;
long result = 1;
for (int i = 0; i < r; i++) {
result *= (n - i); // multiply only the r terms that would survive the division
}
System.out.println("P(" + n + ", " + r + ") = " + result);
}
}
Output
Core Logic
Since the factorial formula's numerator and denominator share every factor below n − r + 1, only the top r terms of n! actually survive the division — so those are the only ones worth multiplying in the first place.
- 1The loop multiplies exactly
rterms:n, n - 1, ..., n - r + 1. - 2Each iteration multiplies
resultby(n - i), counting down fromn. - 3No factorial of the full
nis ever computed — only the terms that would have survived the division in the formula-based version. - 4After
rmultiplications,resultalready holds the final answer.
n = 6, r = 2, the loop multiplies just 6 × 5 = 30 — the same answer, without ever computing factorial(6).Key Point: When r is much smaller than n, this does dramatically less work than computing the full factorial(n) — and it also avoids overflowing for larger n, since the intermediate product never grows past the final answer.
Why: Only the r terms actually needed — n down to n − r + 1 — are multiplied together, without ever computing the full factorial(n).
Key Concepts
Approach 3: Java 8
import java.util.stream.IntStream;
public class PermutationStream {
public static void main(String[] args) {
int n = 6, r = 2;
// Maps each offset to its term (n, n-1, ...) and multiplies them all together
long result = IntStream.range(0, r)
.mapToLong(i -> n - i)
.reduce(1, (a, b) -> a * b);
System.out.println("P(" + n + ", " + r + ") = " + result);
}
}
Output
Core Logic
The same idea as the direct-multiplication version — multiply just the top r terms — can be expressed as a single stream reduction instead of a manual loop.
- 1
IntStream.range(0, r)generates the offsets0throughr - 1. - 2
.mapToLong(i -> n - i)maps each offset to the term it represents:n,n - 1, and so on down ton - r + 1. - 3
.reduce(1, (a, b) -> a * b)multiplies every mapped term together, starting from the identity1.
n = 6, r = 2, the offsets 0 and 1 map to 6 and 5, and reducing with multiplication gives 1 × 6 × 5 = 30.Key Point: This is the same top-r-terms technique as the direct-multiplication approach, just expressed as a stream pipeline instead of a for loop.
Why: The stream still visits exactly r terms and reduces them to a single running product, the same work as the manual loop.