public final class LargestSeriesProductCalculator {
private final String stringToSearch;
public LargestSeriesProductCalculator(final String stringToSearch) throws IllegalArgumentException {
this.stringToSearch = stringToSearch;
validateStringToSearch();
}
public long calculateLargestProductForSeriesLength(final int seriesLength) throws IllegalArgumentException {
if (seriesLength < 0) {
throw new IllegalArgumentException("Series length must be non-negative.");
} else if (seriesLength == 0) {
return 1;
} else if (seriesLength > stringToSearch.length()) {
throw new IllegalArgumentException(
"Series length must be less than or equal to the length of the string to search.");
} else {
long result = 0;
int numberOfSeriesToCheck = stringToSearch.length() - seriesLength + 1;
for (int startIndex = 0; startIndex < numberOfSeriesToCheck; startIndex++) {
/*
* Note: computing the product of each series fresh each time is not the most efficient solution, but
* it's the simplest to reason about.
*/
result = Math.max(result, computeProductOfSeries(startIndex, seriesLength));
}
return result;
}
}
private void validateStringToSearch() throws IllegalArgumentException {
if (stringToSearch == null) {
throw new IllegalArgumentException("String to search must be non-null.");
} else if (!stringToSearch.chars().allMatch(Character::isDigit)) {
throw new IllegalArgumentException("String to search may only contains digits.");
}
}
private long computeProductOfSeries(final int startIndex, final int seriesLength) {
// The multiplicative identity is 1.
long result = 1;
final int endIndex = startIndex + seriesLength - 1;
for (int characterIndex = startIndex; characterIndex <= endIndex; characterIndex++) {
result = result * Character.getNumericValue(stringToSearch.charAt(characterIndex));
}
return result;
}
}