Skip to content

Commit 911061d

Browse files
committed
1. shortestCoprimeSegment now returns not the length, but the shortest segment itself.
2. Testcases have been adapted, a few new ones added.
1 parent 151fb27 commit 911061d

File tree

2 files changed

+68
-31
lines changed

2 files changed

+68
-31
lines changed

src/main/java/com/thealgorithms/slidingwindow/ShortestCoprimeSegment.java

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package com.thealgorithms.slidingwindow;
22

3+
import java.util.Arrays;
34
import java.util.LinkedList;
45

56
/**
6-
* The Sliding Window technique together with 2-stack technique is used to find the minimal size of coprime segment in an array.
7+
* The Sliding Window technique together with 2-stack technique is used to find coprime segment of minimal size in an array.
78
* Segment a[i],...,a[i+l] is coprime if gcd(a[i], a[i+1], ..., a[i+l]) = 1
89
* <p>
910
* Run-time complexity: O(n log n)
@@ -12,12 +13,12 @@
1213
* Main observation is that each element gets processed a constant amount of times, hence complexity will be:
1314
* O(n log n), where log n comes from complexity of gcd.
1415
* <p>
15-
* The 2-stack technique enables us to 'remove' an element fast if it is known how to 'add' an element fast to the set.
16+
* More generally, the 2-stack technique enables us to 'remove' an element fast if it is known how to 'add' an element fast to the set.
1617
* In our case 'adding' is calculating d' = gcd(a[i],...,a[i+l+1]), when d = gcd(a[i],...a[i]) with d' = gcd(d, a[i+l+1]).
1718
* and removing is find gcd(a[i+1],...,a[i+l]). We don't calculate it explicitly, but it is pushed in the stack which we can pop in O(1).
1819
* <p>
1920
* One can change methods 'legalSegment' and function 'f' in DoubleStack to adapt this code to other sliding-window type problems.
20-
* I recommend this article for more explanations: <a href="https://codeforces.com/edu/course/2/lesson/9/2">Article 1</a> or https://usaco.guide/gold/sliding-window?lang=cpp#method-2---two-stacks
21+
* I recommend this article for more explanations: "<a href="https://codeforces.com/edu/course/2/lesson/9/2">CF Article</a>">Article 1</a> or <a href="https://usaco.guide/gold/sliding-window?lang=cpp#method-2---two-stacks">USACO Article</a>
2122
* <p>
2223
* Another method to solve this problem is through segment trees. Then query operation would have O(log n), not O(1) time, but runtime complexity would still be O(n log n)
2324
*
@@ -30,26 +31,36 @@ private ShortestCoprimeSegment() {
3031

3132
/**
3233
* @param arr is the input array
33-
* @param n is the array size
34-
* @return the length of the smallest segment in the array which has gcd equal to 1. If no such segment exists, returns -1
34+
* @return shortest segment in the array which has gcd equal to 1. If no such segment exists or array is empty, returns empty array
3535
*/
36-
public static int shortestCoprimeSegment(int n, long[] arr) {
36+
public static long[] shortestCoprimeSegment(long[] arr) {
37+
if (arr == null || arr.length == 0) {
38+
return new long[] {};
39+
}
3740
DoubleStack front = new DoubleStack();
3841
DoubleStack back = new DoubleStack();
42+
int n = arr.length;
3943
int l = 0;
40-
int best = n + 1;
44+
int shortestLength = n + 1;
45+
int beginsAt = -1; // beginning index of the shortest coprime segment
4146
for (int i = 0; i < n; i++) {
4247
back.push(arr[i]);
4348
while (legalSegment(front, back)) {
4449
remove(front, back);
45-
best = Math.min(best, i - l + 1);
50+
if (shortestLength > i - l + 1) {
51+
beginsAt = l;
52+
shortestLength = i - l + 1;
53+
}
4654
l++;
4755
}
4856
}
49-
if (best > n) {
50-
best = -1;
57+
if (shortestLength > n) {
58+
shortestLength = -1;
59+
}
60+
if (shortestLength == -1) {
61+
return new long[] {};
5162
}
52-
return best;
63+
return Arrays.copyOfRange(arr, beginsAt, beginsAt + shortestLength);
5364
}
5465

5566
private static boolean legalSegment(DoubleStack front, DoubleStack back) {
@@ -94,7 +105,7 @@ private static class DoubleStack {
94105
DoubleStack() {
95106
values = new LinkedList<>();
96107
stack = new LinkedList<>();
97-
values.add((long) 0); // Initialise with 0 which is neutral element in terms of gcd, i.e. gcd(a,0) = a
108+
values.add(0L); // Initialise with 0 which is neutral element in terms of gcd, i.e. gcd(a,0) = a
98109
}
99110

100111
long f(long a, long b) { // Can be replaced with other function
Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.thealgorithms.slidingwindow;
22

3-
import static org.junit.jupiter.api.Assertions.assertEquals;
4-
3+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4+
import java.util.Arrays;
55
import org.junit.jupiter.api.Test;
66

77
/**
@@ -12,27 +12,53 @@
1212
public class ShortestCoprimeSegmentTest {
1313
@Test
1414
public void testShortestCoprimeSegment() {
15-
assertEquals(3, ShortestCoprimeSegment.shortestCoprimeSegment(5, new long[] {4, 6, 9, 3, 6}));
16-
assertEquals(2, ShortestCoprimeSegment.shortestCoprimeSegment(5, new long[] {4, 5, 9, 3, 6}));
17-
assertEquals(2, ShortestCoprimeSegment.shortestCoprimeSegment(2, new long[] {3, 2}));
18-
assertEquals(2, ShortestCoprimeSegment.shortestCoprimeSegment(5, new long[] {3, 9, 9, 9, 10}));
19-
assertEquals(4, ShortestCoprimeSegment.shortestCoprimeSegment(4, new long[] {3 * 7, 7 * 5, 5 * 7 * 3, 3 * 5}));
20-
assertEquals(4, ShortestCoprimeSegment.shortestCoprimeSegment(4, new long[] {3 * 11, 11 * 7, 11 * 7 * 3, 3 * 7}));
21-
assertEquals(5, ShortestCoprimeSegment.shortestCoprimeSegment(5, new long[] {3 * 11, 11 * 7, 11 * 7 * 3, 11 * 7 * 3 * 5, 5 * 7}));
22-
assertEquals(6, ShortestCoprimeSegment.shortestCoprimeSegment(6, new long[] {3 * 11, 11 * 7, 11 * 7 * 3, 11 * 7 * 3 * 5, 11 * 7 * 3 * 5 * 13, 7 * 13}));
23-
assertEquals(6, ShortestCoprimeSegment.shortestCoprimeSegment(7, new long[] {3 * 11, 11 * 7, 11 * 7 * 3, 11 * 7 * 3 * 5, 11 * 7 * 3 * 5 * 13, 7 * 13, 11 * 7 * 3 * 5 * 13}));
24-
assertEquals(10, ShortestCoprimeSegment.shortestCoprimeSegment(10, new long[] {3 * 11, 7 * 11, 3 * 7 * 11, 3 * 5 * 7 * 11, 3 * 5 * 7 * 11 * 13, 2 * 3 * 5 * 7 * 11 * 13, 2 * 3 * 5 * 7 * 11 * 13 * 17, 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19, 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23, 7 * 13}));
15+
assertArrayEquals(new long[] {4, 6, 9}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {4, 6, 9, 3, 6}));
16+
assertArrayEquals(new long[] {4, 5}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {4, 5, 9, 3, 6}));
17+
assertArrayEquals(new long[] {3, 2}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {3, 2}));
18+
assertArrayEquals(new long[] {9, 10}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {3, 9, 9, 9, 10}));
19+
20+
long[] test5 = new long[] {3 * 11, 11 * 7, 11 * 7 * 3, 11 * 7 * 3 * 5, 11 * 7 * 3 * 5 * 13, 7 * 13, 11 * 7 * 3 * 5 * 13};
21+
long[] answer5 = Arrays.copyOfRange(test5, 0, test5.length - 1);
22+
assertArrayEquals(answer5, ShortestCoprimeSegment.shortestCoprimeSegment(test5));
23+
24+
// Test suite, when the entire array needs to be taken
25+
long[] test6 = new long[] {3 * 7, 7 * 5, 5 * 7 * 3, 3 * 5};
26+
assertArrayEquals(test6, ShortestCoprimeSegment.shortestCoprimeSegment(test6));
27+
28+
long[] test7 = new long[] {3 * 11, 11 * 7, 11 * 7 * 3, 3 * 7};
29+
assertArrayEquals(test7, ShortestCoprimeSegment.shortestCoprimeSegment(test7));
30+
31+
long[] test8 = new long[] {3 * 11, 11 * 7, 11 * 7 * 3, 11 * 7 * 3 * 5, 5 * 7};
32+
assertArrayEquals(test8, ShortestCoprimeSegment.shortestCoprimeSegment(test8));
33+
34+
long[] test9 = new long[] {3 * 11, 11 * 7, 11 * 7 * 3, 11 * 7 * 3 * 5, 11 * 7 * 3 * 5 * 13, 7 * 13};
35+
assertArrayEquals(test9, ShortestCoprimeSegment.shortestCoprimeSegment(test9));
36+
37+
long[] test10 = new long[] {3 * 11, 7 * 11, 3 * 7 * 11, 3 * 5 * 7 * 11, 3 * 5 * 7 * 11 * 13, 2 * 3 * 5 * 7 * 11 * 13, 2 * 3 * 5 * 7 * 11 * 13 * 17, 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19, 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23, 7 * 13};
38+
assertArrayEquals(test10, ShortestCoprimeSegment.shortestCoprimeSegment(test10));
39+
2540
// Segment can consist of one element
26-
assertEquals(1, ShortestCoprimeSegment.shortestCoprimeSegment(5, new long[] {4, 6, 1, 3, 6}));
27-
assertEquals(1, ShortestCoprimeSegment.shortestCoprimeSegment(1, new long[] {1}));
41+
long[] test11 = new long[] {1};
42+
assertArrayEquals(test11, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {4, 6, 1, 3, 6}));
43+
long[] test12 = new long[] {1};
44+
assertArrayEquals(test12, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {1}));
45+
}
46+
@Test
47+
public void testShortestCoprimeSegment2() {
48+
assertArrayEquals(new long[] {2 * 3, 2 * 3 * 5, 2 * 3 * 5 * 7, 5 * 7}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {2 * 3, 2 * 3 * 5, 2 * 3 * 5 * 7, 5 * 7, 2 * 3 * 5 * 7}));
49+
assertArrayEquals(new long[] {5 * 7, 2}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {2 * 3, 2 * 3 * 5, 2 * 3 * 5 * 7, 5 * 7, 2}));
50+
assertArrayEquals(new long[] {5 * 7, 2 * 5 * 7, 2 * 11}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {2 * 3, 2 * 3 * 5, 2 * 3 * 5 * 7, 5 * 7, 2 * 5 * 7, 2 * 11}));
51+
assertArrayEquals(new long[] {3 * 5 * 7, 2 * 3, 2}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {2, 2 * 3, 2 * 3 * 5, 3 * 5 * 7, 2 * 3, 2}));
2852
}
29-
3053
@Test
3154
public void testNoCoprimeSegment() {
3255
// There may not be a coprime segment
33-
assertEquals(-1, ShortestCoprimeSegment.shortestCoprimeSegment(5, new long[] {4, 6, 8, 12, 8}));
34-
assertEquals(-1, ShortestCoprimeSegment.shortestCoprimeSegment(10, new long[] {4, 4, 4, 4, 10, 4, 6, 8, 12, 8}));
35-
assertEquals(-1, ShortestCoprimeSegment.shortestCoprimeSegment(1, new long[] {100}));
36-
assertEquals(-1, ShortestCoprimeSegment.shortestCoprimeSegment(3, new long[] {2, 2, 2}));
56+
long[] empty = new long[] {};
57+
assertArrayEquals(empty, ShortestCoprimeSegment.shortestCoprimeSegment(null));
58+
assertArrayEquals(empty, ShortestCoprimeSegment.shortestCoprimeSegment(empty));
59+
assertArrayEquals(empty, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {4, 6, 8, 12, 8}));
60+
assertArrayEquals(empty, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {4, 4, 4, 4, 10, 4, 6, 8, 12, 8}));
61+
assertArrayEquals(empty, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {100}));
62+
assertArrayEquals(empty, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {2, 2, 2}));
3763
}
3864
}

0 commit comments

Comments
 (0)