diff --git a/.github/workflows/close-failed-prs.yml b/.github/workflows/close-failed-prs.yml index 6deea88f0daf..4013e87b6569 100644 --- a/.github/workflows/close-failed-prs.yml +++ b/.github/workflows/close-failed-prs.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Close stale PRs - uses: actions/github-script@v8 + uses: actions/github-script@v9 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/src/main/java/com/thealgorithms/geometry/LineIntersection.java b/src/main/java/com/thealgorithms/geometry/LineIntersection.java new file mode 100644 index 000000000000..8d65833816b3 --- /dev/null +++ b/src/main/java/com/thealgorithms/geometry/LineIntersection.java @@ -0,0 +1,105 @@ +package com.thealgorithms.geometry; + +import java.awt.geom.Point2D; +import java.util.Optional; + +/** + * Utility methods for checking and computing 2D line segment intersections. + */ +public final class LineIntersection { + private LineIntersection() { + } + + /** + * Checks whether two line segments intersect. + * + * @param p1 first endpoint of segment 1 + * @param p2 second endpoint of segment 1 + * @param q1 first endpoint of segment 2 + * @param q2 second endpoint of segment 2 + * @return true when the segments intersect (including touching endpoints) + */ + public static boolean intersects(Point p1, Point p2, Point q1, Point q2) { + int o1 = orientation(p1, p2, q1); + int o2 = orientation(p1, p2, q2); + int o3 = orientation(q1, q2, p1); + int o4 = orientation(q1, q2, p2); + + if (o1 != o2 && o3 != o4) { + return true; + } + + if (o1 == 0 && onSegment(p1, q1, p2)) { + return true; + } + if (o2 == 0 && onSegment(p1, q2, p2)) { + return true; + } + if (o3 == 0 && onSegment(q1, p1, q2)) { + return true; + } + if (o4 == 0 && onSegment(q1, p2, q2)) { + return true; + } + + return false; + } + + /** + * Computes the single geometric intersection point between two non-parallel + * segments when it exists. + * + *
For parallel/collinear overlap, this method returns {@code Optional.empty()}.
+ *
+ * @param p1 first endpoint of segment 1
+ * @param p2 second endpoint of segment 1
+ * @param q1 first endpoint of segment 2
+ * @param q2 second endpoint of segment 2
+ * @return the intersection point when uniquely defined and on both segments
+ */
+ public static Optional This class provides static methods to calculate the arithmetic mean
+ * of arrays of both {@code double} and {@code int} values. It also offers
+ * a Stream-based alternative for modern, declarative usage.
+ *
+ * All methods guard against {@code null} or empty inputs.
*/
public final class Average {
@@ -13,11 +20,14 @@ private Average() {
}
/**
- * Computes the average of a {@code double} array.
+ * Computes the arithmetic mean of a {@code double} array.
+ *
+ * The average is calculated as the sum of all elements divided
+ * by the number of elements: {@code avg = Σ(numbers[i]) / n}.
*
- * @param numbers an array of {@code double} values
- * @return the average of the given numbers
- * @throws IllegalArgumentException if the input array is {@code null} or empty
+ * @param numbers a non-null, non-empty array of {@code double} values
+ * @return the arithmetic mean of the given numbers
+ * @throws IllegalArgumentException if {@code numbers} is {@code null} or empty
*/
public static double average(double[] numbers) {
if (numbers == null || numbers.length == 0) {
@@ -31,11 +41,14 @@ public static double average(double[] numbers) {
}
/**
- * Computes the average of an {@code int} array.
+ * Computes the arithmetic mean of an {@code int} array.
+ *
+ * The sum is accumulated in a {@code long} to prevent integer overflow
+ * when processing large arrays or large values.
*
- * @param numbers an array of {@code int} values
- * @return the average of the given numbers
- * @throws IllegalArgumentException if the input array is {@code null} or empty
+ * @param numbers a non-null, non-empty array of {@code int} values
+ * @return the arithmetic mean as a {@code long} (truncated toward zero)
+ * @throws IllegalArgumentException if {@code numbers} is {@code null} or empty
*/
public static long average(int[] numbers) {
if (numbers == null || numbers.length == 0) {
@@ -47,4 +60,21 @@ public static long average(int[] numbers) {
}
return sum / numbers.length;
}
+
+ /**
+ * Computes the arithmetic mean of a {@code double} array using Java Streams.
+ *
+ * This method is a declarative alternative to {@link #average(double[])}.
+ * Instead of throwing on empty input, it returns an empty {@link OptionalDouble},
+ * following the convention of the Stream API.
+ *
+ * @param numbers an array of {@code double} values, may be {@code null} or empty
+ * @return an {@link OptionalDouble} with the mean, or empty if input is null/empty
+ */
+ public static OptionalDouble averageStream(double[] numbers) {
+ if (numbers == null || numbers.length == 0) {
+ return OptionalDouble.empty();
+ }
+ return Arrays.stream(numbers).average();
+ }
}
diff --git a/src/main/java/com/thealgorithms/strings/Alphabetical.java b/src/main/java/com/thealgorithms/strings/Alphabetical.java
index ef2974eb427d..37b1fb068b44 100644
--- a/src/main/java/com/thealgorithms/strings/Alphabetical.java
+++ b/src/main/java/com/thealgorithms/strings/Alphabetical.java
@@ -1,32 +1,58 @@
package com.thealgorithms.strings;
+import java.util.Locale;
+
/**
- * Utility class for checking if a string's characters are in alphabetical order.
+ * Utility class for checking whether a string's characters are in non-decreasing
+ * lexicographical order based on Unicode code points (case-insensitive).
+ *
+ * This does NOT implement language-aware alphabetical ordering (collation rules).
+ * It simply compares lowercase Unicode character values.
*
- * Alphabetical order is a system whereby character strings are placed in order
- * based on the position of the characters in the conventional ordering of an
- * alphabet.
+ * Non-letter characters are not allowed and will cause the check to fail.
*
- * Reference: Wikipedia: Alphabetical Order
+ * Reference:
+ * Wikipedia: Alphabetical order
*/
public final class Alphabetical {
+
private Alphabetical() {
}
/**
- * Checks whether the characters in the given string are in alphabetical order.
- * Non-letter characters will cause the check to fail.
+ * Checks whether the characters in the given string are in non-decreasing
+ * lexicographical order (case-insensitive).
+ *
+ * Rules:
+ *
+ *
*
- * @param s the input string
- * @return {@code true} if all characters are in alphabetical order (case-insensitive), otherwise {@code false}
+ * @param s input string
+ * @return {@code true} if characters are in non-decreasing order, otherwise {@code false}
*/
public static boolean isAlphabetical(String s) {
- s = s.toLowerCase();
- for (int i = 0; i < s.length() - 1; ++i) {
- if (!Character.isLetter(s.charAt(i)) || s.charAt(i) > s.charAt(i + 1)) {
+ if (s == null || s.isBlank()) {
+ return false;
+ }
+
+ String normalized = s.toLowerCase(Locale.ROOT);
+
+ if (!Character.isLetter(normalized.charAt(0))) {
+ return false;
+ }
+
+ for (int i = 1; i < normalized.length(); i++) {
+ char prev = normalized.charAt(i - 1);
+ char curr = normalized.charAt(i);
+
+ if (!Character.isLetter(curr) || prev > curr) {
return false;
}
}
- return !s.isEmpty() && Character.isLetter(s.charAt(s.length() - 1));
+ return true;
}
}
diff --git a/src/test/java/com/thealgorithms/geometry/LineIntersectionTest.java b/src/test/java/com/thealgorithms/geometry/LineIntersectionTest.java
new file mode 100644
index 000000000000..9f60df51b65f
--- /dev/null
+++ b/src/test/java/com/thealgorithms/geometry/LineIntersectionTest.java
@@ -0,0 +1,101 @@
+package com.thealgorithms.geometry;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.awt.geom.Point2D;
+import java.util.Optional;
+import org.junit.jupiter.api.Test;
+
+class LineIntersectionTest {
+
+ @Test
+ void testCrossingSegments() {
+ Point p1 = new Point(0, 0);
+ Point p2 = new Point(4, 4);
+ Point q1 = new Point(0, 4);
+ Point q2 = new Point(4, 0);
+
+ assertTrue(LineIntersection.intersects(p1, p2, q1, q2));
+ Optional