Skip to content

Commit d75cae5

Browse files
authored
Merge branch 'master' into feat-knearestneighbors
2 parents 5d9addb + 6ec6339 commit d75cae5

19 files changed

Lines changed: 613 additions & 58 deletions

File tree

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
steps:
1111
- uses: actions/checkout@v7
1212
- name: Set up JDK
13-
uses: actions/setup-java@v5.6.0
13+
uses: actions/setup-java@v6.0.0
1414
with:
1515
java-version: 21
1616
distribution: 'temurin'

.github/workflows/codeql.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,21 @@ jobs:
2424
uses: actions/checkout@v7
2525

2626
- name: Set up JDK
27-
uses: actions/setup-java@v5.6.0
27+
uses: actions/setup-java@v6.0.0
2828
with:
2929
java-version: 21
3030
distribution: 'temurin'
3131

3232
- name: Initialize CodeQL
33-
uses: github/codeql-action/init@v4.37.3
33+
uses: github/codeql-action/init@v4.37.9
3434
with:
3535
languages: 'java-kotlin'
3636

3737
- name: Build
3838
run: mvn --batch-mode --update-snapshots verify
3939

4040
- name: Perform CodeQL Analysis
41-
uses: github/codeql-action/analyze@v4.37.3
41+
uses: github/codeql-action/analyze@v4.37.9
4242
with:
4343
category: "/language:java-kotlin"
4444

@@ -55,12 +55,12 @@ jobs:
5555
uses: actions/checkout@v7
5656

5757
- name: Initialize CodeQL
58-
uses: github/codeql-action/init@v4.37.3
58+
uses: github/codeql-action/init@v4.37.9
5959
with:
6060
languages: 'actions'
6161

6262
- name: Perform CodeQL Analysis
63-
uses: github/codeql-action/analyze@v4.37.3
63+
uses: github/codeql-action/analyze@v4.37.9
6464
with:
6565
category: "/language:actions"
6666
...

.github/workflows/infer.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
- uses: actions/checkout@v7
1919

2020
- name: Set up JDK
21-
uses: actions/setup-java@v5.6.0
21+
uses: actions/setup-java@v6.0.0
2222
with:
2323
java-version: 21
2424
distribution: 'temurin'

.github/workflows/stale.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
pull-requests: write
1212
runs-on: ubuntu-latest
1313
steps:
14-
- uses: actions/stale@v10.4.0
14+
- uses: actions/stale@v11.0.0
1515
with:
1616
stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution!'
1717
close-issue-message: 'Please reopen this issue once you have made the required changes. If you need help, feel free to ask in our [Discord](https://the-algorithms.com/discord) server or ping one of the maintainers here. Thank you for your contribution!'

pom.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<dependency>
2121
<groupId>org.junit</groupId>
2222
<artifactId>junit-bom</artifactId>
23-
<version>6.1.2</version>
23+
<version>6.1.3</version>
2424
<type>pom</type>
2525
<scope>import</scope>
2626
</dependency>
@@ -53,7 +53,7 @@
5353
<dependency>
5454
<groupId>org.apache.commons</groupId>
5555
<artifactId>commons-collections4</artifactId>
56-
<version>4.5.0</version>
56+
<version>4.6.0</version>
5757
</dependency>
5858
</dependencies>
5959

@@ -112,14 +112,14 @@
112112
<dependency>
113113
<groupId>com.puppycrawl.tools</groupId>
114114
<artifactId>checkstyle</artifactId>
115-
<version>13.8.0</version>
115+
<version>14.0.0</version>
116116
</dependency>
117117
</dependencies>
118118
</plugin>
119119
<plugin>
120120
<groupId>com.github.spotbugs</groupId>
121121
<artifactId>spotbugs-maven-plugin</artifactId>
122-
<version>4.10.3.0</version>
122+
<version>4.10.4.0</version>
123123
<configuration>
124124
<excludeFilterFile>spotbugs-exclude.xml</excludeFilterFile>
125125
<includeTests>true</includeTests>

src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.thealgorithms.ciphers;
22

