Skip to content

Commit f7f6152

Browse files
authored
Merge branch 'master' into refactor/LongestNonRepeativeSubstring
2 parents fed1525 + 622a3bf commit f7f6152

File tree

11 files changed

+386
-56
lines changed

11 files changed

+386
-56
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.thealgorithms.conversions;
2+
3+
public final class AffineConverter {
4+
private final double slope;
5+
private final double intercept;
6+
public AffineConverter(final double inSlope, final double inIntercept) {
7+
slope = inSlope;
8+
intercept = inIntercept;
9+
}
10+
11+
public double convert(final double inValue) {
12+
return slope * inValue + intercept;
13+
}
14+
15+
public AffineConverter invert() {
16+
assert slope != 0.0;
17+
return new AffineConverter(1.0 / slope, -intercept / slope);
18+
}
19+
20+
public AffineConverter compose(final AffineConverter other) {
21+
return new AffineConverter(slope * other.slope, slope * other.intercept + intercept);
22+
}
23+
}

src/main/java/com/thealgorithms/conversions/AnyBaseToDecimal.java

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,54 +3,50 @@
33
/**
44
* @author Varun Upadhyay (<a href="https://github.com/varunu28">...</a>)
55
*/
6-
// Driver program
76
public final class AnyBaseToDecimal {
8-
private AnyBaseToDecimal() {
9-
}
7+
private static final int CHAR_OFFSET_FOR_DIGIT = '0';
8+
private static final int CHAR_OFFSET_FOR_UPPERCASE = 'A' - 10;
109

11-
public static void main(String[] args) {
12-
assert convertToDecimal("1010", 2) == Integer.valueOf("1010", 2);
13-
assert convertToDecimal("777", 8) == Integer.valueOf("777", 8);
14-
assert convertToDecimal("999", 10) == Integer.valueOf("999", 10);
15-
assert convertToDecimal("ABCDEF", 16) == Integer.valueOf("ABCDEF", 16);
16-
assert convertToDecimal("XYZ", 36) == Integer.valueOf("XYZ", 36);
10+
private AnyBaseToDecimal() {
1711
}
1812

1913
/**
20-
* Convert any radix to decimal number
14+
* Convert any radix to a decimal number.
2115
*
22-
* @param s the string to be convert
23-
* @param radix the radix
24-
* @return decimal of bits
25-
* @throws NumberFormatException if {@code bits} or {@code radix} is invalid
16+
* @param input the string to be converted
17+
* @param radix the radix (base) of the input string
18+
* @return the decimal equivalent of the input string
19+
* @throws NumberFormatException if the input string or radix is invalid
2620
*/
27-
public static int convertToDecimal(String s, int radix) {
28-
int num = 0;
29-
int pow = 1;
21+
public static int convertToDecimal(String input, int radix) {
22+
int result = 0;
23+
int power = 1;
3024

31-
for (int i = s.length() - 1; i >= 0; i--) {
32-
int digit = valOfChar(s.charAt(i));
25+
for (int i = input.length() - 1; i >= 0; i--) {
26+
int digit = valOfChar(input.charAt(i));
3327
if (digit >= radix) {
34-
throw new NumberFormatException("For input string " + s);
28+
throw new NumberFormatException("For input string: " + input);
3529
}
36-
num += valOfChar(s.charAt(i)) * pow;
37-
pow *= radix;
30+
result += digit * power;
31+
power *= radix;
3832
}
39-
return num;
33+
return result;
4034
}
4135

4236
/**
43-
* Convert character to integer
37+
* Convert a character to its integer value.
4438
*
45-
* @param c the character
46-
* @return represented digit of given character
47-
* @throws NumberFormatException if {@code ch} is not UpperCase or Digit
48-
* character.
39+
* @param character the character to be converted
40+
* @return the integer value represented by the character
41+
* @throws NumberFormatException if the character is not an uppercase letter or a digit
4942
*/
50-
public static int valOfChar(char c) {
51-
if (!(Character.isUpperCase(c) || Character.isDigit(c))) {
52-
throw new NumberFormatException("invalid character :" + c);
43+
private static int valOfChar(char character) {
44+
if (Character.isDigit(character)) {
45+
return character - CHAR_OFFSET_FOR_DIGIT;
46+
} else if (Character.isUpperCase(character)) {
47+
return character - CHAR_OFFSET_FOR_UPPERCASE;
48+
} else {
49+
throw new NumberFormatException("invalid character:" + character);
5350
}
54-
return Character.isDigit(c) ? c - '0' : c - 'A' + 10;
5551
}
5652
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.thealgorithms.conversions;
2+
3+
import static java.util.Map.entry;
4+
5+
import java.util.Map;
6+
import org.apache.commons.lang3.tuple.Pair;
7+
8+
public final class UnitConversions {
9+
private UnitConversions() {
10+
}
11+
12+
public static final UnitsConverter TEMPERATURE = new UnitsConverter(Map.ofEntries(entry(Pair.of("Kelvin", "Celsius"), new AffineConverter(1.0, -273.15)), entry(Pair.of("Celsius", "Fahrenheit"), new AffineConverter(9.0 / 5.0, 32.0)),
13+
entry(Pair.of("Réaumur", "Celsius"), new AffineConverter(5.0 / 4.0, 0.0)), entry(Pair.of("Delisle", "Celsius"), new AffineConverter(-2.0 / 3.0, 100.0)), entry(Pair.of("Rankine", "Kelvin"), new AffineConverter(5.0 / 9.0, 0.0))));
14+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.thealgorithms.conversions;
2+
3+
import java.util.HashMap;
4+
import java.util.HashSet;
5+
import java.util.Map;
6+
import java.util.Set;
7+
import org.apache.commons.lang3.tuple.Pair;
8+
9+
public final class UnitsConverter {
10+
private final Map<Pair<String, String>, AffineConverter> conversions;
11+
private final Set<String> units;
12+
13+
private static void putIfNeeded(Map<Pair<String, String>, AffineConverter> conversions, final String inputUnit, final String outputUnit, final AffineConverter converter) {
14+
if (!inputUnit.equals(outputUnit)) {
15+
final var key = Pair.of(inputUnit, outputUnit);
16+
conversions.putIfAbsent(key, converter);
17+
}
18+
}
19+
20+
private static Map<Pair<String, String>, AffineConverter> addInversions(final Map<Pair<String, String>, AffineConverter> knownConversions) {
21+
Map<Pair<String, String>, AffineConverter> res = new HashMap<Pair<String, String>, AffineConverter>();
22+
for (final var curConversion : knownConversions.entrySet()) {
23+
final var inputUnit = curConversion.getKey().getKey();
24+
final var outputUnit = curConversion.getKey().getValue();
25+
putIfNeeded(res, inputUnit, outputUnit, curConversion.getValue());
26+
putIfNeeded(res, outputUnit, inputUnit, curConversion.getValue().invert());
27+
}
28+
return res;
29+
}
30+
31+
private static Map<Pair<String, String>, AffineConverter> addCompositions(final Map<Pair<String, String>, AffineConverter> knownConversions) {
32+
Map<Pair<String, String>, AffineConverter> res = new HashMap<Pair<String, String>, AffineConverter>();
33+
for (final var first : knownConversions.entrySet()) {
34+
final var firstKey = first.getKey();
35+
putIfNeeded(res, firstKey.getKey(), firstKey.getValue(), first.getValue());
36+
for (final var second : knownConversions.entrySet()) {
37+
final var secondKey = second.getKey();
38+
if (firstKey.getValue().equals(secondKey.getKey())) {
39+
final var newConversion = second.getValue().compose(first.getValue());
40+
putIfNeeded(res, firstKey.getKey(), secondKey.getValue(), newConversion);
41+
}
42+
}
43+
}
44+
return res;
45+
}
46+
47+
private static Map<Pair<String, String>, AffineConverter> addAll(final Map<Pair<String, String>, AffineConverter> knownConversions) {
48+
final var res = addInversions(knownConversions);
49+
return addCompositions(res);
50+
}
51+
52+
private static Map<Pair<String, String>, AffineConverter> computeAllConversions(final Map<Pair<String, String>, AffineConverter> basicConversions) {
53+
var tmp = basicConversions;
54+
var res = addAll(tmp);
55+
while (res.size() != tmp.size()) {
56+
tmp = res;
57+
res = addAll(tmp);
58+
}
59+
return res;
60+
}
61+
62+
private static Set<String> extractUnits(final Map<Pair<String, String>, AffineConverter> conversions) {
63+
Set<String> res = new HashSet<>();
64+
for (final var conversion : conversions.entrySet()) {
65+
res.add(conversion.getKey().getKey());
66+
}
67+
return res;
68+
}
69+
70+
public UnitsConverter(final Map<Pair<String, String>, AffineConverter> basicConversions) {
71+
conversions = computeAllConversions(basicConversions);
72+
units = extractUnits(conversions);
73+
}
74+
75+
public double convert(final String inputUnit, final String outputUnit, final double value) {
76+
if (inputUnit.equals(outputUnit)) {
77+
throw new IllegalArgumentException("inputUnit must be different from outputUnit.");
78+
}
79+
final var conversionKey = Pair.of(inputUnit, outputUnit);
80+
return conversions.get(conversionKey).convert(value);
81+
}
82+
83+
public Set<String> availableUnits() {
84+
return units;
85+
}
86+
}

src/main/java/com/thealgorithms/strings/AhoCorasick.java

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.util.ArrayList;
1515
import java.util.HashMap;
1616
import java.util.LinkedList;
17+
import java.util.List;
1718
import java.util.Map;
1819
import java.util.Queue;
1920

@@ -24,7 +25,7 @@ private AhoCorasick() {
2425
// Trie Node Class
2526
private static class Node {
2627
// Represents a character in the trie
27-
private HashMap<Character, Node> child = new HashMap<>(); // Child nodes of the current node
28+
private final Map<Character, Node> child = new HashMap<>(); // Child nodes of the current node
2829
private Node suffixLink; // Suffix link to another node in the trie
2930
private Node outputLink; // Output link to another node in the trie
3031
private int patternInd; // Index of the pattern that ends at this node
@@ -35,7 +36,7 @@ private static class Node {
3536
this.patternInd = -1;
3637
}
3738

38-
public HashMap<Character, Node> getChild() {
39+
public Map<Character, Node> getChild() {
3940
return child;
4041
}
4142

@@ -148,16 +149,16 @@ private void buildSuffixAndOutputLinks() {
148149
}
149150
}
150151

151-
private ArrayList<ArrayList<Integer>> initializePositionByStringIndexValue() {
152-
ArrayList<ArrayList<Integer>> positionByStringIndexValue = new ArrayList<>(patterns.length); // Stores positions where patterns are found in the text
152+
private List<List<Integer>> initializePositionByStringIndexValue() {
153+
List<List<Integer>> positionByStringIndexValue = new ArrayList<>(patterns.length); // Stores positions where patterns are found in the text
153154
for (int i = 0; i < patterns.length; i++) {
154-
positionByStringIndexValue.add(new ArrayList<Integer>());
155+
positionByStringIndexValue.add(new ArrayList<>());
155156
}
156157
return positionByStringIndexValue;
157158
}
158159

159160
// Searches for patterns in the input text and records their positions
160-
public ArrayList<ArrayList<Integer>> searchIn(final String text) {
161+
public List<List<Integer>> searchIn(final String text) {
161162
var positionByStringIndexValue = initializePositionByStringIndexValue(); // Initialize a list to store positions of the current pattern
162163
Node parent = root; // Start searching from the root node
163164

@@ -187,7 +188,7 @@ public ArrayList<ArrayList<Integer>> searchIn(final String text) {
187188

188189
// by default positionByStringIndexValue contains end-points. This function converts those
189190
// endpoints to start points
190-
private void setUpStartPoints(ArrayList<ArrayList<Integer>> positionByStringIndexValue) {
191+
private void setUpStartPoints(List<List<Integer>> positionByStringIndexValue) {
191192
for (int i = 0; i < patterns.length; i++) {
192193
for (int j = 0; j < positionByStringIndexValue.get(i).size(); j++) {
193194
int endpoint = positionByStringIndexValue.get(i).get(j);
@@ -198,20 +199,15 @@ private void setUpStartPoints(ArrayList<ArrayList<Integer>> positionByStringInde
198199
}
199200

200201
// Class to handle pattern position recording
201-
private static class PatternPositionRecorder {
202-
private ArrayList<ArrayList<Integer>> positionByStringIndexValue;
203-
202+
private record PatternPositionRecorder(List<List<Integer>> positionByStringIndexValue) {
204203
// Constructor to initialize the recorder with the position list
205-
PatternPositionRecorder(final ArrayList<ArrayList<Integer>> positionByStringIndexValue) {
206-
this.positionByStringIndexValue = positionByStringIndexValue;
207-
}
208204

209205
/**
210206
* Records positions for a pattern when it's found in the input text and follows
211207
* output links to record positions of other patterns.
212208
*
213-
* @param parent The current node representing a character in the pattern trie.
214-
* @param currentPosition The current position in the input text.
209+
* @param parent The current node representing a character in the pattern trie.
210+
* @param currentPosition The current position in the input text.
215211
*/
216212
public void recordPatternPositions(final Node parent, final int currentPosition) {
217213
// Check if the current node represents the end of a pattern
@@ -229,19 +225,20 @@ public void recordPatternPositions(final Node parent, final int currentPosition)
229225
}
230226
}
231227
}
228+
232229
// method to search for patterns in text
233-
public static Map<String, ArrayList<Integer>> search(final String text, final String[] patterns) {
230+
public static Map<String, List<Integer>> search(final String text, final String[] patterns) {
234231
final var trie = new Trie(patterns);
235232
final var positionByStringIndexValue = trie.searchIn(text);
236233
return convert(positionByStringIndexValue, patterns);
237234
}
238235

239236
// method for converting results to a map
240-
private static Map<String, ArrayList<Integer>> convert(final ArrayList<ArrayList<Integer>> positionByStringIndexValue, final String[] patterns) {
241-
Map<String, ArrayList<Integer>> positionByString = new HashMap<>();
237+
private static Map<String, List<Integer>> convert(final List<List<Integer>> positionByStringIndexValue, final String[] patterns) {
238+
Map<String, List<Integer>> positionByString = new HashMap<>();
242239
for (int i = 0; i < patterns.length; i++) {
243240
String pattern = patterns[i];
244-
ArrayList<Integer> positions = positionByStringIndexValue.get(i);
241+
List<Integer> positions = positionByStringIndexValue.get(i);
245242
positionByString.put(pattern, new ArrayList<>(positions));
246243
}
247244
return positionByString;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.thealgorithms.conversions;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
5+
6+
import org.junit.jupiter.api.Test;
7+
import org.junit.jupiter.params.ParameterizedTest;
8+
import org.junit.jupiter.params.provider.CsvSource;
9+
10+
public class AnyBaseToDecimalTest {
11+
@ParameterizedTest
12+
@CsvSource({"1010, 2, 10", "777, 8, 511", "999, 10, 999", "ABCDEF, 16, 11259375", "XYZ, 36, 44027", "0, 2, 0", "A, 16, 10", "Z, 36, 35"})
13+
void testConvertToDecimal(String input, int radix, int expected) {
14+
assertEquals(expected, AnyBaseToDecimal.convertToDecimal(input, radix));
15+
}
16+
17+
@Test
18+
void testIncorrectInput() {
19+
assertThrows(NumberFormatException.class, () -> AnyBaseToDecimal.convertToDecimal("G", 16));
20+
assertThrows(NumberFormatException.class, () -> AnyBaseToDecimal.convertToDecimal("XYZ", 10));
21+
}
22+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.thealgorithms.conversions;
2+
3+
import static java.util.Map.entry;
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
6+
import java.util.Map;
7+
import java.util.Set;
8+
import java.util.stream.Stream;
9+
import org.junit.jupiter.api.Test;
10+
import org.junit.jupiter.params.ParameterizedTest;
11+
import org.junit.jupiter.params.provider.Arguments;
12+
import org.junit.jupiter.params.provider.MethodSource;
13+
14+
public class UnitConversionsTest {
15+
private static void addData(Stream.Builder<Arguments> builder, Map<String, Double> values) {
16+
for (final var first : values.entrySet()) {
17+
for (final var second : values.entrySet()) {
18+
if (!first.getKey().equals(second.getKey())) {
19+
builder.add(Arguments.of(first.getKey(), second.getKey(), first.getValue(), second.getValue()));
20+
}
21+
}
22+
}
23+
}
24+
25+
private static Stream<Arguments> temperatureData() {
26+
final Map<String, Double> boilingPointOfWater = Map.ofEntries(entry("Celsius", 99.9839), entry("Fahrenheit", 211.97102), entry("Kelvin", 373.1339), entry("Réaumur", 79.98712), entry("Delisle", 0.02415), entry("Rankine", 671.64102));
27+
28+
final Map<String, Double> freezingPointOfWater = Map.ofEntries(entry("Celsius", 0.0), entry("Fahrenheit", 32.0), entry("Kelvin", 273.15), entry("Réaumur", 0.0), entry("Delisle", 150.0), entry("Rankine", 491.67));
29+
30+
Stream.Builder<Arguments> builder = Stream.builder();
31+
addData(builder, boilingPointOfWater);
32+
addData(builder, freezingPointOfWater);
33+
return builder.build();
34+
}
35+
36+
@ParameterizedTest
37+
@MethodSource("temperatureData")
38+
void testTemperature(String inputUnit, String outputUnit, double value, double expected) {
39+
final double result = UnitConversions.TEMPERATURE.convert(inputUnit, outputUnit, value);
40+
assertEquals(expected, result, 0.00001);
41+
}
42+
43+
@Test
44+
void testTemperatureUnits() {
45+
final Set<String> expectedUnits = Set.of("Celsius", "Fahrenheit", "Kelvin", "Réaumur", "Rankine", "Delisle");
46+
assertEquals(expectedUnits, UnitConversions.TEMPERATURE.availableUnits());
47+
}
48+
}

0 commit comments

Comments
 (0)