Skip to content

Commit c66e342

Browse files
authored
Merge branch 'TheAlgorithms:master' into feat/add-tarjan-bridges
2 parents 8193e47 + cc75b5e commit c66e342

File tree

10 files changed

+325
-28
lines changed

10 files changed

+325
-28
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ jobs:
2020
if: >-
2121
github.event_name == 'pull_request' &&
2222
github.event.pull_request.head.repo.full_name != github.repository
23-
uses: codecov/codecov-action@v5
23+
uses: codecov/codecov-action@v6
2424
with:
2525
fail_ci_if_error: true
2626
- name: Upload coverage to codecov (with token)
2727
if: >
2828
github.repository == 'TheAlgorithms/Java' &&
2929
(github.event_name != 'pull_request' ||
3030
github.event.pull_request.head.repo.full_name == github.repository)
31-
uses: codecov/codecov-action@v5
31+
uses: codecov/codecov-action@v6
3232
with:
3333
token: ${{ secrets.CODECOV_TOKEN }}
3434
fail_ci_if_error: true

src/main/java/com/thealgorithms/maths/Volume.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,16 @@ public static double volumeFrustumOfPyramid(double upperBaseArea, double lowerBa
125125
public static double volumeTorus(double majorRadius, double minorRadius) {
126126
return 2 * Math.PI * Math.PI * majorRadius * minorRadius * minorRadius;
127127
}
128+
129+
/**
130+
* Calculate the volume of an ellipsoid.
131+
*
132+
* @param a first semi-axis of an ellipsoid
133+
* @param b second semi-axis of an ellipsoid
134+
* @param c third semi-axis of an ellipsoid
135+
* @return volume of the ellipsoid
136+
*/
137+
public static double volumeEllipsoid(double a, double b, double c) {
138+
return (4 * Math.PI * a * b * c) / 3;
139+
}
128140
}

src/main/java/com/thealgorithms/searches/InterpolationSearch.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
/**
2+
* Interpolation Search estimates the position of the target value
3+
* based on the distribution of values.
4+
*
5+
* Example:
6+
* Input: [10, 20, 30, 40], target = 30
7+
* Output: Index = 2
8+
*
9+
* Time Complexity: O(log log n) (average case)
10+
* Space Complexity: O(1)
11+
*/
112
package com.thealgorithms.searches;
213

