diff --git a/src/main/java/com/thealgorithms/maths/KeithNumber.java b/src/main/java/com/thealgorithms/maths/KeithNumber.java index 1756cfbae91b..eb7f800d378f 100644 --- a/src/main/java/com/thealgorithms/maths/KeithNumber.java +++ b/src/main/java/com/thealgorithms/maths/KeithNumber.java @@ -4,57 +4,98 @@ import java.util.Collections; import java.util.Scanner; -final class KeithNumber { +/** + * A Keith number is an n-digit positive integer where the sequence formed by + * starting with its digits and repeatedly adding the previous n terms, + * eventually reaches the number itself. + * + *

+ * For example: + *

+ * + * @see Keith Number - + * Wikipedia + * @see Keith Number - + * MathWorld + */ +public final class KeithNumber { private KeithNumber() { } - // user-defined function that checks if the given number is Keith or not - static boolean isKeith(int x) { - // List stores all the digits of the X + /** + * Checks if a given number is a Keith number. + * + *

+ * The algorithm works as follows: + *

    + *
  1. Extract all digits of the number and store them in a list
  2. + *
  3. Generate subsequent terms by summing the last n digits
  4. + *
  5. Continue until a term equals or exceeds the original number
  6. + *
  7. If a term equals the number, it is a Keith number
  8. + *
+ * + * @param number the number to check (must be positive) + * @return {@code true} if the number is a Keith number, {@code false} otherwise + * @throws IllegalArgumentException if the number is not positive + */ + public static boolean isKeith(int number) { + if (number <= 0) { + throw new IllegalArgumentException("Number must be positive"); + } + + // Extract digits and store them in the list ArrayList terms = new ArrayList<>(); - // n denotes the number of digits - int temp = x; - int n = 0; - // executes until the condition becomes false + int temp = number; + int digitCount = 0; + while (temp > 0) { - // determines the last digit of the number and add it to the List terms.add(temp % 10); - // removes the last digit temp = temp / 10; - // increments the number of digits (n) by 1 - n++; + digitCount++; } - // reverse the List + + // Reverse the list to get digits in correct order Collections.reverse(terms); + + // Generate subsequent terms in the sequence int nextTerm = 0; - int i = n; - // finds next term for the series - // loop executes until the condition returns true - while (nextTerm < x) { + int currentIndex = digitCount; + + while (nextTerm < number) { nextTerm = 0; - // next term is the sum of previous n terms (it depends on number of digits the number - // has) - for (int j = 1; j <= n; j++) { - nextTerm = nextTerm + terms.get(i - j); + // Sum the last 'digitCount' terms + for (int j = 1; j <= digitCount; j++) { + nextTerm = nextTerm + terms.get(currentIndex - j); } terms.add(nextTerm); - i++; + currentIndex++; } - // when the control comes out of the while loop, there will be two conditions: - // either nextTerm will be equal to x or greater than x - // if equal, the given number is Keith, else not - return (nextTerm == x); + + // Check if the generated term equals the original number + return (nextTerm == number); } - // driver code + /** + * Main method for demonstrating Keith number detection. + * Reads a number from standard input and checks if it is a Keith number. + * + * @param args command line arguments (not used) + */ public static void main(String[] args) { - Scanner in = new Scanner(System.in); - int n = in.nextInt(); - if (isKeith(n)) { - System.out.println("Yes, the given number is a Keith number."); + Scanner scanner = new Scanner(System.in); + System.out.print("Enter a positive integer: "); + int number = scanner.nextInt(); + + if (isKeith(number)) { + System.out.println("Yes, " + number + " is a Keith number."); } else { - System.out.println("No, the given number is not a Keith number."); + System.out.println("No, " + number + " is not a Keith number."); } - in.close(); + scanner.close(); } } diff --git a/src/test/java/com/thealgorithms/maths/KeithNumberTest.java b/src/test/java/com/thealgorithms/maths/KeithNumberTest.java new file mode 100644 index 000000000000..cac6b925e5c1 --- /dev/null +++ b/src/test/java/com/thealgorithms/maths/KeithNumberTest.java @@ -0,0 +1,153 @@ +package com.thealgorithms.maths; + +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 cases for {@link KeithNumber}. + */ +class KeithNumberTest { + + /** + * Tests single-digit Keith numbers. + * All single-digit numbers (1-9) are Keith numbers by definition. + */ + @Test + void testSingleDigitKeithNumbers() { + assertTrue(KeithNumber.isKeith(1)); + assertTrue(KeithNumber.isKeith(2)); + assertTrue(KeithNumber.isKeith(3)); + assertTrue(KeithNumber.isKeith(4)); + assertTrue(KeithNumber.isKeith(5)); + assertTrue(KeithNumber.isKeith(6)); + assertTrue(KeithNumber.isKeith(7)); + assertTrue(KeithNumber.isKeith(8)); + assertTrue(KeithNumber.isKeith(9)); + } + + /** + * Tests two-digit Keith numbers. + * Known two-digit Keith numbers: 14, 19, 28, 47, 61, 75. + */ + @Test + void testTwoDigitKeithNumbers() { + assertTrue(KeithNumber.isKeith(14)); + assertTrue(KeithNumber.isKeith(19)); + assertTrue(KeithNumber.isKeith(28)); + assertTrue(KeithNumber.isKeith(47)); + assertTrue(KeithNumber.isKeith(61)); + assertTrue(KeithNumber.isKeith(75)); + } + + /** + * Tests three-digit Keith numbers. + * Known three-digit Keith numbers: 197, 742. + */ + @Test + void testThreeDigitKeithNumbers() { + assertTrue(KeithNumber.isKeith(197)); + assertTrue(KeithNumber.isKeith(742)); + } + + /** + * Tests four-digit Keith numbers. + * Known four-digit Keith numbers: 1104, 1537, 2208, 2580, 3684, 4788, 7385, + * 7647, 7909. + */ + @Test + void testFourDigitKeithNumbers() { + assertTrue(KeithNumber.isKeith(1104)); + assertTrue(KeithNumber.isKeith(1537)); + assertTrue(KeithNumber.isKeith(2208)); + } + + /** + * Tests two-digit non-Keith numbers. + */ + @Test + void testTwoDigitNonKeithNumbers() { + assertFalse(KeithNumber.isKeith(10)); + assertFalse(KeithNumber.isKeith(11)); + assertFalse(KeithNumber.isKeith(12)); + assertFalse(KeithNumber.isKeith(13)); + assertFalse(KeithNumber.isKeith(15)); + assertFalse(KeithNumber.isKeith(20)); + assertFalse(KeithNumber.isKeith(30)); + assertFalse(KeithNumber.isKeith(50)); + } + + /** + * Tests three-digit non-Keith numbers. + */ + @Test + void testThreeDigitNonKeithNumbers() { + assertFalse(KeithNumber.isKeith(100)); + assertFalse(KeithNumber.isKeith(123)); + assertFalse(KeithNumber.isKeith(196)); + assertFalse(KeithNumber.isKeith(198)); + assertFalse(KeithNumber.isKeith(456)); + assertFalse(KeithNumber.isKeith(741)); + assertFalse(KeithNumber.isKeith(743)); + assertFalse(KeithNumber.isKeith(999)); + } + + /** + * Tests validation for edge case 14 in detail. + * 14 is a Keith number: 1, 4, 5 (1+4), 9 (4+5), 14 (5+9). + */ + @Test + void testKeithNumber14() { + assertTrue(KeithNumber.isKeith(14)); + } + + /** + * Tests validation for edge case 197 in detail. + * 197 is a Keith number: 1, 9, 7, 17, 33, 57, 107, 197. + */ + @Test + void testKeithNumber197() { + assertTrue(KeithNumber.isKeith(197)); + } + + /** + * Tests that zero throws an IllegalArgumentException. + */ + @Test + void testZeroThrowsException() { + assertThrows(IllegalArgumentException.class, () -> KeithNumber.isKeith(0)); + } + + /** + * Tests that negative numbers throw an IllegalArgumentException. + */ + @Test + void testNegativeNumbersThrowException() { + assertThrows(IllegalArgumentException.class, () -> KeithNumber.isKeith(-1)); + assertThrows(IllegalArgumentException.class, () -> KeithNumber.isKeith(-14)); + assertThrows(IllegalArgumentException.class, () -> KeithNumber.isKeith(-100)); + } + + /** + * Tests various edge cases with larger numbers. + */ + @Test + void testLargerNumbers() { + assertTrue(KeithNumber.isKeith(2208)); + assertFalse(KeithNumber.isKeith(2207)); + assertFalse(KeithNumber.isKeith(2209)); + } + + /** + * Tests the expected behavior with all two-digit Keith numbers. + */ + @Test + void testAllKnownTwoDigitKeithNumbers() { + int[] knownKeithNumbers = {14, 19, 28, 47, 61, 75}; + for (int number : knownKeithNumbers) { + assertTrue(KeithNumber.isKeith(number), "Expected " + number + " to be a Keith number"); + } + } +}