Exercism v3 launches on Sept 1st 2021. Learn more! ๐๐๐

# rootulp's solution

## to Largest Series Product in the Java Track

Published at Jul 13 2018 · 0 comments
Instructions
Test suite
Solution

#### Note:

This solution was written on an old version of Exercism. The tests below might not correspond to the solution code, and the exercise may have changed since this code was written.

Given a string of digits, calculate the largest product for a contiguous substring of digits of length n.

For example, for the input `'1027839564'`, the largest product for a series of 3 digits is 270 (9 * 5 * 6), and the largest product for a series of 5 digits is 7560 (7 * 8 * 3 * 9 * 5).

Note that these series are only required to occupy adjacent positions in the input; the digits need not be numerically consecutive.

For the input `'73167176531330624919225119674426574742355349194934'`, the largest product for a series of 6 digits is 23520.

# Running the tests

You can run all the tests for an exercise by entering

``````\$ gradle test
``````

## Source

A variation on Problem 8 at Project Euler http://projecteuler.net/problem=8

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### LargestSeriesProductCalculatorTest.java

``````import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.junit.Assert.assertEquals;

public class LargestSeriesProductCalculatorTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void testCorrectlyCalculatesLargestProductWhenSeriesLengthEqualsStringToSearchLength() {
LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("29");
long expectedProduct = 18;

long actualProduct = calculator.calculateLargestProductForSeriesLength(2);

assertEquals(expectedProduct, actualProduct);
}

@Ignore("Remove to run test")
@Test
public void testCorrectlyCalculatesLargestProductOfLengthTwoWithNumbersInOrder() {
LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("0123456789");
long expectedProduct = 72;

long actualProduct = calculator.calculateLargestProductForSeriesLength(2);

assertEquals(expectedProduct, actualProduct);
}

@Ignore("Remove to run test")
@Test
public void testCorrectlyCalculatesLargestProductOfLengthTwoWithNumbersNotInOrder() {
LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("576802143");
long expectedProduct = 48;

long actualProduct = calculator.calculateLargestProductForSeriesLength(2);

assertEquals(expectedProduct, actualProduct);
}

@Ignore("Remove to run test")
@Test
public void testCorrectlyCalculatesLargestProductOfLengthThreeWithNumbersInOrder() {
LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("0123456789");
long expectedProduct = 504;

long actualProduct = calculator.calculateLargestProductForSeriesLength(3);

assertEquals(expectedProduct, actualProduct);
}

@Ignore("Remove to run test")
@Test
public void testCorrectlyCalculatesLargestProductOfLengthThreeWithNumbersNotInOrder() {
LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("1027839564");
long expectedProduct = 270;

long actualProduct = calculator.calculateLargestProductForSeriesLength(3);

assertEquals(expectedProduct, actualProduct);
}

@Ignore("Remove to run test")
@Test
public void testCorrectlyCalculatesLargestProductOfLengthFiveWithNumbersInOrder() {
LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("0123456789");
long expectedProduct = 15120;

long actualProduct = calculator.calculateLargestProductForSeriesLength(5);

assertEquals(expectedProduct, actualProduct);
}

@Ignore("Remove to run test")
@Test
public void testCorrectlyCalculatesLargestProductInLongStringToSearchV1() {
LargestSeriesProductCalculator calculator
= new LargestSeriesProductCalculator("73167176531330624919225119674426574742355349194934");

long expectedProduct = 23520;

long actualProduct = calculator.calculateLargestProductForSeriesLength(6);

assertEquals(expectedProduct, actualProduct);
}

@Ignore("Remove to run test")
@Test
public void testCorrectlyCalculatesLargestProductOfZeroIfAllDigitsAreZeroes() {
LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("0000");
long expectedProduct = 0;

long actualProduct = calculator.calculateLargestProductForSeriesLength(2);

assertEquals(expectedProduct, actualProduct);
}