3-
import java.util.Arrays;
4-
53
/**
64
* The rail fence cipher (also called a zigzag cipher) is a classical type of transposition cipher.
75
* It derives its name from the manner in which encryption is performed, in analogy to a fence built with horizontal rails.
@@ -14,28 +12,27 @@ public class RailFenceCipher {
1412
// Encrypts the input string using the rail fence cipher method with the given number of rails.
1513
public String encrypt(String str, int rails) {
1614

15+
checkInput(str, rails);
16+
1717
// Base case of single rail or rails are more than the number of characters in the string
1818
if (rails == 1 || rails >= str.length()) {
1919
return str;
2020
}
2121

22-
// Boolean flag to determine if the movement is downward or upward in the rail matrix.
22+
// Boolean flag to determine if the movement is downward or upward in the rail pattern.
2323
boolean down = true;
24-
// Create a 2D array to represent the rails (rows) and the length of the string (columns).
25-
char[][] strRail = new char[rails][str.length()];
26-
27-
// Initialize all positions in the rail matrix with a placeholder character ('\n').
24+
// Collect the characters of every rail separately. Using one buffer per rail (instead of a
25+
// rails x length matrix with a placeholder character) keeps every character of the input,
26+
// including characters that would otherwise be indistinguishable from the placeholder.
27+
StringBuilder[] railBuffers = new StringBuilder[rails];
2828
for (int i = 0; i < rails; i++) {
29-
Arrays.fill(strRail[i], '\n');
29+
railBuffers[i] = new StringBuilder();
3030
}
3131

32-
int row = 0; // Start at the first row
33-
int col = 0; // Start at the first column
32+
int row = 0; // Start at the first rail
3433

35-
int i = 0;
36-
37-
// Fill the rail matrix with characters from the string based on the rail pattern.
38-
while (col < str.length()) {
34+
// Distribute the characters of the string over the rails following the zigzag pattern.
35+
for (int i = 0; i < str.length(); i++) {
3936
// Change direction to down when at the first row.
4037
if (row == 0) {
4138
down = true;
@@ -45,33 +42,28 @@ else if (row == rails - 1) {
4542
down = false;
4643
}
4744

48-
// Place the character in the current position of the rail matrix.
49-
strRail[row][col] = str.charAt(i);
50-
col++; // Move to the next column.
45+
// Append the character to the rail it belongs to.
46+
railBuffers[row].append(str.charAt(i));
5147
// Move to the next row based on the direction.
5248
if (down) {
5349
row++;
5450
} else {
5551
row--;
5652
}
57-
58-
i++;
5953
}
6054

61-
// Construct the encrypted string by reading characters row by row.
62-
StringBuilder encryptedString = new StringBuilder();
63-
for (char[] chRow : strRail) {
64-
for (char ch : chRow) {
65-
if (ch != '\n') {
66-
encryptedString.append(ch);
67-
}
68-
}
55+
// Construct the encrypted string by reading the rails top to bottom.
56+
StringBuilder encryptedString = new StringBuilder(str.length());
57+
for (StringBuilder railBuffer : railBuffers) {
58+
encryptedString.append(railBuffer);
6959
}
7060
return encryptedString.toString();
7161
}
7262
// Decrypts the input string using the rail fence cipher method with the given number of rails.
7363
public String decrypt(String str, int rails) {
7464

65+
checkInput(str, rails);
66+
7567
// Base case of single rail or rails are more than the number of characters in the string
7668
if (rails == 1 || rails >= str.length()) {
7769
return str;
@@ -144,4 +136,14 @@ else if (row == rails - 1) {
144136

145137
return decryptedString.toString();
146138
}
139+
140+
// Rejects inputs the zigzag pattern is not defined for.
141+
private static void checkInput(String str, int rails) {
142+
if (str == null) {
143+
throw new IllegalArgumentException("Input string must not be null");
144+
}
145+
if (rails <= 0) {
146+
throw new IllegalArgumentException("Number of rails must be positive, but was " + rails);
147+
}
148+
}
147149
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package com.thealgorithms.datastructures.lists;
2+
3+
import java.util.Objects;
4+
5+
/**
6+
* A Self-Organizing Linked List implementation using the Move-To-Front (MTF) strategy.
7+
* When an element is searched, it is automatically moved to the head of the list
8+
* to optimize subsequent lookups.
9+
*
10+
* @param <E> the type of elements held in this list
11+
*/
12+
public class SelfOrganizingLinkedList<E> {
13+
14+
/**
15+
* Node structure for the self-organizing linked list.
16+
*
17+
* @param <E> the type of element held in this node
18+
*/
19+
private static class Node<E> {
20+
E value;
21+
Node<E> next;
22+
23+
Node(E value) {
24+
this.value = value;
25+
this.next = null;
26+
}
27+
}
28+
29+
private Node<E> head;
30+
private int size;
31+
32+
public SelfOrganizingLinkedList() {
33+
this.size = 0;
34+
this.head = null;
35+
}
36+
37+
/**
38+
* Inserts a new value at the end of the list.
39+
*
40+
* @param value the element to add
41+
*/
42+
public void insert(E value) {
43+
Node<E> newNode = new Node<>(value);
44+
if (head == null) {
45+
head = newNode;
46+
} else {
47+
Node<E> temp = head;
48+
while (temp.next != null) {
49+
temp = temp.next;
50+
}
51+
temp.next = newNode;
52+
}
53+
size++;
54+
}
55+
56+
/**
57+
* Searches for a value in the list.
58+
* If found, moves the node to the front (head) of the list.
59+
*
60+
* @param key the value to search for
61+
* @return true if the element is present, false otherwise
62+
*/
63+
public boolean search(E key) {
64+
if (head == null) {
65+
return false;
66+
}
67+
// If the key is already at the head, no pointers need to be rewired
68+
if (Objects.equals(head.value, key)) {
69+
return true;
70+
}
71+
72+
Node<E> prev = head;
73+
Node<E> curr = head.next;
74+
75+
while (curr != null && !Objects.equals(curr.value, key)) {
76+
prev = curr;
77+
curr = curr.next;
78+
}
79+
80+
if (curr == null) {
81+
return false;
82+
}
83+
84+
// Unlink curr from its current position and move it to head
85+
prev.next = curr.next;
86+
curr.next = head;
87+
head = curr;
88+
return true;
89+
}
90+
91+
/** Gets the current head value of the list. */
92+
public E getHeadValue() {
93+
return head != null ? head.value : null;
94+
}
95+
96+
/** Returns the size of the list. */
97+
public int getSize() {
98+
return size;
99+
}
100+
101+
/** Returns true if the list contains no elements. */
102+
public boolean isEmpty() {
103+
return size == 0;
104+
}
105+
}