314
/**

src/main/java/com/thealgorithms/searches/IterativeBinarySearch.java

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,50 +3,53 @@
33
import com.thealgorithms.devutils.searches.SearchAlgorithm;
44

55
/**
6-
* Binary search is one of the most popular algorithms This class represents
7-
* iterative version {@link BinarySearch} Iterative binary search is likely to
8-
* have lower constant factors because it doesn't involve the overhead of
9-
* manipulating the call stack. But in java the recursive version can be
10-
* optimized by the compiler to this version.
6+
* Binary search is one of the most popular algorithms.
7+
* This class represents the iterative version of {@link BinarySearch}.
118
*
12-
* <p>
13-
* Worst-case performance O(log n) Best-case performance O(1) Average
14-
* performance O(log n) Worst-case space complexity O(1)
9+
* <p>Iterative binary search avoids recursion overhead and uses constant space.
1510
*
16-
* @author Gabriele La Greca : https://github.com/thegabriele97
17-
* @author Podshivalov Nikita (https://github.com/nikitap492)
11+
* <p>Performance:
12+
* <ul>
13+
* <li>Best-case: O(1)</li>
14+
* <li>Average-case: O(log n)</li>
15+
* <li>Worst-case: O(log n)</li>
16+
* <li>Space complexity: O(1)</li>
17+
* </ul>
18+
*
19+
* @author Gabriele La Greca
20+
* @author Podshivalov Nikita
1821
* @see SearchAlgorithm
1922
* @see BinarySearch
2023
*/
2124
public final class IterativeBinarySearch implements SearchAlgorithm {
2225

2326
/**
24-
* This method implements an iterative version of binary search algorithm
27+
* Performs iterative binary search on a sorted array.
2528
*
26-
* @param array a sorted array
27-
* @param key the key to search in array
28-
* @return the index of key in the array or -1 if not found
29+
* @param array the sorted array
30+
* @param key the element to search
31+
* @param <T> type of elements (must be Comparable)
32+
* @return index of the key if found, otherwise -1
2933
*/
3034
@Override
3135
public <T extends Comparable<T>> int find(T[] array, T key) {
32-
int l;
33-
int r;
34-
int k;
35-
int cmp;
36+
if (array == null || array.length == 0) {
37+
return -1;
38+
}
3639

37-
l = 0;
38-
r = array.length - 1;
40+
int left = 0;
41+
int right = array.length - 1;
3942

40-
while (l <= r) {
41-
k = (l + r) >>> 1;
42-
cmp = key.compareTo(array[k]);
43+
while (left <= right) {
44+
int mid = (left + right) >>> 1;
45+
int cmp = key.compareTo(array[mid]);
4346

4447
if (cmp == 0) {
45-
return k;
48+
return mid;
4649
} else if (cmp < 0) {
47-
r = --k;
50+
right = mid - 1;
4851
} else {
49-
l = ++k;
52+
left = mid + 1;
5053
}
5154
}
5255

src/main/java/com/thealgorithms/searches/LinearSearch.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/**
2+
* Performs Linear Search on an array.
3+
*
4+
* Linear search checks each element one by one until the target is found
5+
* or the array ends.
6+
*
7+
* Example:
8+
* Input: [2, 4, 6, 8], target = 6
9+
* Output: Index = 2
10+
*
11+
* Time Complexity: O(n)
12+
* Space Complexity: O(1)
13+
*/
114
package com.thealgorithms.searches;
215

316
import com.thealgorithms.devutils.searches.SearchAlgorithm;
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.thealgorithms.stacks;
2+
3+
import java.util.Stack;
4+
5+
/**
6+
* Calculates the stock span for each day in a series of stock prices.
7+
*
8+
* <p>The span of a price on a given day is the number of consecutive days ending on that day
9+
* for which the price was less than or equal to the current day's price.
10+
*
11+
* <p>Idea: keep a stack of indices whose prices are strictly greater than the current price.
12+
* While processing each day, pop smaller or equal prices because they are part of the current
13+
* span. After popping, the nearest greater price left on the stack tells us where the span stops.
14+
*
15+
* <p>Time complexity is O(n) because each index is pushed onto the stack once and popped at most
16+
* once, so the total number of stack operations grows linearly with the number of prices. This
17+
* makes the stack approach efficient because it avoids rechecking earlier days repeatedly, unlike
18+
* a naive nested-loop solution that can take O(n^2) time.
19+
*
20+
* <p>Example: for prices [100, 80, 60, 70, 60, 75, 85], the spans are
21+
* [1, 1, 1, 2, 1, 4, 6].
22+
*/
23+
public final class StockSpanProblem {
24+
private StockSpanProblem() {
25+
}
26+
27+
/**
28+
* Calculates the stock span for each price in the input array.
29+
*
30+
* @param prices the stock prices
31+
* @return the span for each day
32+
* @throws IllegalArgumentException if the input array is null
33+
*/
34+
public static int[] calculateSpan(int[] prices) {
35+
if (prices == null) {
36+
throw new IllegalArgumentException("Input prices cannot be null");
37+
}
38+
39+
int[] spans = new int[prices.length];
40+
Stack<Integer> stack = new Stack<>();
41+
42+
// Small example:
43+
// prices = [100, 80, 60, 70]
44+
// spans = [ 1, 1, 1, 2]
45+
// When we process 70, we pop 60 because 60 <= 70, so the span becomes 2.
46+
//
47+
// The stack stores indices of days with prices greater than the current day's price.
48+
for (int index = 0; index < prices.length; index++) {
49+
// Remove all previous days whose prices are less than or equal to the current price.
50+
while (!stack.isEmpty() && prices[stack.peek()] <= prices[index]) {
51+
stack.pop();
52+
}
53+
54+
// If the stack is empty, there is no earlier day with a greater price,
55+
// so the count will be from day 0 to this day (index + 1).
56+
//
57+
// Otherwise, the span is the number of days between
58+
// the nearest earlier day with a greater price and the current day.
59+
spans[index] = stack.isEmpty() ? index + 1 : index - stack.peek();
60+
61+
// Store the current index as a candidate for future span calculations.
62+
stack.push(index);
63+
}
64+
65+
return spans;
66+
}
67+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package com.thealgorithms.strings;
2+
3+
/**
4+
* Kasai's Algorithm for constructing the Longest Common Prefix (LCP) array.
5+
*
6+
* <p>
7+
* The LCP array stores the lengths of the longest common prefixes between
8+
* lexicographically adjacent suffixes of a string. Kasai's algorithm computes
9+
* this array in O(N) time given the string and its suffix array.
10+
* </p>
11+
*
12+
* @see <a href="https://en.wikipedia.org/wiki/LCP_array">LCP array - Wikipedia</a>
13+
*/
14+
public final class KasaiAlgorithm {
15+
16+
private KasaiAlgorithm() {
17+
}
18+
19+
/**
20+
* Computes the LCP array using Kasai's algorithm.
21+
*
22+
* @param text the original string
23+
* @param suffixArr the suffix array of the string
24+
* @return the LCP array of length N, where LCP[i] is the length of the longest
25+
* common prefix of the suffixes indexed by suffixArr[i] and suffixArr[i+1].
26+
* The last element LCP[N-1] is always 0.
27+
* @throws IllegalArgumentException if text or suffixArr is null, or their lengths differ
28+
*/
29+
public static int[] kasai(String text, int[] suffixArr) {
30+
if (text == null || suffixArr == null) {
31+
throw new IllegalArgumentException("Text and suffix array must not be null.");
32+
}
33+
int n = text.length();
34+
if (suffixArr.length != n) {
35+
throw new IllegalArgumentException("Suffix array length must match text length.");
36+
}
37+
if (n == 0) {
38+
return new int[0];
39+
}
40+
41+
// Compute the inverse suffix array
42+
// invSuff[i] stores the index of the suffix text.substring(i) in the suffix array
43+
int[] invSuff = new int[n];
44+
for (int i = 0; i < n; i++) {
45+
if (suffixArr[i] < 0 || suffixArr[i] >= n) {
46+
throw new IllegalArgumentException("Suffix array contains out-of-bounds index.");
47+
}
48+
invSuff[suffixArr[i]] = i;
49+
}
50+
51+
int[] lcp = new int[n];
52+
int k = 0; // Length of the longest common prefix
53+
54+
for (int i = 0; i < n; i++) {
55+
// Suffix at index i has not a next suffix in suffix array
56+
int rank = invSuff[i];
57+
if (rank == n - 1) {
58+
k = 0;
59+
continue;
60+
}
61+
62+
int nextSuffixIndex = suffixArr[rank + 1];
63+
64+
// Directly match characters to find LCP
65+
while (i + k < n && nextSuffixIndex + k < n && text.charAt(i + k) == text.charAt(nextSuffixIndex + k)) {
66+
k++;
67+
}
68+
69+
lcp[rank] = k;
70+
71+
// Delete the starting character from the string
72+
if (k > 0) {
73+
k--;
74+
}
75+
}
76+
77+
return lcp;
78+
}
79+
}

src/test/java/com/thealgorithms/maths/VolumeTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,8 @@ public void volume() {
4141

4242
/* test torus */
4343
assertEquals(39.47841760435743, Volume.volumeTorus(2, 1));
44+
45+
/* test ellipsoid */
46+
assertEquals(25.1327412287183459, Volume.volumeEllipsoid(3, 2, 1));
4447
}
4548
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.thealgorithms.stacks;
2+
3+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
5+
6+
import java.util.stream.Stream;
7+
import org.junit.jupiter.params.ParameterizedTest;
8+
import org.junit.jupiter.params.provider.Arguments;
9+
import org.junit.jupiter.params.provider.MethodSource;
10+
11+
class StockSpanProblemTest {
12+
13+
@ParameterizedTest
14+
@MethodSource("validTestCases")
15+
void testCalculateSpan(int[] prices, int[] expectedSpans) {
16+
assertArrayEquals(expectedSpans, StockSpanProblem.calculateSpan(prices));
17+
}
18+
19+
private static Stream<Arguments> validTestCases() {
20+
return Stream.of(Arguments.of(new int[] {10, 4, 5, 90, 120, 80}, new int[] {1, 1, 2, 4, 5, 1}), Arguments.of(new int[] {100, 50, 60, 70, 80, 90}, new int[] {1, 1, 2, 3, 4, 5}), Arguments.of(new int[] {5, 4, 3, 2, 1}, new int[] {1, 1, 1, 1, 1}),
21+
Arguments.of(new int[] {1, 2, 3, 4, 5}, new int[] {1, 2, 3, 4, 5}), Arguments.of(new int[] {10, 20, 30, 40, 50}, new int[] {1, 2, 3, 4, 5}), Arguments.of(new int[] {100, 80, 60, 70, 60, 75, 85}, new int[] {1, 1, 1, 2, 1, 4, 6}),
22+
Arguments.of(new int[] {7, 7, 7, 7}, new int[] {1, 2, 3, 4}), Arguments.of(new int[] {}, new int[] {}), Arguments.of(new int[] {42}, new int[] {1}));
23+
}
24+
25+
@ParameterizedTest
26+
@MethodSource("invalidTestCases")
27+
void testCalculateSpanInvalidInput(int[] prices) {
28+
assertThrows(IllegalArgumentException.class, () -> StockSpanProblem.calculateSpan(prices));
29+
}
30+
31+
private static Stream<Arguments> invalidTestCases() {
32+
return Stream.of(Arguments.of((int[]) null));
33+
}
34+
}

0 commit comments

Comments
 (0)