Skip to content

Commit ececfdd

Browse files
committed
largest-series-product: add to track
1 parent 91a65d7 commit ececfdd

File tree

6 files changed

+300
-1
lines changed

6 files changed

+300
-1
lines changed

config.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@
4343
"nth-prime",
4444
"pascals-triangle",
4545
"beer-song",
46-
"difference-of-squares"
46+
"difference-of-squares",
47+
"largest-series-product"
4748
],
4849
"exercises": [
4950
{
@@ -245,6 +246,11 @@
245246
"slug": "difference-of-squares",
246247
"difficulty": 1,
247248
"topics": []
249+
},
250+
{
251+
"slug": "largest-series-product",
252+
"difficulty": 1,
253+
"topics": []
248254
}
249255
],
250256
"deprecated": [
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
apply plugin: "java"
2+
apply plugin: "eclipse"
3+
apply plugin: "idea"
4+
5+
repositories {
6+
mavenCentral()
7+
}
8+
9+
dependencies {
10+
testCompile "junit:junit:4.12"
11+
}
12+
test {
13+
testLogging {
14+
exceptionFormat = 'full'
15+
events = ["passed", "failed", "skipped"]
16+
}
17+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
public final class LargestSeriesProductCalculator {
2+
3+
private final String stringToSearch;
4+
5+
public LargestSeriesProductCalculator(final String stringToSearch) throws IllegalArgumentException {
6+
this.stringToSearch = stringToSearch;
7+
validateStringToSearch();
8+
}
9+
10+
public long calculateLargestProductForSeriesLength(final int seriesLength) throws IllegalArgumentException {
11+
if (seriesLength < 0) {
12+
throw new IllegalArgumentException("Series length must be non-negative.");
13+
} else if (seriesLength == 0) {
14+
return 1;
15+
} else if (seriesLength > stringToSearch.length()) {
16+
throw new IllegalArgumentException(
17+
"Series length must be less than or equal to the length of the string to search.");
18+
} else {
19+
long result = 0;
20+
21+
int numberOfSeriesToCheck = stringToSearch.length() - seriesLength + 1;
22+
23+
for (int startIndex = 0; startIndex < numberOfSeriesToCheck; startIndex++) {
24+
/*
25+
* Note: computing the product of each series fresh each time is not the most efficient solution, but
26+
* it's the simplest to reason about.
27+
*/
28+
result = Math.max(result, computeProductOfSeries(startIndex, seriesLength));
29+
}
30+
31+
return result;
32+
}
33+
}
34+
35+
private void validateStringToSearch() throws IllegalArgumentException {
36+
if (stringToSearch == null) {
37+
throw new IllegalArgumentException("String to search must be non-null.");
38+
} else if (!stringToSearch.chars().allMatch(Character::isDigit)) {
39+
throw new IllegalArgumentException("String to search may only contains digits.");
40+
}
41+
}
42+
43+
private long computeProductOfSeries(final int startIndex, final int seriesLength) {
44+
// The multiplicative identity is 1.
45+
long result = 1;
46+
47+
final int endIndex = startIndex + seriesLength - 1;
48+
49+
for (int characterIndex = startIndex; characterIndex <= endIndex; characterIndex++) {
50+
result = result * Character.getNumericValue(stringToSearch.charAt(characterIndex));
51+
}
52+
53+
return result;
54+
}
55+
56+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public class LargestSeriesProductCalculator {
2+
3+
4+
5+
}
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
import org.junit.Ignore;
2+
import org.junit.Rule;
3+
import org.junit.Test;
4+
import org.junit.rules.ExpectedException;
5+
6+
import static org.junit.Assert.assertEquals;
7+
8+
public final class LargestSeriesProductCalculatorTest {
9+
10+
@Rule
11+
public ExpectedException expectedException = ExpectedException.none();
12+
13+
@Test
14+
public void testCorrectlyCalculatesLargestProductOfLengthTwoWithNumbersInOrder() {
15+
final LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("0123456789");
16+
final long expectedProduct = 72;
17+
18+
final long actualProduct = calculator.calculateLargestProductForSeriesLength(2);
19+
20+
assertEquals(expectedProduct, actualProduct);
21+
}
22+
23+
@Ignore
24+
@Test
25+
public void testCorrectlyCalculatesLargestProductOfLengthTwoWithNumbersNotInOrder() {
26+
final LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("576802143");
27+
final long expectedProduct = 48;
28+
29+
final long actualProduct = calculator.calculateLargestProductForSeriesLength(2);
30+
31+
assertEquals(expectedProduct, actualProduct);
32+
}
33+
34+
@Ignore
35+
@Test
36+
public void testCorrectlyCalculatesLargestProductWhenSeriesLengthEqualsStringToSearchLength() {
37+
final LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("29");
38+
final long expectedProduct = 18;
39+
40+
final long actualProduct = calculator.calculateLargestProductForSeriesLength(2);
41+
42+
assertEquals(expectedProduct, actualProduct);
43+
}
44+
45+
@Ignore
46+
@Test
47+
public void testCorrectlyCalculatesLargestProductOfLengthThreeWithNumbersInOrder() {
48+
final LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("0123456789");
49+
final long expectedProduct = 504;
50+
51+
final long actualProduct = calculator.calculateLargestProductForSeriesLength(3);
52+
53+
assertEquals(expectedProduct, actualProduct);
54+
}
55+
56+
@Ignore
57+
@Test
58+
public void testCorrectlyCalculatesLargestProductOfLengthThreeWithNumbersNotInOrder() {
59+
final LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("1027839564");
60+
final long expectedProduct = 270;
61+
62+
final long actualProduct = calculator.calculateLargestProductForSeriesLength(3);
63+
64+
assertEquals(expectedProduct, actualProduct);
65+
}
66+
67+
@Ignore
68+
@Test
69+
public void testCorrectlyCalculatesLargestProductOfLengthFiveWithNumbersInOrder() {
70+
final LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("0123456789");
71+
final long expectedProduct = 15120;
72+
73+
final long actualProduct = calculator.calculateLargestProductForSeriesLength(5);
74+
75+
assertEquals(expectedProduct, actualProduct);
76+
}
77+
78+
@Ignore
79+
@Test
80+
public void testCorrectlyCalculatesLargestProductInLongStringToSearchV1() {
81+
final LargestSeriesProductCalculator calculator
82+
= new LargestSeriesProductCalculator("73167176531330624919225119674426574742355349194934");
83+
84+
final long expectedProduct = 23520;
85+
86+
final long actualProduct = calculator.calculateLargestProductForSeriesLength(6);
87+
88+
assertEquals(expectedProduct, actualProduct);
89+
}
90+
91+
@Ignore
92+
@Test
93+
public void testCorrectlyCalculatesLargestProductInLongStringToSearchV2() {
94+
final LargestSeriesProductCalculator calculator
95+
= new LargestSeriesProductCalculator("52677741234314237566414902593461595376319419139427");
96+
97+
final long expectedProduct = 28350;
98+
99+
final long actualProduct = calculator.calculateLargestProductForSeriesLength(6);
100+
101+
assertEquals(expectedProduct, actualProduct);
102+
}
103+
104+
@Ignore
105+
@Test
106+
public void testCorrectlyCalculatesLargestProductInLongStringToSearchFromProjectEuler() {
107+
final LargestSeriesProductCalculator calculator
108+
= new LargestSeriesProductCalculator("7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450");
109+
110+
final long expectedProduct = 23514624000L;
111+
112+
final long actualProduct = calculator.calculateLargestProductForSeriesLength(13);
113+
114+
assertEquals(expectedProduct, actualProduct);
115+
}
116+
117+
@Ignore
118+
@Test
119+
public void testCorrectlyCalculatesLargestProductOfZeroIfAllDigitsAreZeroes() {
120+
final LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("0000");
121+
final long expectedProduct = 0;
122+
123+
final long actualProduct = calculator.calculateLargestProductForSeriesLength(2);
124+
125+
assertEquals(expectedProduct, actualProduct);
126+
}
127+
128+
@Ignore
129+
@Test
130+
public void testCorrectlyCalculatesLargestProductOfZeroIfAllSeriesOfGivenLengthContainZero() {
131+
final LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("99099");
132+
final long expectedProduct = 0;
133+
134+
final long actualProduct = calculator.calculateLargestProductForSeriesLength(3);
135+
136+
assertEquals(expectedProduct, actualProduct);
137+
}
138+
139+
@Ignore
140+
@Test
141+
public void testSeriesLengthLongerThanLengthOfStringToTestIsRejected() {
142+
final LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("123");
143+
144+
expectedException.expect(IllegalArgumentException.class);
145+
expectedException.expectMessage(
146+
"Series length must be less than or equal to the length of the string to search.");
147+
148+
calculator.calculateLargestProductForSeriesLength(4);
149+
}
150+
151+
@Ignore
152+
@Test
153+
public void testCorrectlyCalculatesLargestProductOfLength0ForEmptyStringToSearch() {
154+
final LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("");
155+
final long expectedProduct = 1;
156+
157+
final long actualProduct = calculator.calculateLargestProductForSeriesLength(0);
158+
159+
assertEquals(expectedProduct, actualProduct);
160+
}
161+
162+
@Ignore
163+
@Test
164+
public void testCorrectlyCalculatesLargestProductOfLength0ForNonEmptyStringToSearch() {
165+
final LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("123");
166+
final long expectedProduct = 1;
167+
168+
final long actualProduct = calculator.calculateLargestProductForSeriesLength(0);
169+
170+
assertEquals(expectedProduct, actualProduct);
171+
}
172+
173+
@Ignore
174+
@Test
175+
public void testEmptyStringToSearchAndSeriesOfNonZeroLengthIsRejected() {
176+
final LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("");
177+
178+
expectedException.expect(IllegalArgumentException.class);
179+
expectedException.expectMessage(
180+
"Series length must be less than or equal to the length of the string to search.");
181+
182+
calculator.calculateLargestProductForSeriesLength(1);
183+
}
184+
185+
@Ignore
186+
@Test
187+
public void testStringToSearchContainingNonDigitCharacterIsRejected() {
188+
expectedException.expect(IllegalArgumentException.class);
189+
expectedException.expectMessage("String to search may only contains digits.");
190+
191+
new LargestSeriesProductCalculator("1234a5");
192+
}
193+
194+
@Ignore
195+
@Test
196+
public void testNegativeSeriesLengthIsRejected() {
197+
final LargestSeriesProductCalculator calculator = new LargestSeriesProductCalculator("12345");
198+
199+
expectedException.expect(IllegalArgumentException.class);
200+
expectedException.expectMessage("Series length must be non-negative.");
201+
202+
calculator.calculateLargestProductForSeriesLength(-1);
203+
}
204+
205+
@Ignore
206+
@Test
207+
public void testNullStringToSearchIsRejected() {
208+
expectedException.expect(IllegalArgumentException.class);
209+
expectedException.expectMessage("String to search must be non-null.");
210+
211+
new LargestSeriesProductCalculator(null);
212+
}
213+
214+
}

exercises/settings.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ include 'grade-school'
1414
include 'hamming'
1515
include 'hexadecimal'
1616
include 'hello-world'
17+
include 'largest-series-product'
1718
include 'linked-list'
1819
include 'luhn'
1920
include 'meetup'

0 commit comments

Comments
 (0)