Skip to content

Commit 387ecef

Browse files
Hardvanalxkm
andauthored
refactor: Enhance docs, code, add tests in KeithNumber (#6748)
* refactor: Enhance docs, code, add tests in `KeithNumber` * Fix --------- Co-authored-by: a <[email protected]>
1 parent 297634d commit 387ecef

File tree

2 files changed

+227
-33
lines changed

2 files changed

+227
-33
lines changed

src/main/java/com/thealgorithms/maths/KeithNumber.java

Lines changed: 74 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,57 +4,98 @@
44
import java.util.Collections;
55
import java.util.Scanner;
66

7-
final class KeithNumber {
7+
/**
8+
* A Keith number is an n-digit positive integer where the sequence formed by
9+
* starting with its digits and repeatedly adding the previous n terms,
10+
* eventually reaches the number itself.
11+
*
12+
* <p>
13+
* For example:
14+
* <ul>
15+
* <li>14 is a Keith number: 1, 4, 5, 9, 14</li>
16+
* <li>19 is a Keith number: 1, 9, 10, 19</li>
17+
* <li>28 is a Keith number: 2, 8, 10, 18, 28</li>
18+
* <li>197 is a Keith number: 1, 9, 7, 17, 33, 57, 107, 197</li>
19+
* </ul>
20+
*
21+
* @see <a href="https://en.wikipedia.org/wiki/Keith_number">Keith Number -
22+
* Wikipedia</a>
23+
* @see <a href="https://mathworld.wolfram.com/KeithNumber.html">Keith Number -
24+
* MathWorld</a>
25+
*/
26+
public final class KeithNumber {
827
private KeithNumber() {
928
}
1029

11-
// user-defined function that checks if the given number is Keith or not
12-
static boolean isKeith(int x) {
13-
// List stores all the digits of the X
30+
/**
31+
* Checks if a given number is a Keith number.
32+
*
33+
* <p>
34+
* The algorithm works as follows:
35+
* <ol>
36+
* <li>Extract all digits of the number and store them in a list</li>
37+
* <li>Generate subsequent terms by summing the last n digits</li>
38+
* <li>Continue until a term equals or exceeds the original number</li>
39+
* <li>If a term equals the number, it is a Keith number</li>
40+
* </ol>
41+
*
42+
* @param number the number to check (must be positive)
43+
* @return {@code true} if the number is a Keith number, {@code false} otherwise
44+
* @throws IllegalArgumentException if the number is not positive
45+
*/
46+
public static boolean isKeith(int number) {
47+
if (number <= 0) {
48+
throw new IllegalArgumentException("Number must be positive");
49+
}
50+
51+
// Extract digits and store them in the list
1452
ArrayList<Integer> terms = new ArrayList<>();
15-
// n denotes the number of digits
16-
int temp = x;
17-
int n = 0;
18-
// executes until the condition becomes false
53+
int temp = number;
54+
int digitCount = 0;
55+
1956
while (temp > 0) {
20-
// determines the last digit of the number and add it to the List
2157
terms.add(temp % 10);
22-
// removes the last digit
2358
temp = temp / 10;
24-
// increments the number of digits (n) by 1
25-
n++;
59+
digitCount++;
2660
}
27-
// reverse the List
61+
62+
// Reverse the list to get digits in correct order
2863
Collections.reverse(terms);
64+
65+
// Generate subsequent terms in the sequence
2966
int nextTerm = 0;
30-
int i = n;
31-
// finds next term for the series
32-
// loop executes until the condition returns true
33-
while (nextTerm < x) {
67+
int currentIndex = digitCount;
68+
69+
while (nextTerm < number) {
3470
nextTerm = 0;
35-
// next term is the sum of previous n terms (it depends on number of digits the number
36-
// has)
37-
for (int j = 1; j <= n; j++) {
38-
nextTerm = nextTerm + terms.get(i - j);
71+
// Sum the last 'digitCount' terms
72+
for (int j = 1; j <= digitCount; j++) {
73+
nextTerm = nextTerm + terms.get(currentIndex - j);
3974
}
4075
terms.add(nextTerm);
41-
i++;
76+
currentIndex++;
4277
}
43-
// when the control comes out of the while loop, there will be two conditions:
44-
// either nextTerm will be equal to x or greater than x
45-
// if equal, the given number is Keith, else not
46-
return (nextTerm == x);
78+
79+
// Check if the generated term equals the original number
80+
return (nextTerm == number);
4781
}
4882

49-
// driver code
83+
/**
84+
* Main method for demonstrating Keith number detection.
85+
* Reads a number from standard input and checks if it is a Keith number.
86+
*
87+
* @param args command line arguments (not used)
88+
*/
5089
public static void main(String[] args) {
51-
Scanner in = new Scanner(System.in);
52-
int n = in.nextInt();
53-
if (isKeith(n)) {
54-
System.out.println("Yes, the given number is a Keith number.");
90+
Scanner scanner = new Scanner(System.in);
91+
System.out.print("Enter a positive integer: ");
92+
int number = scanner.nextInt();
93+
94+
if (isKeith(number)) {
95+
System.out.println("Yes, " + number + " is a Keith number.");
5596
} else {
56-
System.out.println("No, the given number is not a Keith number.");
97+
System.out.println("No, " + number + " is not a Keith number.");
5798
}
58-
in.close();
99+
scanner.close();
59100
}
60101
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package com.thealgorithms.maths;
2+
3+
import static org.junit.jupiter.api.Assertions.assertFalse;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
5+
import static org.junit.jupiter.api.Assertions.assertTrue;
6+
7+
import org.junit.jupiter.api.Test;
8+
9+
/**
10+
* Test cases for {@link KeithNumber}.
11+
*/
12+
class KeithNumberTest {
13+
14+
/**
15+
* Tests single-digit Keith numbers.
16+
* All single-digit numbers (1-9) are Keith numbers by definition.
17+
*/
18+
@Test
19+
void testSingleDigitKeithNumbers() {
20+
assertTrue(KeithNumber.isKeith(1));
21+
assertTrue(KeithNumber.isKeith(2));
22+
assertTrue(KeithNumber.isKeith(3));
23+
assertTrue(KeithNumber.isKeith(4));
24+
assertTrue(KeithNumber.isKeith(5));
25+
assertTrue(KeithNumber.isKeith(6));
26+
assertTrue(KeithNumber.isKeith(7));
27+
assertTrue(KeithNumber.isKeith(8));
28+
assertTrue(KeithNumber.isKeith(9));
29+
}
30+
31+
/**
32+
* Tests two-digit Keith numbers.
33+
* Known two-digit Keith numbers: 14, 19, 28, 47, 61, 75.
34+
*/
35+
@Test
36+
void testTwoDigitKeithNumbers() {
37+
assertTrue(KeithNumber.isKeith(14));
38+
assertTrue(KeithNumber.isKeith(19));
39+
assertTrue(KeithNumber.isKeith(28));
40+
assertTrue(KeithNumber.isKeith(47));
41+
assertTrue(KeithNumber.isKeith(61));
42+
assertTrue(KeithNumber.isKeith(75));
43+
}
44+
45+
/**
46+
* Tests three-digit Keith numbers.
47+
* Known three-digit Keith numbers: 197, 742.
48+
*/
49+
@Test
50+
void testThreeDigitKeithNumbers() {
51+
assertTrue(KeithNumber.isKeith(197));
52+
assertTrue(KeithNumber.isKeith(742));
53+
}
54+
55+
/**
56+
* Tests four-digit Keith numbers.
57+
* Known four-digit Keith numbers: 1104, 1537, 2208, 2580, 3684, 4788, 7385,
58+
* 7647, 7909.
59+
*/
60+
@Test
61+
void testFourDigitKeithNumbers() {
62+
assertTrue(KeithNumber.isKeith(1104));
63+
assertTrue(KeithNumber.isKeith(1537));
64+
assertTrue(KeithNumber.isKeith(2208));
65+
}
66+
67+
/**
68+
* Tests two-digit non-Keith numbers.
69+
*/
70+
@Test
71+
void testTwoDigitNonKeithNumbers() {
72+
assertFalse(KeithNumber.isKeith(10));
73+
assertFalse(KeithNumber.isKeith(11));
74+
assertFalse(KeithNumber.isKeith(12));
75+
assertFalse(KeithNumber.isKeith(13));
76+
assertFalse(KeithNumber.isKeith(15));
77+
assertFalse(KeithNumber.isKeith(20));
78+
assertFalse(KeithNumber.isKeith(30));
79+
assertFalse(KeithNumber.isKeith(50));
80+
}
81+
82+
/**
83+
* Tests three-digit non-Keith numbers.
84+
*/
85+
@Test
86+
void testThreeDigitNonKeithNumbers() {
87+
assertFalse(KeithNumber.isKeith(100));
88+
assertFalse(KeithNumber.isKeith(123));
89+
assertFalse(KeithNumber.isKeith(196));
90+
assertFalse(KeithNumber.isKeith(198));
91+
assertFalse(KeithNumber.isKeith(456));
92+
assertFalse(KeithNumber.isKeith(741));
93+
assertFalse(KeithNumber.isKeith(743));
94+
assertFalse(KeithNumber.isKeith(999));
95+
}
96+
97+
/**
98+
* Tests validation for edge case 14 in detail.
99+
* 14 is a Keith number: 1, 4, 5 (1+4), 9 (4+5), 14 (5+9).
100+
*/
101+
@Test
102+
void testKeithNumber14() {
103+
assertTrue(KeithNumber.isKeith(14));
104+
}
105+
106+
/**
107+
* Tests validation for edge case 197 in detail.
108+
* 197 is a Keith number: 1, 9, 7, 17, 33, 57, 107, 197.
109+
*/
110+
@Test
111+
void testKeithNumber197() {
112+
assertTrue(KeithNumber.isKeith(197));
113+
}
114+
115+
/**
116+
* Tests that zero throws an IllegalArgumentException.
117+
*/
118+
@Test
119+
void testZeroThrowsException() {
120+
assertThrows(IllegalArgumentException.class, () -> KeithNumber.isKeith(0));
121+
}
122+
123+
/**
124+
* Tests that negative numbers throw an IllegalArgumentException.
125+
*/
126+
@Test
127+
void testNegativeNumbersThrowException() {
128+
assertThrows(IllegalArgumentException.class, () -> KeithNumber.isKeith(-1));
129+
assertThrows(IllegalArgumentException.class, () -> KeithNumber.isKeith(-14));
130+
assertThrows(IllegalArgumentException.class, () -> KeithNumber.isKeith(-100));
131+
}
132+
133+
/**
134+
* Tests various edge cases with larger numbers.
135+
*/
136+
@Test
137+
void testLargerNumbers() {
138+
assertTrue(KeithNumber.isKeith(2208));
139+
assertFalse(KeithNumber.isKeith(2207));
140+
assertFalse(KeithNumber.isKeith(2209));
141+
}
142+
143+
/**
144+
* Tests the expected behavior with all two-digit Keith numbers.
145+
*/
146+
@Test
147+
void testAllKnownTwoDigitKeithNumbers() {
148+
int[] knownKeithNumbers = {14, 19, 28, 47, 61, 75};
149+
for (int number : knownKeithNumbers) {
150+
assertTrue(KeithNumber.isKeith(number), "Expected " + number + " to be a Keith number");
151+
}
152+
}
153+
}

0 commit comments

Comments
 (0)