mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-12-19 07:00:35 +08:00
refactor: Enhance docs, code, add tests in HappyNumbersSeq
This commit is contained in:
@@ -5,12 +5,52 @@ import java.util.HashSet;
|
||||
import java.util.Scanner;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A utility class for working with Happy Numbers.
|
||||
*
|
||||
* <p>
|
||||
* A Happy Number is defined by the following process:
|
||||
* Starting with any positive integer, replace the number by the sum of the
|
||||
* squares of its digits.
|
||||
* Repeat the process until the number equals 1 (where it will stay), or it
|
||||
* loops endlessly in a
|
||||
* cycle which does not include 1.
|
||||
* Those numbers for which this process ends in 1 are happy numbers, while those
|
||||
* that do not end
|
||||
* in 1 are unhappy (or sad) numbers.
|
||||
*
|
||||
* <p>
|
||||
* For example:
|
||||
* <ul>
|
||||
* <li>7 is a happy number: 7 → 49 → 97 → 130 → 10 → 1</li>
|
||||
* <li>2 is not a happy number (sad number): 2 → 4 → 16 → 37 → 58 → 89 → 145 →
|
||||
* 42 → 20 → 4 (cycle)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see <a href="https://en.wikipedia.org/wiki/Happy_number">Happy Number -
|
||||
* Wikipedia</a>
|
||||
* @see <a href="https://mathworld.wolfram.com/HappyNumber.html">Happy Number -
|
||||
* Wolfram MathWorld</a>
|
||||
*/
|
||||
public final class HappyNumbersSeq {
|
||||
private HappyNumbersSeq() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Known cycle numbers that indicate a sad number.
|
||||
* If the sequence reaches any of these numbers, it will cycle indefinitely
|
||||
* without reaching 1.
|
||||
*/
|
||||
private static final Set<Integer> CYCLE_NUMS = new HashSet<>(Arrays.asList(4, 16, 20, 37, 58, 145));
|
||||
|
||||
/**
|
||||
* Main method to demonstrate happy number detection.
|
||||
* Reads a number from user input and displays the sequence until it reaches 1
|
||||
* (happy)
|
||||
* or enters a cycle (sad).
|
||||
*
|
||||
* @param args command-line arguments (not used)
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Scanner in = new Scanner(System.in);
|
||||
System.out.print("Enter number: ");
|
||||
@@ -24,16 +64,47 @@ public final class HappyNumbersSeq {
|
||||
in.close();
|
||||
}
|
||||
|
||||
private static int sumSquares(int n) {
|
||||
int s = 0;
|
||||
for (; n > 0; n /= 10) {
|
||||
int r = n % 10;
|
||||
s += r * r;
|
||||
/**
|
||||
* Determines if a number is a happy number.
|
||||
*
|
||||
* @param n the number to check (must be positive)
|
||||
* @return {@code true} if the number is happy, {@code false} otherwise
|
||||
* @throws IllegalArgumentException if n is not positive
|
||||
*/
|
||||
public static boolean isHappy(int n) {
|
||||
if (n <= 0) {
|
||||
throw new IllegalArgumentException("Number must be positive");
|
||||
}
|
||||
return s;
|
||||
while (n != 1 && !isSad(n)) {
|
||||
n = sumSquares(n);
|
||||
}
|
||||
return n == 1;
|
||||
}
|
||||
|
||||
private static boolean isSad(int n) {
|
||||
/**
|
||||
* Computes the sum of the squares of the digits of a number.
|
||||
*
|
||||
* @param n the number whose digits will be squared and summed
|
||||
* @return the sum of the squares of the digits
|
||||
*/
|
||||
static int sumSquares(int n) {
|
||||
int sum = 0;
|
||||
while (n > 0) {
|
||||
int digit = n % 10;
|
||||
sum += digit * digit;
|
||||
n /= 10;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a number is part of the known cycle that indicates a sad number.
|
||||
*
|
||||
* @param n the number to check
|
||||
* @return {@code true} if the number is in the sad cycle, {@code false}
|
||||
* otherwise
|
||||
*/
|
||||
static boolean isSad(int n) {
|
||||
return CYCLE_NUMS.contains(n);
|
||||
}
|
||||
}
|
||||
|
||||
179
src/test/java/com/thealgorithms/others/HappyNumbersSeqTest.java
Normal file
179
src/test/java/com/thealgorithms/others/HappyNumbersSeqTest.java
Normal file
@@ -0,0 +1,179 @@
|
||||
package com.thealgorithms.others;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test class for {@link HappyNumbersSeq}.
|
||||
*
|
||||
* @author Hardvan (https://github.com/Hardvan)
|
||||
*/
|
||||
class HappyNumbersSeqTest {
|
||||
|
||||
@Test
|
||||
void testIsHappyWithHappyNumbers() {
|
||||
// Test known happy numbers
|
||||
assertTrue(HappyNumbersSeq.isHappy(1));
|
||||
assertTrue(HappyNumbersSeq.isHappy(7));
|
||||
assertTrue(HappyNumbersSeq.isHappy(10));
|
||||
assertTrue(HappyNumbersSeq.isHappy(13));
|
||||
assertTrue(HappyNumbersSeq.isHappy(19));
|
||||
assertTrue(HappyNumbersSeq.isHappy(23));
|
||||
assertTrue(HappyNumbersSeq.isHappy(28));
|
||||
assertTrue(HappyNumbersSeq.isHappy(31));
|
||||
assertTrue(HappyNumbersSeq.isHappy(32));
|
||||
assertTrue(HappyNumbersSeq.isHappy(44));
|
||||
assertTrue(HappyNumbersSeq.isHappy(49));
|
||||
assertTrue(HappyNumbersSeq.isHappy(68));
|
||||
assertTrue(HappyNumbersSeq.isHappy(70));
|
||||
assertTrue(HappyNumbersSeq.isHappy(79));
|
||||
assertTrue(HappyNumbersSeq.isHappy(82));
|
||||
assertTrue(HappyNumbersSeq.isHappy(86));
|
||||
assertTrue(HappyNumbersSeq.isHappy(91));
|
||||
assertTrue(HappyNumbersSeq.isHappy(94));
|
||||
assertTrue(HappyNumbersSeq.isHappy(97));
|
||||
assertTrue(HappyNumbersSeq.isHappy(100));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsHappyWithSadNumbers() {
|
||||
// Test known sad numbers
|
||||
assertFalse(HappyNumbersSeq.isHappy(2));
|
||||
assertFalse(HappyNumbersSeq.isHappy(3));
|
||||
assertFalse(HappyNumbersSeq.isHappy(4));
|
||||
assertFalse(HappyNumbersSeq.isHappy(5));
|
||||
assertFalse(HappyNumbersSeq.isHappy(6));
|
||||
assertFalse(HappyNumbersSeq.isHappy(8));
|
||||
assertFalse(HappyNumbersSeq.isHappy(9));
|
||||
assertFalse(HappyNumbersSeq.isHappy(11));
|
||||
assertFalse(HappyNumbersSeq.isHappy(12));
|
||||
assertFalse(HappyNumbersSeq.isHappy(14));
|
||||
assertFalse(HappyNumbersSeq.isHappy(15));
|
||||
assertFalse(HappyNumbersSeq.isHappy(16));
|
||||
assertFalse(HappyNumbersSeq.isHappy(17));
|
||||
assertFalse(HappyNumbersSeq.isHappy(18));
|
||||
assertFalse(HappyNumbersSeq.isHappy(20));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsHappyWithLargeNumbers() {
|
||||
// Test larger happy numbers
|
||||
assertTrue(HappyNumbersSeq.isHappy(1000));
|
||||
assertFalse(HappyNumbersSeq.isHappy(999));
|
||||
assertFalse(HappyNumbersSeq.isHappy(1001));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsHappyWithInvalidInput() {
|
||||
// Test with zero
|
||||
assertThrows(IllegalArgumentException.class, () -> HappyNumbersSeq.isHappy(0));
|
||||
|
||||
// Test with negative numbers
|
||||
assertThrows(IllegalArgumentException.class, () -> HappyNumbersSeq.isHappy(-1));
|
||||
assertThrows(IllegalArgumentException.class, () -> HappyNumbersSeq.isHappy(-10));
|
||||
assertThrows(IllegalArgumentException.class, () -> HappyNumbersSeq.isHappy(-100));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSumSquaresSingleDigit() {
|
||||
assertEquals(0, HappyNumbersSeq.sumSquares(0));
|
||||
assertEquals(1, HappyNumbersSeq.sumSquares(1));
|
||||
assertEquals(4, HappyNumbersSeq.sumSquares(2));
|
||||
assertEquals(9, HappyNumbersSeq.sumSquares(3));
|
||||
assertEquals(16, HappyNumbersSeq.sumSquares(4));
|
||||
assertEquals(25, HappyNumbersSeq.sumSquares(5));
|
||||
assertEquals(36, HappyNumbersSeq.sumSquares(6));
|
||||
assertEquals(49, HappyNumbersSeq.sumSquares(7));
|
||||
assertEquals(64, HappyNumbersSeq.sumSquares(8));
|
||||
assertEquals(81, HappyNumbersSeq.sumSquares(9));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSumSquaresMultipleDigits() {
|
||||
// 10: 1^2 + 0^2 = 1
|
||||
assertEquals(1, HappyNumbersSeq.sumSquares(10));
|
||||
|
||||
// 23: 2^2 + 3^2 = 4 + 9 = 13
|
||||
assertEquals(13, HappyNumbersSeq.sumSquares(23));
|
||||
|
||||
// 82: 8^2 + 2^2 = 64 + 4 = 68
|
||||
assertEquals(68, HappyNumbersSeq.sumSquares(82));
|
||||
|
||||
// 130: 1^2 + 3^2 + 0^2 = 1 + 9 + 0 = 10
|
||||
assertEquals(10, HappyNumbersSeq.sumSquares(130));
|
||||
|
||||
// 999: 9^2 + 9^2 + 9^2 = 81 + 81 + 81 = 243
|
||||
assertEquals(243, HappyNumbersSeq.sumSquares(999));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSumSquaresLargeNumbers() {
|
||||
// 1234: 1^2 + 2^2 + 3^2 + 4^2 = 1 + 4 + 9 + 16 = 30
|
||||
assertEquals(30, HappyNumbersSeq.sumSquares(1234));
|
||||
|
||||
// 9876: 9^2 + 8^2 + 7^2 + 6^2 = 81 + 64 + 49 + 36 = 230
|
||||
assertEquals(230, HappyNumbersSeq.sumSquares(9876));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsSadWithCycleNumbers() {
|
||||
// Test all known cycle numbers
|
||||
assertTrue(HappyNumbersSeq.isSad(4));
|
||||
assertTrue(HappyNumbersSeq.isSad(16));
|
||||
assertTrue(HappyNumbersSeq.isSad(20));
|
||||
assertTrue(HappyNumbersSeq.isSad(37));
|
||||
assertTrue(HappyNumbersSeq.isSad(58));
|
||||
assertTrue(HappyNumbersSeq.isSad(145));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsSadWithNonCycleNumbers() {
|
||||
// Test numbers that are not in the cycle
|
||||
assertFalse(HappyNumbersSeq.isSad(1));
|
||||
assertFalse(HappyNumbersSeq.isSad(7));
|
||||
assertFalse(HappyNumbersSeq.isSad(10));
|
||||
assertFalse(HappyNumbersSeq.isSad(13));
|
||||
assertFalse(HappyNumbersSeq.isSad(19));
|
||||
assertFalse(HappyNumbersSeq.isSad(23));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHappyNumberSequenceFor7() {
|
||||
// Test the sequence for happy number 7: 7 → 49 → 97 → 130 → 10 → 1
|
||||
int n = 7;
|
||||
assertEquals(49, HappyNumbersSeq.sumSquares(n));
|
||||
n = 49;
|
||||
assertEquals(97, HappyNumbersSeq.sumSquares(n));
|
||||
n = 97;
|
||||
assertEquals(130, HappyNumbersSeq.sumSquares(n));
|
||||
n = 130;
|
||||
assertEquals(10, HappyNumbersSeq.sumSquares(n));
|
||||
n = 10;
|
||||
assertEquals(1, HappyNumbersSeq.sumSquares(n));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHappyNumberSequenceFor19() {
|
||||
// Test the sequence for happy number 19: 19 → 82 → 68 → 100 → 1
|
||||
int n = 19;
|
||||
assertEquals(82, HappyNumbersSeq.sumSquares(n));
|
||||
n = 82;
|
||||
assertEquals(68, HappyNumbersSeq.sumSquares(n));
|
||||
n = 68;
|
||||
assertEquals(100, HappyNumbersSeq.sumSquares(n));
|
||||
n = 100;
|
||||
assertEquals(1, HappyNumbersSeq.sumSquares(n));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSadNumberEntersCycle() {
|
||||
// Test that sad number 2 eventually reaches a cycle number
|
||||
int n = 2;
|
||||
assertEquals(4, HappyNumbersSeq.sumSquares(n)); // 2 → 4 (cycle number)
|
||||
assertTrue(HappyNumbersSeq.isSad(4));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user