Exercism v3 launches on Sept 1st 2021. Learn more! ๐Ÿš€๐Ÿš€๐Ÿš€
Avatar of rootulp

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

in your terminal.

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.");
    }
  }
}

Community comments

Find this solution interesting? Ask the author a question to learn more.

What can you learn from this solution?

A huge amount can be learned from reading other peopleโ€™s code. This is why we wanted to give exercism users the option of making their solutions public.

Here are some questions to help you reflect on this solution and learn the most from it.

  • What compromises have been made?
  • Are there new concepts here that you could read more about to improve your understanding?