src/main/java/com/thealgorithms/datastructures/trees/SegmentTree.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,18 @@ public class SegmentTree {
88

99
/* Constructor which takes the size of the array and the array as a parameter*/
1010
public SegmentTree(int n, int[] arr) {
11+
if (arr == null) {
12+
throw new IllegalArgumentException("Input array must not be null");
13+
}
14+
if (n <= 0 || n > arr.length) {
15+
throw new IllegalArgumentException("Size must be in the range [1, " + arr.length + "], but was " + n);
16+
}
1117
this.n = n;
1218
int x = (int) (Math.ceil(Math.log(n) / Math.log(2)));
1319
int segSize = 2 * (int) Math.pow(2, x) - 1;
1420

1521
this.segTree = new int[segSize];
1622
this.arr = arr;
17-
this.n = n;
1823
constructTree(arr, 0, n - 1, 0);
1924
}
2025

@@ -47,7 +52,8 @@ private void updateTree(int start, int end, int index, int diff, int segIndex) {
4752

4853
/* A function to update the value at a particular index*/
4954
public void update(int index, int value) {
50-
if (index < 0 || index > n) {
55+
// Valid positions are 0..n-1; index == n is out of bounds and must not reach arr[index].
56+
if (index < 0 || index >= n) {
5157
return;
5258
}
5359

@@ -73,7 +79,8 @@ private int getSumTree(int start, int end, int qStart, int qEnd, int segIndex) {
7379

7480
/* A function to query the sum of the subarray [start...end]*/
7581
public int getSum(int start, int end) {
76-
if (start < 0 || end > n || start > end) {
82+
// The last queryable position is n-1, so end == n is an out of range query.
83+
if (start < 0 || end >= n || start > end) {
7784
return 0;
7885
}
7986
return getSumTree(0, n - 1, start, end, 0);

src/main/java/com/thealgorithms/maths/Prime/MobiusFunction.java

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,28 @@ public static int mobius(int number) {
3131
throw new IllegalArgumentException("Number must be greater than zero.");
3232
}
3333

34-
if (number == 1) {
35-
// return 1 if number passed is less or is 1
36-
return 1;
37-
}
38-
3934
int primeFactorCount = 0;
35+
int remaining = number;
4036

41-
for (int i = 1; i <= number; i++) {
42-
// find prime factors of number
43-
if (number % i == 0 && PrimeCheck.isPrime(i)) {
44-
// check if number is divisible by square of prime factor
45-
if (number % (i * i) == 0) {
46-
// if number is divisible by square of prime factor
37+
/* Divide out every prime factor in turn. Trial division only has to run up to the square
38+
root of the remaining value, and the multiplication is widened to long so that the bound
39+
does not overflow for numbers close to Integer.MAX_VALUE. */
40+
for (int factor = 2; (long) factor * factor <= remaining; factor++) {
41+
if (remaining % factor == 0) {
42+
remaining /= factor;
43+
if (remaining % factor == 0) {
44+
// number is divisible by the square of this prime factor
4745
return 0;
4846
}
49-
/*increment primeFactorCount by 1
50-
if number is not divisible by square of found prime factor*/
5147
primeFactorCount++;
5248
}
5349
}
5450

51+
/* Whatever is left is either 1 or a single prime factor larger than the square root. */
52+
if (remaining > 1) {
53+
primeFactorCount++;
54+
}
55+
5556
return (primeFactorCount % 2 == 0) ? 1 : -1;
5657
}
5758
}

0 commit comments

Comments
 (0)