@Ignore("Remove to run test")
@Test
public void testCorrectlyCalculatesLargestProductOfZeroIfAllSeriesOfGivenLengthContainZero() {
LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("99099");
long expectedProduct = 0;

long actualProduct = calculator.calculateLargestProductForSeriesLength(3);

assertEquals(expectedProduct, actualProduct);
}

@Ignore("Remove to run test")
@Test
public void testSeriesLengthLongerThanLengthOfStringToTestIsRejected() {
LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("123");

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage(
"Series length must be less than or equal to the length of the string to search.");

calculator.calculateLargestProductForSeriesLength(4);
}

@Ignore("Remove to run test")
@Test
public void testCorrectlyCalculatesLargestProductOfLength0ForEmptyStringToSearch() {
LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("");
long expectedProduct = 1;

long actualProduct = calculator.calculateLargestProductForSeriesLength(0);

assertEquals(expectedProduct, actualProduct);
}

@Ignore("Remove to run test")
@Test
public void testCorrectlyCalculatesLargestProductOfLength0ForNonEmptyStringToSearch() {
LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("123");
long expectedProduct = 1;

long actualProduct = calculator.calculateLargestProductForSeriesLength(0);

assertEquals(expectedProduct, actualProduct);
}

@Ignore("Remove to run test")
@Test
public void testEmptyStringToSearchAndSeriesOfNonZeroLengthIsRejected() {
LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("");

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage(
"Series length must be less than or equal to the length of the string to search.");

calculator.calculateLargestProductForSeriesLength(1);
}

@Ignore("Remove to run test")
@Test
public void testStringToSearchContainingNonDigitCharacterIsRejected() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("String to search may only contain digits.");

new LargestSeriesProductCalculator("1234a5");
}

@Ignore("Remove to run test")
@Test
public void testNegativeSeriesLengthIsRejected() {
LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("12345");

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Series length must be non-negative.");

calculator.calculateLargestProductForSeriesLength(-1);
}

}``````
``````import java.util.Arrays;
import java.util.stream.IntStream;

public class LargestSeriesProductCalculator {

private long[] digits;

public LargestSeriesProductCalculator(String series) {
throwExceptionIfInvalidSeries(series);
this.digits = parseDigits(series);
}

public long calculateLargestProductForSeriesLength(int seriesLength) {
throwExceptionIfInvalidSeriesLength(seriesLength);
return calculateLargestProduct(seriesLength);
}

private long calculateLargestProduct(int seriesLength) {
long largestProduct = Long.MIN_VALUE;
for (int i = 0; i <= digits.length - seriesLength; i++) {
long product = calculateProductForSubseries(seriesLength, i);
if (product > largestProduct) {
largestProduct = product;
}
}
return largestProduct;
}

private long calculateProductForSubseries(int seriesLength, int startingIndex) {
long[] series = Arrays.copyOfRange(digits, startingIndex, startingIndex + seriesLength);
return productOfSeries(series);
}

private static long productOfSeries (long[] series) {
return Arrays.stream(series).reduce(1, (a, b) -> a * b);
}

private long[] parseDigits(String series) {
// This is for https://github.com/exercism/problem-specifications/blob/master/exercises/largest-series-product/canonical-data.json#L89
if (series != "") {
return Arrays.stream(series.split("")).mapToLong(Long::parseLong).toArray();
}
return new long[]{};
}

private void throwExceptionIfInvalidSeries(String series) {
if (series == null) {
throw new IllegalArgumentException("String to search must be non-null.");
}
if (seriesContainsNonDigitCharacters(series)) {
throw new IllegalArgumentException("String to search may only contains digits.");
}
}

private boolean seriesContainsNonDigitCharacters(String series) {
return !series.matches("\\d*");
}

private void throwExceptionIfInvalidSeriesLength(int seriesLength) {
if (seriesLength > digits.length) {
throw new IllegalArgumentException("Series length must be less than or equal to the length of the string to search.");
}
if (seriesLength < 0) {
throw new IllegalArgumentException("Series length must be non-negative.");
}
}
}``````