diff --git a/src/main/java/com/thealgorithms/others/LowestBasePalindrome.java b/src/main/java/com/thealgorithms/others/LowestBasePalindrome.java
index 3d50b4840..addf82554 100644
--- a/src/main/java/com/thealgorithms/others/LowestBasePalindrome.java
+++ b/src/main/java/com/thealgorithms/others/LowestBasePalindrome.java
@@ -1,153 +1,93 @@
package com.thealgorithms.others;
-import java.util.InputMismatchException;
-import java.util.Scanner;
+import java.util.ArrayList;
/**
- * Class for finding the lowest base in which a given integer is a palindrome.
- * Includes auxiliary methods for converting between bases and reversing
- * strings.
- *
- *
- * NOTE: There is potential for error, see note at line 63.
- *
- * @author RollandMichael
- * @version 2017.09.28
+ * @brief Class for finding the lowest base in which a given integer is a palindrome.
+ cf. https://oeis.org/A016026
*/
-public class LowestBasePalindrome {
+final public class LowestBasePalindrome {
+ private LowestBasePalindrome() {
+ }
- public static void main(String[] args) {
- Scanner in = new Scanner(System.in);
- int n = 0;
- while (true) {
- try {
- System.out.print("Enter number: ");
- n = in.nextInt();
- break;
- } catch (InputMismatchException e) {
- System.out.println("Invalid input!");
- in.next();
- }
+ private static void checkBase(int base) {
+ if (base <= 1) {
+ throw new IllegalArgumentException("base must be greater than 1.");
+ }
+ }
+
+ private static void checkNumber(int number) {
+ if (number < 0) {
+ throw new IllegalArgumentException("number must be nonnegative.");
}
- System.out.println(
- n + " is a palindrome in base " + lowestBasePalindrome(n)
- );
- System.out.println(
- base2base(Integer.toString(n), 10, lowestBasePalindrome(n))
- );
- in.close();
}
/**
- * Given a number in base 10, returns the lowest base in which the number is
- * represented by a palindrome (read the same left-to-right and
- * right-to-left).
- *
- * @param num A number in base 10.
- * @return The lowest base in which num is a palindrome.
+ * @brief computes the representation of the input number in given base
+ * @param number the input number
+ * @param base the given base
+ * @exception IllegalArgumentException number is negative or base is less than 2
+ * @return the list containing the digits of the input number in the given base, the most significant digit is at the end of the array
*/
- public static int lowestBasePalindrome(int num) {
- int base, num2 = num;
- int digit;
- char digitC;
- boolean foundBase = false;
- String newNum = "";
- String digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
- while (!foundBase) {
- // Try from bases 2 to num-1
- for (base = 2; base < num2; base++) {
- newNum = "";
- while (num > 0) {
- // Obtain the first digit of n in the current base,
- // which is equivalent to the integer remainder of (n/base).
- // The next digit is obtained by dividing n by the base and
- // continuing the process of getting the remainder. This is done
- // until n is <=0 and the number in the new base is obtained.
- digit = (num % base);
- num /= base;
- // If the digit isn't in the set of [0-9][A-Z] (beyond base 36), its character
- // form is just its value in ASCII.
-
- // NOTE: This may cause problems, as the capital letters are ASCII values
- // 65-90. It may cause false positives when one digit is, for instance 10 and assigned
- // 'A' from the character array and the other is 65 and also assigned 'A'.
- // Regardless, the character is added to the representation of n
- // in the current base.
- if (digit >= digits.length()) {
- digitC = (char) (digit);
- newNum += digitC;
- continue;
- }
- newNum += digits.charAt(digit);
- }
- // Num is assigned back its original value for the next iteration.
- num = num2;
- // Auxiliary method reverses the number.
- String reverse = reverse(newNum);
- // If the number is read the same as its reverse, then it is a palindrome.
- // The current base is returned.
- if (reverse.equals(newNum)) {
- foundBase = true;
- return base;
- }
- }
+ public static ArrayList computeDigitsInBase(int number, int base) {
+ checkNumber(number);
+ checkBase(base);
+ var result = new ArrayList();
+ while (number > 0) {
+ result.add(number % base);
+ number /= base;
}
- // If all else fails, n is always a palindrome in base n-1. ("11")
- return num - 1;
+ return result;
}
- private static String reverse(String str) {
- String reverse = "";
- for (int i = str.length() - 1; i >= 0; i--) {
- reverse += str.charAt(i);
+ /**
+ * @brief checks if the input array is a palindrome
+ * @brief list the input array
+ * @return true, if the input array is a palindrome, false otherwise
+ */
+ public static boolean isPalindromic(ArrayList list) {
+ for (int pos = 0; pos < list.size()/2; ++pos) {
+ if(list.get(pos) != list.get(list.size()-1-pos)) {
+ return false;
+ }
}
- return reverse;
+ return true;
}
- private static String base2base(String n, int b1, int b2) {
- // Declare variables: decimal value of n,
- // character of base b1, character of base b2,
- // and the string that will be returned.
- int decimalValue = 0, charB2;
- char charB1;
- String output = "";
- // Go through every character of n
- for (int i = 0; i < n.length(); i++) {
- // store the character in charB1
- charB1 = n.charAt(i);
- // if it is a non-number, convert it to a decimal value >9 and store it in charB2
- if (charB1 >= 'A' && charB1 <= 'Z') {
- charB2 = 10 + (charB1 - 'A');
- } // Else, store the integer value in charB2
- else {
- charB2 = charB1 - '0';
- }
- // Convert the digit to decimal and add it to the
- // decimalValue of n
- decimalValue = decimalValue * b1 + charB2;
+ /**
+ * @brief checks if representation of the input number in given base is a palindrome
+ * @param number the input number
+ * @param base the given base
+ * @exception IllegalArgumentException number is negative or base is less than 2
+ * @return true, if the input number represented in the given base is a palindrome, false otherwise
+ */
+ public static boolean isPalindromicInBase(int number, int base) {
+ checkNumber(number);
+ checkBase(base);
+
+ if (number <= 1) {
+ return true;
}
- // Converting the decimal value to base b2:
- // A number is converted from decimal to another base
- // by continuously dividing by the base and recording
- // the remainder until the quotient is zero. The number in the
- // new base is the remainders, with the last remainder
- // being the left-most digit.
- // While the quotient is NOT zero:
- while (decimalValue != 0) {
- // If the remainder is a digit < 10, simply add it to
- // the left side of the new number.
- if (decimalValue % b2 < 10) {
- output = decimalValue % b2 + output;
- } // If the remainder is >= 10, add a character with the
- // corresponding value to the new number. (A = 10, B = 11, C = 12, ...)
- else {
- output = (char) ((decimalValue % b2) + 55) + output;
- }
- // Divide by the new base again
- decimalValue /= b2;
+ if (number % base == 0) {
+ // the last digit of number written in base is 0
+ return false;
}
- return output;
+
+ return isPalindromic(computeDigitsInBase(number, base));
+ }
+
+ /**
+ * @brief finds the smallest base for which the representation of the input number is a palindrome
+ * @param number the input number
+ * @exception IllegalArgumentException number is negative
+ * @return the smallest base for which the representation of the input number is a palindrome
+ */
+ public static int lowestBasePalindrome(int number) {
+ int base = 2;
+ while(!isPalindromicInBase(number, base)) {
+ ++base;
+ }
+ return base;
}
}
diff --git a/src/test/java/com/thealgorithms/others/LowestBasePalindromeTest.java b/src/test/java/com/thealgorithms/others/LowestBasePalindromeTest.java
new file mode 100644
index 000000000..3124d7b02
--- /dev/null
+++ b/src/test/java/com/thealgorithms/others/LowestBasePalindromeTest.java
@@ -0,0 +1,87 @@
+package com.thealgorithms.others;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.junit.jupiter.api.Test;
+
+public class LowestBasePalindromeTest {
+ @Test
+ public void testIsPalindromicPositive() {
+ assertTrue(LowestBasePalindrome.isPalindromic(new ArrayList()));
+ assertTrue(LowestBasePalindrome.isPalindromic(new ArrayList(Arrays.asList(1))));
+ assertTrue(LowestBasePalindrome.isPalindromic(new ArrayList(Arrays.asList(1, 1))));
+ assertTrue(LowestBasePalindrome.isPalindromic(new ArrayList(Arrays.asList(1, 2, 1))));
+ assertTrue(LowestBasePalindrome.isPalindromic(new ArrayList(Arrays.asList(1, 2, 2, 1))));
+ }
+
+ @Test
+ public void testIsPalindromicNegative() {
+ assertFalse(LowestBasePalindrome.isPalindromic(new ArrayList(Arrays.asList(1, 2))));
+ assertFalse(LowestBasePalindrome.isPalindromic(new ArrayList(Arrays.asList(1, 2, 1, 1))));
+ }
+
+ @Test
+ public void testIsPalindromicInBasePositive() {
+ assertTrue(LowestBasePalindrome.isPalindromicInBase(101, 10));
+ assertTrue(LowestBasePalindrome.isPalindromicInBase(1, 190));
+ assertTrue(LowestBasePalindrome.isPalindromicInBase(0, 11));
+ assertTrue(LowestBasePalindrome.isPalindromicInBase(10101, 10));
+ assertTrue(LowestBasePalindrome.isPalindromicInBase(23, 22));
+ }
+
+ @Test
+ public void testIsPalindromicInBaseNegative() {
+ assertFalse(LowestBasePalindrome.isPalindromicInBase(1010, 10));
+ assertFalse(LowestBasePalindrome.isPalindromicInBase(123, 10));
+ }
+
+ @Test
+ public void testIsPalindromicInBaseThrowsExceptionForNegativeNumbers() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> LowestBasePalindrome.isPalindromicInBase(-1, 5)
+ );
+ }
+
+ @Test
+ public void testIsPalindromicInBaseThrowsExceptionForWrongBases() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> LowestBasePalindrome.isPalindromicInBase(10, 1)
+ );
+ }
+
+ @Test
+ public void testLowestBasePalindrome() {
+ HashMap testCases = new HashMap<>();
+ testCases.put(0, 2);
+ testCases.put(1, 2);
+ testCases.put(2, 3);
+ testCases.put(3, 2);
+ testCases.put(10, 3);
+ testCases.put(11, 10);
+ testCases.put(15, 2);
+ testCases.put(39, 12);
+ testCases.put(44, 10);
+ testCases.put(58, 28);
+ testCases.put(69, 22);
+ testCases.put(79, 78);
+ testCases.put(87, 28);
+ testCases.put(90, 14);
+ testCases.put(5591, 37);
+ testCases.put(5895, 130);
+ testCases.put(9950, 198);
+ testCases.put(9974, 4986);
+
+ for (final var tc : testCases.entrySet()) {
+ assertEquals(LowestBasePalindrome.lowestBasePalindrome(tc.getKey()), tc.getValue());
+ }
+ }
+}