Skip to content

Commit 9041247

Browse files
Merge branch 'master' into improve-factorial
2 parents b7942fb + d9f2ac8 commit 9041247

30 files changed

+1595
-25
lines changed

.github/workflows/infer.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333

3434
- name: Cache infer build
3535
id: cache-infer
36-
uses: actions/cache@v4
36+
uses: actions/cache@v5
3737
with:
3838
path: infer
3939
key: ${{ runner.os }}-infer-${{ env.year_week }}

.gitpod.dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM gitpod/workspace-java-21:2025-10-06-13-14-25
1+
FROM gitpod/workspace-java-21:2025-11-14-10-05-32
22

33
ENV LLVM_SCRIPT="tmp_llvm.sh"
44

DIRECTORY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,7 @@
822822
- 📄 [Upper](src/main/java/com/thealgorithms/strings/Upper.java)
823823
- 📄 [ValidParentheses](src/main/java/com/thealgorithms/strings/ValidParentheses.java)
824824
- 📄 [WordLadder](src/main/java/com/thealgorithms/strings/WordLadder.java)
825+
- 📄 [ZAlgorithm](src/main/java/com/thealgorithms/strings/ZAlgorithm.java)
825826
- 📁 **zigZagPattern**
826827
- 📄 [ZigZagPattern](src/main/java/com/thealgorithms/strings/zigZagPattern/ZigZagPattern.java)
827828
- 📁 **tree**
@@ -1579,6 +1580,7 @@
15791580
- 📄 [UpperTest](src/test/java/com/thealgorithms/strings/UpperTest.java)
15801581
- 📄 [ValidParenthesesTest](src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java)
15811582
- 📄 [WordLadderTest](src/test/java/com/thealgorithms/strings/WordLadderTest.java)
1583+
- 📄 [ZAlgorithmTest](src/test/java/com/thealgorithms/strings/ZAlgorithmTest.java)
15821584
- 📁 **zigZagPattern**
15831585
- 📄 [ZigZagPatternTest](src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java)
15841586
- 📁 **tree**

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
<dependency>
4343
<groupId>org.mockito</groupId>
4444
<artifactId>mockito-core</artifactId>
45-
<version>5.20.0</version>
45+
<version>5.21.0</version>
4646
<scope>test</scope>
4747
</dependency>
4848
<dependency>
@@ -112,7 +112,7 @@
112112
<dependency>
113113
<groupId>com.puppycrawl.tools</groupId>
114114
<artifactId>checkstyle</artifactId>
115-
<version>12.1.2</version>
115+
<version>12.2.0</version>
116116
</dependency>
117117
</dependencies>
118118
</plugin>
@@ -127,7 +127,7 @@
127127
<plugin>
128128
<groupId>com.mebigfatguy.fb-contrib</groupId>
129129
<artifactId>fb-contrib</artifactId>
130-
<version>7.7.1</version>
130+
<version>7.7.2</version>
131131
</plugin>
132132
<plugin>
133133
<groupId>com.h3xstream.findsecbugs</groupId>
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package com.thealgorithms.ciphers;
2+
3+
import java.security.SecureRandom;
4+
import java.util.Objects;
5+
6+
/**
7+
* One-Time Pad (OTP) cipher implementation.
8+
*
9+
* <p>The One-Time Pad is information-theoretically secure if:
10+
* <ul>
11+
* <li>The key is truly random.</li>
12+
* <li>The key length is at least as long as the plaintext.</li>
13+
* <li>The key is used only once and kept secret.</li>
14+
* </ul>
15+
*
16+
* <p>This implementation is for <b>educational purposes only</b> and should not be
17+
* used in production systems.
18+
*/
19+
public final class OneTimePadCipher {
20+
21+
private static final SecureRandom RANDOM = new SecureRandom();
22+
23+
private OneTimePadCipher() {
24+
// utility class
25+
}
26+
27+
/**
28+
* Generates a random key of the given length in bytes.
29+
*
30+
* @param length the length of the key in bytes, must be non-negative
31+
* @return a new random key
32+
* @throws IllegalArgumentException if length is negative
33+
*/
34+
public static byte[] generateKey(int length) {
35+
if (length < 0) {
36+
throw new IllegalArgumentException("length must be non-negative");
37+
}
38+
byte[] key = new byte[length];
39+
RANDOM.nextBytes(key);
40+
return key;
41+
}
42+
43+
/**
44+
* Encrypts the given plaintext bytes using the provided key.
45+
* <p>The key length must be exactly the same as the plaintext length.
46+
*
47+
* @param plaintext the plaintext bytes, must not be {@code null}
48+
* @param key the one-time pad key bytes, must not be {@code null}
49+
* @return the ciphertext bytes
50+
* @throws IllegalArgumentException if the key length does not match plaintext length
51+
* @throws NullPointerException if plaintext or key is {@code null}
52+
*/
53+
public static byte[] encrypt(byte[] plaintext, byte[] key) {
54+
validateInputs(plaintext, key);
55+
return xor(plaintext, key);
56+
}
57+
58+
/**
59+
* Decrypts the given ciphertext bytes using the provided key.
60+
* <p>For a One-Time Pad, decryption is identical to encryption:
61+
* {@code plaintext = ciphertext XOR key}.
62+
*
63+
* @param ciphertext the ciphertext bytes, must not be {@code null}
64+
* @param key the one-time pad key bytes, must not be {@code null}
65+
* @return the decrypted plaintext bytes
66+
* @throws IllegalArgumentException if the key length does not match ciphertext length
67+
* @throws NullPointerException if ciphertext or key is {@code null}
68+
*/
69+
public static byte[] decrypt(byte[] ciphertext, byte[] key) {
70+
validateInputs(ciphertext, key);
71+
return xor(ciphertext, key);
72+
}
73+
74+
private static void validateInputs(byte[] input, byte[] key) {
75+
Objects.requireNonNull(input, "input must not be null");
76+
Objects.requireNonNull(key, "key must not be null");
77+
if (input.length != key.length) {
78+
throw new IllegalArgumentException("Key length must match input length");
79+
}
80+
}
81+
82+
private static byte[] xor(byte[] data, byte[] key) {
83+
byte[] result = new byte[data.length];
84+
for (int i = 0; i < data.length; i++) {
85+
result[i] = (byte) (data[i] ^ key[i]);
86+
}
87+
return result;
88+
}
89+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package com.thealgorithms.datastructures.trees;
2+
3+
/**
4+
* Leetcode 606: Construct String from Binary Tree:
5+
* https://leetcode.com/problems/construct-string-from-binary-tree/
6+
*
7+
* Utility class to convert a {@link BinaryTree} into its string representation.
8+
* <p>
9+
* The conversion follows a preorder traversal pattern (root → left → right)
10+
* and uses parentheses to denote the tree structure.
11+
* Empty parentheses "()" are used to explicitly represent missing left children
12+
* when a right child exists, ensuring the structure is unambiguous.
13+
* </p>
14+
*
15+
* <h2>Rules:</h2>
16+
* <ul>
17+
* <li>Each node is represented as {@code (value)}.</li>
18+
* <li>If a node has only a right child, include {@code ()} before the right
19+
* child
20+
* to indicate the missing left child.</li>
21+
* <li>If a node has no children, it appears as just {@code (value)}.</li>
22+
* <li>The outermost parentheses are removed from the final string.</li>
23+
* </ul>
24+
*
25+
* <h3>Example:</h3>
26+
*
27+
* <pre>
28+
* Input tree:
29+
* 1
30+
* / \
31+
* 2 3
32+
* \
33+
* 4
34+
*
35+
* Output string:
36+
* "1(2()(4))(3)"
37+
* </pre>
38+
*
39+
* <p>
40+
* This implementation matches the logic from LeetCode problem 606:
41+
* <i>Construct String from Binary Tree</i>.
42+
* </p>
43+
*
44+
* @author Muhammad Junaid
45+
* @see BinaryTree
46+
*/
47+
public class BinaryTreeToString {
48+
49+
/** String builder used to accumulate the string representation. */
50+
private StringBuilder sb;
51+
52+
/**
53+
* Converts a binary tree (given its root node) to its string representation.
54+
*
55+
* @param root the root node of the binary tree
56+
* @return the string representation of the binary tree, or an empty string if
57+
* the tree is null
58+
*/
59+
public String tree2str(BinaryTree.Node root) {
60+
if (root == null) {
61+
return "";
62+
}
63+
64+
sb = new StringBuilder();
65+
dfs(root);
66+
67+
// Remove the leading and trailing parentheses added by the root call
68+
return sb.substring(1, sb.length() - 1);
69+
}
70+
71+
/**
72+
* Performs a recursive depth-first traversal to build the string.
73+
* Each recursive call appends the node value and its children (if any)
74+
* enclosed in parentheses.
75+
*
76+
* @param node the current node being processed
77+
*/
78+
private void dfs(BinaryTree.Node node) {
79+
if (node == null) {
80+
return;
81+
}
82+
83+
sb.append("(").append(node.data);
84+
85+
// Recursively build left and right subtrees
86+
if (node.left != null) {
87+
dfs(node.left);
88+
}
89+
90+
// Handle the special case: right child exists but left child is null
91+
if (node.right != null && node.left == null) {
92+
sb.append("()");
93+
dfs(node.right);
94+
} else if (node.right != null) {
95+
dfs(node.right);
96+
}
97+
98+
sb.append(")");
99+
}
100+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* TheAlgorithms (https://github.com/TheAlgorithms/Java)
3+
* Author: Shewale41
4+
* This file is licensed under the MIT License.
5+
*/
6+
7+
package com.thealgorithms.datastructures.trees;
8+
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
12+
/**
13+
* Threaded binary tree implementation that supports insertion and
14+
* in-order traversal without recursion or stack by using threads.
15+
*
16+
* <p>In this implementation, a node's null left/right pointers are used
17+
* to point to the in-order predecessor/successor respectively. Two flags
18+
* indicate whether left/right pointers are real children or threads.
19+
*
20+
* @see <a href="https://en.wikipedia.org/wiki/Threaded_binary_tree">Wikipedia:
21+
* Threaded binary tree</a>
22+
*/
23+
public final class ThreadedBinaryTree {
24+
25+
private Node root;
26+
27+
private static final class Node {
28+
int value;
29+
Node left;
30+
Node right;
31+
boolean leftIsThread;
32+
boolean rightIsThread;
33+
34+
Node(int value) {
35+
this.value = value;
36+
this.left = null;
37+
this.right = null;
38+
this.leftIsThread = false;
39+
this.rightIsThread = false;
40+
}
41+
}
42+
43+
public ThreadedBinaryTree() {
44+
this.root = null;
45+
}
46+
47+
/**
48+
* Inserts a value into the threaded binary tree. Duplicate values are inserted
49+
* to the right subtree (consistent deterministic rule).
50+
*
51+
* @param value the integer value to insert
52+
*/
53+
public void insert(int value) {
54+
Node newNode = new Node(value);
55+
if (root == null) {
56+
root = newNode;
57+
return;
58+
}
59+
60+
Node current = root;
61+
Node parent = null;
62+
63+
while (true) {
64+
parent = current;
65+
if (value < current.value) {
66+
if (!current.leftIsThread && current.left != null) {
67+
current = current.left;
68+
} else {
69+
break;
70+
}
71+
} else { // value >= current.value
72+
if (!current.rightIsThread && current.right != null) {
73+
current = current.right;
74+
} else {
75+
break;
76+
}
77+
}
78+
}
79+
80+
if (value < parent.value) {
81+
// attach newNode as left child
82+
newNode.left = parent.left;
83+
newNode.leftIsThread = parent.leftIsThread;
84+
newNode.right = parent;
85+
newNode.rightIsThread = true;
86+
87+
parent.left = newNode;
88+
parent.leftIsThread = false;
89+
} else {
90+
// attach newNode as right child
91+
newNode.right = parent.right;
92+
newNode.rightIsThread = parent.rightIsThread;
93+
newNode.left = parent;
94+
newNode.leftIsThread = true;
95+
96+
parent.right = newNode;
97+
parent.rightIsThread = false;
98+
}
99+
}
100+
101+
/**
102+
* Returns the in-order traversal of the tree as a list of integers.
103+
* Traversal is done without recursion or an explicit stack by following threads.
104+
*
105+
* @return list containing the in-order sequence of node values
106+
*/
107+
public List<Integer> inorderTraversal() {
108+
List<Integer> result = new ArrayList<>();
109+
Node current = root;
110+
if (current == null) {
111+
return result;
112+
}
113+
114+
// Move to the leftmost node
115+
while (current.left != null && !current.leftIsThread) {
116+
current = current.left;
117+
}
118+
119+
while (current != null) {
120+
result.add(current.value);
121+
122+
// If right pointer is a thread, follow it
123+
if (current.rightIsThread) {
124+
current = current.right;
125+
} else {
126+
// Move to leftmost node in right subtree
127+
current = current.right;
128+
while (current != null && !current.leftIsThread && current.left != null) {
129+
current = current.left;
130+
}
131+
}
132+
}
133+
134+
return result;
135+
}
136+
137+
/**
138+
* Helper: checks whether the tree is empty.
139+
*
140+
* @return true if tree has no nodes
141+
*/
142+
public boolean isEmpty() {
143+
return root == null;
144+
}
145+
}

0 commit comments

Comments
 (0)