Print Happy Numbers in a Range in Java
Problem
A happy number is one where repeatedly summing the squares of its digits eventually reaches 1 — printing them in a range means checking every candidate one by one.
Given a range of numbers, print every happy number it contains.
Java Program
import java.util.HashSet;
import java.util.Set;
public class HappyRange {
static int digitSquareSum(int num) {
int sum = 0;
while (num > 0) {
int digit = num % 10;
sum += digit * digit;
num /= 10;
}
return sum;
}
static boolean isHappy(int num) {
Set<Integer> seen = new HashSet<>(); // fresh set per candidate, for cycle detection
while (num != 1 && !seen.contains(num)) {
seen.add(num);
num = digitSquareSum(num);
}
return num == 1;
}
public static void main(String[] args) {
StringBuilder result = new StringBuilder();
for (int i = 1; i <= 50; i++) {
if (isHappy(i)) { // reuse the single-number check for every candidate
if (result.length() > 0) result.append(", ");
result.append(i);
}
}
System.out.println("Happy numbers: " + result);
}
}Output
Core Logic
Testing every number in the range with the same cycle-detecting happy check used to test a single number finds every happy number at once.
- 1
isHappy(n)is the single-number check, pulled out into its own method — a freshseenset is created for every candidate. - 2The main loop tries every number from
1to50, callingisHappy()on each. - 3A number that passes the check is appended to the result, separated by commas.
- 41 qualifies immediately, since it's already the target value the process is looking for.
Key Point: A fresh seen set has to be created for every candidate — reusing one set across the whole range would incorrectly treat a value seen while checking an earlier number as already visited for a later one.
Why: Each of the n candidates runs its own bounded cycle-detection check, and only one candidate's seen set is held in memory at a time.
Key Concepts
Approach 2: Java 8
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class HappyRangeStream {
static int digitSquareSum(int num) {
int sum = 0;
while (num > 0) {
int digit = num % 10;
sum += digit * digit;
num /= 10;
}
return sum;
}
static boolean isHappy(int num) {
Set<Integer> seen = new HashSet<>();
while (num != 1 && !seen.contains(num)) {
seen.add(num);
num = digitSquareSum(num);
}
return num == 1;
}
public static void main(String[] args) {
// Keeps only the numbers that pass the happy check, then joins them
String result = IntStream.rangeClosed(1, 50)
.filter(HappyRangeStream::isHappy)
.mapToObj(String::valueOf)
.collect(Collectors.joining(", "));
System.out.println("Happy numbers: " + result);
}
}
Output
Core Logic
The same range scan can filter a stream of candidate numbers down to just the happy ones, then join the survivors.
- 1
IntStream.rangeClosed(1, 50)generates every candidate number in the range. - 2
.filter(HappyRangeStream::isHappy)keeps only the numbers that pass the happy 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: Each call to isHappy() inside the filter still creates its own fresh seen set internally — streaming the range doesn't change that per-candidate requirement.
Why: The stream still runs a full cycle-detection check per candidate, and Collectors.joining() builds a result string holding every happy number found.