Print Automorphic Numbers in a Range in Java
Problem
An automorphic number is a number that appears unchanged as the trailing digits of its own square — printing them in a range means checking every candidate one by one.
Given a range of numbers, print every automorphic number it contains.
Java Program
public class AutomorphicRange {
static boolean isAutomorphic(int num) {
long square = (long) num * num; // long avoids overflow for larger candidates
return String.valueOf(square).endsWith(String.valueOf(num));
}
public static void main(String[] args) {
StringBuilder result = new StringBuilder();
for (int i = 1; i <= 100; i++) {
if (isAutomorphic(i)) { // reuse the single-number check for every candidate
if (result.length() > 0) result.append(", ");
result.append(i);
}
}
System.out.println("Automorphic numbers: " + result);
}
}Output
Core Logic
Testing every number in the range with the same trailing-digits check used to test a single number finds every automorphic number at once.
- 1
isAutomorphic(n)is the single-number check, pulled out into its own method so it can be reused for every candidate. - 2The main loop tries every number from
1to100, callingisAutomorphic()on each. - 3A number that passes the check is appended to the result, separated by commas.
- 41 qualifies trivially, since
1 × 1 = 1ends with1.
Key Point: Automorphic numbers get progressively rarer as the range grows — there's exactly one automorphic number of most digit lengths ending in 5, and one ending in 6, with a handful of exceptions.
Why: Each of the n candidates gets a constant-time squaring and comparison check, independent of the candidate's own magnitude.
Key Concepts
Approach 2: Java 8
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class AutomorphicRangeStream {
static boolean isAutomorphic(int num) {
long square = (long) num * num;
return String.valueOf(square).endsWith(String.valueOf(num));
}
public static void main(String[] args) {
// Keeps only the numbers that pass the automorphic check, then joins them
String result = IntStream.rangeClosed(1, 100)
.filter(AutomorphicRangeStream::isAutomorphic)
.mapToObj(String::valueOf)
.collect(Collectors.joining(", "));
System.out.println("Automorphic numbers: " + result);
}
}
Output
Core Logic
The same range scan can filter a stream of candidate numbers down to just the automorphic ones, then join the survivors.
- 1
IntStream.rangeClosed(1, 100)generates every candidate number in the range. - 2
.filter(AutomorphicRangeStream::isAutomorphic)keeps only the numbers that pass the trailing-digits check, reusing the same helper method as a method reference. - 3
.mapToObj(String::valueOf)converts each surviving number into aString. - 4
.collect(Collectors.joining(", "))joins them into the final comma-separated result.
Key Point: Reusing isAutomorphic() as a method reference keeps the trailing-digits logic in exactly one place, whether it's called once or streamed across a whole range.
Why: The stream still checks every candidate in constant time each, and Collectors.joining() builds a result string holding every automorphic number found.