Skip to content

Commit 5d7a596

Browse files
authored
Refactor LowestBasePalindrome (TheAlgorithms#4207)
1 parent 96c1a96 commit 5d7a596

File tree

2 files changed

+157
-130
lines changed

2 files changed

+157
-130
lines changed
Lines changed: 70 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,93 @@
11
package com.thealgorithms.others;
22

3-
import java.util.InputMismatchException;
4-
import java.util.Scanner;
3+
import java.util.ArrayList;
54

65
/**
7-
* Class for finding the lowest base in which a given integer is a palindrome.
8-
* Includes auxiliary methods for converting between bases and reversing
9-
* strings.
10-
*
11-
* <p>
12-
* NOTE: There is potential for error, see note at line 63.
13-
*
14-
* @author RollandMichael
15-
* @version 2017.09.28
6+
* @brief Class for finding the lowest base in which a given integer is a palindrome.
7+
cf. https://oeis.org/A016026
168
*/
17-
public class LowestBasePalindrome {
9+
final public class LowestBasePalindrome {
10+
private LowestBasePalindrome() {
11+
}
1812

19-
public static void main(String[] args) {
20-
Scanner in = new Scanner(System.in);
21-
int n = 0;
22-
while (true) {
23-
try {
24-
System.out.print("Enter number: ");
25-
n = in.nextInt();
26-
break;
27-
} catch (InputMismatchException e) {
28-
System.out.println("Invalid input!");
29-
in.next();
30-
}
13+
private static void checkBase(int base) {
14+
if (base <= 1) {
15+
throw new IllegalArgumentException("base must be greater than 1.");
16+
}
17+
}
18+
19+
private static void checkNumber(int number) {
20+
if (number < 0) {
21+
throw new IllegalArgumentException("number must be nonnegative.");
3122
}
32-
System.out.println(
33-
n + " is a palindrome in base " + lowestBasePalindrome(n)
34-
);
35-
System.out.println(
36-
base2base(Integer.toString(n), 10, lowestBasePalindrome(n))
37-
);
38-
in.close();
3923
}
4024

4125
/**
42-
* Given a number in base 10, returns the lowest base in which the number is
43-
* represented by a palindrome (read the same left-to-right and
44-
* right-to-left).
45-
*
46-
* @param num A number in base 10.
47-
* @return The lowest base in which num is a palindrome.
26+
* @brief computes the representation of the input number in given base
27+
* @param number the input number
28+
* @param base the given base
29+
* @exception IllegalArgumentException number is negative or base is less than 2
30+
* @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
4831
*/
49-
public static int lowestBasePalindrome(int num) {
50-
int base, num2 = num;
51-
int digit;
52-
char digitC;
53-
boolean foundBase = false;
54-
String newNum = "";
55-
String digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
56-
57-
while (!foundBase) {
58-
// Try from bases 2 to num-1
59-
for (base = 2; base < num2; base++) {
60-
newNum = "";
61-
while (num > 0) {
62-
// Obtain the first digit of n in the current base,
63-
// which is equivalent to the integer remainder of (n/base).
64-
// The next digit is obtained by dividing n by the base and
65-
// continuing the process of getting the remainder. This is done
66-
// until n is <=0 and the number in the new base is obtained.
67-
digit = (num % base);
68-
num /= base;
69-
// If the digit isn't in the set of [0-9][A-Z] (beyond base 36), its character
70-
// form is just its value in ASCII.
32+
public static ArrayList<Integer> computeDigitsInBase(int number, int base) {
33+
checkNumber(number);
34+
checkBase(base);
35+
var result = new ArrayList<Integer>();
36+
while (number > 0) {
37+
result.add(number % base);
38+
number /= base;
39+
}
40+
return result;
41+
}
7142

72-
// NOTE: This may cause problems, as the capital letters are ASCII values
73-
// 65-90. It may cause false positives when one digit is, for instance 10 and assigned
74-
// 'A' from the character array and the other is 65 and also assigned 'A'.
75-
// Regardless, the character is added to the representation of n
76-
// in the current base.
77-
if (digit >= digits.length()) {
78-
digitC = (char) (digit);
79-
newNum += digitC;
80-
continue;
81-
}
82-
newNum += digits.charAt(digit);
83-
}
84-
// Num is assigned back its original value for the next iteration.
85-
num = num2;
86-
// Auxiliary method reverses the number.
87-
String reverse = reverse(newNum);
88-
// If the number is read the same as its reverse, then it is a palindrome.
89-
// The current base is returned.
90-
if (reverse.equals(newNum)) {
91-
foundBase = true;
92-
return base;
93-
}
43+
/**
44+
* @brief checks if the input array is a palindrome
45+
* @brief list the input array
46+
* @return true, if the input array is a palindrome, false otherwise
47+
*/
48+
public static boolean isPalindromic(ArrayList<Integer> list) {
49+
for (int pos = 0; pos < list.size()/2; ++pos) {
50+
if(list.get(pos) != list.get(list.size()-1-pos)) {
51+
return false;
9452
}
9553
}
96-
// If all else fails, n is always a palindrome in base n-1. ("11")
97-
return num - 1;
54+
return true;
9855
}
9956

100-
private static String reverse(String str) {
101-
String reverse = "";
102-
for (int i = str.length() - 1; i >= 0; i--) {
103-
reverse += str.charAt(i);
57+
/**
58+
* @brief checks if representation of the input number in given base is a palindrome
59+
* @param number the input number
60+
* @param base the given base
61+
* @exception IllegalArgumentException number is negative or base is less than 2
62+
* @return true, if the input number represented in the given base is a palindrome, false otherwise
63+
*/
64+
public static boolean isPalindromicInBase(int number, int base) {
65+
checkNumber(number);
66+
checkBase(base);
67+
68+
if (number <= 1) {
69+
return true;
10470
}
105-
return reverse;
106-
}
10771

108-
private static String base2base(String n, int b1, int b2) {
109-
// Declare variables: decimal value of n,
110-
// character of base b1, character of base b2,
111-
// and the string that will be returned.
112-
int decimalValue = 0, charB2;
113-
char charB1;
114-
String output = "";
115-
// Go through every character of n
116-
for (int i = 0; i < n.length(); i++) {
117-
// store the character in charB1
118-
charB1 = n.charAt(i);
119-
// if it is a non-number, convert it to a decimal value >9 and store it in charB2
120-
if (charB1 >= 'A' && charB1 <= 'Z') {
121-
charB2 = 10 + (charB1 - 'A');
122-
} // Else, store the integer value in charB2
123-
else {
124-
charB2 = charB1 - '0';
125-
}
126-
// Convert the digit to decimal and add it to the
127-
// decimalValue of n
128-
decimalValue = decimalValue * b1 + charB2;
72+
if (number % base == 0) {
73+
// the last digit of number written in base is 0
74+
return false;
12975
}
13076

131-
// Converting the decimal value to base b2:
132-
// A number is converted from decimal to another base
133-
// by continuously dividing by the base and recording
134-
// the remainder until the quotient is zero. The number in the
135-
// new base is the remainders, with the last remainder
136-
// being the left-most digit.
137-
// While the quotient is NOT zero:
138-
while (decimalValue != 0) {
139-
// If the remainder is a digit < 10, simply add it to
140-
// the left side of the new number.
141-
if (decimalValue % b2 < 10) {
142-
output = decimalValue % b2 + output;
143-
} // If the remainder is >= 10, add a character with the
144-
// corresponding value to the new number. (A = 10, B = 11, C = 12, ...)
145-
else {
146-
output = (char) ((decimalValue % b2) + 55) + output;
147-
}
148-
// Divide by the new base again
149-
decimalValue /= b2;
77+
return isPalindromic(computeDigitsInBase(number, base));
78+
}
79+
80+
/**
81+
* @brief finds the smallest base for which the representation of the input number is a palindrome
82+
* @param number the input number
83+
* @exception IllegalArgumentException number is negative
84+
* @return the smallest base for which the representation of the input number is a palindrome
85+
*/
86+
public static int lowestBasePalindrome(int number) {
87+
int base = 2;
88+
while(!isPalindromicInBase(number, base)) {
89+
++base;
15090
}
151-
return output;
91+
return base;
15292
}
15393
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.thealgorithms.others;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertTrue;
5+
import static org.junit.jupiter.api.Assertions.assertFalse;
6+
import static org.junit.jupiter.api.Assertions.assertThrows;
7+
8+
import java.util.HashMap;
9+
import java.util.ArrayList;
10+
import java.util.Arrays;
11+
12+
import org.junit.jupiter.api.Test;
13+
14+
public class LowestBasePalindromeTest {
15+
@Test
16+
public void testIsPalindromicPositive() {
17+
assertTrue(LowestBasePalindrome.isPalindromic(new ArrayList<Integer>()));
18+
assertTrue(LowestBasePalindrome.isPalindromic(new ArrayList<Integer>(Arrays.asList(1))));
19+
assertTrue(LowestBasePalindrome.isPalindromic(new ArrayList<Integer>(Arrays.asList(1, 1))));
20+
assertTrue(LowestBasePalindrome.isPalindromic(new ArrayList<Integer>(Arrays.asList(1, 2, 1))));
21+
assertTrue(LowestBasePalindrome.isPalindromic(new ArrayList<Integer>(Arrays.asList(1, 2, 2, 1))));
22+
}
23+
24+
@Test
25+
public void testIsPalindromicNegative() {
26+
assertFalse(LowestBasePalindrome.isPalindromic(new ArrayList<Integer>(Arrays.asList(1, 2))));
27+
assertFalse(LowestBasePalindrome.isPalindromic(new ArrayList<Integer>(Arrays.asList(1, 2, 1, 1))));
28+
}
29+
30+
@Test
31+
public void testIsPalindromicInBasePositive() {
32+
assertTrue(LowestBasePalindrome.isPalindromicInBase(101, 10));
33+
assertTrue(LowestBasePalindrome.isPalindromicInBase(1, 190));
34+
assertTrue(LowestBasePalindrome.isPalindromicInBase(0, 11));
35+
assertTrue(LowestBasePalindrome.isPalindromicInBase(10101, 10));
36+
assertTrue(LowestBasePalindrome.isPalindromicInBase(23, 22));
37+
}
38+
39+
@Test
40+
public void testIsPalindromicInBaseNegative() {
41+
assertFalse(LowestBasePalindrome.isPalindromicInBase(1010, 10));
42+
assertFalse(LowestBasePalindrome.isPalindromicInBase(123, 10));
43+
}
44+
45+
@Test
46+
public void testIsPalindromicInBaseThrowsExceptionForNegativeNumbers() {
47+
assertThrows(
48+
IllegalArgumentException.class,
49+
() -> LowestBasePalindrome.isPalindromicInBase(-1, 5)
50+
);
51+
}
52+
53+
@Test
54+
public void testIsPalindromicInBaseThrowsExceptionForWrongBases() {
55+
assertThrows(
56+
IllegalArgumentException.class,
57+
() -> LowestBasePalindrome.isPalindromicInBase(10, 1)
58+
);
59+
}
60+
61+
@Test
62+
public void testLowestBasePalindrome() {
63+
HashMap<Integer, Integer> testCases = new HashMap<>();
64+
testCases.put(0, 2);
65+
testCases.put(1, 2);
66+
testCases.put(2, 3);
67+
testCases.put(3, 2);
68+
testCases.put(10, 3);
69+
testCases.put(11, 10);
70+
testCases.put(15, 2);
71+
testCases.put(39, 12);
72+
testCases.put(44, 10);
73+
testCases.put(58, 28);
74+
testCases.put(69, 22);
75+
testCases.put(79, 78);
76+
testCases.put(87, 28);
77+
testCases.put(90, 14);
78+
testCases.put(5591, 37);
79+
testCases.put(5895, 130);
80+
testCases.put(9950, 198);
81+
testCases.put(9974, 4986);
82+
83+
for (final var tc : testCases.entrySet()) {
84+
assertEquals(LowestBasePalindrome.lowestBasePalindrome(tc.getKey()), tc.getValue());
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)