diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index d9cc4c3c35c5..30b46bbf45b5 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -13,4 +13,5 @@ In order to reduce the number of notifications sent to the maintainers, please:
- [ ] All filenames are in PascalCase.
- [ ] All functions and variable names follow Java naming conventions.
- [ ] All new algorithms have a URL in their comments that points to Wikipedia or other similar explanations.
-- [ ] All new code is formatted with `clang-format -i --style=file path/to/your/file.java`
\ No newline at end of file
+- [ ] All new algorithms include a corresponding test class that validates their functionality.
+- [ ] All new code is formatted with `clang-format -i --style=file path/to/your/file.java`
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 39bde758d68e..c5f200c12836 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -8,7 +8,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml
index ca014e115282..dc0c9754ed1b 100644
--- a/.github/workflows/clang-format-lint.yml
+++ b/.github/workflows/clang-format-lint.yml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- uses: DoozyX/clang-format-lint-action@v0.20
with:
source: './src'
diff --git a/.github/workflows/close-failed-prs.yml b/.github/workflows/close-failed-prs.yml
new file mode 100644
index 000000000000..6deea88f0daf
--- /dev/null
+++ b/.github/workflows/close-failed-prs.yml
@@ -0,0 +1,156 @@
+name: Close stale PRs with failed workflows
+
+on:
+ schedule:
+ - cron: '0 3 * * *' # runs daily at 03:00 UTC
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ issues: write
+ pull-requests: write
+
+jobs:
+ close-stale:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Close stale PRs
+ uses: actions/github-script@v8
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const mainBranches = ['main', 'master'];
+ const cutoffDays = 14;
+ const cutoff = new Date();
+ cutoff.setDate(cutoff.getDate() - cutoffDays);
+
+ console.log(`Checking PRs older than: ${cutoff.toISOString()}`);
+
+ try {
+ const { data: prs } = await github.rest.pulls.list({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ state: 'open',
+ sort: 'updated',
+ direction: 'asc',
+ per_page: 100
+ });
+
+ console.log(`Found ${prs.length} open PRs to check`);
+
+ for (const pr of prs) {
+ try {
+ const updated = new Date(pr.updated_at);
+
+ if (updated > cutoff) {
+ console.log(`⏩ Skipping PR #${pr.number} - updated recently`);
+ continue;
+ }
+
+ console.log(`🔍 Checking PR #${pr.number}: "${pr.title}"`);
+
+ // Get commits
+ const commits = await github.paginate(github.rest.pulls.listCommits, {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ pull_number: pr.number,
+ per_page: 100
+ });
+
+ const meaningfulCommits = commits.filter(c => {
+ const msg = c.commit.message.toLowerCase();
+ const date = new Date(c.commit.committer.date);
+ const isMergeFromMain = mainBranches.some(branch =>
+ msg.startsWith(`merge branch '${branch}'`) ||
+ msg.includes(`merge remote-tracking branch '${branch}'`)
+ );
+
+ return !isMergeFromMain && date > cutoff;
+ });
+
+ // Get checks with error handling
+ let hasFailedChecks = false;
+ let allChecksCompleted = false;
+ let hasChecks = false;
+
+ try {
+ const { data: checks } = await github.rest.checks.listForRef({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ ref: pr.head.sha
+ });
+
+ hasChecks = checks.check_runs.length > 0;
+ hasFailedChecks = checks.check_runs.some(c => c.conclusion === 'failure');
+ allChecksCompleted = checks.check_runs.every(c =>
+ c.status === 'completed' || c.status === 'skipped'
+ );
+ } catch (error) {
+ console.log(`⚠️ Could not fetch checks for PR #${pr.number}: ${error.message}`);
+ }
+
+ // Get workflow runs with error handling
+ let hasFailedWorkflows = false;
+ let allWorkflowsCompleted = false;
+ let hasWorkflows = false;
+
+ try {
+ const { data: runs } = await github.rest.actions.listWorkflowRuns({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ head_sha: pr.head.sha,
+ per_page: 50
+ });
+
+ hasWorkflows = runs.workflow_runs.length > 0;
+ hasFailedWorkflows = runs.workflow_runs.some(r => r.conclusion === 'failure');
+ allWorkflowsCompleted = runs.workflow_runs.every(r =>
+ ['completed', 'skipped', 'cancelled'].includes(r.status)
+ );
+
+ console.log(`PR #${pr.number}: ${runs.workflow_runs.length} workflow runs found`);
+
+ } catch (error) {
+ console.log(`⚠️ Could not fetch workflow runs for PR #${pr.number}: ${error.message}`);
+ }
+
+ console.log(`PR #${pr.number}: ${meaningfulCommits.length} meaningful commits`);
+ console.log(`Checks - has: ${hasChecks}, failed: ${hasFailedChecks}, completed: ${allChecksCompleted}`);
+ console.log(`Workflows - has: ${hasWorkflows}, failed: ${hasFailedWorkflows}, completed: ${allWorkflowsCompleted}`);
+
+ // Combine conditions - only consider if we actually have checks/workflows
+ const hasAnyFailure = (hasChecks && hasFailedChecks) || (hasWorkflows && hasFailedWorkflows);
+ const allCompleted = (!hasChecks || allChecksCompleted) && (!hasWorkflows || allWorkflowsCompleted);
+
+ if (meaningfulCommits.length === 0 && hasAnyFailure && allCompleted) {
+ console.log(`✅ Closing PR #${pr.number} (${pr.title})`);
+
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: pr.number,
+ body: `This pull request has been automatically closed because its workflows or checks failed and it has been inactive for more than ${cutoffDays} days. Please fix the workflows and reopen if you'd like to continue. Merging from main/master alone does not count as activity.`
+ });
+
+ await github.rest.pulls.update({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ pull_number: pr.number,
+ state: 'closed'
+ });
+
+ console.log(`✅ Successfully closed PR #${pr.number}`);
+ } else {
+ console.log(`⏩ Not closing PR #${pr.number} - conditions not met`);
+ }
+
+ } catch (prError) {
+ console.error(`❌ Error processing PR #${pr.number}: ${prError.message}`);
+ continue;
+ }
+ }
+
+ } catch (error) {
+ console.error(`❌ Fatal error: ${error.message}`);
+ throw error;
+ }
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 3a4cfd829b6b..152d0d766fd2 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -21,7 +21,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
@@ -52,7 +52,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
diff --git a/.github/workflows/infer.yml b/.github/workflows/infer.yml
index 3df7c4b1fc9e..9d4dcf63000b 100644
--- a/.github/workflows/infer.yml
+++ b/.github/workflows/infer.yml
@@ -15,7 +15,7 @@ jobs:
run_infer:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
@@ -33,7 +33,7 @@ jobs:
- name: Cache infer build
id: cache-infer
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: infer
key: ${{ runner.os }}-infer-${{ env.year_week }}
@@ -44,7 +44,7 @@ jobs:
cd ..
git clone https://github.com/facebook/infer.git
cd infer
- git checkout 01aaa268f9d38723ba69c139e10f9e2a04b40b1c
+ git checkout 02c2c43b71e4c5110c0be841e66153942fda06c9
./build-infer.sh java
cp -r infer ../Java
diff --git a/.github/workflows/project_structure.yml b/.github/workflows/project_structure.yml
index f9fb82a2781c..5aadc6353791 100644
--- a/.github/workflows/project_structure.yml
+++ b/.github/workflows/project_structure.yml
@@ -15,7 +15,7 @@ jobs:
check_structure:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: '3.13'
diff --git a/.github/workflows/update-directorymd.yml b/.github/workflows/update-directorymd.yml
index 6692a884a867..aa553b46a23b 100644
--- a/.github/workflows/update-directorymd.yml
+++ b/.github/workflows/update-directorymd.yml
@@ -14,7 +14,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
+ with:
+ persist-credentials: false
- name: Run Directory Tree Generator
uses: DenizAltunkapan/directory-tree-generator@v2
@@ -31,7 +33,7 @@ jobs:
git diff --cached --quiet || git commit -m "Update DIRECTORY.md"
- name: Create Pull Request
- uses: peter-evans/create-pull-request@v7
+ uses: peter-evans/create-pull-request@v8
with:
token: ${{ secrets.REPO_SCOPED_TOKEN }}
branch: update-directory
diff --git a/.gitpod.dockerfile b/.gitpod.dockerfile
index 4195f928d1bc..a8951da7de26 100644
--- a/.gitpod.dockerfile
+++ b/.gitpod.dockerfile
@@ -1,4 +1,4 @@
-FROM gitpod/workspace-java-21:2025-10-06-13-14-25
+FROM gitpod/workspace-java-21:2025-11-14-10-05-32
ENV LLVM_SCRIPT="tmp_llvm.sh"
diff --git a/.inferconfig b/.inferconfig
index 6af4f9e2e818..239172177b38 100644
--- a/.inferconfig
+++ b/.inferconfig
@@ -1,6 +1,8 @@
{
"report-block-list-path-regex": [
"src/main/java/com/thealgorithms/ciphers/a5/CompositeLFSR.java",
+ "src/main/java/com/thealgorithms/compression/ArithmeticCoding.java",
+ "src/main/java/com/thealgorithms/datastructures/caches/FIFOCache.java",
"src/main/java/com/thealgorithms/datastructures/crdt/GCounter.java",
"src/main/java/com/thealgorithms/datastructures/crdt/PNCounter.java",
"src/main/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithm.java",
@@ -8,15 +10,18 @@
"src/main/java/com/thealgorithms/datastructures/lists/DoublyLinkedList.java",
"src/main/java/com/thealgorithms/datastructures/trees/CreateBinaryTreeFromInorderPreorder.java",
"src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java",
+ "src/main/java/com/thealgorithms/dynamicprogramming/DamerauLevenshteinDistance.java",
"src/main/java/com/thealgorithms/dynamicprogramming/Fibonacci.java",
"src/main/java/com/thealgorithms/maths/SimpsonIntegration.java",
"src/main/java/com/thealgorithms/others/Dijkstra.java",
"src/main/java/com/thealgorithms/sorts/TopologicalSort.java",
"src/main/java/com/thealgorithms/strings/AhoCorasick.java",
+ "src/test/java/com/thealgorithms/compression/ShannonFanoTest.java",
"src/test/java/com/thealgorithms/datastructures/caches/LRUCacheTest.java",
"src/test/java/com/thealgorithms/datastructures/lists/SkipListTest.java",
"src/test/java/com/thealgorithms/datastructures/trees/KDTreeTest.java",
"src/test/java/com/thealgorithms/datastructures/trees/LazySegmentTreeTest.java",
+ "src/test/java/com/thealgorithms/others/HuffmanTest.java",
"src/test/java/com/thealgorithms/searches/QuickSelectTest.java",
"src/test/java/com/thealgorithms/stacks/PostfixToInfixTest.java",
"src/test/java/com/thealgorithms/strings/HorspoolSearchTest.java"
diff --git a/DIRECTORY.md b/DIRECTORY.md
index b311b10fa177..deaf59636fa4 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -13,6 +13,7 @@
- 📄 [AllPathsFromSourceToTarget](src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java)
- 📄 [ArrayCombination](src/main/java/com/thealgorithms/backtracking/ArrayCombination.java)
- 📄 [Combination](src/main/java/com/thealgorithms/backtracking/Combination.java)
+ - 📄 [CombinationSum](src/main/java/com/thealgorithms/backtracking/CombinationSum.java)
- 📄 [CrosswordSolver](src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java)
- 📄 [FloodFill](src/main/java/com/thealgorithms/backtracking/FloodFill.java)
- 📄 [KnightsTour](src/main/java/com/thealgorithms/backtracking/KnightsTour.java)
@@ -23,14 +24,19 @@
- 📄 [Permutation](src/main/java/com/thealgorithms/backtracking/Permutation.java)
- 📄 [PowerSum](src/main/java/com/thealgorithms/backtracking/PowerSum.java)
- 📄 [SubsequenceFinder](src/main/java/com/thealgorithms/backtracking/SubsequenceFinder.java)
+ - 📄 [SudokuSolver](src/main/java/com/thealgorithms/backtracking/SudokuSolver.java)
+ - 📄 [UniquePermutation](src/main/java/com/thealgorithms/backtracking/UniquePermutation.java)
- 📄 [WordPatternMatcher](src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java)
- 📄 [WordSearch](src/main/java/com/thealgorithms/backtracking/WordSearch.java)
- 📁 **bitmanipulation**
- 📄 [BcdConversion](src/main/java/com/thealgorithms/bitmanipulation/BcdConversion.java)
- 📄 [BinaryPalindromeCheck](src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java)
+ - 📄 [BitRotate](src/main/java/com/thealgorithms/bitmanipulation/BitRotate.java)
- 📄 [BitSwap](src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java)
+ - 📄 [BitwiseGCD](src/main/java/com/thealgorithms/bitmanipulation/BitwiseGCD.java)
- 📄 [BooleanAlgebraGates](src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java)
- 📄 [ClearLeftmostSetBit](src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java)
+ - 📄 [CountBitsFlip](src/main/java/com/thealgorithms/bitmanipulation/CountBitsFlip.java)
- 📄 [CountLeadingZeros](src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java)
- 📄 [CountSetBits](src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java)
- 📄 [FindNthBit](src/main/java/com/thealgorithms/bitmanipulation/FindNthBit.java)
@@ -74,6 +80,8 @@
- 📄 [ECC](src/main/java/com/thealgorithms/ciphers/ECC.java)
- 📄 [HillCipher](src/main/java/com/thealgorithms/ciphers/HillCipher.java)
- 📄 [MonoAlphabetic](src/main/java/com/thealgorithms/ciphers/MonoAlphabetic.java)
+ - 📄 [OneTimePadCipher](src/main/java/com/thealgorithms/ciphers/OneTimePadCipher.java)
+ - 📄 [PermutationCipher](src/main/java/com/thealgorithms/ciphers/PermutationCipher.java)
- 📄 [PlayfairCipher](src/main/java/com/thealgorithms/ciphers/PlayfairCipher.java)
- 📄 [Polybius](src/main/java/com/thealgorithms/ciphers/Polybius.java)
- 📄 [ProductCipher](src/main/java/com/thealgorithms/ciphers/ProductCipher.java)
@@ -89,6 +97,15 @@
- 📄 [CompositeLFSR](src/main/java/com/thealgorithms/ciphers/a5/CompositeLFSR.java)
- 📄 [LFSR](src/main/java/com/thealgorithms/ciphers/a5/LFSR.java)
- 📄 [Utils](src/main/java/com/thealgorithms/ciphers/a5/Utils.java)
+ - 📁 **compression**
+ - 📄 [ArithmeticCoding](src/main/java/com/thealgorithms/compression/ArithmeticCoding.java)
+ - 📄 [BurrowsWheelerTransform](src/main/java/com/thealgorithms/compression/BurrowsWheelerTransform.java)
+ - 📄 [LZ77](src/main/java/com/thealgorithms/compression/LZ77.java)
+ - 📄 [LZ78](src/main/java/com/thealgorithms/compression/LZ78.java)
+ - 📄 [LZW](src/main/java/com/thealgorithms/compression/LZW.java)
+ - 📄 [MoveToFront](src/main/java/com/thealgorithms/compression/MoveToFront.java)
+ - 📄 [RunLengthEncoding](src/main/java/com/thealgorithms/compression/RunLengthEncoding.java)
+ - 📄 [ShannonFano](src/main/java/com/thealgorithms/compression/ShannonFano.java)
- 📁 **conversions**
- 📄 [AffineConverter](src/main/java/com/thealgorithms/conversions/AffineConverter.java)
- 📄 [AnyBaseToAnyBase](src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java)
@@ -98,6 +115,7 @@
- 📄 [BinaryToDecimal](src/main/java/com/thealgorithms/conversions/BinaryToDecimal.java)
- 📄 [BinaryToHexadecimal](src/main/java/com/thealgorithms/conversions/BinaryToHexadecimal.java)
- 📄 [BinaryToOctal](src/main/java/com/thealgorithms/conversions/BinaryToOctal.java)
+ - 📄 [CoordinateConverter](src/main/java/com/thealgorithms/conversions/CoordinateConverter.java)
- 📄 [DecimalToAnyBase](src/main/java/com/thealgorithms/conversions/DecimalToAnyBase.java)
- 📄 [DecimalToBinary](src/main/java/com/thealgorithms/conversions/DecimalToBinary.java)
- 📄 [DecimalToHexadecimal](src/main/java/com/thealgorithms/conversions/DecimalToHexadecimal.java)
@@ -118,6 +136,8 @@
- 📄 [PhoneticAlphabetConverter](src/main/java/com/thealgorithms/conversions/PhoneticAlphabetConverter.java)
- 📄 [RgbHsvConversion](src/main/java/com/thealgorithms/conversions/RgbHsvConversion.java)
- 📄 [RomanToInteger](src/main/java/com/thealgorithms/conversions/RomanToInteger.java)
+ - 📄 [TemperatureConverter](src/main/java/com/thealgorithms/conversions/TemperatureConverter.java)
+ - 📄 [TimeConverter](src/main/java/com/thealgorithms/conversions/TimeConverter.java)
- 📄 [TurkishToLatinConversion](src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java)
- 📄 [UnitConversions](src/main/java/com/thealgorithms/conversions/UnitConversions.java)
- 📄 [UnitsConverter](src/main/java/com/thealgorithms/conversions/UnitsConverter.java)
@@ -157,6 +177,7 @@
- 📄 [BoruvkaAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/BoruvkaAlgorithm.java)
- 📄 [ConnectedComponent](src/main/java/com/thealgorithms/datastructures/graphs/ConnectedComponent.java)
- 📄 [Cycles](src/main/java/com/thealgorithms/datastructures/graphs/Cycles.java)
+ - 📄 [DialsAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/DialsAlgorithm.java)
- 📄 [DijkstraAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithm.java)
- 📄 [DijkstraOptimizedAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/DijkstraOptimizedAlgorithm.java)
- 📄 [EdmondsBlossomAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java)
@@ -171,6 +192,7 @@
- 📄 [MatrixGraphs](src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java)
- 📄 [PrimMST](src/main/java/com/thealgorithms/datastructures/graphs/PrimMST.java)
- 📄 [TarjansAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/TarjansAlgorithm.java)
+ - 📄 [TwoSat](src/main/java/com/thealgorithms/datastructures/graphs/TwoSat.java)
- 📄 [UndirectedAdjacencyListGraph](src/main/java/com/thealgorithms/datastructures/graphs/UndirectedAdjacencyListGraph.java)
- 📄 [WelshPowell](src/main/java/com/thealgorithms/datastructures/graphs/WelshPowell.java)
- 📁 **hashmap**
@@ -179,6 +201,7 @@
- 📄 [GenericHashMapUsingArrayList](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayList.java)
- 📄 [HashMap](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/HashMap.java)
- 📄 [HashMapCuckooHashing](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/HashMapCuckooHashing.java)
+ - 📄 [ImmutableHashMap](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/ImmutableHashMap.java)
- 📄 [Intersection](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/Intersection.java)
- 📄 [LinearProbingHashMap](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMap.java)
- 📄 [MainCuckooHashing](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/MainCuckooHashing.java)
@@ -190,6 +213,7 @@
- 📄 [GenericHeap](src/main/java/com/thealgorithms/datastructures/heaps/GenericHeap.java)
- 📄 [Heap](src/main/java/com/thealgorithms/datastructures/heaps/Heap.java)
- 📄 [HeapElement](src/main/java/com/thealgorithms/datastructures/heaps/HeapElement.java)
+ - 📄 [IndexedPriorityQueue](src/main/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueue.java)
- 📄 [KthElementFinder](src/main/java/com/thealgorithms/datastructures/heaps/KthElementFinder.java)
- 📄 [LeftistHeap](src/main/java/com/thealgorithms/datastructures/heaps/LeftistHeap.java)
- 📄 [MaxHeap](src/main/java/com/thealgorithms/datastructures/heaps/MaxHeap.java)
@@ -199,10 +223,12 @@
- 📄 [MinPriorityQueue](src/main/java/com/thealgorithms/datastructures/heaps/MinPriorityQueue.java)
- 📁 **lists**
- 📄 [CircleLinkedList](src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java)
+ - 📄 [CircularDoublyLinkedList](src/main/java/com/thealgorithms/datastructures/lists/CircularDoublyLinkedList.java)
- 📄 [CountSinglyLinkedListRecursion](src/main/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursion.java)
- 📄 [CreateAndDetectLoop](src/main/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoop.java)
- 📄 [CursorLinkedList](src/main/java/com/thealgorithms/datastructures/lists/CursorLinkedList.java)
- 📄 [DoublyLinkedList](src/main/java/com/thealgorithms/datastructures/lists/DoublyLinkedList.java)
+ - 📄 [FlattenMultilevelLinkedList](src/main/java/com/thealgorithms/datastructures/lists/FlattenMultilevelLinkedList.java)
- 📄 [MergeKSortedLinkedList](src/main/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedList.java)
- 📄 [MergeSortedArrayList](src/main/java/com/thealgorithms/datastructures/lists/MergeSortedArrayList.java)
- 📄 [MergeSortedSinglyLinkedList](src/main/java/com/thealgorithms/datastructures/lists/MergeSortedSinglyLinkedList.java)
@@ -215,6 +241,7 @@
- 📄 [SinglyLinkedListNode](src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedListNode.java)
- 📄 [SkipList](src/main/java/com/thealgorithms/datastructures/lists/SkipList.java)
- 📄 [SortedLinkedList](src/main/java/com/thealgorithms/datastructures/lists/SortedLinkedList.java)
+ - 📄 [TortoiseHareAlgo](src/main/java/com/thealgorithms/datastructures/lists/TortoiseHareAlgo.java)
- 📁 **queues**
- 📄 [CircularQueue](src/main/java/com/thealgorithms/datastructures/queues/CircularQueue.java)
- 📄 [Deque](src/main/java/com/thealgorithms/datastructures/queues/Deque.java)
@@ -241,8 +268,10 @@
- 📄 [BSTRecursiveGeneric](src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java)
- 📄 [BTree](src/main/java/com/thealgorithms/datastructures/trees/BTree.java)
- 📄 [BinaryTree](src/main/java/com/thealgorithms/datastructures/trees/BinaryTree.java)
+ - 📄 [BinaryTreeToString](src/main/java/com/thealgorithms/datastructures/trees/BinaryTreeToString.java)
- 📄 [BoundaryTraversal](src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java)
- 📄 [CeilInBinarySearchTree](src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java)
+ - 📄 [CentroidDecomposition](src/main/java/com/thealgorithms/datastructures/trees/CentroidDecomposition.java)
- 📄 [CheckBinaryTreeIsValidBST](src/main/java/com/thealgorithms/datastructures/trees/CheckBinaryTreeIsValidBST.java)
- 📄 [CheckIfBinaryTreeBalanced](src/main/java/com/thealgorithms/datastructures/trees/CheckIfBinaryTreeBalanced.java)
- 📄 [CheckTreeIsSymmetric](src/main/java/com/thealgorithms/datastructures/trees/CheckTreeIsSymmetric.java)
@@ -262,6 +291,7 @@
- 📄 [SameTreesCheck](src/main/java/com/thealgorithms/datastructures/trees/SameTreesCheck.java)
- 📄 [SegmentTree](src/main/java/com/thealgorithms/datastructures/trees/SegmentTree.java)
- 📄 [SplayTree](src/main/java/com/thealgorithms/datastructures/trees/SplayTree.java)
+ - 📄 [ThreadedBinaryTree](src/main/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTree.java)
- 📄 [Treap](src/main/java/com/thealgorithms/datastructures/trees/Treap.java)
- 📄 [TreeRandomNode](src/main/java/com/thealgorithms/datastructures/trees/TreeRandomNode.java)
- 📄 [Trie](src/main/java/com/thealgorithms/datastructures/trees/Trie.java)
@@ -299,6 +329,7 @@
- 📄 [ClimbingStairs](src/main/java/com/thealgorithms/dynamicprogramming/ClimbingStairs.java)
- 📄 [CoinChange](src/main/java/com/thealgorithms/dynamicprogramming/CoinChange.java)
- 📄 [CountFriendsPairing](src/main/java/com/thealgorithms/dynamicprogramming/CountFriendsPairing.java)
+ - 📄 [DamerauLevenshteinDistance](src/main/java/com/thealgorithms/dynamicprogramming/DamerauLevenshteinDistance.java)
- 📄 [DiceThrow](src/main/java/com/thealgorithms/dynamicprogramming/DiceThrow.java)
- 📄 [EditDistance](src/main/java/com/thealgorithms/dynamicprogramming/EditDistance.java)
- 📄 [EggDropping](src/main/java/com/thealgorithms/dynamicprogramming/EggDropping.java)
@@ -319,9 +350,11 @@
- 📄 [LongestValidParentheses](src/main/java/com/thealgorithms/dynamicprogramming/LongestValidParentheses.java)
- 📄 [MatrixChainMultiplication](src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplication.java)
- 📄 [MatrixChainRecursiveTopDownMemoisation](src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisation.java)
+ - 📄 [MaximumProductSubarray](src/main/java/com/thealgorithms/dynamicprogramming/MaximumProductSubarray.java)
- 📄 [MaximumSumOfNonAdjacentElements](src/main/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElements.java)
- 📄 [MinimumPathSum](src/main/java/com/thealgorithms/dynamicprogramming/MinimumPathSum.java)
- 📄 [MinimumSumPartition](src/main/java/com/thealgorithms/dynamicprogramming/MinimumSumPartition.java)
+ - 📄 [NeedlemanWunsch](src/main/java/com/thealgorithms/dynamicprogramming/NeedlemanWunsch.java)
- 📄 [NewManShanksPrime](src/main/java/com/thealgorithms/dynamicprogramming/NewManShanksPrime.java)
- 📄 [OptimalJobScheduling](src/main/java/com/thealgorithms/dynamicprogramming/OptimalJobScheduling.java)
- 📄 [PalindromicPartitioning](src/main/java/com/thealgorithms/dynamicprogramming/PalindromicPartitioning.java)
@@ -329,6 +362,7 @@
- 📄 [RegexMatching](src/main/java/com/thealgorithms/dynamicprogramming/RegexMatching.java)
- 📄 [RodCutting](src/main/java/com/thealgorithms/dynamicprogramming/RodCutting.java)
- 📄 [ShortestCommonSupersequenceLength](src/main/java/com/thealgorithms/dynamicprogramming/ShortestCommonSupersequenceLength.java)
+ - 📄 [SmithWaterman](src/main/java/com/thealgorithms/dynamicprogramming/SmithWaterman.java)
- 📄 [SubsetCount](src/main/java/com/thealgorithms/dynamicprogramming/SubsetCount.java)
- 📄 [SubsetSum](src/main/java/com/thealgorithms/dynamicprogramming/SubsetSum.java)
- 📄 [SubsetSumSpaceOptimized](src/main/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimized.java)
@@ -340,18 +374,34 @@
- 📄 [WildcardMatching](src/main/java/com/thealgorithms/dynamicprogramming/WildcardMatching.java)
- 📄 [WineProblem](src/main/java/com/thealgorithms/dynamicprogramming/WineProblem.java)
- 📁 **geometry**
+ - 📄 [BentleyOttmann](src/main/java/com/thealgorithms/geometry/BentleyOttmann.java)
- 📄 [BresenhamLine](src/main/java/com/thealgorithms/geometry/BresenhamLine.java)
- 📄 [ConvexHull](src/main/java/com/thealgorithms/geometry/ConvexHull.java)
+ - 📄 [DDALine](src/main/java/com/thealgorithms/geometry/DDALine.java)
- 📄 [GrahamScan](src/main/java/com/thealgorithms/geometry/GrahamScan.java)
+ - 📄 [Haversine](src/main/java/com/thealgorithms/geometry/Haversine.java)
- 📄 [MidpointCircle](src/main/java/com/thealgorithms/geometry/MidpointCircle.java)
- 📄 [MidpointEllipse](src/main/java/com/thealgorithms/geometry/MidpointEllipse.java)
- 📄 [Point](src/main/java/com/thealgorithms/geometry/Point.java)
+ - 📄 [WusLine](src/main/java/com/thealgorithms/geometry/WusLine.java)
- 📁 **graph**
+ - 📄 [BronKerbosch](src/main/java/com/thealgorithms/graph/BronKerbosch.java)
- 📄 [ConstrainedShortestPath](src/main/java/com/thealgorithms/graph/ConstrainedShortestPath.java)
+ - 📄 [Dinic](src/main/java/com/thealgorithms/graph/Dinic.java)
+ - 📄 [Edmonds](src/main/java/com/thealgorithms/graph/Edmonds.java)
+ - 📄 [EdmondsKarp](src/main/java/com/thealgorithms/graph/EdmondsKarp.java)
+ - 📄 [GomoryHuTree](src/main/java/com/thealgorithms/graph/GomoryHuTree.java)
+ - 📄 [HierholzerAlgorithm](src/main/java/com/thealgorithms/graph/HierholzerAlgorithm.java)
+ - 📄 [HierholzerEulerianPath](src/main/java/com/thealgorithms/graph/HierholzerEulerianPath.java)
- 📄 [HopcroftKarp](src/main/java/com/thealgorithms/graph/HopcroftKarp.java)
+ - 📄 [HungarianAlgorithm](src/main/java/com/thealgorithms/graph/HungarianAlgorithm.java)
- 📄 [PredecessorConstrainedDfs](src/main/java/com/thealgorithms/graph/PredecessorConstrainedDfs.java)
+ - 📄 [PushRelabel](src/main/java/com/thealgorithms/graph/PushRelabel.java)
+ - 📄 [StoerWagner](src/main/java/com/thealgorithms/graph/StoerWagner.java)
- 📄 [StronglyConnectedComponentOptimized](src/main/java/com/thealgorithms/graph/StronglyConnectedComponentOptimized.java)
- 📄 [TravelingSalesman](src/main/java/com/thealgorithms/graph/TravelingSalesman.java)
+ - 📄 [YensKShortestPaths](src/main/java/com/thealgorithms/graph/YensKShortestPaths.java)
+ - 📄 [ZeroOneBfs](src/main/java/com/thealgorithms/graph/ZeroOneBfs.java)
- 📁 **greedyalgorithms**
- 📄 [ActivitySelection](src/main/java/com/thealgorithms/greedyalgorithms/ActivitySelection.java)
- 📄 [BandwidthAllocation](src/main/java/com/thealgorithms/greedyalgorithms/BandwidthAllocation.java)
@@ -381,6 +431,7 @@
- 📄 [AbsoluteMax](src/main/java/com/thealgorithms/maths/AbsoluteMax.java)
- 📄 [AbsoluteMin](src/main/java/com/thealgorithms/maths/AbsoluteMin.java)
- 📄 [AbsoluteValue](src/main/java/com/thealgorithms/maths/AbsoluteValue.java)
+ - 📄 [AbundantNumber](src/main/java/com/thealgorithms/maths/AbundantNumber.java)
- 📄 [AliquotSum](src/main/java/com/thealgorithms/maths/AliquotSum.java)
- 📄 [AmicableNumber](src/main/java/com/thealgorithms/maths/AmicableNumber.java)
- 📄 [Area](src/main/java/com/thealgorithms/maths/Area.java)
@@ -392,6 +443,7 @@
- 📄 [BinomialCoefficient](src/main/java/com/thealgorithms/maths/BinomialCoefficient.java)
- 📄 [CatalanNumbers](src/main/java/com/thealgorithms/maths/CatalanNumbers.java)
- 📄 [Ceil](src/main/java/com/thealgorithms/maths/Ceil.java)
+ - 📄 [ChebyshevIteration](src/main/java/com/thealgorithms/maths/ChebyshevIteration.java)
- 📄 [ChineseRemainderTheorem](src/main/java/com/thealgorithms/maths/ChineseRemainderTheorem.java)
- 📄 [CircularConvolutionFFT](src/main/java/com/thealgorithms/maths/CircularConvolutionFFT.java)
- 📄 [CollatzConjecture](src/main/java/com/thealgorithms/maths/CollatzConjecture.java)
@@ -404,11 +456,13 @@
- 📄 [DistanceFormula](src/main/java/com/thealgorithms/maths/DistanceFormula.java)
- 📄 [DudeneyNumber](src/main/java/com/thealgorithms/maths/DudeneyNumber.java)
- 📄 [EulerMethod](src/main/java/com/thealgorithms/maths/EulerMethod.java)
+ - 📄 [EulerPseudoprime](src/main/java/com/thealgorithms/maths/EulerPseudoprime.java)
- 📄 [EulersFunction](src/main/java/com/thealgorithms/maths/EulersFunction.java)
+ - 📄 [EvilNumber](src/main/java/com/thealgorithms/maths/EvilNumber.java)
+ - 📄 [ExtendedEuclideanAlgorithm](src/main/java/com/thealgorithms/maths/ExtendedEuclideanAlgorithm.java)
- 📄 [FFT](src/main/java/com/thealgorithms/maths/FFT.java)
- 📄 [FFTBluestein](src/main/java/com/thealgorithms/maths/FFTBluestein.java)
- 📄 [Factorial](src/main/java/com/thealgorithms/maths/Factorial.java)
- - 📄 [FactorialRecursion](src/main/java/com/thealgorithms/maths/FactorialRecursion.java)
- 📄 [FastExponentiation](src/main/java/com/thealgorithms/maths/FastExponentiation.java)
- 📄 [FastInverseSqrt](src/main/java/com/thealgorithms/maths/FastInverseSqrt.java)
- 📄 [FibonacciJavaStreams](src/main/java/com/thealgorithms/maths/FibonacciJavaStreams.java)
@@ -426,7 +480,9 @@
- 📄 [GCDRecursion](src/main/java/com/thealgorithms/maths/GCDRecursion.java)
- 📄 [Gaussian](src/main/java/com/thealgorithms/maths/Gaussian.java)
- 📄 [GenericRoot](src/main/java/com/thealgorithms/maths/GenericRoot.java)
+ - 📄 [GermainPrimeAndSafePrime](src/main/java/com/thealgorithms/maths/GermainPrimeAndSafePrime.java)
- 📄 [GoldbachConjecture](src/main/java/com/thealgorithms/maths/GoldbachConjecture.java)
+ - 📄 [HappyNumber](src/main/java/com/thealgorithms/maths/HappyNumber.java)
- 📄 [HarshadNumber](src/main/java/com/thealgorithms/maths/HarshadNumber.java)
- 📄 [HeronsFormula](src/main/java/com/thealgorithms/maths/HeronsFormula.java)
- 📄 [JosephusProblem](src/main/java/com/thealgorithms/maths/JosephusProblem.java)
@@ -440,6 +496,7 @@
- 📄 [LinearDiophantineEquationsSolver](src/main/java/com/thealgorithms/maths/LinearDiophantineEquationsSolver.java)
- 📄 [LongDivision](src/main/java/com/thealgorithms/maths/LongDivision.java)
- 📄 [LucasSeries](src/main/java/com/thealgorithms/maths/LucasSeries.java)
+ - 📄 [LuckyNumber](src/main/java/com/thealgorithms/maths/LuckyNumber.java)
- 📄 [MagicSquare](src/main/java/com/thealgorithms/maths/MagicSquare.java)
- 📄 [MathBuilder](src/main/java/com/thealgorithms/maths/MathBuilder.java)
- 📄 [MaxValue](src/main/java/com/thealgorithms/maths/MaxValue.java)
@@ -447,9 +504,11 @@
- 📄 [Median](src/main/java/com/thealgorithms/maths/Median.java)
- 📄 [MinValue](src/main/java/com/thealgorithms/maths/MinValue.java)
- 📄 [Mode](src/main/java/com/thealgorithms/maths/Mode.java)
+ - 📄 [Neville](src/main/java/com/thealgorithms/maths/Neville.java)
- 📄 [NonRepeatingElement](src/main/java/com/thealgorithms/maths/NonRepeatingElement.java)
- 📄 [NthUglyNumber](src/main/java/com/thealgorithms/maths/NthUglyNumber.java)
- 📄 [NumberOfDigits](src/main/java/com/thealgorithms/maths/NumberOfDigits.java)
+ - 📄 [NumberPersistence](src/main/java/com/thealgorithms/maths/NumberPersistence.java)
- 📄 [PalindromeNumber](src/main/java/com/thealgorithms/maths/PalindromeNumber.java)
- 📄 [ParseInteger](src/main/java/com/thealgorithms/maths/ParseInteger.java)
- 📄 [PascalTriangle](src/main/java/com/thealgorithms/maths/PascalTriangle.java)
@@ -457,9 +516,11 @@
- 📄 [PerfectNumber](src/main/java/com/thealgorithms/maths/PerfectNumber.java)
- 📄 [PerfectSquare](src/main/java/com/thealgorithms/maths/PerfectSquare.java)
- 📄 [Perimeter](src/main/java/com/thealgorithms/maths/Perimeter.java)
+ - 📄 [PiApproximation](src/main/java/com/thealgorithms/maths/PiApproximation.java)
- 📄 [PiNilakantha](src/main/java/com/thealgorithms/maths/PiNilakantha.java)
- 📄 [PollardRho](src/main/java/com/thealgorithms/maths/PollardRho.java)
- 📄 [Pow](src/main/java/com/thealgorithms/maths/Pow.java)
+ - 📄 [PowerOfFour](src/main/java/com/thealgorithms/maths/PowerOfFour.java)
- 📄 [PowerOfTwoOrNot](src/main/java/com/thealgorithms/maths/PowerOfTwoOrNot.java)
- 📄 [PowerUsingRecursion](src/main/java/com/thealgorithms/maths/PowerUsingRecursion.java)
- 📁 **Prime**
@@ -475,8 +536,10 @@
- 📄 [ReverseNumber](src/main/java/com/thealgorithms/maths/ReverseNumber.java)
- 📄 [RomanNumeralUtil](src/main/java/com/thealgorithms/maths/RomanNumeralUtil.java)
- 📄 [SecondMinMax](src/main/java/com/thealgorithms/maths/SecondMinMax.java)
+ - 📄 [SieveOfAtkin](src/main/java/com/thealgorithms/maths/SieveOfAtkin.java)
- 📄 [SieveOfEratosthenes](src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java)
- 📄 [SimpsonIntegration](src/main/java/com/thealgorithms/maths/SimpsonIntegration.java)
+ - 📄 [SmithNumber](src/main/java/com/thealgorithms/maths/SmithNumber.java)
- 📄 [SolovayStrassenPrimalityTest](src/main/java/com/thealgorithms/maths/SolovayStrassenPrimalityTest.java)
- 📄 [SquareRootWithBabylonianMethod](src/main/java/com/thealgorithms/maths/SquareRootWithBabylonianMethod.java)
- 📄 [SquareRootWithNewtonRaphsonMethod](src/main/java/com/thealgorithms/maths/SquareRootWithNewtonRaphsonMethod.java)
@@ -486,6 +549,7 @@
- 📄 [SumOfArithmeticSeries](src/main/java/com/thealgorithms/maths/SumOfArithmeticSeries.java)
- 📄 [SumOfDigits](src/main/java/com/thealgorithms/maths/SumOfDigits.java)
- 📄 [SumOfOddNumbers](src/main/java/com/thealgorithms/maths/SumOfOddNumbers.java)
+ - 📄 [SumOfSquares](src/main/java/com/thealgorithms/maths/SumOfSquares.java)
- 📄 [SumWithoutArithmeticOperators](src/main/java/com/thealgorithms/maths/SumWithoutArithmeticOperators.java)
- 📄 [TrinomialTriangle](src/main/java/com/thealgorithms/maths/TrinomialTriangle.java)
- 📄 [TwinPrime](src/main/java/com/thealgorithms/maths/TwinPrime.java)
@@ -493,8 +557,10 @@
- 📄 [VampireNumber](src/main/java/com/thealgorithms/maths/VampireNumber.java)
- 📄 [VectorCrossProduct](src/main/java/com/thealgorithms/maths/VectorCrossProduct.java)
- 📄 [Volume](src/main/java/com/thealgorithms/maths/Volume.java)
+ - 📄 [ZellersCongruence](src/main/java/com/thealgorithms/maths/ZellersCongruence.java)
- 📁 **matrix**
- 📄 [InverseOfMatrix](src/main/java/com/thealgorithms/matrix/InverseOfMatrix.java)
+ - 📄 [LUDecomposition](src/main/java/com/thealgorithms/matrix/LUDecomposition.java)
- 📄 [MatrixMultiplication](src/main/java/com/thealgorithms/matrix/MatrixMultiplication.java)
- 📄 [MatrixRank](src/main/java/com/thealgorithms/matrix/MatrixRank.java)
- 📄 [MatrixTranspose](src/main/java/com/thealgorithms/matrix/MatrixTranspose.java)
@@ -503,6 +569,7 @@
- 📄 [PrintAMatrixInSpiralOrder](src/main/java/com/thealgorithms/matrix/PrintAMatrixInSpiralOrder.java)
- 📄 [RotateMatrixBy90Degrees](src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java)
- 📄 [SolveSystem](src/main/java/com/thealgorithms/matrix/SolveSystem.java)
+ - 📄 [StochasticMatrix](src/main/java/com/thealgorithms/matrix/StochasticMatrix.java)
- 📁 **matrixexponentiation**
- 📄 [Fibonacci](src/main/java/com/thealgorithms/matrix/matrixexponentiation/Fibonacci.java)
- 📁 **utils**
@@ -538,12 +605,11 @@
- 📄 [Dijkstra](src/main/java/com/thealgorithms/others/Dijkstra.java)
- 📄 [FloydTriangle](src/main/java/com/thealgorithms/others/FloydTriangle.java)
- 📄 [GaussLegendre](src/main/java/com/thealgorithms/others/GaussLegendre.java)
- - 📄 [HappyNumbersSeq](src/main/java/com/thealgorithms/others/HappyNumbersSeq.java)
- 📄 [Huffman](src/main/java/com/thealgorithms/others/Huffman.java)
- 📄 [Implementing_auto_completing_features_using_trie](src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java)
- 📄 [InsertDeleteInArray](src/main/java/com/thealgorithms/others/InsertDeleteInArray.java)
+ - 📄 [IterativeFloodFill](src/main/java/com/thealgorithms/others/IterativeFloodFill.java)
- 📄 [KochSnowflake](src/main/java/com/thealgorithms/others/KochSnowflake.java)
- - 📄 [Krishnamurthy](src/main/java/com/thealgorithms/others/Krishnamurthy.java)
- 📄 [LineSweep](src/main/java/com/thealgorithms/others/LineSweep.java)
- 📄 [LinearCongruentialGenerator](src/main/java/com/thealgorithms/others/LinearCongruentialGenerator.java)
- 📄 [LowestBasePalindrome](src/main/java/com/thealgorithms/others/LowestBasePalindrome.java)
@@ -552,18 +618,28 @@
- 📄 [MaximumSumOfDistinctSubarraysWithLengthK](src/main/java/com/thealgorithms/others/MaximumSumOfDistinctSubarraysWithLengthK.java)
- 📄 [MemoryManagementAlgorithms](src/main/java/com/thealgorithms/others/MemoryManagementAlgorithms.java)
- 📄 [MiniMaxAlgorithm](src/main/java/com/thealgorithms/others/MiniMaxAlgorithm.java)
+ - 📄 [MosAlgorithm](src/main/java/com/thealgorithms/others/MosAlgorithm.java)
- 📄 [PageRank](src/main/java/com/thealgorithms/others/PageRank.java)
- 📄 [PasswordGen](src/main/java/com/thealgorithms/others/PasswordGen.java)
- 📄 [PerlinNoise](src/main/java/com/thealgorithms/others/PerlinNoise.java)
- - 📄 [PrintAMatrixInSpiralOrder](src/main/java/com/thealgorithms/others/PrintAMatrixInSpiralOrder.java)
- 📄 [QueueUsingTwoStacks](src/main/java/com/thealgorithms/others/QueueUsingTwoStacks.java)
- 📄 [SkylineProblem](src/main/java/com/thealgorithms/others/SkylineProblem.java)
- 📄 [TwoPointers](src/main/java/com/thealgorithms/others/TwoPointers.java)
- 📄 [Verhoeff](src/main/java/com/thealgorithms/others/Verhoeff.java)
- 📁 **cn**
- 📄 [HammingDistance](src/main/java/com/thealgorithms/others/cn/HammingDistance.java)
+ - 📁 **physics**
+ - 📄 [CoulombsLaw](src/main/java/com/thealgorithms/physics/CoulombsLaw.java)
+ - 📄 [DampedOscillator](src/main/java/com/thealgorithms/physics/DampedOscillator.java)
+ - 📄 [ElasticCollision2D](src/main/java/com/thealgorithms/physics/ElasticCollision2D.java)
+ - 📄 [Gravitation](src/main/java/com/thealgorithms/physics/Gravitation.java)
+ - 📄 [GroundToGroundProjectileMotion](src/main/java/com/thealgorithms/physics/GroundToGroundProjectileMotion.java)
+ - 📄 [Kinematics](src/main/java/com/thealgorithms/physics/Kinematics.java)
+ - 📄 [ProjectileMotion](src/main/java/com/thealgorithms/physics/ProjectileMotion.java)
+ - 📄 [SimplePendulumRK4](src/main/java/com/thealgorithms/physics/SimplePendulumRK4.java)
+ - 📄 [SnellLaw](src/main/java/com/thealgorithms/physics/SnellLaw.java)
+ - 📄 [ThinLens](src/main/java/com/thealgorithms/physics/ThinLens.java)
- 📁 **puzzlesandgames**
- - 📄 [Sudoku](src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java)
- 📄 [TowerOfHanoi](src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java)
- 📄 [WordBoggle](src/main/java/com/thealgorithms/puzzlesandgames/WordBoggle.java)
- 📁 **randomized**
@@ -574,8 +650,11 @@
- 📄 [RandomizedQuickSort](src/main/java/com/thealgorithms/randomized/RandomizedQuickSort.java)
- 📄 [ReservoirSampling](src/main/java/com/thealgorithms/randomized/ReservoirSampling.java)
- 📁 **recursion**
+ - 📄 [DiceThrower](src/main/java/com/thealgorithms/recursion/DiceThrower.java)
+ - 📄 [FactorialRecursion](src/main/java/com/thealgorithms/recursion/FactorialRecursion.java)
- 📄 [FibonacciSeries](src/main/java/com/thealgorithms/recursion/FibonacciSeries.java)
- 📄 [GenerateSubsets](src/main/java/com/thealgorithms/recursion/GenerateSubsets.java)
+ - 📄 [SylvesterSequence](src/main/java/com/thealgorithms/recursion/SylvesterSequence.java)
- 📁 **scheduling**
- 📄 [AgingScheduling](src/main/java/com/thealgorithms/scheduling/AgingScheduling.java)
- 📄 [EDFScheduling](src/main/java/com/thealgorithms/scheduling/EDFScheduling.java)
@@ -609,7 +688,7 @@
- 📄 [BoyerMoore](src/main/java/com/thealgorithms/searches/BoyerMoore.java)
- 📄 [BreadthFirstSearch](src/main/java/com/thealgorithms/searches/BreadthFirstSearch.java)
- 📄 [DepthFirstSearch](src/main/java/com/thealgorithms/searches/DepthFirstSearch.java)
- - 📄 [ExponentalSearch](src/main/java/com/thealgorithms/searches/ExponentalSearch.java)
+ - 📄 [ExponentialSearch](src/main/java/com/thealgorithms/searches/ExponentialSearch.java)
- 📄 [FibonacciSearch](src/main/java/com/thealgorithms/searches/FibonacciSearch.java)
- 📄 [HowManyTimesRotated](src/main/java/com/thealgorithms/searches/HowManyTimesRotated.java)
- 📄 [InterpolationSearch](src/main/java/com/thealgorithms/searches/InterpolationSearch.java)
@@ -630,6 +709,7 @@
- 📄 [RowColumnWiseSorted2dArrayBinarySearch](src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java)
- 📄 [SaddlebackSearch](src/main/java/com/thealgorithms/searches/SaddlebackSearch.java)
- 📄 [SearchInARowAndColWiseSortedMatrix](src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java)
+ - 📄 [SentinelLinearSearch](src/main/java/com/thealgorithms/searches/SentinelLinearSearch.java)
- 📄 [SortOrderAgnosticBinarySearch](src/main/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearch.java)
- 📄 [SquareRootBinarySearch](src/main/java/com/thealgorithms/searches/SquareRootBinarySearch.java)
- 📄 [TernarySearch](src/main/java/com/thealgorithms/searches/TernarySearch.java)
@@ -641,6 +721,7 @@
- 📄 [MaxSumKSizeSubarray](src/main/java/com/thealgorithms/slidingwindow/MaxSumKSizeSubarray.java)
- 📄 [MaximumSlidingWindow](src/main/java/com/thealgorithms/slidingwindow/MaximumSlidingWindow.java)
- 📄 [MinSumKSizeSubarray](src/main/java/com/thealgorithms/slidingwindow/MinSumKSizeSubarray.java)
+ - 📄 [MinimumWindowSubstring](src/main/java/com/thealgorithms/slidingwindow/MinimumWindowSubstring.java)
- 📄 [ShortestCoprimeSegment](src/main/java/com/thealgorithms/slidingwindow/ShortestCoprimeSegment.java)
- 📁 **sorts**
- 📄 [AdaptiveMergeSort](src/main/java/com/thealgorithms/sorts/AdaptiveMergeSort.java)
@@ -716,9 +797,12 @@
- 📄 [SortStack](src/main/java/com/thealgorithms/stacks/SortStack.java)
- 📄 [StackPostfixNotation](src/main/java/com/thealgorithms/stacks/StackPostfixNotation.java)
- 📄 [StackUsingTwoQueues](src/main/java/com/thealgorithms/stacks/StackUsingTwoQueues.java)
+ - 📄 [TrappingRainwater](src/main/java/com/thealgorithms/stacks/TrappingRainwater.java)
+ - 📄 [ValidParentheses](src/main/java/com/thealgorithms/stacks/ValidParentheses.java)
- 📁 **strings**
- 📄 [AhoCorasick](src/main/java/com/thealgorithms/strings/AhoCorasick.java)
- 📄 [Alphabetical](src/main/java/com/thealgorithms/strings/Alphabetical.java)
+ - 📄 [AlternativeStringArrange](src/main/java/com/thealgorithms/strings/AlternativeStringArrange.java)
- 📄 [Anagrams](src/main/java/com/thealgorithms/strings/Anagrams.java)
- 📄 [CharactersSame](src/main/java/com/thealgorithms/strings/CharactersSame.java)
- 📄 [CheckVowels](src/main/java/com/thealgorithms/strings/CheckVowels.java)
@@ -726,8 +810,10 @@
- 📄 [CountWords](src/main/java/com/thealgorithms/strings/CountWords.java)
- 📄 [HammingDistance](src/main/java/com/thealgorithms/strings/HammingDistance.java)
- 📄 [HorspoolSearch](src/main/java/com/thealgorithms/strings/HorspoolSearch.java)
+ - 📄 [Isogram](src/main/java/com/thealgorithms/strings/Isogram.java)
- 📄 [Isomorphic](src/main/java/com/thealgorithms/strings/Isomorphic.java)
- 📄 [KMP](src/main/java/com/thealgorithms/strings/KMP.java)
+ - 📄 [LengthOfLastWord](src/main/java/com/thealgorithms/strings/LengthOfLastWord.java)
- 📄 [LetterCombinationsOfPhoneNumber](src/main/java/com/thealgorithms/strings/LetterCombinationsOfPhoneNumber.java)
- 📄 [LongestCommonPrefix](src/main/java/com/thealgorithms/strings/LongestCommonPrefix.java)
- 📄 [LongestNonRepetitiveSubstring](src/main/java/com/thealgorithms/strings/LongestNonRepetitiveSubstring.java)
@@ -750,6 +836,7 @@
- 📄 [Upper](src/main/java/com/thealgorithms/strings/Upper.java)
- 📄 [ValidParentheses](src/main/java/com/thealgorithms/strings/ValidParentheses.java)
- 📄 [WordLadder](src/main/java/com/thealgorithms/strings/WordLadder.java)
+ - 📄 [ZAlgorithm](src/main/java/com/thealgorithms/strings/ZAlgorithm.java)
- 📁 **zigZagPattern**
- 📄 [ZigZagPattern](src/main/java/com/thealgorithms/strings/zigZagPattern/ZigZagPattern.java)
- 📁 **tree**
@@ -764,6 +851,7 @@
- 📁 **backtracking**
- 📄 [AllPathsFromSourceToTargetTest](src/test/java/com/thealgorithms/backtracking/AllPathsFromSourceToTargetTest.java)
- 📄 [ArrayCombinationTest](src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java)
+ - 📄 [CombinationSumTest](src/test/java/com/thealgorithms/backtracking/CombinationSumTest.java)
- 📄 [CombinationTest](src/test/java/com/thealgorithms/backtracking/CombinationTest.java)
- 📄 [CrosswordSolverTest](src/test/java/com/thealgorithms/backtracking/CrosswordSolverTest.java)
- 📄 [FloodFillTest](src/test/java/com/thealgorithms/backtracking/FloodFillTest.java)
@@ -775,14 +863,19 @@
- 📄 [PermutationTest](src/test/java/com/thealgorithms/backtracking/PermutationTest.java)
- 📄 [PowerSumTest](src/test/java/com/thealgorithms/backtracking/PowerSumTest.java)
- 📄 [SubsequenceFinderTest](src/test/java/com/thealgorithms/backtracking/SubsequenceFinderTest.java)
+ - 📄 [SudokuSolverTest](src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java)
+ - 📄 [UniquePermutationTest](src/test/java/com/thealgorithms/backtracking/UniquePermutationTest.java)
- 📄 [WordPatternMatcherTest](src/test/java/com/thealgorithms/backtracking/WordPatternMatcherTest.java)
- 📄 [WordSearchTest](src/test/java/com/thealgorithms/backtracking/WordSearchTest.java)
- 📁 **bitmanipulation**
- 📄 [BcdConversionTest](src/test/java/com/thealgorithms/bitmanipulation/BcdConversionTest.java)
- 📄 [BinaryPalindromeCheckTest](src/test/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheckTest.java)
+ - 📄 [BitRotateTest](src/test/java/com/thealgorithms/bitmanipulation/BitRotateTest.java)
- 📄 [BitSwapTest](src/test/java/com/thealgorithms/bitmanipulation/BitSwapTest.java)
+ - 📄 [BitwiseGCDTest](src/test/java/com/thealgorithms/bitmanipulation/BitwiseGCDTest.java)
- 📄 [BooleanAlgebraGatesTest](src/test/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGatesTest.java)
- 📄 [ClearLeftmostSetBitTest](src/test/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBitTest.java)
+ - 📄 [CountBitsFlipTest](src/test/java/com/thealgorithms/bitmanipulation/CountBitsFlipTest.java)
- 📄 [CountLeadingZerosTest](src/test/java/com/thealgorithms/bitmanipulation/CountLeadingZerosTest.java)
- 📄 [CountSetBitsTest](src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java)
- 📄 [FindNthBitTest](src/test/java/com/thealgorithms/bitmanipulation/FindNthBitTest.java)
@@ -825,6 +918,8 @@
- 📄 [ECCTest](src/test/java/com/thealgorithms/ciphers/ECCTest.java)
- 📄 [HillCipherTest](src/test/java/com/thealgorithms/ciphers/HillCipherTest.java)
- 📄 [MonoAlphabeticTest](src/test/java/com/thealgorithms/ciphers/MonoAlphabeticTest.java)
+ - 📄 [OneTimePadCipherTest](src/test/java/com/thealgorithms/ciphers/OneTimePadCipherTest.java)
+ - 📄 [PermutationCipherTest](src/test/java/com/thealgorithms/ciphers/PermutationCipherTest.java)
- 📄 [PlayfairTest](src/test/java/com/thealgorithms/ciphers/PlayfairTest.java)
- 📄 [PolybiusTest](src/test/java/com/thealgorithms/ciphers/PolybiusTest.java)
- 📄 [RSATest](src/test/java/com/thealgorithms/ciphers/RSATest.java)
@@ -836,6 +931,15 @@
- 📄 [A5CipherTest](src/test/java/com/thealgorithms/ciphers/a5/A5CipherTest.java)
- 📄 [A5KeyStreamGeneratorTest](src/test/java/com/thealgorithms/ciphers/a5/A5KeyStreamGeneratorTest.java)
- 📄 [LFSRTest](src/test/java/com/thealgorithms/ciphers/a5/LFSRTest.java)
+ - 📁 **compression**
+ - 📄 [ArithmeticCodingTest](src/test/java/com/thealgorithms/compression/ArithmeticCodingTest.java)
+ - 📄 [BurrowsWheelerTransformTest](src/test/java/com/thealgorithms/compression/BurrowsWheelerTransformTest.java)
+ - 📄 [LZ77Test](src/test/java/com/thealgorithms/compression/LZ77Test.java)
+ - 📄 [LZ78Test](src/test/java/com/thealgorithms/compression/LZ78Test.java)
+ - 📄 [LZWTest](src/test/java/com/thealgorithms/compression/LZWTest.java)
+ - 📄 [MoveToFrontTest](src/test/java/com/thealgorithms/compression/MoveToFrontTest.java)
+ - 📄 [RunLengthEncodingTest](src/test/java/com/thealgorithms/compression/RunLengthEncodingTest.java)
+ - 📄 [ShannonFanoTest](src/test/java/com/thealgorithms/compression/ShannonFanoTest.java)
- 📁 **conversions**
- 📄 [AffineConverterTest](src/test/java/com/thealgorithms/conversions/AffineConverterTest.java)
- 📄 [AnyBaseToDecimalTest](src/test/java/com/thealgorithms/conversions/AnyBaseToDecimalTest.java)
@@ -844,6 +948,7 @@
- 📄 [BinaryToDecimalTest](src/test/java/com/thealgorithms/conversions/BinaryToDecimalTest.java)
- 📄 [BinaryToHexadecimalTest](src/test/java/com/thealgorithms/conversions/BinaryToHexadecimalTest.java)
- 📄 [BinaryToOctalTest](src/test/java/com/thealgorithms/conversions/BinaryToOctalTest.java)
+ - 📄 [CoordinateConverterTest](src/test/java/com/thealgorithms/conversions/CoordinateConverterTest.java)
- 📄 [DecimalToAnyBaseTest](src/test/java/com/thealgorithms/conversions/DecimalToAnyBaseTest.java)
- 📄 [DecimalToBinaryTest](src/test/java/com/thealgorithms/conversions/DecimalToBinaryTest.java)
- 📄 [DecimalToHexadecimalTest](src/test/java/com/thealgorithms/conversions/DecimalToHexadecimalTest.java)
@@ -863,6 +968,8 @@
- 📄 [OctalToHexadecimalTest](src/test/java/com/thealgorithms/conversions/OctalToHexadecimalTest.java)
- 📄 [PhoneticAlphabetConverterTest](src/test/java/com/thealgorithms/conversions/PhoneticAlphabetConverterTest.java)
- 📄 [RomanToIntegerTest](src/test/java/com/thealgorithms/conversions/RomanToIntegerTest.java)
+ - 📄 [TemperatureConverterTest](src/test/java/com/thealgorithms/conversions/TemperatureConverterTest.java)
+ - 📄 [TimeConverterTest](src/test/java/com/thealgorithms/conversions/TimeConverterTest.java)
- 📄 [TurkishToLatinConversionTest](src/test/java/com/thealgorithms/conversions/TurkishToLatinConversionTest.java)
- 📄 [UnitConversionsTest](src/test/java/com/thealgorithms/conversions/UnitConversionsTest.java)
- 📄 [UnitsConverterTest](src/test/java/com/thealgorithms/conversions/UnitsConverterTest.java)
@@ -895,8 +1002,11 @@
- 📄 [DynamicArrayTest](src/test/java/com/thealgorithms/datastructures/dynamicarray/DynamicArrayTest.java)
- 📁 **graphs**
- 📄 [AStarTest](src/test/java/com/thealgorithms/datastructures/graphs/AStarTest.java)
+ - 📄 [BellmanFordTest](src/test/java/com/thealgorithms/datastructures/graphs/BellmanFordTest.java)
- 📄 [BipartiteGraphDFSTest](src/test/java/com/thealgorithms/datastructures/graphs/BipartiteGraphDFSTest.java)
- 📄 [BoruvkaAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/BoruvkaAlgorithmTest.java)
+ - 📄 [ConnectedComponentTest](src/test/java/com/thealgorithms/datastructures/graphs/ConnectedComponentTest.java)
+ - 📄 [DialsAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/DialsAlgorithmTest.java)
- 📄 [DijkstraAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java)
- 📄 [DijkstraOptimizedAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/DijkstraOptimizedAlgorithmTest.java)
- 📄 [EdmondsBlossomAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java)
@@ -910,6 +1020,7 @@
- 📄 [MatrixGraphsTest](src/test/java/com/thealgorithms/datastructures/graphs/MatrixGraphsTest.java)
- 📄 [PrimMSTTest](src/test/java/com/thealgorithms/datastructures/graphs/PrimMSTTest.java)
- 📄 [TarjansAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/TarjansAlgorithmTest.java)
+ - 📄 [TwoSatTest](src/test/java/com/thealgorithms/datastructures/graphs/TwoSatTest.java)
- 📄 [WelshPowellTest](src/test/java/com/thealgorithms/datastructures/graphs/WelshPowellTest.java)
- 📁 **hashmap**
- 📁 **hashing**
@@ -917,6 +1028,7 @@
- 📄 [GenericHashMapUsingArrayTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java)
- 📄 [HashMapCuckooHashingTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/HashMapCuckooHashingTest.java)
- 📄 [HashMapTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/HashMapTest.java)
+ - 📄 [ImmutableHashMapTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/ImmutableHashMapTest.java)
- 📄 [IntersectionTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/IntersectionTest.java)
- 📄 [LinearProbingHashMapTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMapTest.java)
- 📄 [MajorityElementTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/MajorityElementTest.java)
@@ -925,6 +1037,7 @@
- 📄 [FibonacciHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/FibonacciHeapTest.java)
- 📄 [GenericHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/GenericHeapTest.java)
- 📄 [HeapElementTest](src/test/java/com/thealgorithms/datastructures/heaps/HeapElementTest.java)
+ - 📄 [IndexedPriorityQueueTest](src/test/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueueTest.java)
- 📄 [KthElementFinderTest](src/test/java/com/thealgorithms/datastructures/heaps/KthElementFinderTest.java)
- 📄 [LeftistHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/LeftistHeapTest.java)
- 📄 [MaxHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/MaxHeapTest.java)
@@ -934,9 +1047,11 @@
- 📄 [MinPriorityQueueTest](src/test/java/com/thealgorithms/datastructures/heaps/MinPriorityQueueTest.java)
- 📁 **lists**
- 📄 [CircleLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java)
+ - 📄 [CircularDoublyLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/CircularDoublyLinkedListTest.java)
- 📄 [CountSinglyLinkedListRecursionTest](src/test/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursionTest.java)
- 📄 [CreateAndDetectLoopTest](src/test/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoopTest.java)
- 📄 [CursorLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/CursorLinkedListTest.java)
+ - 📄 [FlattenMultilevelLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/FlattenMultilevelLinkedListTest.java)
- 📄 [MergeKSortedLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedListTest.java)
- 📄 [MergeSortedArrayListTest](src/test/java/com/thealgorithms/datastructures/lists/MergeSortedArrayListTest.java)
- 📄 [MergeSortedSinglyLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/MergeSortedSinglyLinkedListTest.java)
@@ -947,6 +1062,7 @@
- 📄 [SinglyLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java)
- 📄 [SkipListTest](src/test/java/com/thealgorithms/datastructures/lists/SkipListTest.java)
- 📄 [SortedLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/SortedLinkedListTest.java)
+ - 📄 [TortoiseHareAlgoTest](src/test/java/com/thealgorithms/datastructures/lists/TortoiseHareAlgoTest.java)
- 📁 **queues**
- 📄 [CircularQueueTest](src/test/java/com/thealgorithms/datastructures/queues/CircularQueueTest.java)
- 📄 [DequeTest](src/test/java/com/thealgorithms/datastructures/queues/DequeTest.java)
@@ -967,11 +1083,14 @@
- 📄 [AVLTreeTest](src/test/java/com/thealgorithms/datastructures/trees/AVLTreeTest.java)
- 📄 [BSTFromSortedArrayTest](src/test/java/com/thealgorithms/datastructures/trees/BSTFromSortedArrayTest.java)
- 📄 [BSTIterativeTest](src/test/java/com/thealgorithms/datastructures/trees/BSTIterativeTest.java)
+ - 📄 [BSTRecursiveGenericTest](src/test/java/com/thealgorithms/datastructures/trees/BSTRecursiveGenericTest.java)
- 📄 [BSTRecursiveTest](src/test/java/com/thealgorithms/datastructures/trees/BSTRecursiveTest.java)
- 📄 [BTreeTest](src/test/java/com/thealgorithms/datastructures/trees/BTreeTest.java)
- 📄 [BinaryTreeTest](src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeTest.java)
+ - 📄 [BinaryTreeToStringTest](src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeToStringTest.java)
- 📄 [BoundaryTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java)
- 📄 [CeilInBinarySearchTreeTest](src/test/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTreeTest.java)
+ - 📄 [CentroidDecompositionTest](src/test/java/com/thealgorithms/datastructures/trees/CentroidDecompositionTest.java)
- 📄 [CheckBinaryTreeIsValidBSTTest](src/test/java/com/thealgorithms/datastructures/trees/CheckBinaryTreeIsValidBSTTest.java)
- 📄 [CheckIfBinaryTreeBalancedTest](src/test/java/com/thealgorithms/datastructures/trees/CheckIfBinaryTreeBalancedTest.java)
- 📄 [CheckTreeIsSymmetricTest](src/test/java/com/thealgorithms/datastructures/trees/CheckTreeIsSymmetricTest.java)
@@ -985,11 +1104,15 @@
- 📄 [QuadTreeTest](src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java)
- 📄 [SameTreesCheckTest](src/test/java/com/thealgorithms/datastructures/trees/SameTreesCheckTest.java)
- 📄 [SplayTreeTest](src/test/java/com/thealgorithms/datastructures/trees/SplayTreeTest.java)
+ - 📄 [ThreadedBinaryTreeTest](src/test/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTreeTest.java)
- 📄 [TreapTest](src/test/java/com/thealgorithms/datastructures/trees/TreapTest.java)
- 📄 [TreeTestUtils](src/test/java/com/thealgorithms/datastructures/trees/TreeTestUtils.java)
- 📄 [TrieTest](src/test/java/com/thealgorithms/datastructures/trees/TrieTest.java)
- 📄 [VerticalOrderTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/VerticalOrderTraversalTest.java)
- 📄 [ZigzagTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/ZigzagTraversalTest.java)
+ - 📁 **devutils**
+ - 📁 **entities**
+ - 📄 [ProcessDetailsTest](src/test/java/com/thealgorithms/devutils/entities/ProcessDetailsTest.java)
- 📁 **divideandconquer**
- 📄 [BinaryExponentiationTest](src/test/java/com/thealgorithms/divideandconquer/BinaryExponentiationTest.java)
- 📄 [ClosestPairTest](src/test/java/com/thealgorithms/divideandconquer/ClosestPairTest.java)
@@ -1010,6 +1133,7 @@
- 📄 [CoinChangeTest](src/test/java/com/thealgorithms/dynamicprogramming/CoinChangeTest.java)
- 📄 [CountFriendsPairingTest](src/test/java/com/thealgorithms/dynamicprogramming/CountFriendsPairingTest.java)
- 📄 [DPTest](src/test/java/com/thealgorithms/dynamicprogramming/DPTest.java)
+ - 📄 [DamerauLevenshteinDistanceTest](src/test/java/com/thealgorithms/dynamicprogramming/DamerauLevenshteinDistanceTest.java)
- 📄 [EditDistanceTest](src/test/java/com/thealgorithms/dynamicprogramming/EditDistanceTest.java)
- 📄 [EggDroppingTest](src/test/java/com/thealgorithms/dynamicprogramming/EggDroppingTest.java)
- 📄 [FibonacciTest](src/test/java/com/thealgorithms/dynamicprogramming/FibonacciTest.java)
@@ -1028,9 +1152,11 @@
- 📄 [LongestValidParenthesesTest](src/test/java/com/thealgorithms/dynamicprogramming/LongestValidParenthesesTest.java)
- 📄 [MatrixChainMultiplicationTest](src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplicationTest.java)
- 📄 [MatrixChainRecursiveTopDownMemoisationTest](src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisationTest.java)
+ - 📄 [MaximumProductSubarrayTest](src/test/java/com/thealgorithms/dynamicprogramming/MaximumProductSubarrayTest.java)
- 📄 [MaximumSumOfNonAdjacentElementsTest](src/test/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElementsTest.java)
- 📄 [MinimumPathSumTest](src/test/java/com/thealgorithms/dynamicprogramming/MinimumPathSumTest.java)
- 📄 [MinimumSumPartitionTest](src/test/java/com/thealgorithms/dynamicprogramming/MinimumSumPartitionTest.java)
+ - 📄 [NeedlemanWunschTest](src/test/java/com/thealgorithms/dynamicprogramming/NeedlemanWunschTest.java)
- 📄 [NewManShanksPrimeTest](src/test/java/com/thealgorithms/dynamicprogramming/NewManShanksPrimeTest.java)
- 📄 [OptimalJobSchedulingTest](src/test/java/com/thealgorithms/dynamicprogramming/OptimalJobSchedulingTest.java)
- 📄 [PalindromicPartitioningTest](src/test/java/com/thealgorithms/dynamicprogramming/PalindromicPartitioningTest.java)
@@ -1038,6 +1164,7 @@
- 📄 [RegexMatchingTest](src/test/java/com/thealgorithms/dynamicprogramming/RegexMatchingTest.java)
- 📄 [RodCuttingTest](src/test/java/com/thealgorithms/dynamicprogramming/RodCuttingTest.java)
- 📄 [ShortestCommonSupersequenceLengthTest](src/test/java/com/thealgorithms/dynamicprogramming/ShortestCommonSupersequenceLengthTest.java)
+ - 📄 [SmithWatermanTest](src/test/java/com/thealgorithms/dynamicprogramming/SmithWatermanTest.java)
- 📄 [SubsetCountTest](src/test/java/com/thealgorithms/dynamicprogramming/SubsetCountTest.java)
- 📄 [SubsetSumSpaceOptimizedTest](src/test/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimizedTest.java)
- 📄 [SubsetSumTest](src/test/java/com/thealgorithms/dynamicprogramming/SubsetSumTest.java)
@@ -1049,18 +1176,34 @@
- 📄 [WildcardMatchingTest](src/test/java/com/thealgorithms/dynamicprogramming/WildcardMatchingTest.java)
- 📄 [WineProblemTest](src/test/java/com/thealgorithms/dynamicprogramming/WineProblemTest.java)
- 📁 **geometry**
+ - 📄 [BentleyOttmannTest](src/test/java/com/thealgorithms/geometry/BentleyOttmannTest.java)
- 📄 [BresenhamLineTest](src/test/java/com/thealgorithms/geometry/BresenhamLineTest.java)
- 📄 [ConvexHullTest](src/test/java/com/thealgorithms/geometry/ConvexHullTest.java)
+ - 📄 [DDALineTest](src/test/java/com/thealgorithms/geometry/DDALineTest.java)
- 📄 [GrahamScanTest](src/test/java/com/thealgorithms/geometry/GrahamScanTest.java)
+ - 📄 [HaversineTest](src/test/java/com/thealgorithms/geometry/HaversineTest.java)
- 📄 [MidpointCircleTest](src/test/java/com/thealgorithms/geometry/MidpointCircleTest.java)
- 📄 [MidpointEllipseTest](src/test/java/com/thealgorithms/geometry/MidpointEllipseTest.java)
- 📄 [PointTest](src/test/java/com/thealgorithms/geometry/PointTest.java)
+ - 📄 [WusLineTest](src/test/java/com/thealgorithms/geometry/WusLineTest.java)
- 📁 **graph**
+ - 📄 [BronKerboschTest](src/test/java/com/thealgorithms/graph/BronKerboschTest.java)
- 📄 [ConstrainedShortestPathTest](src/test/java/com/thealgorithms/graph/ConstrainedShortestPathTest.java)
+ - 📄 [DinicTest](src/test/java/com/thealgorithms/graph/DinicTest.java)
+ - 📄 [EdmondsKarpTest](src/test/java/com/thealgorithms/graph/EdmondsKarpTest.java)
+ - 📄 [EdmondsTest](src/test/java/com/thealgorithms/graph/EdmondsTest.java)
+ - 📄 [GomoryHuTreeTest](src/test/java/com/thealgorithms/graph/GomoryHuTreeTest.java)
+ - 📄 [HierholzerAlgorithmTest](src/test/java/com/thealgorithms/graph/HierholzerAlgorithmTest.java)
+ - 📄 [HierholzerEulerianPathTest](src/test/java/com/thealgorithms/graph/HierholzerEulerianPathTest.java)
- 📄 [HopcroftKarpTest](src/test/java/com/thealgorithms/graph/HopcroftKarpTest.java)
+ - 📄 [HungarianAlgorithmTest](src/test/java/com/thealgorithms/graph/HungarianAlgorithmTest.java)
- 📄 [PredecessorConstrainedDfsTest](src/test/java/com/thealgorithms/graph/PredecessorConstrainedDfsTest.java)
+ - 📄 [PushRelabelTest](src/test/java/com/thealgorithms/graph/PushRelabelTest.java)
+ - 📄 [StoerWagnerTest](src/test/java/com/thealgorithms/graph/StoerWagnerTest.java)
- 📄 [StronglyConnectedComponentOptimizedTest](src/test/java/com/thealgorithms/graph/StronglyConnectedComponentOptimizedTest.java)
- 📄 [TravelingSalesmanTest](src/test/java/com/thealgorithms/graph/TravelingSalesmanTest.java)
+ - 📄 [YensKShortestPathsTest](src/test/java/com/thealgorithms/graph/YensKShortestPathsTest.java)
+ - 📄 [ZeroOneBfsTest](src/test/java/com/thealgorithms/graph/ZeroOneBfsTest.java)
- 📁 **greedyalgorithms**
- 📄 [ActivitySelectionTest](src/test/java/com/thealgorithms/greedyalgorithms/ActivitySelectionTest.java)
- 📄 [BandwidthAllocationTest](src/test/java/com/thealgorithms/greedyalgorithms/BandwidthAllocationTest.java)
@@ -1087,6 +1230,7 @@
- 📄 [AbsoluteMaxTest](src/test/java/com/thealgorithms/maths/AbsoluteMaxTest.java)
- 📄 [AbsoluteMinTest](src/test/java/com/thealgorithms/maths/AbsoluteMinTest.java)
- 📄 [AbsoluteValueTest](src/test/java/com/thealgorithms/maths/AbsoluteValueTest.java)
+ - 📄 [AbundantNumberTest](src/test/java/com/thealgorithms/maths/AbundantNumberTest.java)
- 📄 [AliquotSumTest](src/test/java/com/thealgorithms/maths/AliquotSumTest.java)
- 📄 [AmicableNumberTest](src/test/java/com/thealgorithms/maths/AmicableNumberTest.java)
- 📄 [AreaTest](src/test/java/com/thealgorithms/maths/AreaTest.java)
@@ -1098,6 +1242,7 @@
- 📄 [BinomialCoefficientTest](src/test/java/com/thealgorithms/maths/BinomialCoefficientTest.java)
- 📄 [CatalanNumbersTest](src/test/java/com/thealgorithms/maths/CatalanNumbersTest.java)
- 📄 [CeilTest](src/test/java/com/thealgorithms/maths/CeilTest.java)
+ - 📄 [ChebyshevIterationTest](src/test/java/com/thealgorithms/maths/ChebyshevIterationTest.java)
- 📄 [ChineseRemainderTheoremTest](src/test/java/com/thealgorithms/maths/ChineseRemainderTheoremTest.java)
- 📄 [CollatzConjectureTest](src/test/java/com/thealgorithms/maths/CollatzConjectureTest.java)
- 📄 [CombinationsTest](src/test/java/com/thealgorithms/maths/CombinationsTest.java)
@@ -1109,9 +1254,11 @@
- 📄 [DistanceFormulaTest](src/test/java/com/thealgorithms/maths/DistanceFormulaTest.java)
- 📄 [DudeneyNumberTest](src/test/java/com/thealgorithms/maths/DudeneyNumberTest.java)
- 📄 [EulerMethodTest](src/test/java/com/thealgorithms/maths/EulerMethodTest.java)
+ - 📄 [EulerPseudoprimeTest](src/test/java/com/thealgorithms/maths/EulerPseudoprimeTest.java)
- 📄 [EulersFunctionTest](src/test/java/com/thealgorithms/maths/EulersFunctionTest.java)
+ - 📄 [EvilNumberTest](src/test/java/com/thealgorithms/maths/EvilNumberTest.java)
+ - 📄 [ExtendedEuclideanAlgorithmTest](src/test/java/com/thealgorithms/maths/ExtendedEuclideanAlgorithmTest.java)
- 📄 [FFTTest](src/test/java/com/thealgorithms/maths/FFTTest.java)
- - 📄 [FactorialRecursionTest](src/test/java/com/thealgorithms/maths/FactorialRecursionTest.java)
- 📄 [FactorialTest](src/test/java/com/thealgorithms/maths/FactorialTest.java)
- 📄 [FastExponentiationTest](src/test/java/com/thealgorithms/maths/FastExponentiationTest.java)
- 📄 [FastInverseSqrtTests](src/test/java/com/thealgorithms/maths/FastInverseSqrtTests.java)
@@ -1130,26 +1277,34 @@
- 📄 [GCDTest](src/test/java/com/thealgorithms/maths/GCDTest.java)
- 📄 [GaussianTest](src/test/java/com/thealgorithms/maths/GaussianTest.java)
- 📄 [GenericRootTest](src/test/java/com/thealgorithms/maths/GenericRootTest.java)
+ - 📄 [GermainPrimeAndSafePrimeTest](src/test/java/com/thealgorithms/maths/GermainPrimeAndSafePrimeTest.java)
- 📄 [GoldbachConjectureTest](src/test/java/com/thealgorithms/maths/GoldbachConjectureTest.java)
+ - 📄 [HappyNumberTest](src/test/java/com/thealgorithms/maths/HappyNumberTest.java)
- 📄 [HarshadNumberTest](src/test/java/com/thealgorithms/maths/HarshadNumberTest.java)
- 📄 [HeronsFormulaTest](src/test/java/com/thealgorithms/maths/HeronsFormulaTest.java)
- 📄 [JosephusProblemTest](src/test/java/com/thealgorithms/maths/JosephusProblemTest.java)
+ - 📄 [JugglerSequenceTest](src/test/java/com/thealgorithms/maths/JugglerSequenceTest.java)
- 📄 [KaprekarNumbersTest](src/test/java/com/thealgorithms/maths/KaprekarNumbersTest.java)
- 📄 [KaratsubaMultiplicationTest](src/test/java/com/thealgorithms/maths/KaratsubaMultiplicationTest.java)
+ - 📄 [KeithNumberTest](src/test/java/com/thealgorithms/maths/KeithNumberTest.java)
- 📄 [KrishnamurthyNumberTest](src/test/java/com/thealgorithms/maths/KrishnamurthyNumberTest.java)
- 📄 [LeastCommonMultipleTest](src/test/java/com/thealgorithms/maths/LeastCommonMultipleTest.java)
- 📄 [LeonardoNumberTest](src/test/java/com/thealgorithms/maths/LeonardoNumberTest.java)
+ - 📄 [LinearDiophantineEquationsSolverTest](src/test/java/com/thealgorithms/maths/LinearDiophantineEquationsSolverTest.java)
- 📄 [LongDivisionTest](src/test/java/com/thealgorithms/maths/LongDivisionTest.java)
- 📄 [LucasSeriesTest](src/test/java/com/thealgorithms/maths/LucasSeriesTest.java)
+ - 📄 [LuckyNumberTest](src/test/java/com/thealgorithms/maths/LuckyNumberTest.java)
- 📄 [MathBuilderTest](src/test/java/com/thealgorithms/maths/MathBuilderTest.java)
- 📄 [MaxValueTest](src/test/java/com/thealgorithms/maths/MaxValueTest.java)
- 📄 [MeansTest](src/test/java/com/thealgorithms/maths/MeansTest.java)
- 📄 [MedianTest](src/test/java/com/thealgorithms/maths/MedianTest.java)
- 📄 [MinValueTest](src/test/java/com/thealgorithms/maths/MinValueTest.java)
- 📄 [ModeTest](src/test/java/com/thealgorithms/maths/ModeTest.java)
+ - 📄 [NevilleTest](src/test/java/com/thealgorithms/maths/NevilleTest.java)
- 📄 [NonRepeatingElementTest](src/test/java/com/thealgorithms/maths/NonRepeatingElementTest.java)
- 📄 [NthUglyNumberTest](src/test/java/com/thealgorithms/maths/NthUglyNumberTest.java)
- 📄 [NumberOfDigitsTest](src/test/java/com/thealgorithms/maths/NumberOfDigitsTest.java)
+ - 📄 [NumberPersistenceTest](src/test/java/com/thealgorithms/maths/NumberPersistenceTest.java)
- 📄 [PalindromeNumberTest](src/test/java/com/thealgorithms/maths/PalindromeNumberTest.java)
- 📄 [ParseIntegerTest](src/test/java/com/thealgorithms/maths/ParseIntegerTest.java)
- 📄 [PascalTriangleTest](src/test/java/com/thealgorithms/maths/PascalTriangleTest.java)
@@ -1157,8 +1312,10 @@
- 📄 [PerfectNumberTest](src/test/java/com/thealgorithms/maths/PerfectNumberTest.java)
- 📄 [PerfectSquareTest](src/test/java/com/thealgorithms/maths/PerfectSquareTest.java)
- 📄 [PerimeterTest](src/test/java/com/thealgorithms/maths/PerimeterTest.java)
+ - 📄 [PiApproximationTest](src/test/java/com/thealgorithms/maths/PiApproximationTest.java)
- 📄 [PollardRhoTest](src/test/java/com/thealgorithms/maths/PollardRhoTest.java)
- 📄 [PowTest](src/test/java/com/thealgorithms/maths/PowTest.java)
+ - 📄 [PowerOfFourTest](src/test/java/com/thealgorithms/maths/PowerOfFourTest.java)
- 📄 [PowerOfTwoOrNotTest](src/test/java/com/thealgorithms/maths/PowerOfTwoOrNotTest.java)
- 📄 [PowerUsingRecursionTest](src/test/java/com/thealgorithms/maths/PowerUsingRecursionTest.java)
- 📄 [PronicNumberTest](src/test/java/com/thealgorithms/maths/PronicNumberTest.java)
@@ -1166,7 +1323,9 @@
- 📄 [QuadraticEquationSolverTest](src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java)
- 📄 [ReverseNumberTest](src/test/java/com/thealgorithms/maths/ReverseNumberTest.java)
- 📄 [SecondMinMaxTest](src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java)
+ - 📄 [SieveOfAtkinTest](src/test/java/com/thealgorithms/maths/SieveOfAtkinTest.java)
- 📄 [SieveOfEratosthenesTest](src/test/java/com/thealgorithms/maths/SieveOfEratosthenesTest.java)
+ - 📄 [SmithNumberTest](src/test/java/com/thealgorithms/maths/SmithNumberTest.java)
- 📄 [SolovayStrassenPrimalityTestTest](src/test/java/com/thealgorithms/maths/SolovayStrassenPrimalityTestTest.java)
- 📄 [SquareFreeIntegerTest](src/test/java/com/thealgorithms/maths/SquareFreeIntegerTest.java)
- 📄 [SquareRootWithNewtonRaphsonTestMethod](src/test/java/com/thealgorithms/maths/SquareRootWithNewtonRaphsonTestMethod.java)
@@ -1177,12 +1336,14 @@
- 📄 [SumOfArithmeticSeriesTest](src/test/java/com/thealgorithms/maths/SumOfArithmeticSeriesTest.java)
- 📄 [SumOfDigitsTest](src/test/java/com/thealgorithms/maths/SumOfDigitsTest.java)
- 📄 [SumOfOddNumbersTest](src/test/java/com/thealgorithms/maths/SumOfOddNumbersTest.java)
+ - 📄 [SumOfSquaresTest](src/test/java/com/thealgorithms/maths/SumOfSquaresTest.java)
- 📄 [SumWithoutArithmeticOperatorsTest](src/test/java/com/thealgorithms/maths/SumWithoutArithmeticOperatorsTest.java)
- 📄 [TestArmstrong](src/test/java/com/thealgorithms/maths/TestArmstrong.java)
- 📄 [TwinPrimeTest](src/test/java/com/thealgorithms/maths/TwinPrimeTest.java)
- 📄 [UniformNumbersTest](src/test/java/com/thealgorithms/maths/UniformNumbersTest.java)
- 📄 [VampireNumberTest](src/test/java/com/thealgorithms/maths/VampireNumberTest.java)
- 📄 [VolumeTest](src/test/java/com/thealgorithms/maths/VolumeTest.java)
+ - 📄 [ZellersCongruenceTest](src/test/java/com/thealgorithms/maths/ZellersCongruenceTest.java)
- 📁 **prime**
- 📄 [LiouvilleLambdaFunctionTest](src/test/java/com/thealgorithms/maths/prime/LiouvilleLambdaFunctionTest.java)
- 📄 [MillerRabinPrimalityCheckTest](src/test/java/com/thealgorithms/maths/prime/MillerRabinPrimalityCheckTest.java)
@@ -1191,14 +1352,16 @@
- 📄 [PrimeFactorizationTest](src/test/java/com/thealgorithms/maths/prime/PrimeFactorizationTest.java)
- 📁 **matrix**
- 📄 [InverseOfMatrixTest](src/test/java/com/thealgorithms/matrix/InverseOfMatrixTest.java)
+ - 📄 [LUDecompositionTest](src/test/java/com/thealgorithms/matrix/LUDecompositionTest.java)
- 📄 [MatrixMultiplicationTest](src/test/java/com/thealgorithms/matrix/MatrixMultiplicationTest.java)
- 📄 [MatrixRankTest](src/test/java/com/thealgorithms/matrix/MatrixRankTest.java)
- 📄 [MatrixTransposeTest](src/test/java/com/thealgorithms/matrix/MatrixTransposeTest.java)
- 📄 [MatrixUtilTest](src/test/java/com/thealgorithms/matrix/MatrixUtilTest.java)
- 📄 [MedianOfMatrixTest](src/test/java/com/thealgorithms/matrix/MedianOfMatrixTest.java)
- 📄 [MirrorOfMatrixTest](src/test/java/com/thealgorithms/matrix/MirrorOfMatrixTest.java)
+ - 📄 [PrintAMatrixInSpiralOrderTest](src/test/java/com/thealgorithms/matrix/PrintAMatrixInSpiralOrderTest.java)
- 📄 [SolveSystemTest](src/test/java/com/thealgorithms/matrix/SolveSystemTest.java)
- - 📄 [TestPrintMatrixInSpiralOrder](src/test/java/com/thealgorithms/matrix/TestPrintMatrixInSpiralOrder.java)
+ - 📄 [StochasticMatrixTest](src/test/java/com/thealgorithms/matrix/StochasticMatrixTest.java)
- 📁 **misc**
- 📄 [ColorContrastRatioTest](src/test/java/com/thealgorithms/misc/ColorContrastRatioTest.java)
- 📄 [MapReduceTest](src/test/java/com/thealgorithms/misc/MapReduceTest.java)
@@ -1222,23 +1385,39 @@
- 📄 [CountFriendsPairingTest](src/test/java/com/thealgorithms/others/CountFriendsPairingTest.java)
- 📄 [FirstFitCPUTest](src/test/java/com/thealgorithms/others/FirstFitCPUTest.java)
- 📄 [FloydTriangleTest](src/test/java/com/thealgorithms/others/FloydTriangleTest.java)
+ - 📄 [HuffmanTest](src/test/java/com/thealgorithms/others/HuffmanTest.java)
+ - 📄 [InsertDeleteInArrayTest](src/test/java/com/thealgorithms/others/InsertDeleteInArrayTest.java)
+ - 📄 [IterativeFloodFillTest](src/test/java/com/thealgorithms/others/IterativeFloodFillTest.java)
- 📄 [KadaneAlogrithmTest](src/test/java/com/thealgorithms/others/KadaneAlogrithmTest.java)
- 📄 [LineSweepTest](src/test/java/com/thealgorithms/others/LineSweepTest.java)
- 📄 [LinkListSortTest](src/test/java/com/thealgorithms/others/LinkListSortTest.java)
- 📄 [LowestBasePalindromeTest](src/test/java/com/thealgorithms/others/LowestBasePalindromeTest.java)
- 📄 [MaximumSumOfDistinctSubarraysWithLengthKTest](src/test/java/com/thealgorithms/others/MaximumSumOfDistinctSubarraysWithLengthKTest.java)
+ - 📄 [MiniMaxAlgorithmTest](src/test/java/com/thealgorithms/others/MiniMaxAlgorithmTest.java)
+ - 📄 [MosAlgorithmTest](src/test/java/com/thealgorithms/others/MosAlgorithmTest.java)
- 📄 [NewManShanksPrimeTest](src/test/java/com/thealgorithms/others/NewManShanksPrimeTest.java)
- 📄 [NextFitTest](src/test/java/com/thealgorithms/others/NextFitTest.java)
+ - 📄 [PageRankTest](src/test/java/com/thealgorithms/others/PageRankTest.java)
- 📄 [PasswordGenTest](src/test/java/com/thealgorithms/others/PasswordGenTest.java)
+ - 📄 [PerlinNoiseTest](src/test/java/com/thealgorithms/others/PerlinNoiseTest.java)
- 📄 [QueueUsingTwoStacksTest](src/test/java/com/thealgorithms/others/QueueUsingTwoStacksTest.java)
- 📄 [SkylineProblemTest](src/test/java/com/thealgorithms/others/SkylineProblemTest.java)
- - 📄 [TestPrintMatrixInSpiralOrder](src/test/java/com/thealgorithms/others/TestPrintMatrixInSpiralOrder.java)
- 📄 [TwoPointersTest](src/test/java/com/thealgorithms/others/TwoPointersTest.java)
- 📄 [WorstFitCPUTest](src/test/java/com/thealgorithms/others/WorstFitCPUTest.java)
- 📁 **cn**
- 📄 [HammingDistanceTest](src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java)
+ - 📁 **physics**
+ - 📄 [CoulombsLawTest](src/test/java/com/thealgorithms/physics/CoulombsLawTest.java)
+ - 📄 [DampedOscillatorTest](src/test/java/com/thealgorithms/physics/DampedOscillatorTest.java)
+ - 📄 [ElasticCollision2DTest](src/test/java/com/thealgorithms/physics/ElasticCollision2DTest.java)
+ - 📄 [GravitationTest](src/test/java/com/thealgorithms/physics/GravitationTest.java)
+ - 📄 [GroundToGroundProjectileMotionTest](src/test/java/com/thealgorithms/physics/GroundToGroundProjectileMotionTest.java)
+ - 📄 [KinematicsTest](src/test/java/com/thealgorithms/physics/KinematicsTest.java)
+ - 📄 [ProjectileMotionTest](src/test/java/com/thealgorithms/physics/ProjectileMotionTest.java)
+ - 📄 [SimplePendulumRK4Test](src/test/java/com/thealgorithms/physics/SimplePendulumRK4Test.java)
+ - 📄 [SnellLawTest](src/test/java/com/thealgorithms/physics/SnellLawTest.java)
+ - 📄 [ThinLensTest](src/test/java/com/thealgorithms/physics/ThinLensTest.java)
- 📁 **puzzlesandgames**
- - 📄 [SudokuTest](src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java)
- 📄 [TowerOfHanoiTest](src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java)
- 📄 [WordBoggleTest](src/test/java/com/thealgorithms/puzzlesandgames/WordBoggleTest.java)
- 📁 **randomized**
@@ -1249,8 +1428,11 @@
- 📄 [RandomizedQuickSortTest](src/test/java/com/thealgorithms/randomized/RandomizedQuickSortTest.java)
- 📄 [ReservoirSamplingTest](src/test/java/com/thealgorithms/randomized/ReservoirSamplingTest.java)
- 📁 **recursion**
+ - 📄 [DiceThrowerTest](src/test/java/com/thealgorithms/recursion/DiceThrowerTest.java)
+ - 📄 [FactorialRecursionTest](src/test/java/com/thealgorithms/recursion/FactorialRecursionTest.java)
- 📄 [FibonacciSeriesTest](src/test/java/com/thealgorithms/recursion/FibonacciSeriesTest.java)
- 📄 [GenerateSubsetsTest](src/test/java/com/thealgorithms/recursion/GenerateSubsetsTest.java)
+ - 📄 [SylvesterSequenceTest](src/test/java/com/thealgorithms/recursion/SylvesterSequenceTest.java)
- 📁 **scheduling**
- 📄 [AgingSchedulingTest](src/test/java/com/thealgorithms/scheduling/AgingSchedulingTest.java)
- 📄 [EDFSchedulingTest](src/test/java/com/thealgorithms/scheduling/EDFSchedulingTest.java)
@@ -1305,6 +1487,7 @@
- 📄 [RowColumnWiseSorted2dArrayBinarySearchTest](src/test/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearchTest.java)
- 📄 [SaddlebackSearchTest](src/test/java/com/thealgorithms/searches/SaddlebackSearchTest.java)
- 📄 [SearchInARowAndColWiseSortedMatrixTest](src/test/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrixTest.java)
+ - 📄 [SentinelLinearSearchTest](src/test/java/com/thealgorithms/searches/SentinelLinearSearchTest.java)
- 📄 [SortOrderAgnosticBinarySearchTest](src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java)
- 📄 [SquareRootBinarySearchTest](src/test/java/com/thealgorithms/searches/SquareRootBinarySearchTest.java)
- 📄 [TernarySearchTest](src/test/java/com/thealgorithms/searches/TernarySearchTest.java)
@@ -1317,6 +1500,7 @@
- 📄 [MaxSumKSizeSubarrayTest](src/test/java/com/thealgorithms/slidingwindow/MaxSumKSizeSubarrayTest.java)
- 📄 [MaximumSlidingWindowTest](src/test/java/com/thealgorithms/slidingwindow/MaximumSlidingWindowTest.java)
- 📄 [MinSumKSizeSubarrayTest](src/test/java/com/thealgorithms/slidingwindow/MinSumKSizeSubarrayTest.java)
+ - 📄 [MinimumWindowSubstringTest](src/test/java/com/thealgorithms/slidingwindow/MinimumWindowSubstringTest.java)
- 📄 [ShortestCoprimeSegmentTest](src/test/java/com/thealgorithms/slidingwindow/ShortestCoprimeSegmentTest.java)
- 📁 **sorts**
- 📄 [AdaptiveMergeSortTest](src/test/java/com/thealgorithms/sorts/AdaptiveMergeSortTest.java)
@@ -1390,9 +1574,12 @@
- 📄 [SortStackTest](src/test/java/com/thealgorithms/stacks/SortStackTest.java)
- 📄 [StackPostfixNotationTest](src/test/java/com/thealgorithms/stacks/StackPostfixNotationTest.java)
- 📄 [StackUsingTwoQueuesTest](src/test/java/com/thealgorithms/stacks/StackUsingTwoQueuesTest.java)
+ - 📄 [TrappingRainwaterTest](src/test/java/com/thealgorithms/stacks/TrappingRainwaterTest.java)
+ - 📄 [ValidParenthesesTest](src/test/java/com/thealgorithms/stacks/ValidParenthesesTest.java)
- 📁 **strings**
- 📄 [AhoCorasickTest](src/test/java/com/thealgorithms/strings/AhoCorasickTest.java)
- 📄 [AlphabeticalTest](src/test/java/com/thealgorithms/strings/AlphabeticalTest.java)
+ - 📄 [AlternativeStringArrangeTest](src/test/java/com/thealgorithms/strings/AlternativeStringArrangeTest.java)
- 📄 [AnagramsTest](src/test/java/com/thealgorithms/strings/AnagramsTest.java)
- 📄 [CharactersSameTest](src/test/java/com/thealgorithms/strings/CharactersSameTest.java)
- 📄 [CheckVowelsTest](src/test/java/com/thealgorithms/strings/CheckVowelsTest.java)
@@ -1400,7 +1587,9 @@
- 📄 [CountWordsTest](src/test/java/com/thealgorithms/strings/CountWordsTest.java)
- 📄 [HammingDistanceTest](src/test/java/com/thealgorithms/strings/HammingDistanceTest.java)
- 📄 [HorspoolSearchTest](src/test/java/com/thealgorithms/strings/HorspoolSearchTest.java)
+ - 📄 [IsogramTest](src/test/java/com/thealgorithms/strings/IsogramTest.java)
- 📄 [IsomorphicTest](src/test/java/com/thealgorithms/strings/IsomorphicTest.java)
+ - 📄 [LengthOfLastWordTest](src/test/java/com/thealgorithms/strings/LengthOfLastWordTest.java)
- 📄 [LetterCombinationsOfPhoneNumberTest](src/test/java/com/thealgorithms/strings/LetterCombinationsOfPhoneNumberTest.java)
- 📄 [LongestCommonPrefixTest](src/test/java/com/thealgorithms/strings/LongestCommonPrefixTest.java)
- 📄 [LongestNonRepetitiveSubstringTest](src/test/java/com/thealgorithms/strings/LongestNonRepetitiveSubstringTest.java)
@@ -1422,6 +1611,7 @@
- 📄 [UpperTest](src/test/java/com/thealgorithms/strings/UpperTest.java)
- 📄 [ValidParenthesesTest](src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java)
- 📄 [WordLadderTest](src/test/java/com/thealgorithms/strings/WordLadderTest.java)
+ - 📄 [ZAlgorithmTest](src/test/java/com/thealgorithms/strings/ZAlgorithmTest.java)
- 📁 **zigZagPattern**
- 📄 [ZigZagPatternTest](src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java)
- 📁 **tree**
diff --git a/pom.xml b/pom.xml
index e0e3516c08eb..d3db730327d3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,7 +20,7 @@
This algorithm performs a Depth First Search (DFS) traversal while keeping track
+ * of visited vertices to avoid cycles. Whenever the destination vertex is reached,
+ * the current path is stored as one valid path. Key Characteristics: Time Complexity: Space Complexity: This implementation is intended for educational purposes. This class provides methods for both left and right circular rotations,
+ * supporting only 32-bit integer operations with proper shift normalization
+ * and error handling. The One-Time Pad is information-theoretically secure if:
+ * This implementation is for educational purposes only and should not be
+ * used in production systems.
+ */
+public final class OneTimePadCipher {
+
+ private static final SecureRandom RANDOM = new SecureRandom();
+
+ private OneTimePadCipher() {
+ // utility class
+ }
+
+ /**
+ * Generates a random key of the given length in bytes.
+ *
+ * @param length the length of the key in bytes, must be non-negative
+ * @return a new random key
+ * @throws IllegalArgumentException if length is negative
+ */
+ public static byte[] generateKey(int length) {
+ if (length < 0) {
+ throw new IllegalArgumentException("length must be non-negative");
+ }
+ byte[] key = new byte[length];
+ RANDOM.nextBytes(key);
+ return key;
+ }
+
+ /**
+ * Encrypts the given plaintext bytes using the provided key.
+ * The key length must be exactly the same as the plaintext length.
+ *
+ * @param plaintext the plaintext bytes, must not be {@code null}
+ * @param key the one-time pad key bytes, must not be {@code null}
+ * @return the ciphertext bytes
+ * @throws IllegalArgumentException if the key length does not match plaintext length
+ * @throws NullPointerException if plaintext or key is {@code null}
+ */
+ public static byte[] encrypt(byte[] plaintext, byte[] key) {
+ validateInputs(plaintext, key);
+ return xor(plaintext, key);
+ }
+
+ /**
+ * Decrypts the given ciphertext bytes using the provided key.
+ * For a One-Time Pad, decryption is identical to encryption:
+ * {@code plaintext = ciphertext XOR key}.
+ *
+ * @param ciphertext the ciphertext bytes, must not be {@code null}
+ * @param key the one-time pad key bytes, must not be {@code null}
+ * @return the decrypted plaintext bytes
+ * @throws IllegalArgumentException if the key length does not match ciphertext length
+ * @throws NullPointerException if ciphertext or key is {@code null}
+ */
+ public static byte[] decrypt(byte[] ciphertext, byte[] key) {
+ validateInputs(ciphertext, key);
+ return xor(ciphertext, key);
+ }
+
+ private static void validateInputs(byte[] input, byte[] key) {
+ Objects.requireNonNull(input, "input must not be null");
+ Objects.requireNonNull(key, "key must not be null");
+ if (input.length != key.length) {
+ throw new IllegalArgumentException("Key length must match input length");
+ }
+ }
+
+ private static byte[] xor(byte[] data, byte[] key) {
+ byte[] result = new byte[data.length];
+ for (int i = 0; i < data.length; i++) {
+ result[i] = (byte) (data[i] ^ key[i]);
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/compression/ArithmeticCoding.java b/src/main/java/com/thealgorithms/compression/ArithmeticCoding.java
new file mode 100644
index 000000000000..b5ccf359d1be
--- /dev/null
+++ b/src/main/java/com/thealgorithms/compression/ArithmeticCoding.java
@@ -0,0 +1,157 @@
+package com.thealgorithms.compression;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An implementation of the Arithmetic Coding algorithm.
+ *
+ *
+ * Arithmetic coding is a form of entropy encoding used in lossless data
+ * compression. It encodes an entire message into a single number, a fraction n
+ * where (0.0 <= n < 1.0). Unlike Huffman coding, which assigns a specific
+ * bit sequence to each symbol, arithmetic coding represents the message as a
+ * sub-interval of the [0, 1) interval.
+ *
+ * This implementation uses BigDecimal for precision to handle the shrinking
+ * intervals, making it suitable for educational purposes to demonstrate the
+ * core logic.
+ *
+ * Time Complexity: O(n*m) for compression and decompression where n is the
+ * length of the input and m is the number of unique symbols, due to the need
+ * to calculate symbol probabilities.
+ *
+ * References:
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * > combinationSum(int[] candidates, int target) {
+ List
> results = new ArrayList<>();
+ if (candidates == null || candidates.length == 0) {
+ return results;
+ }
+
+ // Sort to help with pruning duplicates and early termination
+ Arrays.sort(candidates);
+ backtrack(candidates, target, 0, new ArrayList<>(), results);
+ return results;
+ }
+
+ private static void backtrack(int[] candidates, int remaining, int start, List
> results) {
+ if (remaining == 0) {
+ // Found valid combination; add a copy
+ results.add(new ArrayList<>(combination));
+ return;
+ }
+
+ for (int i = start; i < candidates.length; i++) {
+ int candidate = candidates[i];
+
+ // If candidate is greater than remaining target, further candidates (sorted) will also be too big
+ if (candidate > remaining) {
+ break;
+ }
+
+ // include candidate
+ combination.add(candidate);
+ // Because we can reuse the same element, we pass i (not i + 1)
+ backtrack(candidates, remaining - candidate, i, combination, results);
+ // backtrack: remove last
+ combination.remove(combination.size() - 1);
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/FloodFill.java b/src/main/java/com/thealgorithms/backtracking/FloodFill.java
index c8219ca8ba7e..0f31a9c5a30e 100644
--- a/src/main/java/com/thealgorithms/backtracking/FloodFill.java
+++ b/src/main/java/com/thealgorithms/backtracking/FloodFill.java
@@ -12,8 +12,8 @@ private FloodFill() {
* Get the color at the given coordinates of a 2D image
*
* @param image The image to be filled
- * @param x The x co-ordinate of which color is to be obtained
- * @param y The y co-ordinate of which color is to be obtained
+ * @param x The x coordinate of which color is to be obtained
+ * @param y The y coordinate of which color is to be obtained
*/
public static int getPixel(final int[][] image, final int x, final int y) {
@@ -24,8 +24,8 @@ public static int getPixel(final int[][] image, final int x, final int y) {
* Put the color at the given coordinates of a 2D image
*
* @param image The image to be filled
- * @param x The x co-ordinate at which color is to be filled
- * @param y The y co-ordinate at which color is to be filled
+ * @param x The x coordinate at which color is to be filled
+ * @param y The y coordinate at which color is to be filled
*/
public static void putPixel(final int[][] image, final int x, final int y, final int newColor) {
image[x][y] = newColor;
@@ -35,8 +35,8 @@ public static void putPixel(final int[][] image, final int x, final int y, final
* Fill the 2D image with new color
*
* @param image The image to be filled
- * @param x The x co-ordinate at which color is to be filled
- * @param y The y co-ordinate at which color is to be filled
+ * @param x The x coordinate at which color is to be filled
+ * @param y The y coordinate at which color is to be filled
* @param newColor The new color which to be filled in the image
* @param oldColor The old color which is to be replaced in the image
*/
diff --git a/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java b/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java
new file mode 100644
index 000000000000..543fe2d02b50
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java
@@ -0,0 +1,157 @@
+package com.thealgorithms.backtracking;
+
+/**
+ * Sudoku Solver using Backtracking Algorithm
+ * Solves a 9x9 Sudoku puzzle by filling empty cells with valid digits (1-9)
+ *
+ * @author Navadeep0007
+ */
+public final class SudokuSolver {
+
+ private static final int GRID_SIZE = 9;
+ private static final int SUBGRID_SIZE = 3;
+ private static final int EMPTY_CELL = 0;
+
+ private SudokuSolver() {
+ // Utility class, prevent instantiation
+ }
+
+ /**
+ * Solves the Sudoku puzzle using backtracking
+ *
+ * @param board 9x9 Sudoku board with 0 representing empty cells
+ * @return true if puzzle is solved, false otherwise
+ */
+ public static boolean solveSudoku(int[][] board) {
+ if (board == null || board.length != GRID_SIZE) {
+ return false;
+ }
+
+ for (int row = 0; row < GRID_SIZE; row++) {
+ if (board[row].length != GRID_SIZE) {
+ return false;
+ }
+ }
+
+ return solve(board);
+ }
+
+ /**
+ * Recursive helper method to solve the Sudoku puzzle
+ *
+ * @param board the Sudoku board
+ * @return true if solution is found, false otherwise
+ */
+ private static boolean solve(int[][] board) {
+ for (int row = 0; row < GRID_SIZE; row++) {
+ for (int col = 0; col < GRID_SIZE; col++) {
+ if (board[row][col] == EMPTY_CELL) {
+ for (int number = 1; number <= GRID_SIZE; number++) {
+ if (isValidPlacement(board, row, col, number)) {
+ board[row][col] = number;
+
+ if (solve(board)) {
+ return true;
+ }
+
+ // Backtrack
+ board[row][col] = EMPTY_CELL;
+ }
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks if placing a number at given position is valid
+ *
+ * @param board the Sudoku board
+ * @param row row index
+ * @param col column index
+ * @param number number to place (1-9)
+ * @return true if placement is valid, false otherwise
+ */
+ private static boolean isValidPlacement(int[][] board, int row, int col, int number) {
+ return !isNumberInRow(board, row, number) && !isNumberInColumn(board, col, number) && !isNumberInSubgrid(board, row, col, number);
+ }
+
+ /**
+ * Checks if number exists in the given row
+ *
+ * @param board the Sudoku board
+ * @param row row index
+ * @param number number to check
+ * @return true if number exists in row, false otherwise
+ */
+ private static boolean isNumberInRow(int[][] board, int row, int number) {
+ for (int col = 0; col < GRID_SIZE; col++) {
+ if (board[row][col] == number) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if number exists in the given column
+ *
+ * @param board the Sudoku board
+ * @param col column index
+ * @param number number to check
+ * @return true if number exists in column, false otherwise
+ */
+ private static boolean isNumberInColumn(int[][] board, int col, int number) {
+ for (int row = 0; row < GRID_SIZE; row++) {
+ if (board[row][col] == number) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if number exists in the 3x3 subgrid
+ *
+ * @param board the Sudoku board
+ * @param row row index
+ * @param col column index
+ * @param number number to check
+ * @return true if number exists in subgrid, false otherwise
+ */
+ private static boolean isNumberInSubgrid(int[][] board, int row, int col, int number) {
+ int subgridRowStart = row - row % SUBGRID_SIZE;
+ int subgridColStart = col - col % SUBGRID_SIZE;
+
+ for (int i = subgridRowStart; i < subgridRowStart + SUBGRID_SIZE; i++) {
+ for (int j = subgridColStart; j < subgridColStart + SUBGRID_SIZE; j++) {
+ if (board[i][j] == number) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Prints the Sudoku board
+ *
+ * @param board the Sudoku board
+ */
+ public static void printBoard(int[][] board) {
+ for (int row = 0; row < GRID_SIZE; row++) {
+ if (row % SUBGRID_SIZE == 0 && row != 0) {
+ System.out.println("-----------");
+ }
+ for (int col = 0; col < GRID_SIZE; col++) {
+ if (col % SUBGRID_SIZE == 0 && col != 0) {
+ System.out.print("|");
+ }
+ System.out.print(board[row][col]);
+ }
+ System.out.println();
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/UniquePermutation.java b/src/main/java/com/thealgorithms/backtracking/UniquePermutation.java
new file mode 100644
index 000000000000..4804e247ab03
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/UniquePermutation.java
@@ -0,0 +1,62 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Generates all UNIQUE permutations of a string, even when duplicate characters exist.
+ *
+ * Example:
+ * Input: "AAB"
+ * Output: ["AAB", "ABA", "BAA"]
+ *
+ * Time Complexity: O(n! * n)
+ */
+public final class UniquePermutation {
+
+ private UniquePermutation() {
+ // Prevent instantiation
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ public static List
+ *
+ *
+ *
+ *
+ *
+ * BWT is a reversible data transformation algorithm that rearranges a string into runs of + * similar characters. While not a compression algorithm itself, it significantly improves + * the compressibility of data for subsequent algorithms like Move-to-Front encoding and + * Run-Length Encoding. + *
+ * + *The transform works by: + *
Important: The input string should end with a unique end-of-string marker + * (typically '$') that: + *
Time Complexity: + *
Example:
+ *
+ * Input: "banana$"
+ * Output: BWTResult("annb$aa", 4)
+ * - "annb$aa" is the transformed string (groups similar characters)
+ * - 4 is the index of the original string in the sorted rotations
+ *
+ *
+ * @see Burrows–Wheeler transform (Wikipedia)
+ */
+public final class BurrowsWheelerTransform {
+
+ private BurrowsWheelerTransform() {
+ }
+
+ /**
+ * A container for the result of the forward BWT.
+ * + * Contains the transformed string and the index of the original string + * in the sorted rotations matrix, both of which are required for the + * inverse transformation. + *
+ */ + public static class BWTResult { + /** The transformed string (last column of the sorted rotation matrix) */ + public final String transformed; + + /** The index of the original string in the sorted rotations matrix */ + public final int originalIndex; + + /** + * Constructs a BWTResult with the transformed string and original index. + * + * @param transformed the transformed string (L-column) + * @param originalIndex the index of the original string in sorted rotations + */ + public BWTResult(String transformed, int originalIndex) { + this.transformed = transformed; + this.originalIndex = originalIndex; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + BWTResult bwtResult = (BWTResult) obj; + return originalIndex == bwtResult.originalIndex && transformed.equals(bwtResult.transformed); + } + + @Override + public int hashCode() { + return 31 * transformed.hashCode() + originalIndex; + } + + @Override + public String toString() { + return "BWTResult[transformed=" + transformed + ", originalIndex=" + originalIndex + "]"; + } + } + + /** + * Performs the forward Burrows-Wheeler Transform on the input string. + *+ * The algorithm generates all cyclic rotations of the input, sorts them + * lexicographically, and returns the last column of this sorted matrix + * along with the position of the original string. + *
+ * + *Note: It is strongly recommended that the input string ends with + * a unique end-of-string marker (e.g., '$') that is lexicographically smaller + * than any other character in the string. This ensures correct inversion.
+ * + * @param text the input string to transform; must not be {@code null} + * @return a {@link BWTResult} object containing the transformed string (L-column) + * and the index of the original string in the sorted rotations matrix; + * returns {@code BWTResult("", -1)} for empty input + * @throws NullPointerException if {@code text} is {@code null} + */ + public static BWTResult transform(String text) { + if (text == null || text.isEmpty()) { + return new BWTResult("", -1); + } + + int n = text.length(); + + // Generate all rotations of the input string + String[] rotations = new String[n]; + for (int i = 0; i < n; i++) { + rotations[i] = text.substring(i) + text.substring(0, i); + } + + // Sort rotations lexicographically + Arrays.sort(rotations); + int originalIndex = Arrays.binarySearch(rotations, text); + StringBuilder lastColumn = new StringBuilder(n); + for (int i = 0; i < n; i++) { + lastColumn.append(rotations[i].charAt(n - 1)); + } + + return new BWTResult(lastColumn.toString(), originalIndex); + } + + /** + * Performs the inverse Burrows-Wheeler Transform using the LF-mapping technique. + *+ * The LF-mapping (Last-First mapping) is an efficient method to reconstruct + * the original string from the BWT output without explicitly reconstructing + * the entire sorted rotations matrix. + *
+ * + *The algorithm works by: + *
+ * LZ77 is a lossless data compression algorithm that works by finding repeated + * occurrences of data in a sliding window. It replaces subsequent occurrences + * with references (offset, length) to the first occurrence within the window. + *
+ *+ * This implementation uses a simple sliding window and lookahead buffer approach. + * Output format is a sequence of tuples (offset, length, next_character). + *
+ *+ * Time Complexity: O(n*W) in this naive implementation, where n is the input length + * and W is the window size, due to the search for the longest match. More advanced + * data structures (like suffix trees) can improve this. + *
+ *+ * References: + *
+ * LZ78 is a dictionary-based lossless data compression algorithm. It processes + * input data sequentially, building a dictionary of phrases encountered so far. + * It outputs pairs (dictionary_index, next_character), representing + * the longest match found in the dictionary plus the character that follows it. + *
+ *+ * This implementation builds the dictionary dynamically during compression. + * The dictionary index 0 represents the empty string (no prefix). + *
+ *+ * Time Complexity: O(n) on average for compression and decompression, assuming + * efficient dictionary lookups (using a HashMap), where n is the + * length of the input string. + *
+ *+ * References: + *
+ * LZW is a universal lossless data compression algorithm created by Abraham + * Lempel, Jacob Ziv, and Terry Welch. It works by building a dictionary of + * strings encountered during compression and replacing occurrences of those + * strings with a shorter code. + *
+ * + *+ * This implementation handles standard ASCII characters and provides methods for + * both compression and decompression. + *
+ * Time Complexity: O(n) for both compression and decompression, where n is the + * length of the input string. + *
+ * + *+ * References: + *
+ * MTF is a data transformation algorithm that encodes each symbol in the input + * as its current position in a dynamically-maintained list, then moves that symbol + * to the front of the list. This transformation is particularly effective when used + * after the Burrows-Wheeler Transform (BWT), as BWT groups similar characters together. + *
+ * + *The transform converts runs of repeated characters into sequences of small integers + * (often zeros), which are highly compressible by subsequent entropy encoding algorithms + * like Run-Length Encoding (RLE) or Huffman coding. This technique is used in the + * bzip2 compression algorithm. + *
+ * + *How it works: + *
Time Complexity: + *
Example:
+ *+ * Input: "annb$aa" + * Alphabet: "$abn" (initial order) + * Output: [1, 3, 0, 3, 3, 3, 0] + * + * Step-by-step: + * - 'a': index 1 in [$,a,b,n] → output 1, list becomes [a,$,b,n] + * - 'n': index 3 in [a,$,b,n] → output 3, list becomes [n,a,$,b] + * - 'n': index 0 in [n,a,$,b] → output 0, list stays [n,a,$,b] + * - 'b': index 3 in [n,a,$,b] → output 3, list becomes [b,n,a,$] + * - etc. + * + * Notice how repeated 'n' characters produce zeros after the first occurrence! + *+ * + * @see Move-to-front transform (Wikipedia) + */ +public final class MoveToFront { + + private MoveToFront() { + } + + /** + * Performs the forward Move-to-Front transform. + *
+ * Converts the input string into a list of integers, where each integer represents + * the position of the corresponding character in a dynamically-maintained alphabet list. + *
+ * + *Note: All characters in the input text must exist in the provided alphabet, + * otherwise an {@link IllegalArgumentException} is thrown. The alphabet should contain + * all unique characters that may appear in the input.
+ * + * @param text the input string to transform; if empty, returns an empty list + * @param initialAlphabet a string containing the initial ordered set of symbols + * (e.g., "$abn" or the full ASCII set); must not be empty + * when {@code text} is non-empty + * @return a list of integers representing the transformed data, where each integer + * is the index of the corresponding input character in the current alphabet state + * @throws IllegalArgumentException if {@code text} is non-empty and {@code initialAlphabet} + * is {@code null} or empty + * @throws IllegalArgumentException if any character in {@code text} is not found in + * {@code initialAlphabet} + */ + public static List+ * Reconstructs the original string from the list of indices produced by the + * forward transform. This requires the exact same initial alphabet that was + * used in the forward transform. + *
+ * + *Important: The {@code initialAlphabet} parameter must be identical + * to the one used in the forward transform, including character order, or the + * output will be incorrect.
+ * + * @param indices The list of integers from the forward transform. + * @param initialAlphabet the exact same initial alphabet string used for the forward transform; + * if {@code null} or empty, returns an empty string + * @return the original, untransformed string + * @throws IllegalArgumentException if any index in {@code indices} is negative or + * exceeds the current alphabet size + */ + public static String inverseTransform(CollectionRun-Length Encoding is a simple form of lossless data compression in which + * runs of data (sequences in which the same data value occurs in many + * consecutive data elements) are stored as a single data value and count, + * rather than as the original run. + * + *
This implementation provides methods for both compressing and decompressing + * a string. For example: + *
Time Complexity: O(n) for both compression and decompression, where n is the + * length of the input string. + * + *
References: + *
Shannon-Fano coding is an entropy encoding technique for lossless data + * compression. It assigns variable-length codes to symbols based on their + * frequencies of occurrence. It is a precursor to Huffman coding and works by + * recursively partitioning a sorted list of symbols into two sub-lists with + * nearly equal total frequencies. + * + *
The algorithm works as follows: + *
Time Complexity: O(n^2) in this implementation due to the partitioning logic, + * or O(n log n) if a more optimized partitioning strategy is used. + * Sorting takes O(n log n), where n is the number of unique symbols. + * + *
References: + *
+ */ +public final class ShannonFano { + + /** + * Private constructor to prevent instantiation of this utility class. + */ + private ShannonFano() { + } + + /** + * A private inner class to represent a symbol and its frequency. + * Implements Comparable to allow sorting based on frequency. + */ + private static class Symbol implements ComparableThis class supports conversions between the following units: + *
This class is final and cannot be instantiated. + * + * @author krishna-medapati (https://github.com/krishna-medapati) + * @see Wikipedia: Temperature Conversion + */ +public final class TemperatureConverter { + + private TemperatureConverter() { + } + + public static double celsiusToFahrenheit(double celsius) { + return celsius * 9.0 / 5.0 + 32.0; + } + + public static double celsiusToKelvin(double celsius) { + return celsius + 273.15; + } + + public static double fahrenheitToCelsius(double fahrenheit) { + return (fahrenheit - 32.0) * 5.0 / 9.0; + } + + public static double fahrenheitToKelvin(double fahrenheit) { + return (fahrenheit - 32.0) * 5.0 / 9.0 + 273.15; + } + + public static double kelvinToCelsius(double kelvin) { + return kelvin - 273.15; + } + + public static double kelvinToFahrenheit(double kelvin) { + return (kelvin - 273.15) * 9.0 / 5.0 + 32.0; + } +} diff --git a/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java b/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java index 30030de6c1bd..50726380621a 100644 --- a/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java +++ b/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java @@ -16,7 +16,7 @@ private TurkishToLatinConversion() { * 2. Replace all turkish characters with their corresponding latin characters * 3. Return the converted string * - * @param param String paramter + * @param param String parameter * @return String */ public static String convertTurkishToLatin(String param) { diff --git a/src/main/java/com/thealgorithms/datastructures/bloomfilter/BloomFilter.java b/src/main/java/com/thealgorithms/datastructures/bloomfilter/BloomFilter.java index d60b95110fc2..90625ad1c902 100644 --- a/src/main/java/com/thealgorithms/datastructures/bloomfilter/BloomFilter.java +++ b/src/main/java/com/thealgorithms/datastructures/bloomfilter/BloomFilter.java @@ -1,12 +1,15 @@ package com.thealgorithms.datastructures.bloomfilter; +import java.util.Arrays; import java.util.BitSet; /** * A generic BloomFilter implementation for probabilistic membership checking. *
- * Bloom filters are space-efficient data structures that provide a fast way to test whether an - * element is a member of a set. They may produce false positives, indicating an element is + * Bloom filters are space-efficient data structures that provide a fast way to + * test whether an + * element is a member of a set. They may produce false positives, indicating an + * element is * in the set when it is not, but they will never produce false negatives. *
* @@ -20,11 +23,14 @@ public class BloomFilter- * This method hashes the element using all defined hash functions and sets the corresponding + * This method hashes the element using all defined hash functions and sets the + * corresponding * bits in the bit array. *
* @@ -65,13 +73,16 @@ public void insert(T key) { /** * Checks if an element might be in the Bloom filter. *- * This method checks the bits at the positions computed by each hash function. If any of these - * bits are not set, the element is definitely not in the filter. If all bits are set, the element + * This method checks the bits at the positions computed by each hash function. + * If any of these + * bits are not set, the element is definitely not in the filter. If all bits + * are set, the element * might be in the filter. *
* * @param key the element to check for membership in the Bloom filter - * @return {@code true} if the element might be in the Bloom filter, {@code false} if it is definitely not + * @return {@code true} if the element might be in the Bloom filter, + * {@code false} if it is definitely not */ public boolean contains(T key) { for (Hash- * Each instance of this class represents a different hash function based on its index. + * Each instance of this class represents a different hash function based on its + * index. *
* * @param+ * Brief Idea: + *
+ * + *+ * 1. From each clause (a ∨ b), we can derive implications: + * (¬a → b) and (¬b → a) + * + * 2. We construct an implication graph using these implications. + * + * 3. For each variable x, its negation ¬x is also represented as a node. + * If x and ¬x belong to the same SCC, the expression is unsatisfiable. + * + * 4. Otherwise, we assign truth values based on the SCC order: + * If SCC(x) > SCC(¬x), then x = true; otherwise, x = false. + *+ * + *
+ * Complexities: + *
+ *+ * Usage Example: + *
+ * + *
+ * TwoSat twoSat = new TwoSat(5); // Initialize with 5 variables: x1, x2, x3, x4, x5
+ *
+ * // Add clauses
+ * twoSat.addClause(1, false, 2, false); // (x1 ∨ x2)
+ * twoSat.addClause(3, true, 2, false); // (¬x3 ∨ x2)
+ * twoSat.addClause(4, false, 5, true); // (x4 ∨ ¬x5)
+ *
+ * twoSat.solve(); // Solve the problem
+ *
+ * if (twoSat.isSolutionExists()) {
+ * boolean[] solution = twoSat.getSolutions();
+ * for (int i = 1; i <= 5; i++) {
+ * System.out.println("x" + i + " = " + solution[i]);
+ * }
+ * }
+ *
+ * Reference
+ * CP Algorithm+ * Example: To add (¬x₁ ∨ x₂), call: + *
+ * + *{@code
+ * addClause(1, true, 2, false);
+ * }
+ *
+ * @param a the first variable (1 ≤ a ≤ numberOfVariables)
+ * @param isNegateA {@code true} if variable {@code a} is negated
+ * @param b the second variable (1 ≤ b ≤ numberOfVariables)
+ * @param isNegateB {@code true} if variable {@code b} is negated
+ * @throws IllegalArgumentException if {@code a} or {@code b} are out of range
+ */
+ void addClause(int a, boolean isNegateA, int b, boolean isNegateB) {
+ if (a <= 0 || a > numberOfVariables) {
+ throw new IllegalArgumentException("Variable number must be between 1 and " + numberOfVariables);
+ }
+ if (b <= 0 || b > numberOfVariables) {
+ throw new IllegalArgumentException("Variable number must be between 1 and " + numberOfVariables);
+ }
+
+ a = isNegateA ? negate(a) : a;
+ b = isNegateB ? negate(b) : b;
+ int notA = negate(a);
+ int notB = negate(b);
+
+ // Add implications: (¬a → b) and (¬b → a)
+ graph[notA].add(b);
+ graph[notB].add(a);
+
+ // Build transpose graph
+ graphTranspose[b].add(notA);
+ graphTranspose[a].add(notB);
+ }
+
+ /**
+ * Solves the 2-SAT problem using Kosaraju's algorithm to find SCCs
+ * and determines whether a satisfying assignment exists.
+ */
+ void solve() {
+ isSolved = true;
+ int n = 2 * numberOfVariables + 1;
+
+ boolean[] visited = new boolean[n];
+ int[] component = new int[n];
+ Stack+ * Mapping rule: + *
+ * + *+ * For a variable i: + * negate(i) = i + n + * For a negated variable (i + n): + * negate(i + n) = i + * where n = numberOfVariables + *+ * + * @param a the variable index + * @return the index representing its negation + */ + private int negate(int a) { + return a <= numberOfVariables ? a + numberOfVariables : a - numberOfVariables; + } +} diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/Readme.md b/src/main/java/com/thealgorithms/datastructures/hashmap/Readme.md index 252b06ea59b0..4400a97d8128 100644 --- a/src/main/java/com/thealgorithms/datastructures/hashmap/Readme.md +++ b/src/main/java/com/thealgorithms/datastructures/hashmap/Readme.md @@ -2,6 +2,8 @@ A hash map organizes data so you can quickly look up values for a given key. +> Note: The term “hash map” refers to the data structure concept, while `HashMap` refers specifically to Java’s implementation. + ## Strengths: - **Fast lookups**: Lookups take O(1) time on average. - **Flexible keys**: Most data types can be used for keys, as long as they're hashable. diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/ImmutableHashMap.java b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/ImmutableHashMap.java new file mode 100644 index 000000000000..f6e09ec623b6 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/ImmutableHashMap.java @@ -0,0 +1,115 @@ +package com.thealgorithms.datastructures.hashmap.hashing; + +/** + * Immutable HashMap implementation using separate chaining. + * + *
This HashMap does not allow modification of existing instances.
+ * Any update operation returns a new ImmutableHashMap.
+ *
+ * @param Key features:
+ * Complexities:
+ * {@code offer, poll, remove(e), changeKey, decreaseKey, increaseKey} are O(log n);
+ * {@code peek, isEmpty, size, contains} are O(1).
+ */
+public class IndexedPriorityQueue We use IdentityHashMap by default to:
+ * IMPORTANT: The mutator must not change {@code equals/hashCode} of {@code e}
+ * if you migrate this implementation to value-based indexing (HashMap).
+ *
+ * @throws IllegalArgumentException if {@code e} is not in the queue
+ */
+ public void changeKey(E e, Consumer Returns nothing; the standard {@code PriorityQueue} returns a displaced
+ * element in a rare case to help its iterator. We don't need that here, so
+ * we keep the API simple.
+ */
+ @SuppressWarnings("unchecked")
+ private void removeAt(int i) {
+ int n = --size; // last index after removal
+ E moved = (E) heap[n];
+ E removed = (E) heap[i];
+ heap[n] = null; // help GC
+ index.remove(removed); // drop mapping for removed element
+
+ if (i == n) {
+ return; // removed last element; done
+ }
+
+ heap[i] = moved;
+ index.put(moved, i);
+
+ // Try sift-up first (cheap if key decreased); if no movement, sift-down.
+ if (!siftUp(i)) {
+ siftDown(i);
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/datastructures/lists/FlattenMultilevelLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/FlattenMultilevelLinkedList.java
new file mode 100644
index 000000000000..3c4106f178b9
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/lists/FlattenMultilevelLinkedList.java
@@ -0,0 +1,92 @@
+package com.thealgorithms.datastructures.lists;
+/**
+ * Implements an algorithm to flatten a multilevel linked list.
+ *
+ * In this specific problem structure, each node has a `next` pointer (to the
+ * next node at the same level) and a `child` pointer (which points to the head
+ * of another sorted linked list). The goal is to merge all these lists into a
+ * single, vertically sorted linked list using the `child` pointer.
+ *
+ * The approach is a recursive one that leverages a merge utility, similar to
+ * the merge step in Merge Sort. It recursively flattens the list starting from
+ * the rightmost node and merges each node's child list with the already
+ * flattened list to its right.
+ * @see GeeksforGeeks: Flattening a Linked List
+ */
+public final class FlattenMultilevelLinkedList {
+ /**
+ * Private constructor to prevent instantiation of this utility class.
+ */
+ private FlattenMultilevelLinkedList() {
+ }
+ /**
+ * Node represents an element in the multilevel linked list. It contains the
+ * integer data, a reference to the next node at the same level, and a
+ * reference to the head of a child list.
+ */
+ static class Node {
+ int data;
+ Node next;
+ Node child;
+
+ Node(int data) {
+ this.data = data;
+ this.next = null;
+ this.child = null;
+ }
+ }
+
+ /**
+ * Merges two sorted linked lists (connected via the `child` pointer).
+ * This is a helper function for the main flatten algorithm.
+ *
+ * @param a The head of the first sorted list.
+ * @param b The head of the second sorted list.
+ * @return The head of the merged sorted list.
+ */
+ private static Node merge(Node a, Node b) {
+ // If one of the lists is empty, return the other.
+ if (a == null) {
+ return b;
+ }
+ if (b == null) {
+ return a;
+ }
+
+ Node result;
+
+ // Choose the smaller value as the new head.
+ if (a.data < b.data) {
+ result = a;
+ result.child = merge(a.child, b);
+ } else {
+ result = b;
+ result.child = merge(a, b.child);
+ }
+ result.next = null; // Ensure the merged list has no `next` pointers.
+ return result;
+ }
+
+ /**
+ * Flattens a multilevel linked list into a single sorted list.
+ * The flattened list is connected using the `child` pointers.
+ *
+ * @param head The head of the top-level list (connected via `next` pointers).
+ * @return The head of the fully flattened and sorted list.
+ */
+ public static Node flatten(Node head) {
+ // Base case: if the list is empty or has only one node, it's already flattened.
+ if (head == null || head.next == null) {
+ return head;
+ }
+
+ // Recursively flatten the list starting from the next node.
+ head.next = flatten(head.next);
+
+ // Now, merge the current list (head's child list) with the flattened rest of the list.
+ head = merge(head, head.next);
+
+ // Return the head of the fully merged list.
+ return head;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/datastructures/lists/README.md b/src/main/java/com/thealgorithms/datastructures/lists/README.md
index 6aefa4c98e6d..5a0a43b923e1 100644
--- a/src/main/java/com/thealgorithms/datastructures/lists/README.md
+++ b/src/main/java/com/thealgorithms/datastructures/lists/README.md
@@ -28,5 +28,6 @@ The `next` variable points to the next node in the data structure and value stor
4. `CreateAndDetectLoop.java` : Create and detect a loop in a linked list.
5. `DoublyLinkedList.java` : A modification of singly linked list which has a `prev` pointer to point to the previous node.
6. `MergeKSortedLinkedlist.java` : Merges K sorted linked list with mergesort (mergesort is also the most efficient sorting algorithm for linked list).
-7. `RandomNode.java` : Selects a random node from given linked list and diplays it.
+7. `RandomNode.java` : Selects a random node from given linked list and displays it.
8. `SkipList.java` : Data Structure used for storing a sorted list of elements with help of a Linked list hierarchy that connects to subsequences of elements.
+9. `TortoiseHareAlgo.java` : Finds the middle element of a linked list using the fast and slow pointer (Tortoise-Hare) algorithm.
diff --git a/src/main/java/com/thealgorithms/datastructures/lists/TortoiseHareAlgo.java b/src/main/java/com/thealgorithms/datastructures/lists/TortoiseHareAlgo.java
new file mode 100644
index 000000000000..9d803003c658
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/lists/TortoiseHareAlgo.java
@@ -0,0 +1,63 @@
+package com.thealgorithms.datastructures.lists;
+
+public class TortoiseHareAlgo
- * Additional contibutions made by: PuneetTri(https://github.com/PuneetTri)
+ * Additional contributions made by: PuneetTri(https://github.com/PuneetTri)
*/
class PriorityQueue {
@@ -32,8 +32,8 @@ class PriorityQueue {
PriorityQueue() {
/* If capacity is not defined, default size of 11 would be used
- * capacity=max+1 because we cant access 0th element of PQ, and to
- * accomodate (max)th elements we need capacity to be max+1.
+ * capacity=max+1 because we can't access 0th element of PQ, and to
+ * accommodate (max)th elements we need capacity to be max+1.
* Parent is at position k, child at position (k*2,k*2+1), if we
* use position 0 in our queue, its child would be at:
* (0*2, 0*2+1) -> (0,0). This is why we start at position 1
@@ -127,7 +127,7 @@ public int remove() {
if (isEmpty()) {
throw new RuntimeException("Queue is Empty");
} else {
- int max = queueArray[1]; // By defintion of our max-heap, value at queueArray[1] pos is
+ int max = queueArray[1]; // By definition of our max-heap, value at queueArray[1] pos is
// the greatest
// Swap max and last element
diff --git a/src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java b/src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java
index e0309122cc12..07fc5c87b6c4 100644
--- a/src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java
+++ b/src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java
@@ -1,7 +1,7 @@
package com.thealgorithms.datastructures.trees;
/*
-* Avl is algo that balance itself while adding new alues to tree
+* Avl is algo that balance itself while adding new values to tree
* by rotating branches of binary tree and make itself Binary seaarch tree
* there are four cases which has to tackle
* rotating - left right ,left left,right right,right left
diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java b/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java
index 0245372fe012..2c94224ddeb4 100644
--- a/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java
+++ b/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java
@@ -30,7 +30,7 @@ public BSTRecursiveGeneric() {
}
/**
- * Displays the tree is a structed format
+ * Displays the tree is a structured format
*/
public void prettyDisplay() {
prettyDisplay(root, 0);
diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BinaryTreeToString.java b/src/main/java/com/thealgorithms/datastructures/trees/BinaryTreeToString.java
new file mode 100644
index 000000000000..2f9b3b489d56
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/trees/BinaryTreeToString.java
@@ -0,0 +1,100 @@
+package com.thealgorithms.datastructures.trees;
+
+/**
+ * Leetcode 606: Construct String from Binary Tree:
+ * https://leetcode.com/problems/construct-string-from-binary-tree/
+ *
+ * Utility class to convert a {@link BinaryTree} into its string representation.
+ *
+ * The conversion follows a preorder traversal pattern (root → left → right)
+ * and uses parentheses to denote the tree structure.
+ * Empty parentheses "()" are used to explicitly represent missing left children
+ * when a right child exists, ensuring the structure is unambiguous.
+ *
+ * This implementation matches the logic from LeetCode problem 606:
+ * Construct String from Binary Tree.
+ *
*
@@ -29,7 +29,7 @@
* into an array.Since array is sorted do a binary search over the array to get
* an element equal to or greater than current key. Time Complexity: O(n) for
* traversal of tree and O(lg(n)) for binary search in array. Total = O(n) Space
- * Complexity: O(n) for auxillary array to save inorder representation of tree.
+ * Complexity: O(n) for auxiliary array to save inorder representation of tree.
*
*
* Solution 3: Optimal We can do a DFS search on given tree in following
diff --git a/src/main/java/com/thealgorithms/datastructures/trees/CentroidDecomposition.java b/src/main/java/com/thealgorithms/datastructures/trees/CentroidDecomposition.java
new file mode 100644
index 000000000000..0b29dd6f5f5e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/trees/CentroidDecomposition.java
@@ -0,0 +1,217 @@
+package com.thealgorithms.datastructures.trees;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Centroid Decomposition is a divide-and-conquer technique for trees.
+ * It recursively partitions a tree by finding centroids - nodes whose removal
+ * creates balanced subtrees (each with at most N/2 nodes).
+ *
+ *
+ * Time Complexity: O(N log N) for construction
+ * Space Complexity: O(N)
+ *
+ *
+ * Applications:
+ * - Distance queries on trees
+ * - Path counting problems
+ * - Nearest neighbor searches
+ *
+ * @see Centroid Decomposition
+ * @see Centroid Decomposition Tutorial
+ * @author lens161
+ */
+public final class CentroidDecomposition {
+
+ private CentroidDecomposition() {
+ }
+
+ /**
+ * Represents the centroid tree structure.
+ */
+ public static final class CentroidTree {
+ private final int n;
+ private final List In this implementation, a node's null left/right pointers are used
+ * to point to the in-order predecessor/successor respectively. Two flags
+ * indicate whether left/right pointers are real children or threads.
+ *
+ * @see Wikipedia:
+ * Threaded binary tree
+ */
+public final class ThreadedBinaryTree {
+
+ private Node root;
+
+ private static final class Node {
+ int value;
+ Node left;
+ Node right;
+ boolean leftIsThread;
+ boolean rightIsThread;
+
+ Node(int value) {
+ this.value = value;
+ this.left = null;
+ this.right = null;
+ this.leftIsThread = false;
+ this.rightIsThread = false;
+ }
+ }
+
+ public ThreadedBinaryTree() {
+ this.root = null;
+ }
+
+ /**
+ * Inserts a value into the threaded binary tree. Duplicate values are inserted
+ * to the right subtree (consistent deterministic rule).
+ *
+ * @param value the integer value to insert
+ */
+ public void insert(int value) {
+ Node newNode = new Node(value);
+ if (root == null) {
+ root = newNode;
+ return;
+ }
+
+ Node current = root;
+ Node parent = null;
+
+ while (true) {
+ parent = current;
+ if (value < current.value) {
+ if (!current.leftIsThread && current.left != null) {
+ current = current.left;
+ } else {
+ break;
+ }
+ } else { // value >= current.value
+ if (!current.rightIsThread && current.right != null) {
+ current = current.right;
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (value < parent.value) {
+ // attach newNode as left child
+ newNode.left = parent.left;
+ newNode.leftIsThread = parent.leftIsThread;
+ newNode.right = parent;
+ newNode.rightIsThread = true;
+
+ parent.left = newNode;
+ parent.leftIsThread = false;
+ } else {
+ // attach newNode as right child
+ newNode.right = parent.right;
+ newNode.rightIsThread = parent.rightIsThread;
+ newNode.left = parent;
+ newNode.leftIsThread = true;
+
+ parent.right = newNode;
+ parent.rightIsThread = false;
+ }
+ }
+
+ /**
+ * Returns the in-order traversal of the tree as a list of integers.
+ * Traversal is done without recursion or an explicit stack by following threads.
+ *
+ * @return list containing the in-order sequence of node values
+ */
+ public List Uses a sweep-line approach with an event queue and status structure to
+ * efficiently detect intersections in 2D plane geometry. An intersection point is reported when two or more segments cross or touch.
+ * For overlapping segments, only actual crossing/touching points are reported,
+ * not all points along the overlap. Time complexity: O(E * V^2) in the worst case, but typically faster in practice
+ * and near O(E * sqrt(V)) for unit networks. The graph is represented using a capacity matrix where capacity[u][v] is the
+ * capacity of the directed edge u -> v. Capacities must be non-negative.
+ * The algorithm builds level graphs using BFS and finds blocking flows using DFS
+ * with current-edge optimization. This implementation mirrors the API and validation style of
+ * {@link EdmondsKarp#maxFlow(int[][], int, int)} for consistency. An MSA is a directed graph equivalent of a Minimum Spanning Tree. It is a tree rooted
+ * at a specific vertex 'r' that reaches all other vertices, such that the sum of the
+ * weights of its edges is minimized.
+ *
+ * The algorithm works recursively:
+ * Time Complexity: O(E * V) where E is the number of edges and V is the number of vertices.
+ *
+ * References:
+ * API: {@code buildTree(int[][])} returns {@code {parent, weight}} arrays for the tree.
+ *
+ * @see Wikipedia: Gomory–Hu tree
+ */
+
+public final class GomoryHuTree {
+ private GomoryHuTree() {
+ }
+
+ public static int[][] buildTree(int[][] cap) {
+ validateCapacityMatrix(cap);
+ final int n = cap.length;
+ if (n == 1) {
+ return new int[][] {new int[] {-1}, new int[] {0}};
+ }
+
+ int[] parent = new int[n];
+ int[] weight = new int[n];
+ Arrays.fill(parent, 0);
+ parent[0] = -1;
+ weight[0] = 0;
+
+ for (int s = 1; s < n; s++) {
+ int t = parent[s];
+ MaxFlowResult res = edmondsKarpWithMinCut(cap, s, t);
+ int f = res.flow;
+ weight[s] = f;
+
+ for (int v = 0; v < n; v++) {
+ if (v != s && parent[v] == t && res.reachable[v]) {
+ parent[v] = s;
+ }
+ }
+
+ if (t != 0 && res.reachable[parent[t]]) {
+ parent[s] = parent[t];
+ parent[t] = s;
+ weight[s] = weight[t];
+ weight[t] = f;
+ }
+ }
+ return new int[][] {parent, weight};
+ }
+
+ private static void validateCapacityMatrix(int[][] cap) {
+ if (cap == null || cap.length == 0) {
+ throw new IllegalArgumentException("Capacity matrix must not be null or empty");
+ }
+ final int n = cap.length;
+ for (int i = 0; i < n; i++) {
+ if (cap[i] == null || cap[i].length != n) {
+ throw new IllegalArgumentException("Capacity matrix must be square");
+ }
+ for (int j = 0; j < n; j++) {
+ if (cap[i][j] < 0) {
+ throw new IllegalArgumentException("Capacities must be non-negative");
+ }
+ }
+ }
+ }
+
+ private static final class MaxFlowResult {
+ final int flow;
+ final boolean[] reachable;
+ MaxFlowResult(int flow, boolean[] reachable) {
+ this.flow = flow;
+ this.reachable = reachable;
+ }
+ }
+
+ private static MaxFlowResult edmondsKarpWithMinCut(int[][] capacity, int source, int sink) {
+ final int n = capacity.length;
+ int[][] residual = new int[n][n];
+ for (int i = 0; i < n; i++) {
+ residual[i] = Arrays.copyOf(capacity[i], n);
+ }
+
+ int[] parent = new int[n];
+ int maxFlow = 0;
+
+ while (bfs(residual, source, sink, parent)) {
+ int pathFlow = Integer.MAX_VALUE;
+ for (int v = sink; v != source; v = parent[v]) {
+ int u = parent[v];
+ pathFlow = Math.min(pathFlow, residual[u][v]);
+ }
+ for (int v = sink; v != source; v = parent[v]) {
+ int u = parent[v];
+ residual[u][v] -= pathFlow;
+ residual[v][u] += pathFlow;
+ }
+ maxFlow += pathFlow;
+ }
+
+ boolean[] reachable = new boolean[n];
+ markReachable(residual, source, reachable);
+ return new MaxFlowResult(maxFlow, reachable);
+ }
+
+ private static boolean bfs(int[][] residual, int source, int sink, int[] parent) {
+ Arrays.fill(parent, -1);
+ parent[source] = source;
+ Queue
+ * An Eulerian circuit is a trail in a graph that visits every edge exactly once,
+ * starting and ending at the same vertex. This algorithm finds such a circuit if one exists.
+ *
+ * This implementation is designed for an undirected graph. For a valid Eulerian
+ * circuit to exist, the graph must satisfy two conditions:
+ *
+ * The algorithm runs in O(E + V) time, where E is the number of edges and V is the number of vertices.
+ * The graph is represented by a Map where keys are vertices and values are a LinkedList of adjacent vertices.
+ *
+ * An Eulerian Circuit is a path that starts and ends at the same vertex
+ * and visits every edge exactly once.
+ *
+ * An Eulerian Path visits every edge exactly once but may start and end
+ * at different vertices.
+ *
+ * Algorithm Summary:
+ * Time Complexity: O(E + V). Given an n x m cost matrix (n tasks, m workers), finds a minimum-cost
+ * one-to-one assignment. If the matrix is rectangular, the algorithm pads to a
+ * square internally. Costs must be finite non-negative integers.
+ *
+ * Time complexity: O(n^3) with n = max(rows, cols).
+ *
+ * API returns the assignment as an array where {@code assignment[i]} is the
+ * column chosen for row i (or -1 if unassigned when rows != cols), and a total
+ * minimal cost.
+ *
+ * @see Wikipedia: Hungarian algorithm
+ */
+public final class HungarianAlgorithm {
+
+ private HungarianAlgorithm() {
+ }
+
+ /** Result holder for the Hungarian algorithm. */
+ public static final class Result {
+ public final int[] assignment; // assignment[row] = col or -1
+ public final int minCost;
+
+ public Result(int[] assignment, int minCost) {
+ this.assignment = assignment;
+ this.minCost = minCost;
+ }
+ }
+
+ /**
+ * Solves the assignment problem for a non-negative cost matrix.
+ *
+ * @param cost an r x c matrix of non-negative costs
+ * @return Result with row-to-column assignment and minimal total cost
+ * @throws IllegalArgumentException for null/empty or negative costs
+ */
+ public static Result solve(int[][] cost) {
+ validate(cost);
+ int rows = cost.length;
+ int cols = cost[0].length;
+ int n = Math.max(rows, cols);
+
+ // Build square matrix with padding 0 for missing cells
+ int[][] a = new int[n][n];
+ for (int i = 0; i < n; i++) {
+ if (i < rows) {
+ for (int j = 0; j < n; j++) {
+ a[i][j] = (j < cols) ? cost[i][j] : 0;
+ }
+ } else {
+ Arrays.fill(a[i], 0);
+ }
+ }
+
+ // Potentials and matching arrays
+ int[] u = new int[n + 1];
+ int[] v = new int[n + 1];
+ int[] p = new int[n + 1];
+ int[] way = new int[n + 1];
+
+ for (int i = 1; i <= n; i++) {
+ p[0] = i;
+ int j0 = 0;
+ int[] minv = new int[n + 1];
+ boolean[] used = new boolean[n + 1];
+ Arrays.fill(minv, Integer.MAX_VALUE);
+ Arrays.fill(used, false);
+ do {
+ used[j0] = true;
+ int i0 = p[j0];
+ int delta = Integer.MAX_VALUE;
+ int j1 = 0;
+ for (int j = 1; j <= n; j++) {
+ if (!used[j]) {
+ int cur = a[i0 - 1][j - 1] - u[i0] - v[j];
+ if (cur < minv[j]) {
+ minv[j] = cur;
+ way[j] = j0;
+ }
+ if (minv[j] < delta) {
+ delta = minv[j];
+ j1 = j;
+ }
+ }
+ }
+ for (int j = 0; j <= n; j++) {
+ if (used[j]) {
+ u[p[j]] += delta;
+ v[j] -= delta;
+ } else {
+ minv[j] -= delta;
+ }
+ }
+ j0 = j1;
+ } while (p[j0] != 0);
+ do {
+ int j1 = way[j0];
+ p[j0] = p[j1];
+ j0 = j1;
+ } while (j0 != 0);
+ }
+
+ int[] matchColForRow = new int[n];
+ Arrays.fill(matchColForRow, -1);
+ for (int j = 1; j <= n; j++) {
+ if (p[j] != 0) {
+ matchColForRow[p[j] - 1] = j - 1;
+ }
+ }
+
+ // Build assignment for original rows only, ignore padded rows
+ int[] assignment = new int[rows];
+ Arrays.fill(assignment, -1);
+ int total = 0;
+ for (int i = 0; i < rows; i++) {
+ int j = matchColForRow[i];
+ if (j >= 0 && j < cols) {
+ assignment[i] = j;
+ total += cost[i][j];
+ }
+ }
+ return new Result(assignment, total);
+ }
+
+ private static void validate(int[][] cost) {
+ if (cost == null || cost.length == 0) {
+ throw new IllegalArgumentException("Cost matrix must not be null or empty");
+ }
+ int c = cost[0].length;
+ if (c == 0) {
+ throw new IllegalArgumentException("Cost matrix must have at least 1 column");
+ }
+ for (int i = 0; i < cost.length; i++) {
+ if (cost[i] == null || cost[i].length != c) {
+ throw new IllegalArgumentException("Cost matrix must be rectangular with equal row lengths");
+ }
+ for (int j = 0; j < c; j++) {
+ if (cost[i][j] < 0) {
+ throw new IllegalArgumentException("Costs must be non-negative");
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/graph/PushRelabel.java b/src/main/java/com/thealgorithms/graph/PushRelabel.java
new file mode 100644
index 000000000000..1bfb5ceacce0
--- /dev/null
+++ b/src/main/java/com/thealgorithms/graph/PushRelabel.java
@@ -0,0 +1,162 @@
+package com.thealgorithms.graph;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Queue;
+
+/**
+ * Push–Relabel (Relabel-to-Front variant simplified to array scanning) for maximum flow.
+ *
+ * Input graph is a capacity matrix where {@code capacity[u][v]} is the capacity of the edge
+ * {@code u -> v}. Capacities must be non-negative. Vertices are indexed in {@code [0, n)}.
+ *
+ * Time complexity: O(V^3) in the worst case for the array-based variant; typically fast in
+ * practice. This implementation uses a residual network over an adjacency-matrix representation.
+ *
+ * The API mirrors {@link EdmondsKarp#maxFlow(int[][], int, int)} and {@link Dinic#maxFlow(int[][], int, int)}.
+ *
+ * @see Wikipedia: Push–Relabel maximum flow algorithm
+ */
+public final class PushRelabel {
+
+ private PushRelabel() {
+ }
+
+ /**
+ * Computes the maximum flow from {@code source} to {@code sink} using Push–Relabel.
+ *
+ * @param capacity square capacity matrix (n x n); entries must be >= 0
+ * @param source source vertex index in [0, n)
+ * @param sink sink vertex index in [0, n)
+ * @return the maximum flow value
+ * @throws IllegalArgumentException if inputs are invalid
+ */
+ public static int maxFlow(int[][] capacity, int source, int sink) {
+ validate(capacity, source, sink);
+ final int n = capacity.length;
+ if (source == sink) {
+ return 0;
+ }
+
+ int[][] residual = new int[n][n];
+ for (int i = 0; i < n; i++) {
+ residual[i] = Arrays.copyOf(capacity[i], n);
+ }
+
+ int[] height = new int[n];
+ int[] excess = new int[n];
+ int[] nextNeighbor = new int[n];
+
+ // Preflow initialization
+ height[source] = n;
+ for (int v = 0; v < n; v++) {
+ int cap = residual[source][v];
+ if (cap > 0) {
+ residual[source][v] -= cap;
+ residual[v][source] += cap;
+ excess[v] += cap;
+ excess[source] -= cap;
+ }
+ }
+
+ // Active queue contains vertices (except source/sink) with positive excess
+ Queue Input is an adjacency matrix of edge weights. A value of -1 indicates no edge.
+ * All existing edge weights must be non-negative. Zero-weight edges are allowed. References:
+ * - Wikipedia: Yen's algorithm (https://en.wikipedia.org/wiki/Yen%27s_algorithm)
+ * - Dijkstra's algorithm for the base shortest path computation.
+ * This method is a "polynomial acceleration" method, meaning it finds the
+ * optimal polynomial to apply to the residual to accelerate convergence.
+ *
+ *
+ * It requires knowledge of the bounds of the eigenvalues of the matrix A:
+ * m(A) (smallest eigenvalue) and M(A) (largest eigenvalue).
+ *
+ *
+ * Wikipedia: https://en.wikipedia.org/wiki/Chebyshev_iteration
+ *
+ * @author Mitrajit Ghorui(KeyKyrios)
+ */
+public final class ChebyshevIteration {
+
+ private ChebyshevIteration() {
+ }
+
+ /**
+ * Solves the linear system Ax = b using the Chebyshev iteration method.
+ *
+ *
+ * NOTE: The matrix A *must* be symmetric positive-definite (SPD) for this
+ * algorithm to converge.
+ *
+ * @param a The matrix A (must be square, SPD).
+ * @param b The vector b.
+ * @param x0 The initial guess vector.
+ * @param minEigenvalue The smallest eigenvalue of A (m(A)).
+ * @param maxEigenvalue The largest eigenvalue of A (M(A)).
+ * @param maxIterations The maximum number of iterations to perform.
+ * @param tolerance The desired tolerance for the residual norm.
+ * @return The solution vector x.
+ * @throws IllegalArgumentException if matrix/vector dimensions are
+ * incompatible,
+ * if maxIterations <= 0, or if eigenvalues are invalid (e.g., minEigenvalue
+ * <= 0, maxEigenvalue <= minEigenvalue).
+ */
+ public static double[] solve(double[][] a, double[] b, double[] x0, double minEigenvalue, double maxEigenvalue, int maxIterations, double tolerance) {
+ validateInputs(a, b, x0, minEigenvalue, maxEigenvalue, maxIterations, tolerance);
+
+ int n = b.length;
+ double[] x = x0.clone();
+ double[] r = vectorSubtract(b, matrixVectorMultiply(a, x));
+ double[] p = new double[n];
+
+ double d = (maxEigenvalue + minEigenvalue) / 2.0;
+ double c = (maxEigenvalue - minEigenvalue) / 2.0;
+
+ double alpha = 0.0;
+ double alphaPrev = 0.0;
+
+ for (int k = 0; k < maxIterations; k++) {
+ double residualNorm = vectorNorm(r);
+ if (residualNorm < tolerance) {
+ return x; // Solution converged
+ }
+
+ if (k == 0) {
+ alpha = 1.0 / d;
+ System.arraycopy(r, 0, p, 0, n); // p = r
+ } else {
+ double beta = c * alphaPrev / 2.0 * (c * alphaPrev / 2.0);
+ alpha = 1.0 / (d - beta / alphaPrev);
+ double[] pUpdate = scalarMultiply(beta / alphaPrev, p);
+ p = vectorAdd(r, pUpdate); // p = r + (beta / alphaPrev) * p
+ }
+
+ double[] xUpdate = scalarMultiply(alpha, p);
+ x = vectorAdd(x, xUpdate); // x = x + alpha * p
+
+ // Recompute residual for accuracy
+ r = vectorSubtract(b, matrixVectorMultiply(a, x));
+ alphaPrev = alpha;
+ }
+
+ return x; // Return best guess after maxIterations
+ }
+
+ /**
+ * Validates the inputs for the Chebyshev solver.
+ */
+ private static void validateInputs(double[][] a, double[] b, double[] x0, double minEigenvalue, double maxEigenvalue, int maxIterations, double tolerance) {
+ int n = a.length;
+ if (n == 0) {
+ throw new IllegalArgumentException("Matrix A cannot be empty.");
+ }
+ if (n != a[0].length) {
+ throw new IllegalArgumentException("Matrix A must be square.");
+ }
+ if (n != b.length) {
+ throw new IllegalArgumentException("Matrix A and vector b dimensions do not match.");
+ }
+ if (n != x0.length) {
+ throw new IllegalArgumentException("Matrix A and vector x0 dimensions do not match.");
+ }
+ if (minEigenvalue <= 0) {
+ throw new IllegalArgumentException("Smallest eigenvalue must be positive (matrix must be positive-definite).");
+ }
+ if (maxEigenvalue <= minEigenvalue) {
+ throw new IllegalArgumentException("Max eigenvalue must be strictly greater than min eigenvalue.");
+ }
+ if (maxIterations <= 0) {
+ throw new IllegalArgumentException("Max iterations must be positive.");
+ }
+ if (tolerance <= 0) {
+ throw new IllegalArgumentException("Tolerance must be positive.");
+ }
+ }
+
+ // --- Vector/Matrix Helper Methods ---
+ /**
+ * Computes the product of a matrix A and a vector v (Av).
+ */
+ private static double[] matrixVectorMultiply(double[][] a, double[] v) {
+ int n = a.length;
+ double[] result = new double[n];
+ for (int i = 0; i < n; i++) {
+ double sum = 0;
+ for (int j = 0; j < n; j++) {
+ sum += a[i][j] * v[j];
+ }
+ result[i] = sum;
+ }
+ return result;
+ }
+
+ /**
+ * Computes the subtraction of two vectors (v1 - v2).
+ */
+ private static double[] vectorSubtract(double[] v1, double[] v2) {
+ int n = v1.length;
+ double[] result = new double[n];
+ for (int i = 0; i < n; i++) {
+ result[i] = v1[i] - v2[i];
+ }
+ return result;
+ }
+
+ /**
+ * Computes the addition of two vectors (v1 + v2).
+ */
+ private static double[] vectorAdd(double[] v1, double[] v2) {
+ int n = v1.length;
+ double[] result = new double[n];
+ for (int i = 0; i < n; i++) {
+ result[i] = v1[i] + v2[i];
+ }
+ return result;
+ }
+
+ /**
+ * Computes the product of a scalar and a vector (s * v).
+ */
+ private static double[] scalarMultiply(double scalar, double[] v) {
+ int n = v.length;
+ double[] result = new double[n];
+ for (int i = 0; i < n; i++) {
+ result[i] = scalar * v[i];
+ }
+ return result;
+ }
+
+ /**
+ * Computes the L2 norm (Euclidean norm) of a vector.
+ */
+ private static double vectorNorm(double[] v) {
+ double sumOfSquares = 0;
+ for (double val : v) {
+ sumOfSquares += val * val;
+ }
+ return Math.sqrt(sumOfSquares);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/maths/EvilNumber.java b/src/main/java/com/thealgorithms/maths/EvilNumber.java
new file mode 100644
index 000000000000..419133702fd4
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/EvilNumber.java
@@ -0,0 +1,39 @@
+package com.thealgorithms.maths;
+
+/**
+ * In number theory, an evil number is a non-negative integer that has an even number of 1s in its binary expansion.
+ * Non-negative integers that are not evil are called odious numbers.
+ *
+ * Evil Number Wiki: https://en.wikipedia.org/wiki/Evil_number
+ * Odious Number Wiki: https://en.wikipedia.org/wiki/Odious_number
+ */
+public final class EvilNumber {
+
+ private EvilNumber() {
+ }
+
+ // Function to count number of one bits in a number using bitwise operators
+ private static int countOneBits(int number) {
+ int oneBitCounter = 0;
+ while (number > 0) {
+ oneBitCounter += number & 1; // increment count if last bit is 1
+ number >>= 1; // right shift to next bit
+ }
+ return oneBitCounter;
+ }
+
+ /**
+ * Check either {@code number} is an Evil number or Odious number
+ *
+ * @param number the number
+ * @return {@code true} if {@code number} is an Evil number, otherwise false (in case of of Odious number)
+ */
+ public static boolean isEvilNumber(int number) {
+ if (number < 0) {
+ throw new IllegalArgumentException("Negative numbers are not allowed.");
+ }
+
+ int noOfOneBits = countOneBits(number);
+ return noOfOneBits % 2 == 0;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/maths/ExtendedEuclideanAlgorithm.java b/src/main/java/com/thealgorithms/maths/ExtendedEuclideanAlgorithm.java
new file mode 100644
index 000000000000..4934d4493bf2
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/ExtendedEuclideanAlgorithm.java
@@ -0,0 +1,48 @@
+package com.thealgorithms.maths;
+
+/**
+ * In mathematics, the extended Euclidean algorithm is an extension to the
+ * Euclidean algorithm, and computes, in addition to the greatest common divisor
+ * (gcd) of integers a and b, also the coefficients of Bézout's identity, which
+ * are integers x and y such that ax + by = gcd(a, b).
+ *
+ *
+ * For more details, see
+ * https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
+ */
+public final class ExtendedEuclideanAlgorithm {
+
+ private ExtendedEuclideanAlgorithm() {
+ }
+
+ /**
+ * This method implements the extended Euclidean algorithm.
+ *
+ * @param a The first number.
+ * @param b The second number.
+ * @return An array of three integers:
+ *
+ * Heron's Formula states that the area of a triangle whose sides have lengths
+ * a, b, and c is:
+ * Area = √(s(s - a)(s - b)(s - c))
+ * where s is the semi-perimeter of the triangle: s = (a + b + c) / 2
+ *
+ * The triangle inequality theorem states that the sum of any two sides
+ * of a triangle must be greater than the third side.
+ *
+ * Given three side lengths a, b, and c, the area is computed as:
+ * Area = √(s(s - a)(s - b)(s - c))
+ * where s is the semi-perimeter: s = (a + b + c) / 2
+ *
+ * A Kaprekar number is a positive integer with the following property:
+ * If you square it, then split the resulting number into two parts (right part
+ * has same number of
+ * digits as the original number, left part has the remaining digits), and
+ * finally add the two
+ * parts together, you get the original number.
+ *
+ * For example:
+ *
+ * Note: The right part can have leading zeros, but must not be all zeros.
+ *
+ * @see Kaprekar Number
+ * - Wikipedia
+ * @author TheAlgorithms (https://github.com/TheAlgorithms)
+ */
public final class KaprekarNumbers {
private KaprekarNumbers() {
}
- /* This program demonstrates if a given number is Kaprekar Number or not.
- Kaprekar Number: A Kaprekar number is an n-digit number which its square can be split into
- two parts where the right part has n digits and sum of these parts is equal to the original
- number. */
-
- // Provides a list of kaprekarNumber in a range
- public static List
+ * The algorithm works as follows:
+ *
+ * Special handling is required for numbers whose squares contain zeros.
+ *
+ * @param num the number to check
+ * @return true if the number is a Kaprekar number, false otherwise
+ * @throws IllegalArgumentException if num is negative
+ */
public static boolean isKaprekarNumber(long num) {
+ if (num < 0) {
+ throw new IllegalArgumentException("Number must be non-negative. Given: " + num);
+ }
+
+ if (num == 0 || num == 1) {
+ return true;
+ }
+
String number = Long.toString(num);
BigInteger originalNumber = BigInteger.valueOf(num);
BigInteger numberSquared = originalNumber.multiply(originalNumber);
- if (number.length() == numberSquared.toString().length()) {
- return number.equals(numberSquared.toString());
- } else {
- BigInteger leftDigits1 = BigInteger.ZERO;
- BigInteger leftDigits2;
- if (numberSquared.toString().contains("0")) {
- leftDigits1 = new BigInteger(numberSquared.toString().substring(0, numberSquared.toString().indexOf("0")));
- }
- leftDigits2 = new BigInteger(numberSquared.toString().substring(0, (numberSquared.toString().length() - number.length())));
- BigInteger rightDigits = new BigInteger(numberSquared.toString().substring(numberSquared.toString().length() - number.length()));
- String x = leftDigits1.add(rightDigits).toString();
- String y = leftDigits2.add(rightDigits).toString();
- return (number.equals(x)) || (number.equals(y));
+ String squaredStr = numberSquared.toString();
+
+ // Special case: if the squared number has the same length as the original
+ if (number.length() == squaredStr.length()) {
+ return number.equals(squaredStr);
+ }
+
+ // Calculate the split position
+ int splitPos = squaredStr.length() - number.length();
+
+ // Split the squared number into left and right parts
+ String leftPart = squaredStr.substring(0, splitPos);
+ String rightPart = squaredStr.substring(splitPos);
+
+ // Parse the parts as BigInteger (handles empty left part as zero)
+ BigInteger leftNum = leftPart.isEmpty() ? BigInteger.ZERO : new BigInteger(leftPart);
+ BigInteger rightNum = new BigInteger(rightPart);
+
+ // Check if right part is all zeros (invalid for Kaprekar numbers except 1)
+ if (rightNum.equals(BigInteger.ZERO)) {
+ return false;
}
+
+ // Check if the sum equals the original number
+ return leftNum.add(rightNum).equals(originalNumber);
}
}
diff --git a/src/main/java/com/thealgorithms/maths/KeithNumber.java b/src/main/java/com/thealgorithms/maths/KeithNumber.java
index 1756cfbae91b..eb7f800d378f 100644
--- a/src/main/java/com/thealgorithms/maths/KeithNumber.java
+++ b/src/main/java/com/thealgorithms/maths/KeithNumber.java
@@ -4,57 +4,98 @@
import java.util.Collections;
import java.util.Scanner;
-final class KeithNumber {
+/**
+ * A Keith number is an n-digit positive integer where the sequence formed by
+ * starting with its digits and repeatedly adding the previous n terms,
+ * eventually reaches the number itself.
+ *
+ *
+ * For example:
+ *
+ * The algorithm works as follows:
+ *
+ * A Krishnamurthy number (also known as a Strong number or Factorion) is a
+ * number
+ * whose sum of the factorials of its digits is equal to the number itself.
+ *
+ * For example, 145 is a Krishnamurthy number because 1! + 4! + 5! = 1 + 24 +
+ * 120 = 145.
+ *
+ * The only Krishnamurthy numbers in base 10 are: 1, 2, 145, and 40585.
+ *
* Example usage:
+ *
+ * A number is a Krishnamurthy number if the sum of the factorials of its digits
+ * equals the number itself.
+ *
+ * Leonardo numbers are a sequence of numbers defined by the recurrence:
+ * L(n) = L(n-1) + L(n-2) + 1, with L(0) = 1 and L(1) = 1
+ *
+ * The sequence begins: 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, ...
+ *
+ * This class provides both a recursive implementation and an optimized
+ * iterative
+ * implementation for calculating Leonardo numbers.
+ *
+ * @see Leonardo Number
+ * - Wikipedia
+ * @see OEIS A001595
*/
public final class LeonardoNumber {
private LeonardoNumber() {
}
/**
- * Calculate nth Leonardo Number (1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, ...)
+ * Calculates the nth Leonardo Number using recursion.
+ *
+ * Time Complexity: O(2^n) - exponential due to repeated calculations
+ * Space Complexity: O(n) - due to recursion stack
+ *
+ * Note: This method is not recommended for large values of n due to exponential
+ * time complexity.
+ * Consider using {@link #leonardoNumberIterative(int)} for better performance.
*
- * @param n the index of Leonardo Number to calculate
- * @return nth number of Leonardo sequences
+ * @param n the index of the Leonardo Number to calculate (must be non-negative)
+ * @return the nth Leonardo Number
+ * @throws IllegalArgumentException if n is negative
*/
public static int leonardoNumber(int n) {
if (n < 0) {
- throw new ArithmeticException();
+ throw new IllegalArgumentException("Input must be non-negative. Received: " + n);
}
if (n == 0 || n == 1) {
return 1;
}
- return (leonardoNumber(n - 1) + leonardoNumber(n - 2) + 1);
+ return leonardoNumber(n - 1) + leonardoNumber(n - 2) + 1;
+ }
+
+ /**
+ * Calculates the nth Leonardo Number using an iterative approach.
+ *
+ * This method provides better performance than the recursive version for large
+ * values of n.
+ *
+ * Time Complexity: O(n)
+ * Space Complexity: O(1)
+ *
+ * @param n the index of the Leonardo Number to calculate (must be non-negative)
+ * @return the nth Leonardo Number
+ * @throws IllegalArgumentException if n is negative
+ */
+ public static int leonardoNumberIterative(int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("Input must be non-negative. Received: " + n);
+ }
+ if (n == 0 || n == 1) {
+ return 1;
+ }
+
+ int previous = 1;
+ int current = 1;
+
+ for (int i = 2; i <= n; i++) {
+ int next = current + previous + 1;
+ previous = current;
+ current = next;
+ }
+
+ return current;
}
}
diff --git a/src/main/java/com/thealgorithms/maths/LinearDiophantineEquationsSolver.java b/src/main/java/com/thealgorithms/maths/LinearDiophantineEquationsSolver.java
index a50cfb218283..a95e7053e210 100644
--- a/src/main/java/com/thealgorithms/maths/LinearDiophantineEquationsSolver.java
+++ b/src/main/java/com/thealgorithms/maths/LinearDiophantineEquationsSolver.java
@@ -2,20 +2,77 @@
import java.util.Objects;
+/**
+ * A solver for linear Diophantine equations of the form ax + by = c.
+ *
+ * A linear Diophantine equation is an equation in which only integer solutions
+ * are allowed.
+ * This solver uses the Extended Euclidean Algorithm to find integer solutions
+ * (x, y)
+ * for equations of the form ax + by = c, where a, b, and c are integers.
+ *
+ * The equation has solutions if and only if gcd(a, b) divides c.
+ * If solutions exist, this solver finds one particular solution.
+ *
+ * The method returns one of three types of solutions:
+ *
+ * This method also finds coefficients x and y such that ax + by = gcd(a, b).
+ * The coefficients are stored in the 'previous' wrapper object.
+ *
+ * Special instances:
+ *
+ * This class is used internally to pass results between recursive calls
+ * of the GCD computation.
+ *
- * by: Punit Patel
+ * This class provides static methods to calculate different types of means
+ * (averages)
+ * from a collection of numbers. All methods accept any {@link Iterable}
+ * collection of
+ * {@link Double} values and return the computed mean as a {@link Double}.
+ *
+ * Supported means:
+ *
+ * The arithmetic mean is calculated as: (x₁ + x₂ + ... + xₙ) / n
+ *
+ * Example: For numbers [2, 4, 6], the arithmetic mean is (2+4+6)/3 = 4.0
+ *
+ * The geometric mean is calculated as: ⁿ√(x₁ × x₂ × ... × xₙ)
+ *
+ * Example: For numbers [2, 8], the geometric mean is √(2×8) = √16 = 4.0
+ *
+ * Note: This method may produce unexpected results for negative numbers,
+ * as it computes the real-valued nth root which may not exist for negative
+ * products.
+ *
+ * The harmonic mean is calculated as: n / (1/x₁ + 1/x₂ + ... + 1/xₙ)
+ *
+ * Example: For numbers [1, 2, 4], the harmonic mean is 3/(1/1 + 1/2 + 1/4) =
+ * 3/1.75 ≈ 1.714
+ *
+ * Note: This method will produce unexpected results if any input number is
+ * zero,
+ * as it involves computing reciprocals.
+ *
+ * Time Complexity: O(n log n) due to sorting
+ *
+ * Space Complexity: O(1) if sorting is done in-place
+ *
+ * @see Median (Wikipedia)
+ * @see Mean,
+ * Median, and Mode Review
*/
public final class Median {
private Median() {
}
/**
- * Calculate average median
- * @param values sorted numbers to find median of
- * @return median of given {@code values}
- * @throws IllegalArgumentException If the input array is empty or null.
+ * Calculates the median of an array of integers.
+ * The array is sorted internally, so the original order is not preserved.
+ * For arrays with an odd number of elements, returns the middle element.
+ * For arrays with an even number of elements, returns the average of the two
+ * middle elements.
+ *
+ * @param values the array of integers to find the median of (can be unsorted)
+ * @return the median value as a double
+ * @throws IllegalArgumentException if the input array is empty or null
*/
public static double median(int[] values) {
if (values == null || values.length == 0) {
@@ -22,6 +40,10 @@ public static double median(int[] values) {
Arrays.sort(values);
int length = values.length;
- return length % 2 == 0 ? (values[length / 2] + values[length / 2 - 1]) / 2.0 : values[length / 2];
+ if (length % 2 == 0) {
+ return (values[length / 2] + values[length / 2 - 1]) / 2.0;
+ } else {
+ return values[length / 2];
+ }
}
}
diff --git a/src/main/java/com/thealgorithms/maths/Neville.java b/src/main/java/com/thealgorithms/maths/Neville.java
new file mode 100644
index 000000000000..ca45f2e8a042
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/Neville.java
@@ -0,0 +1,61 @@
+package com.thealgorithms.maths;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * In numerical analysis, Neville's algorithm is an algorithm used for
+ * polynomial interpolation. Given n+1 points, there is a unique polynomial of
+ * degree at most n that passes through all the points. Neville's algorithm
+ * computes the value of this polynomial at a given point.
+ *
+ *
+ * Wikipedia: https://en.wikipedia.org/wiki/Neville%27s_algorithm
+ *
+ * @author Mitrajit Ghorui(KeyKyrios)
+ */
+public final class Neville {
+
+ private Neville() {
+ }
+
+ /**
+ * Evaluates the polynomial that passes through the given points at a
+ * specific x-coordinate.
+ *
+ * @param x The x-coordinates of the points. Must be the same length as y.
+ * @param y The y-coordinates of the points. Must be the same length as x.
+ * @param target The x-coordinate at which to evaluate the polynomial.
+ * @return The interpolated y-value at the target x-coordinate.
+ * @throws IllegalArgumentException if the lengths of x and y arrays are
+ * different, if the arrays are empty, or if x-coordinates are not unique.
+ */
+ public static double interpolate(double[] x, double[] y, double target) {
+ if (x.length != y.length) {
+ throw new IllegalArgumentException("x and y arrays must have the same length.");
+ }
+ if (x.length == 0) {
+ throw new IllegalArgumentException("Input arrays cannot be empty.");
+ }
+
+ // Check for duplicate x-coordinates to prevent division by zero
+ Set
+ * Given a 2D array (matrix), this class provides a method to return the
+ * elements
+ * of the matrix in spiral order, starting from the top-left corner and moving
+ * clockwise.
+ *
+ * Example:
+ *
+ *
+ * Time Complexity: O(n log n) where n is the number of unique characters
+ * Space Complexity: O(n)
+ *
+ * @see Huffman
+ * Coding
+ */
public final class Huffman {
private Huffman() {
}
- // recursive function to print the
- // huffman-code through the tree traversal.
- // Here s is the huffman - code generated.
- public static void printCode(HuffmanNode root, String s) {
- // base case; if the left and right are null
- // then its a leaf node and we print
- // the code s generated by traversing the tree.
- if (root.left == null && root.right == null && Character.isLetter(root.c)) {
- // c is the character in the node
- System.out.println(root.c + ":" + s);
-
- return;
+ /**
+ * Builds a Huffman tree from the given character array and their frequencies.
+ *
+ * @param charArray array of characters
+ * @param charFreq array of frequencies corresponding to the characters
+ * @return root node of the Huffman tree
+ * @throws IllegalArgumentException if arrays are null, empty, or have different
+ * lengths
+ */
+ public static HuffmanNode buildHuffmanTree(char[] charArray, int[] charFreq) {
+ if (charArray == null || charFreq == null) {
+ throw new IllegalArgumentException("Character array and frequency array cannot be null");
+ }
+ if (charArray.length == 0 || charFreq.length == 0) {
+ throw new IllegalArgumentException("Character array and frequency array cannot be empty");
+ }
+ if (charArray.length != charFreq.length) {
+ throw new IllegalArgumentException("Character array and frequency array must have the same length");
}
- // if we go to left then add "0" to the code.
- // if we go to the right add"1" to the code.
- // recursive calls for left and
- // right sub-tree of the generated tree.
- printCode(root.left, s + "0");
- printCode(root.right, s + "1");
- }
+ int n = charArray.length;
+ PriorityQueue
+ * This class demonstrates how to insert an element at a specific position and
+ * delete an element from a specific position in an integer array. Since arrays
+ * in Java have fixed size, insertion creates a new array with increased size,
+ * and deletion shifts elements to fill the gap.
+ *
+ * Time Complexity:
+ *
+ * Space Complexity:
+ *
+ * Creates a new array with size = original array size + 1.
+ * Elements at positions <= insertPos retain their positions,
+ * while elements at positions > insertPos are shifted right by one position.
+ *
+ * Creates a new array with size = original array size - 1.
+ * Elements after the deletion position are shifted left by one position.
+ *
+ * This method interactively:
+ *
+ * A number is a palindrome in a given base if its representation in that base
+ * reads the same
+ * forwards and backwards. For example, 15 in base 2 is 1111, which is
+ * palindromic.
+ * This class provides methods to check palindromic properties and find the
+ * smallest base
+ * where a number becomes palindromic.
+ *
+ * Example: The number 15 in base 2 is represented as [1,1,1,1], which is
+ * palindromic.
+ * The number 10 in base 3 is represented as [1,0,1], which is also palindromic.
+ *
+ * The digits are returned in reverse order (least significant digit first).
+ * For example, the number 13 in base 2 produces [1,0,1,1] representing 1101 in
+ * binary.
+ *
+ * A list is palindromic if it reads the same forwards and backwards.
+ * For example, [1,2,1] is palindromic, but [1,2,3] is not.
+ *
+ * This method first validates the input, then applies optimization: if the
+ * number
+ * ends with 0 in the given base (i.e., divisible by the base), it cannot be
+ * palindromic
+ * as palindromes cannot start with 0.
+ *
+ * Examples:
+ * - 101 in base 10 is palindromic (101)
+ * - 15 in base 2 is palindromic (1111)
+ * - 10 in base 3 is palindromic (101)
+ *
+ * This method iteratively checks bases starting from 2 until it finds one where
+ * the number is palindromic. For any number n ≥ 2, the number is always
+ * palindromic
+ * in base n-1 (represented as [1, 1]), so this algorithm is guaranteed to
+ * terminate.
+ *
+ * Time Complexity: O(n * log(n)) in the worst case, where we check each base
+ * and
+ * convert the number to that base.
+ *
+ * Examples:
+ * - lowestBasePalindrome(15) returns 2 (15 in base 2 is 1111)
+ * - lowestBasePalindrome(10) returns 3 (10 in base 3 is 101)
+ * - lowestBasePalindrome(11) returns 10 (11 in base 10 is 11)
+ *
+ * The algorithm simulates all possible moves in a game tree and chooses the
+ * move that minimizes the maximum possible loss. The algorithm assumes both
+ * players play optimally.
+ *
+ *
+ * Time Complexity: O(b^d) where b is the branching factor and d is the depth
+ *
+ * Space Complexity: O(d) for the recursive call stack
+ *
+ *
+ * See more:
+ *
+ * This method recursively evaluates the game tree using the minimax algorithm.
+ * At each level, the maximizer tries to maximize the score while the minimizer
+ * tries to minimize it.
+ *
+ * @param depth The current depth in the game tree (0 at root).
+ * @param isMaximizer True if it is the maximizer's turn; false for minimizer.
+ * @param index Index of the current node in the game tree.
+ * @param verbose True to print each player's choice during evaluation.
* @return The optimal score for the player that made the first move.
*/
public int miniMax(int depth, boolean isMaximizer, int index, boolean verbose) {
@@ -75,7 +120,7 @@ public int miniMax(int depth, boolean isMaximizer, int index, boolean verbose) {
}
// Leaf nodes can be sequentially inspected by
- // recurssively multiplying (0 * 2) and ((0 * 2) + 1):
+ // recursively multiplying (0 * 2) and ((0 * 2) + 1):
// (0 x 2) = 0; ((0 x 2) + 1) = 1
// (1 x 2) = 2; ((1 x 2) + 1) = 3
// (2 x 2) = 4; ((2 x 2) + 1) = 5 ...
@@ -87,46 +132,73 @@ public int miniMax(int depth, boolean isMaximizer, int index, boolean verbose) {
}
/**
- * Returns an array of random numbers which lenght is a power of 2.
+ * Returns an array of random numbers whose length is a power of 2.
*
- * @param size The power of 2 that will determine the lenght of the array.
- * @param maxScore The maximum possible score.
- * @return An array of random numbers.
+ * @param size The power of 2 that will determine the length of the array
+ * (array length = 2^size).
+ * @param maxScore The maximum possible score (scores will be between 1 and
+ * maxScore inclusive).
+ * @return An array of random numbers with length 2^size.
*/
public static int[] getRandomScores(int size, int maxScore) {
int[] randomScores = new int[(int) Math.pow(2, size)];
- Random rand = new Random();
for (int i = 0; i < randomScores.length; i++) {
- randomScores[i] = rand.nextInt(maxScore) + 1;
+ randomScores[i] = RANDOM.nextInt(maxScore) + 1;
}
return randomScores;
}
- // A utility function to find Log n in base 2
+ /**
+ * Calculates the logarithm base 2 of a number.
+ *
+ * @param n The number to calculate log2 for (must be a power of 2).
+ * @return The log2 of n.
+ */
private int log2(int n) {
return (n == 1) ? 0 : log2(n / 2) + 1;
}
- // A utility function to check if a number is a power of 2
+ /**
+ * Checks if a number is a power of 2.
+ *
+ * @param n The number to check.
+ * @return True if n is a power of 2, false otherwise.
+ */
private boolean isPowerOfTwo(int n) {
return n > 0 && (n & (n - 1)) == 0;
}
+ /**
+ * Sets the scores array for the game tree.
+ *
+ * @param scores The array of scores. Length must be a power of 2.
+ * @throws IllegalArgumentException if the scores array length is not a power of
+ * 2
+ */
public void setScores(int[] scores) {
if (!isPowerOfTwo(scores.length)) {
- System.out.println("The number of scores must be a power of 2.");
- return;
+ throw new IllegalArgumentException("The number of scores must be a power of 2.");
}
- this.scores = scores;
+ this.scores = Arrays.copyOf(scores, scores.length);
height = log2(this.scores.length);
}
+ /**
+ * Returns a copy of the scores array.
+ *
+ * @return A copy of the scores array.
+ */
public int[] getScores() {
- return scores;
+ return Arrays.copyOf(scores, scores.length);
}
+ /**
+ * Returns the height of the game tree.
+ *
+ * @return The height of the game tree (log2 of the number of leaf nodes).
+ */
public int getHeight() {
return height;
}
diff --git a/src/main/java/com/thealgorithms/others/PageRank.java b/src/main/java/com/thealgorithms/others/PageRank.java
index c7be7a9882bc..2899b80bcee8 100644
--- a/src/main/java/com/thealgorithms/others/PageRank.java
+++ b/src/main/java/com/thealgorithms/others/PageRank.java
@@ -2,94 +2,306 @@
import java.util.Scanner;
-class PageRank {
+/**
+ * PageRank Algorithm Implementation
+ *
+ *
+ * The PageRank algorithm is used by Google Search to rank web pages in their
+ * search engine
+ * results. It was named after Larry Page, one of the founders of Google.
+ * PageRank is a way of
+ * measuring the importance of website pages.
+ *
+ *
+ * Algorithm: 1. Initialize PageRank values for all pages to 1/N (where N is the
+ * total number
+ * of pages) 2. For each iteration: - For each page, calculate the new PageRank
+ * by summing the
+ * contributions from all incoming links - Apply the damping factor: PR(page) =
+ * (1-d) + d *
+ * sum(PR(incoming_page) / outgoing_links(incoming_page)) 3. Repeat until
+ * convergence
+ *
+ * @see PageRank Algorithm
+ */
+public final class PageRank {
+ private static final int MAX_NODES = 10;
+ private static final double DEFAULT_DAMPING_FACTOR = 0.85;
+ private static final int DEFAULT_ITERATIONS = 2;
+
+ private int[][] adjacencyMatrix;
+ private double[] pageRankValues;
+ private int nodeCount;
+
+ /**
+ * Constructor to initialize PageRank with specified number of nodes
+ *
+ * @param numberOfNodes the number of nodes/pages in the graph
+ * @throws IllegalArgumentException if numberOfNodes is less than 1 or greater
+ * than MAX_NODES
+ */
+ public PageRank(int numberOfNodes) {
+ if (numberOfNodes < 1 || numberOfNodes > MAX_NODES) {
+ throw new IllegalArgumentException("Number of nodes must be between 1 and " + MAX_NODES);
+ }
+ this.nodeCount = numberOfNodes;
+ this.adjacencyMatrix = new int[MAX_NODES][MAX_NODES];
+ this.pageRankValues = new double[MAX_NODES];
+ }
+
+ /**
+ * Default constructor for interactive mode
+ */
+ public PageRank() {
+ this.adjacencyMatrix = new int[MAX_NODES][MAX_NODES];
+ this.pageRankValues = new double[MAX_NODES];
+ }
+
+ /**
+ * Main method for interactive PageRank calculation
+ *
+ * @param args command line arguments (not used)
+ */
public static void main(String[] args) {
- int nodes;
- int i;
- int j;
- Scanner in = new Scanner(System.in);
- System.out.print("Enter the Number of WebPages: ");
- nodes = in.nextInt();
- PageRank p = new PageRank();
- System.out.println("Enter the Adjacency Matrix with 1->PATH & 0->NO PATH Between two WebPages: ");
- for (i = 1; i <= nodes; i++) {
- for (j = 1; j <= nodes; j++) {
- p.path[i][j] = in.nextInt();
- if (j == i) {
- p.path[i][j] = 0;
+ try (Scanner scanner = new Scanner(System.in)) {
+ System.out.print("Enter the Number of WebPages: ");
+ int nodes = scanner.nextInt();
+
+ PageRank pageRank = new PageRank(nodes);
+ System.out.println("Enter the Adjacency Matrix with 1->PATH & 0->NO PATH Between two WebPages: ");
+
+ for (int i = 1; i <= nodes; i++) {
+ for (int j = 1; j <= nodes; j++) {
+ int value = scanner.nextInt();
+ pageRank.setEdge(i, j, value);
}
}
+
+ pageRank.calculatePageRank(nodes, DEFAULT_DAMPING_FACTOR, DEFAULT_ITERATIONS, true);
}
- p.calc(nodes);
}
- public int[][] path = new int[10][10];
- public double[] pagerank = new double[10];
+ /**
+ * Sets an edge in the adjacency matrix
+ *
+ * @param from source node (1-indexed)
+ * @param to destination node (1-indexed)
+ * @param value 1 if edge exists, 0 otherwise
+ */
+ public void setEdge(int from, int to, int value) {
+ if (from == to) {
+ adjacencyMatrix[from][to] = 0; // No self-loops
+ } else {
+ adjacencyMatrix[from][to] = value;
+ }
+ }
- public void calc(double totalNodes) {
- double initialPageRank;
- double outgoingLinks = 0;
- double dampingFactor = 0.85;
- double[] tempPageRank = new double[10];
- int externalNodeNumber;
- int internalNodeNumber;
- int k = 1; // For Traversing
- int iterationStep = 1;
- initialPageRank = 1 / totalNodes;
- System.out.printf(" Total Number of Nodes :" + totalNodes + "\t Initial PageRank of All Nodes :" + initialPageRank + "\n");
+ /**
+ * Sets the adjacency matrix for the graph
+ *
+ * @param matrix the adjacency matrix (1-indexed)
+ */
+ public void setAdjacencyMatrix(int[][] matrix) {
+ for (int i = 1; i <= nodeCount; i++) {
+ for (int j = 1; j <= nodeCount; j++) {
+ setEdge(i, j, matrix[i][j]);
+ }
+ }
+ }
- // 0th ITERATION _ OR _ INITIALIZATION PHASE //
- for (k = 1; k <= totalNodes; k++) {
- this.pagerank[k] = initialPageRank;
+ /**
+ * Gets the PageRank value for a specific node
+ *
+ * @param node the node index (1-indexed)
+ * @return the PageRank value
+ */
+ public double getPageRank(int node) {
+ if (node < 1 || node > nodeCount) {
+ throw new IllegalArgumentException("Node index out of bounds");
}
- System.out.print("\n Initial PageRank Values , 0th Step \n");
+ return pageRankValues[node];
+ }
+
+ /**
+ * Gets all PageRank values
+ *
+ * @return array of PageRank values (1-indexed)
+ */
+ public double[] getAllPageRanks() {
+ return pageRankValues.clone();
+ }
+
+ /**
+ * Calculates PageRank using the default damping factor and iterations
+ *
+ * @param totalNodes the total number of nodes
+ * @return array of PageRank values
+ */
+ public double[] calculatePageRank(int totalNodes) {
+ return calculatePageRank(totalNodes, DEFAULT_DAMPING_FACTOR, DEFAULT_ITERATIONS, false);
+ }
+
+ /**
+ * Calculates PageRank with custom parameters
+ *
+ * @param totalNodes the total number of nodes
+ * @param dampingFactor the damping factor (typically 0.85)
+ * @param iterations number of iterations to perform
+ * @param verbose whether to print detailed output
+ * @return array of PageRank values
+ */
+ public double[] calculatePageRank(int totalNodes, double dampingFactor, int iterations, boolean verbose) {
+ validateInputParameters(totalNodes, dampingFactor, iterations);
- for (k = 1; k <= totalNodes; k++) {
- System.out.printf(" Page Rank of " + k + " is :\t" + this.pagerank[k] + "\n");
+ this.nodeCount = totalNodes;
+ double initialPageRank = 1.0 / totalNodes;
+
+ if (verbose) {
+ System.out.printf("Total Number of Nodes: %d\tInitial PageRank of All Nodes: %.6f%n", totalNodes, initialPageRank);
}
- while (iterationStep <= 2) { // Iterations
- // Store the PageRank for All Nodes in Temporary Array
- for (k = 1; k <= totalNodes; k++) {
- tempPageRank[k] = this.pagerank[k];
- this.pagerank[k] = 0;
- }
+ initializePageRanks(totalNodes, initialPageRank, verbose);
+ performIterations(totalNodes, dampingFactor, iterations, verbose);
- for (internalNodeNumber = 1; internalNodeNumber <= totalNodes; internalNodeNumber++) {
- for (externalNodeNumber = 1; externalNodeNumber <= totalNodes; externalNodeNumber++) {
- if (this.path[externalNodeNumber][internalNodeNumber] == 1) {
- k = 1;
- outgoingLinks = 0; // Count the Number of Outgoing Links for each externalNodeNumber
- while (k <= totalNodes) {
- if (this.path[externalNodeNumber][k] == 1) {
- outgoingLinks = outgoingLinks + 1; // Counter for Outgoing Links
- }
- k = k + 1;
- }
- // Calculate PageRank
- this.pagerank[internalNodeNumber] += tempPageRank[externalNodeNumber] * (1 / outgoingLinks);
- }
- }
- System.out.printf("\n After " + iterationStep + "th Step \n");
+ if (verbose) {
+ System.out.println("\nFinal PageRank:");
+ printPageRanks(totalNodes);
+ }
- for (k = 1; k <= totalNodes; k++) {
- System.out.printf(" Page Rank of " + k + " is :\t" + this.pagerank[k] + "\n");
- }
+ return pageRankValues.clone();
+ }
+
+ /**
+ * Validates input parameters for PageRank calculation
+ *
+ * @param totalNodes the total number of nodes
+ * @param dampingFactor the damping factor
+ * @param iterations number of iterations
+ * @throws IllegalArgumentException if parameters are invalid
+ */
+ private void validateInputParameters(int totalNodes, double dampingFactor, int iterations) {
+ if (totalNodes < 1 || totalNodes > MAX_NODES) {
+ throw new IllegalArgumentException("Total nodes must be between 1 and " + MAX_NODES);
+ }
+ if (dampingFactor < 0 || dampingFactor > 1) {
+ throw new IllegalArgumentException("Damping factor must be between 0 and 1");
+ }
+ if (iterations < 1) {
+ throw new IllegalArgumentException("Iterations must be at least 1");
+ }
+ }
+
+ /**
+ * Initializes PageRank values for all nodes
+ *
+ * @param totalNodes the total number of nodes
+ * @param initialPageRank the initial PageRank value
+ * @param verbose whether to print output
+ */
+ private void initializePageRanks(int totalNodes, double initialPageRank, boolean verbose) {
+ for (int i = 1; i <= totalNodes; i++) {
+ pageRankValues[i] = initialPageRank;
+ }
+
+ if (verbose) {
+ System.out.println("\nInitial PageRank Values, 0th Step");
+ printPageRanks(totalNodes);
+ }
+ }
- iterationStep = iterationStep + 1;
+ /**
+ * Performs the iterative PageRank calculation
+ *
+ * @param totalNodes the total number of nodes
+ * @param dampingFactor the damping factor
+ * @param iterations number of iterations
+ * @param verbose whether to print output
+ */
+ private void performIterations(int totalNodes, double dampingFactor, int iterations, boolean verbose) {
+ for (int iteration = 1; iteration <= iterations; iteration++) {
+ double[] tempPageRank = storeCurrentPageRanks(totalNodes);
+ calculateNewPageRanks(totalNodes, tempPageRank);
+ applyDampingFactor(totalNodes, dampingFactor);
+
+ if (verbose) {
+ System.out.printf("%nAfter %d iteration(s)%n", iteration);
+ printPageRanks(totalNodes);
}
+ }
+ }
- // Add the Damping Factor to PageRank
- for (k = 1; k <= totalNodes; k++) {
- this.pagerank[k] = (1 - dampingFactor) + dampingFactor * this.pagerank[k];
+ /**
+ * Stores current PageRank values in a temporary array
+ *
+ * @param totalNodes the total number of nodes
+ * @return temporary array with current PageRank values
+ */
+ private double[] storeCurrentPageRanks(int totalNodes) {
+ double[] tempPageRank = new double[MAX_NODES];
+ for (int i = 1; i <= totalNodes; i++) {
+ tempPageRank[i] = pageRankValues[i];
+ pageRankValues[i] = 0;
+ }
+ return tempPageRank;
+ }
+
+ /**
+ * Calculates new PageRank values based on incoming links
+ *
+ * @param totalNodes the total number of nodes
+ * @param tempPageRank temporary array with previous PageRank values
+ */
+ private void calculateNewPageRanks(int totalNodes, double[] tempPageRank) {
+ for (int targetNode = 1; targetNode <= totalNodes; targetNode++) {
+ for (int sourceNode = 1; sourceNode <= totalNodes; sourceNode++) {
+ if (adjacencyMatrix[sourceNode][targetNode] == 1) {
+ int outgoingLinks = countOutgoingLinks(sourceNode, totalNodes);
+ if (outgoingLinks > 0) {
+ pageRankValues[targetNode] += tempPageRank[sourceNode] / outgoingLinks;
+ }
+ }
}
+ }
+ }
- // Display PageRank
- System.out.print("\n Final Page Rank : \n");
- for (k = 1; k <= totalNodes; k++) {
- System.out.printf(" Page Rank of " + k + " is :\t" + this.pagerank[k] + "\n");
+ /**
+ * Applies the damping factor to all PageRank values
+ *
+ * @param totalNodes the total number of nodes
+ * @param dampingFactor the damping factor
+ */
+ private void applyDampingFactor(int totalNodes, double dampingFactor) {
+ for (int i = 1; i <= totalNodes; i++) {
+ pageRankValues[i] = (1 - dampingFactor) + dampingFactor * pageRankValues[i];
+ }
+ }
+
+ /**
+ * Counts the number of outgoing links from a node
+ *
+ * @param node the source node (1-indexed)
+ * @param totalNodes total number of nodes
+ * @return the count of outgoing links
+ */
+ private int countOutgoingLinks(int node, int totalNodes) {
+ int count = 0;
+ for (int i = 1; i <= totalNodes; i++) {
+ if (adjacencyMatrix[node][i] == 1) {
+ count++;
}
}
+ return count;
+ }
+
+ /**
+ * Prints the PageRank values for all nodes
+ *
+ * @param totalNodes the total number of nodes
+ */
+ private void printPageRanks(int totalNodes) {
+ for (int i = 1; i <= totalNodes; i++) {
+ System.out.printf("PageRank of %d: %.6f%n", i, pageRankValues[i]);
+ }
}
}
diff --git a/src/main/java/com/thealgorithms/others/PrintAMatrixInSpiralOrder.java b/src/main/java/com/thealgorithms/others/PrintAMatrixInSpiralOrder.java
deleted file mode 100644
index abfdd006879e..000000000000
--- a/src/main/java/com/thealgorithms/others/PrintAMatrixInSpiralOrder.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.thealgorithms.others;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class PrintAMatrixInSpiralOrder {
- /**
- * Search a key in row and column wise sorted matrix
- *
- * @param matrix matrix to be searched
- * @param row number of rows matrix has
- * @param col number of columns matrix has
- * @author Sadiul Hakim : https://github.com/sadiul-hakim
- */
- public List The system is defined by the second-order differential equation:
+ * x'' + 2 * gamma * x' + omega₀² * x = 0
+ * where:
+ * This implementation provides:
+ * Usage Example:
+ *
+ * The algorithm works by:
+ * 1. Storing the last element of the array
+ * 2. Placing the search key at the last position (sentinel)
+ * 3. Searching from the beginning without bound checking
+ * 4. If found before the last position, return the index
+ * 5. If found at the last position, check if it was originally there
+ *
+ *
+ * Time Complexity:
+ * - Best case: O(1) - when the element is at the first position
+ * - Average case: O(n) - when the element is in the middle
+ * - Worst case: O(n) - when the element is not present
+ *
+ *
+ * Space Complexity: O(1) - only uses constant extra space
+ *
+ *
+ * Advantages over regular linear search:
+ * - Reduces the number of comparisons by eliminating bound checking
+ * - Slightly more efficient in practice due to fewer conditional checks
+ *
+ * @author TheAlgorithms Contributors
+ * @see LinearSearch
+ * @see SearchAlgorithm
+ */
+public class SentinelLinearSearch implements SearchAlgorithm {
+ /**
+ * Performs sentinel linear search on the given array.
+ *
+ * @param array the array to search in
+ * @param key the element to search for
+ * @param The algorithm selects a pivot element and partitions the array into two
+ * subarrays such that:
+ * The subarrays are then recursively sorted until the entire array is ordered.
+ *
+ * This implementation uses randomization to reduce the probability of
+ * encountering worst-case performance on already sorted inputs.
+ *
+ * Time Complexity:
+ * Space Complexity: O(log n) due to recursion stack (in-place sorting).
+ *
+ * @author Varun Upadhyay
+ * @author Podshivalov Nikita
* @see SortAlgorithm
*/
+
class QuickSort implements SortAlgorithm {
- /**
- * This method implements the Generic Quick Sort
- *
- * @param array The array to be sorted Sorts the array in increasing order
- */
@Override
public It can be viewed as a variant of heapsort that maintains a forest of heap-ordered Leonardo trees
+ * (trees whose sizes are Leonardo numbers). The algorithm is adaptive: when the input is already
+ * sorted or nearly sorted, the heap invariants are often satisfied and the expensive rebalancing
+ * operations do little work, yielding near-linear behavior.
+ *
+ * Time Complexity:
+ * Space Complexity: O(1) auxiliary space (in-place).
+ *
+ * @see Smoothsort
+ * @see Leonardo numbers
+ * @see SortAlgorithm
+ */
+public class SmoothSort implements SortAlgorithm {
+
+ /**
+ * Leonardo numbers (L(0) = L(1) = 1, L(k+2) = L(k+1) + L(k) + 1) up to the largest value that
+ * fits into a signed 32-bit integer.
+ */
+ private static final int[] LEONARDO = {1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337,
+ 126491971, 204668309, 331160281, 535828591, 866988873, 1402817465};
+
+ /**
+ * Sorts the given array in ascending order using Smooth Sort.
+ *
+ * @param array the array to sort
+ * @param A "word" is defined as a maximal substring consisting of non-space
+ * characters only. Trailing spaces at the end of the string are ignored.
+ *
+ * Example:
+ * This implementation runs in O(n) time complexity, where n is the length
+ * of the input string, and uses O(1) additional space.
+ */
+public class LengthOfLastWord {
+
+ /**
+ * Returns the length of the last word in the specified string.
+ *
+ * The method iterates from the end of the string, skipping trailing
+ * spaces first, and then counts the number of consecutive non-space characters
+ * characters until another space (or the beginning of the string) is reached.
+ *
+ * @param s the input string to analyze
+ * @return the length of the last word in {@code s}; returns 0 if there is no word
+ * @throws NullPointerException if {@code s} is {@code null}
+ */
+ public int lengthOfLastWord(String s) {
+ int sizeOfString = s.length() - 1;
+ int lastWordLength = 0;
+
+ // Skip trailing spaces from the end of the string
+ while (sizeOfString >= 0 && s.charAt(sizeOfString) == ' ') {
+ sizeOfString--;
+ }
+
+ // Count the characters of the last word
+ while (sizeOfString >= 0 && s.charAt(sizeOfString) != ' ') {
+ lastWordLength++;
+ sizeOfString--;
+ }
+
+ return lastWordLength;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/strings/Pangram.java b/src/main/java/com/thealgorithms/strings/Pangram.java
index 01307b28f6c6..a92c282d7e52 100644
--- a/src/main/java/com/thealgorithms/strings/Pangram.java
+++ b/src/main/java/com/thealgorithms/strings/Pangram.java
@@ -60,7 +60,7 @@ public static boolean isPangram(String s) {
}
/**
- * Checks if a String is Pangram or not by checking if each alhpabet is present or not
+ * Checks if a String is Pangram or not by checking if each alphabet is present or not
*
* @param s The String to check
* @return {@code true} if s is a Pangram, otherwise {@code false}
diff --git a/src/main/java/com/thealgorithms/strings/Upper.java b/src/main/java/com/thealgorithms/strings/Upper.java
index 5e248cb6ee39..85db7d41e1aa 100644
--- a/src/main/java/com/thealgorithms/strings/Upper.java
+++ b/src/main/java/com/thealgorithms/strings/Upper.java
@@ -15,23 +15,27 @@ public static void main(String[] args) {
}
/**
- * Converts all the characters in this {@code String} to upper case
+ * Converts all the characters in this {@code String} to upper case.
*
* @param s the string to convert
* @return the {@code String}, converted to uppercase.
*/
public static String toUpperCase(String s) {
if (s == null) {
- throw new IllegalArgumentException("Input string connot be null");
+ throw new IllegalArgumentException("Input string cannot be null");
}
if (s.isEmpty()) {
return s;
}
- StringBuilder result = new StringBuilder(s);
- for (int i = 0; i < result.length(); ++i) {
- char currentChar = result.charAt(i);
- if (Character.isLetter(currentChar) && Character.isLowerCase(currentChar)) {
- result.setCharAt(i, Character.toUpperCase(currentChar));
+
+ StringBuilder result = new StringBuilder(s.length());
+
+ for (int i = 0; i < s.length(); ++i) {
+ char currentChar = s.charAt(i);
+ if (Character.isLowerCase(currentChar)) {
+ result.append(Character.toUpperCase(currentChar));
+ } else {
+ result.append(currentChar);
}
}
return result.toString();
diff --git a/src/main/java/com/thealgorithms/strings/ZAlgorithm.java b/src/main/java/com/thealgorithms/strings/ZAlgorithm.java
new file mode 100644
index 000000000000..dc029b751f45
--- /dev/null
+++ b/src/main/java/com/thealgorithms/strings/ZAlgorithm.java
@@ -0,0 +1,48 @@
+/*
+ * https://en.wikipedia.org/wiki/Z-algorithm
+ */
+package com.thealgorithms.strings;
+
+public final class ZAlgorithm {
+
+ private ZAlgorithm() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ public static int[] zFunction(String s) {
+ int n = s.length();
+ int[] z = new int[n];
+ int l = 0;
+ int r = 0;
+
+ for (int i = 1; i < n; i++) {
+ if (i <= r) {
+ z[i] = Math.min(r - i + 1, z[i - l]);
+ }
+
+ while (i + z[i] < n && s.charAt(z[i]) == s.charAt(i + z[i])) {
+ z[i]++;
+ }
+
+ if (i + z[i] - 1 > r) {
+ l = i;
+ r = i + z[i] - 1;
+ }
+ }
+
+ return z;
+ }
+
+ public static int search(String text, String pattern) {
+ String s = pattern + "$" + text;
+ int[] z = zFunction(s);
+ int p = pattern.length();
+
+ for (int i = 0; i < z.length; i++) {
+ if (z[i] == p) {
+ return i - p - 1;
+ }
+ }
+ return -1;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/backtracking/CombinationSumTest.java b/src/test/java/com/thealgorithms/backtracking/CombinationSumTest.java
new file mode 100644
index 000000000000..986c71acebe8
--- /dev/null
+++ b/src/test/java/com/thealgorithms/backtracking/CombinationSumTest.java
@@ -0,0 +1,29 @@
+package com.thealgorithms.backtracking;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+class CombinationSumTest {
+ private static List
+ *
+ *
+ * IMPORTANT contracts
+ *
+ *
+ *
+ *
+ *
+ * If you prefer value-based semantics, replace with HashMapRules:
+ *
+ *
+ *
+ * Example:
+ *
+ *
+ * Input tree:
+ * 1
+ * / \
+ * 2 3
+ * \
+ * 4
+ *
+ * Output string:
+ * "1(2()(4))(3)"
+ *
+ *
+ * > adj;
+ private final int[] parent;
+ private final int[] subtreeSize;
+ private final boolean[] removed;
+ private int root;
+
+ /**
+ * Constructs a centroid tree from an adjacency list.
+ *
+ * @param adj adjacency list representation of the tree (0-indexed)
+ * @throws IllegalArgumentException if tree is empty or null
+ */
+ public CentroidTree(List
> adj) {
+ if (adj == null || adj.isEmpty()) {
+ throw new IllegalArgumentException("Tree cannot be empty or null");
+ }
+
+ this.n = adj.size();
+ this.adj = adj;
+ this.parent = new int[n];
+ this.subtreeSize = new int[n];
+ this.removed = new boolean[n];
+ Arrays.fill(parent, -1);
+
+ // Build centroid tree starting from node 0
+ this.root = decompose(0, -1);
+ }
+
+ /**
+ * Recursively builds the centroid tree.
+ *
+ * @param u current node
+ * @param p parent in centroid tree
+ * @return centroid of current component
+ */
+ private int decompose(int u, int p) {
+ int size = getSubtreeSize(u, -1);
+ int centroid = findCentroid(u, -1, size);
+
+ removed[centroid] = true;
+ parent[centroid] = p;
+
+ // Recursively decompose each subtree
+ for (int v : adj.get(centroid)) {
+ if (!removed[v]) {
+ decompose(v, centroid);
+ }
+ }
+
+ return centroid;
+ }
+
+ /**
+ * Calculates subtree size from node u.
+ *
+ * @param u current node
+ * @param p parent node (-1 for root)
+ * @return size of subtree rooted at u
+ */
+ private int getSubtreeSize(int u, int p) {
+ subtreeSize[u] = 1;
+ for (int v : adj.get(u)) {
+ if (v != p && !removed[v]) {
+ subtreeSize[u] += getSubtreeSize(v, u);
+ }
+ }
+ return subtreeSize[u];
+ }
+
+ /**
+ * Finds the centroid of a subtree.
+ * A centroid is a node whose removal creates components with size <= totalSize/2.
+ *
+ * @param u current node
+ * @param p parent node
+ * @param totalSize total size of current component
+ * @return centroid node
+ */
+ private int findCentroid(int u, int p, int totalSize) {
+ for (int v : adj.get(u)) {
+ if (v != p && !removed[v] && subtreeSize[v] > totalSize / 2) {
+ return findCentroid(v, u, totalSize);
+ }
+ }
+ return u;
+ }
+
+ /**
+ * Gets the parent of a node in the centroid tree.
+ *
+ * @param node the node
+ * @return parent node in centroid tree, or -1 if root
+ */
+ public int getParent(int node) {
+ if (node < 0 || node >= n) {
+ throw new IllegalArgumentException("Invalid node: " + node);
+ }
+ return parent[node];
+ }
+
+ /**
+ * Gets the root of the centroid tree.
+ *
+ * @return root node
+ */
+ public int getRoot() {
+ return root;
+ }
+
+ /**
+ * Gets the number of nodes in the tree.
+ *
+ * @return number of nodes
+ */
+ public int size() {
+ return n;
+ }
+
+ /**
+ * Returns the centroid tree structure as a string.
+ * Format: node -> parent (or ROOT for root node)
+ *
+ * @return string representation
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("Centroid Tree:\n");
+ for (int i = 0; i < n; i++) {
+ sb.append("Node ").append(i).append(" -> ");
+ if (parent[i] == -1) {
+ sb.append("ROOT");
+ } else {
+ sb.append("Parent ").append(parent[i]);
+ }
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+ }
+
+ /**
+ * Creates a centroid tree from an edge list.
+ *
+ * @param n number of nodes (0-indexed: 0 to n-1)
+ * @param edges list of edges where each edge is [u, v]
+ * @return CentroidTree object
+ * @throws IllegalArgumentException if n <= 0 or edges is invalid
+ */
+ public static CentroidTree buildFromEdges(int n, int[][] edges) {
+ if (n <= 0) {
+ throw new IllegalArgumentException("Number of nodes must be positive");
+ }
+ if (edges == null) {
+ throw new IllegalArgumentException("Edges cannot be null");
+ }
+ if (edges.length != n - 1) {
+ throw new IllegalArgumentException("Tree must have exactly n-1 edges");
+ }
+
+ List
> adj = new ArrayList<>();
+ for (int i = 0; i < n; i++) {
+ adj.add(new ArrayList<>());
+ }
+
+ for (int[] edge : edges) {
+ if (edge.length != 2) {
+ throw new IllegalArgumentException("Each edge must have exactly 2 nodes");
+ }
+ int u = edge[0];
+ int v = edge[1];
+
+ if (u < 0 || u >= n || v < 0 || v >= n) {
+ throw new IllegalArgumentException("Invalid node in edge: [" + u + ", " + v + "]");
+ }
+
+ adj.get(u).add(v);
+ adj.get(v).add(u);
+ }
+
+ return new CentroidTree(adj);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTree.java b/src/main/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTree.java
new file mode 100644
index 000000000000..fd8876cecb70
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTree.java
@@ -0,0 +1,145 @@
+/*
+ * TheAlgorithms (https://github.com/TheAlgorithms/Java)
+ * Author: Shewale41
+ * This file is licensed under the MIT License.
+ */
+
+package com.thealgorithms.datastructures.trees;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Threaded binary tree implementation that supports insertion and
+ * in-order traversal without recursion or stack by using threads.
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+public final class Edmonds {
+
+ private Edmonds() {
+ }
+
+ /**
+ * Represents a directed weighted edge in the graph.
+ */
+ public static class Edge {
+ final int from;
+ final int to;
+ final long weight;
+
+ /**
+ * Constructs a directed edge.
+ *
+ * @param from source vertex
+ * @param to destination vertex
+ * @param weight edge weight
+ */
+ public Edge(int from, int to, long weight) {
+ this.from = from;
+ this.to = to;
+ this.weight = weight;
+ }
+ }
+
+ /**
+ * Computes the total weight of the Minimum Spanning Arborescence of a directed,
+ * weighted graph from a given root.
+ *
+ * @param numVertices the number of vertices, labeled {@code 0..numVertices-1}
+ * @param edges list of directed edges in the graph
+ * @param root the root vertex
+ * @return the total weight of the MSA. Returns -1 if not all vertices are reachable
+ * from the root or if a valid arborescence cannot be formed.
+ * @throws IllegalArgumentException if {@code numVertices <= 0} or {@code root} is out of range.
+ */
+ public static long findMinimumSpanningArborescence(int numVertices, List
+ *
+ *
+ * 1. Compute indegree and outdegree for all vertices.
+ * 2. Check if the graph satisfies Eulerian path or circuit conditions.
+ * 3. Verify that all vertices with non-zero degree are weakly connected (undirected connectivity).
+ * 4. Use Hierholzer’s algorithm to build the path by exploring unused edges iteratively.
+ *
+ * Space Complexity: O(V + E).
+ * > adjacencyList;
+
+ /**
+ * Constructs a graph with a given number of vertices.
+ *
+ * @param numNodes number of vertices
+ */
+ public Graph(int numNodes) {
+ adjacencyList = new ArrayList<>();
+ for (int i = 0; i < numNodes; i++) {
+ adjacencyList.add(new ArrayList<>());
+ }
+ }
+
+ /**
+ * Adds a directed edge from vertex {@code from} to vertex {@code to}.
+ *
+ * @param from source vertex
+ * @param to destination vertex
+ */
+ public void addEdge(int from, int to) {
+ adjacencyList.get(from).add(to);
+ }
+
+ /**
+ * Returns a list of outgoing edges from the given vertex.
+ *
+ * @param node vertex index
+ * @return list of destination vertices
+ */
+ public List
> kShortestPaths(int[][] weights, int src, int dst, int k) {
+ validate(weights, src, dst, k);
+ final int n = weights.length;
+ // Make a defensive copy to avoid mutating caller's matrix
+ int[][] weightsCopy = new int[n][n];
+ for (int i = 0; i < n; i++) {
+ weightsCopy[i] = Arrays.copyOf(weights[i], n);
+ }
+
+ List
> result = new ArrayList<>(shortestPaths.size());
+ for (Path p : shortestPaths) {
+ result.add(new ArrayList<>(p.nodes));
+ }
+ return result;
+ }
+
+ private static void validate(int[][] weights, int src, int dst, int k) {
+ if (weights == null || weights.length == 0) {
+ throw new IllegalArgumentException("Weights matrix must not be null or empty");
+ }
+ int n = weights.length;
+ for (int i = 0; i < n; i++) {
+ if (weights[i] == null || weights[i].length != n) {
+ throw new IllegalArgumentException("Weights matrix must be square");
+ }
+ for (int j = 0; j < n; j++) {
+ int val = weights[i][j];
+ if (val < NO_EDGE) {
+ throw new IllegalArgumentException("Weights must be -1 (no edge) or >= 0");
+ }
+ }
+ }
+ if (src < 0 || dst < 0 || src >= n || dst >= n) {
+ throw new IllegalArgumentException("Invalid src/dst indices");
+ }
+ if (k < 1) {
+ throw new IllegalArgumentException("k must be >= 1");
+ }
+ }
+
+ private static boolean startsWith(List
+ *
+ */
+ public static long[] extendedGCD(long a, long b) {
+ if (b == 0) {
+ // Base case: gcd(a, 0) = a. The equation is a*1 + 0*0 = a.
+ return new long[] {a, 1, 0};
+ }
+
+ // Recursive call
+ long[] result = extendedGCD(b, a % b);
+ long gcd = result[0];
+ long x1 = result[1];
+ long y1 = result[2];
+
+ // Update coefficients using the results from the recursive call
+ long x = y1;
+ long y = x1 - a / b * y1;
+
+ return new long[] {gcd, x, y};
+ }
+}
diff --git a/src/main/java/com/thealgorithms/maths/HarshadNumber.java b/src/main/java/com/thealgorithms/maths/HarshadNumber.java
index 5792e925a8aa..abe21cb045ae 100644
--- a/src/main/java/com/thealgorithms/maths/HarshadNumber.java
+++ b/src/main/java/com/thealgorithms/maths/HarshadNumber.java
@@ -1,49 +1,78 @@
package com.thealgorithms.maths;
-// Wikipedia for Harshad Number : https://en.wikipedia.org/wiki/Harshad_number
-
+/**
+ * A Harshad number (or Niven number) in a given number base is an integer that
+ * is divisible by the sum of its digits.
+ * For example, 18 is a Harshad number because 18 is divisible by (1 + 8) = 9.
+ * The name "Harshad" comes from the Sanskrit words "harṣa" (joy) and "da"
+ * (give), meaning "joy-giver".
+ *
+ * @author Hardvan
+ * @see Harshad Number -
+ * Wikipedia
+ */
public final class HarshadNumber {
private HarshadNumber() {
}
/**
- * A function to check if a number is Harshad number or not
+ * Checks if a number is a Harshad number.
+ * A Harshad number is a positive integer that is divisible by the sum of its
+ * digits.
*
- * @param n The number to be checked
- * @return {@code true} if {@code a} is Harshad number, otherwise
+ * @param n the number to be checked (must be positive)
+ * @return {@code true} if {@code n} is a Harshad number, otherwise
* {@code false}
+ * @throws IllegalArgumentException if {@code n} is less than or equal to 0
*/
public static boolean isHarshad(long n) {
if (n <= 0) {
- return false;
+ throw new IllegalArgumentException("Input must be a positive integer. Received: " + n);
}
- long t = n;
+ long temp = n;
long sumOfDigits = 0;
- while (t > 0) {
- sumOfDigits += t % 10;
- t /= 10;
+ while (temp > 0) {
+ sumOfDigits += temp % 10;
+ temp /= 10;
}
return n % sumOfDigits == 0;
}
/**
- * A function to check if a number is Harshad number or not
+ * Checks if a number represented as a string is a Harshad number.
+ * A Harshad number is a positive integer that is divisible by the sum of its
+ * digits.
*
- * @param s The number in String to be checked
- * @return {@code true} if {@code a} is Harshad number, otherwise
+ * @param s the string representation of the number to be checked
+ * @return {@code true} if the number is a Harshad number, otherwise
* {@code false}
+ * @throws IllegalArgumentException if {@code s} is null, empty, or represents a
+ * non-positive integer
+ * @throws NumberFormatException if {@code s} cannot be parsed as a long
*/
public static boolean isHarshad(String s) {
- final Long n = Long.valueOf(s);
+ if (s == null || s.isEmpty()) {
+ throw new IllegalArgumentException("Input string cannot be null or empty");
+ }
+
+ final long n;
+ try {
+ n = Long.parseLong(s);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Input string must be a valid integer: " + s, e);
+ }
+
if (n <= 0) {
- return false;
+ throw new IllegalArgumentException("Input must be a positive integer. Received: " + n);
}
int sumOfDigits = 0;
for (char ch : s.toCharArray()) {
- sumOfDigits += ch - '0';
+ if (Character.isDigit(ch)) {
+ sumOfDigits += ch - '0';
+ }
}
return n % sumOfDigits == 0;
diff --git a/src/main/java/com/thealgorithms/maths/HeronsFormula.java b/src/main/java/com/thealgorithms/maths/HeronsFormula.java
index 5baee715d1ec..10438e2888b9 100644
--- a/src/main/java/com/thealgorithms/maths/HeronsFormula.java
+++ b/src/main/java/com/thealgorithms/maths/HeronsFormula.java
@@ -1,33 +1,76 @@
package com.thealgorithms.maths;
/**
- * Wikipedia for HeronsFormula => https://en.wikipedia.org/wiki/Heron%27s_formula
- * Find the area of a triangle using only side lengths
+ * Heron's Formula implementation for calculating the area of a triangle given
+ * its three side lengths.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * @see Keith Number -
+ * Wikipedia
+ * @see Keith Number -
+ * MathWorld
+ */
+public final class KeithNumber {
private KeithNumber() {
}
- // user-defined function that checks if the given number is Keith or not
- static boolean isKeith(int x) {
- // List stores all the digits of the X
+ /**
+ * Checks if a given number is a Keith number.
+ *
+ *
+ *
+ *
+ * @param number the number to check (must be positive)
+ * @return {@code true} if the number is a Keith number, {@code false} otherwise
+ * @throws IllegalArgumentException if the number is not positive
+ */
+ public static boolean isKeith(int number) {
+ if (number <= 0) {
+ throw new IllegalArgumentException("Number must be positive");
+ }
+
+ // Extract digits and store them in the list
ArrayList
* boolean isKrishnamurthy = KrishnamurthyNumber.isKrishnamurthy(145);
* System.out.println(isKrishnamurthy); // Output: true
@@ -14,40 +29,43 @@
* isKrishnamurthy = KrishnamurthyNumber.isKrishnamurthy(123);
* System.out.println(isKrishnamurthy); // Output: false
*
+ *
+ * @see Factorion
+ * (Wikipedia)
*/
public final class KrishnamurthyNumber {
+ // Pre-computed factorials for digits 0-9 to improve performance
+ private static final int[] FACTORIALS = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
+
private KrishnamurthyNumber() {
}
/**
* Checks if a number is a Krishnamurthy number.
*
- * @param n The number to check
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * int[][] matrix = {
+ * {1, 2, 3},
+ * {4, 5, 6},
+ * {7, 8, 9}
+ * };
+ * print(matrix, 3, 3) returns [1, 2, 3, 6, 9, 8, 7, 4, 5]
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * @author TheAlgorithms community
+ * @see Array
+ * Data Structure
+ */
public final class InsertDeleteInArray {
private InsertDeleteInArray() {
}
+ /**
+ * Inserts an element at the specified position in the array.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * {@code
+ * DampedOscillator oscillator = new DampedOscillator(10.0, 0.5);
+ * double displacement = oscillator.displacementAnalytical(1.0, 0.0, 0.1);
+ * double[] nextState = oscillator.stepEuler(new double[]{1.0, 0.0}, 0.001);
+ * }
+ *
+ * @author [Yash Rajput](https://github.com/the-yash-rajput)
+ */
+public final class DampedOscillator {
+
+ /** Natural (undamped) angular frequency (rad/s). */
+ private final double omega0;
+
+ /** Damping coefficient (s⁻¹). */
+ private final double gamma;
+
+ private DampedOscillator() {
+ throw new AssertionError("No instances.");
+ }
+
+ /**
+ * Constructs a damped oscillator model.
+ *
+ * @param omega0 the natural frequency (rad/s), must be positive
+ * @param gamma the damping coefficient (s⁻¹), must be non-negative
+ * @throws IllegalArgumentException if parameters are invalid
+ */
+ public DampedOscillator(double omega0, double gamma) {
+ if (omega0 <= 0) {
+ throw new IllegalArgumentException("Natural frequency must be positive.");
+ }
+ if (gamma < 0) {
+ throw new IllegalArgumentException("Damping coefficient must be non-negative.");
+ }
+ this.omega0 = omega0;
+ this.gamma = gamma;
+ }
+
+ /**
+ * Computes the analytical displacement of an underdamped oscillator.
+ * Formula: x(t) = A * exp(-γt) * cos(ω_d t + φ)
+ *
+ * @param amplitude the initial amplitude A
+ * @param phase the initial phase φ (radians)
+ * @param time the time t (seconds)
+ * @return the displacement x(t)
+ */
+ public double displacementAnalytical(double amplitude, double phase, double time) {
+ double omegaD = Math.sqrt(Math.max(0.0, omega0 * omega0 - gamma * gamma));
+ return amplitude * Math.exp(-gamma * time) * Math.cos(omegaD * time + phase);
+ }
+
+ /**
+ * Performs a single integration step using the explicit Euler method.
+ * State vector format: [x, v], where v = dx/dt.
+ *
+ * @param state the current state [x, v]
+ * @param dt the time step (seconds)
+ * @return the next state [x_next, v_next]
+ * @throws IllegalArgumentException if the state array is invalid or dt is non-positive
+ */
+ public double[] stepEuler(double[] state, double dt) {
+ if (state == null || state.length != 2) {
+ throw new IllegalArgumentException("State must be a non-null array of length 2.");
+ }
+ if (dt <= 0) {
+ throw new IllegalArgumentException("Time step must be positive.");
+ }
+
+ double x = state[0];
+ double v = state[1];
+ double acceleration = -2.0 * gamma * v - omega0 * omega0 * x;
+
+ double xNext = x + dt * v;
+ double vNext = v + dt * acceleration;
+
+ return new double[] {xNext, vNext};
+ }
+
+ /** @return the natural (undamped) angular frequency (rad/s). */
+ public double getOmega0() {
+ return omega0;
+ }
+
+ /** @return the damping coefficient (s⁻¹). */
+ public double getGamma() {
+ return gamma;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/physics/ElasticCollision2D.java b/src/main/java/com/thealgorithms/physics/ElasticCollision2D.java
new file mode 100644
index 000000000000..399c3f1e041f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/physics/ElasticCollision2D.java
@@ -0,0 +1,73 @@
+package com.thealgorithms.physics;
+
+/**
+ * 2D Elastic collision between two circular bodies
+ * Based on principles of conservation of momentum and kinetic energy.
+ *
+ * @author [Yash Rajput](https://github.com/the-yash-rajput)
+ */
+public final class ElasticCollision2D {
+
+ private ElasticCollision2D() {
+ throw new AssertionError("No instances. Utility class");
+ }
+
+ public static class Body {
+ public double x;
+ public double y;
+ public double vx;
+ public double vy;
+ public double mass;
+ public double radius;
+
+ public Body(double x, double y, double vx, double vy, double mass, double radius) {
+ this.x = x;
+ this.y = y;
+ this.vx = vx;
+ this.vy = vy;
+ this.mass = mass;
+ this.radius = radius;
+ }
+ }
+
+ /**
+ * Resolve instantaneous elastic collision between two circular bodies.
+ *
+ * @param a first body
+ * @param b second body
+ */
+ public static void resolveCollision(Body a, Body b) {
+ double dx = b.x - a.x;
+ double dy = b.y - a.y;
+ double dist = Math.hypot(dx, dy);
+
+ if (dist == 0) {
+ return; // overlapping
+ }
+
+ double nx = dx / dist;
+ double ny = dy / dist;
+
+ // relative velocity along normal
+ double rv = (b.vx - a.vx) * nx + (b.vy - a.vy) * ny;
+
+ if (rv > 0) {
+ return; // moving apart
+ }
+
+ // impulse with masses
+ double m1 = a.mass;
+ double m2 = b.mass;
+
+ double j = -(1 + 1.0) * rv / (1.0 / m1 + 1.0 / m2);
+
+ // impulse vector
+ double impulseX = j * nx;
+ double impulseY = j * ny;
+
+ a.vx -= impulseX / m1;
+ a.vy -= impulseY / m1;
+ b.vx += impulseX / m2;
+ b.vy += impulseY / m2;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/physics/Gravitation.java b/src/main/java/com/thealgorithms/physics/Gravitation.java
new file mode 100644
index 000000000000..292fdc195f85
--- /dev/null
+++ b/src/main/java/com/thealgorithms/physics/Gravitation.java
@@ -0,0 +1,66 @@
+package com.thealgorithms.physics;
+
+/**
+ * Implements Newton's Law of Universal Gravitation.
+ * Provides simple static methods to calculate gravitational force and circular orbit velocity.
+ *
+ * @author [Priyanshu Kumar Singh](https://github.com/Priyanshu1303d)
+ * @see Wikipedia
+ */
+public final class Gravitation {
+
+ /** Gravitational constant in m^3 kg^-1 s^-2 */
+ public static final double GRAVITATIONAL_CONSTANT = 6.67430e-11;
+
+ /**
+ * Private constructor to prevent instantiation of this utility class.
+ */
+ private Gravitation() {
+ }
+
+ /**
+ * Calculates the gravitational force vector exerted by one body on another.
+ *
+ * @param m1 Mass of the first body (kg).
+ * @param x1 X-position of the first body (m).
+ * @param y1 Y-position of the first body (m).
+ * @param m2 Mass of the second body (kg).
+ * @param x2 X-position of the second body (m).
+ * @param y2 Y-position of the second body (m).
+ * @return A double array `[fx, fy]` representing the force vector on the second body.
+ */
+ public static double[] calculateGravitationalForce(double m1, double x1, double y1, double m2, double x2, double y2) {
+ double dx = x1 - x2;
+ double dy = y1 - y2;
+ double distanceSq = dx * dx + dy * dy;
+
+ // If bodies are at the same position, force is zero to avoid division by zero.
+ if (distanceSq == 0) {
+ return new double[] {0, 0};
+ }
+
+ double distance = Math.sqrt(distanceSq);
+ double forceMagnitude = GRAVITATIONAL_CONSTANT * m1 * m2 / distanceSq;
+
+ // Calculate the components of the force vector
+ double fx = forceMagnitude * (dx / distance);
+ double fy = forceMagnitude * (dy / distance);
+
+ return new double[] {fx, fy};
+ }
+
+ /**
+ * Calculates the speed required for a stable circular orbit.
+ *
+ * @param centralMass The mass of the central body (kg).
+ * @param radius The radius of the orbit (m).
+ * @return The orbital speed (m/s).
+ * @throws IllegalArgumentException if mass or radius are not positive.
+ */
+ public static double calculateCircularOrbitVelocity(double centralMass, double radius) {
+ if (centralMass <= 0 || radius <= 0) {
+ throw new IllegalArgumentException("Mass and radius must be positive.");
+ }
+ return Math.sqrt(GRAVITATIONAL_CONSTANT * centralMass / radius);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/physics/Kinematics.java b/src/main/java/com/thealgorithms/physics/Kinematics.java
new file mode 100644
index 000000000000..d017fe787afd
--- /dev/null
+++ b/src/main/java/com/thealgorithms/physics/Kinematics.java
@@ -0,0 +1,69 @@
+package com.thealgorithms.physics;
+/**
+ * Implements the fundamental "SUVAT" equations for motion
+ * under constant acceleration.
+ *
+ * @author [Priyanshu Kumar Singh](https://github.com/Priyanshu1303d)
+ * @see Wikipedia
+ */
+public final class Kinematics {
+ private Kinematics() {
+ }
+
+ /**
+ * Calculates the final velocity (v) of an object.
+ * Formula: v = u + at
+ *
+ * @param u Initial velocity (m/s).
+ * @param a Constant acceleration (m/s^2).
+ * @param t Time elapsed (s).
+ * @return The final velocity (m/s).
+ */
+
+ public static double calculateFinalVelocity(double u, double a, double t) {
+ return u + a * t;
+ }
+
+ /**
+ * Calculates the displacement (s) of an object.
+ * Formula: s = ut + 0.5 * a * t^2
+ *
+ * @param u Initial velocity (m/s).
+ * @param a Constant acceleration (m/s^2).
+ * @param t Time elapsed (s).
+ * @return The displacement (m).
+ */
+
+ public static double calculateDisplacement(double u, double a, double t) {
+ return u * t + 0.5 * a * t * t;
+ }
+
+ /**
+ * Calculates the displacement (s) of an object.
+ * Formula: v^2 = u^2 + 2 * a * s
+ *
+ * @param u Initial velocity (m/s).
+ * @param a Constant acceleration (m/s^2).
+ * @param s Displacement (m).
+ * @return The final velocity squared (m/s)^2.
+ */
+
+ public static double calculateFinalVelocitySquared(double u, double a, double s) {
+ return u * u + 2 * a * s;
+ }
+
+ /**
+ * Calculates the displacement (s) using the average velocity.
+ * Formula: s = (u + v) / 2 * t
+ *
+ * @param u Initial velocity (m/s).
+ * @param v Final velocity (m/s).
+ * @param t Time elapsed (s).
+ * @return The displacement (m).
+ */
+
+ public static double calculateDisplacementFromVelocities(double u, double v, double t) {
+ double velocitySum = u + v;
+ return velocitySum / 2 * t;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/physics/ProjectileMotion.java b/src/main/java/com/thealgorithms/physics/ProjectileMotion.java
new file mode 100644
index 000000000000..cfc79547922c
--- /dev/null
+++ b/src/main/java/com/thealgorithms/physics/ProjectileMotion.java
@@ -0,0 +1,96 @@
+package com.thealgorithms.physics;
+
+/**
+ *
+ * This implementation calculates the flight path of a projectile launched from any INITIAL HEIGHT.
+ * It is a more flexible version of the ground-to-ground model.
+ *
+ * @see Wikipedia - Projectile Motion
+ * @author [Priyanshu Kumar Singh](https://github.com/Priyanshu1303d)
+ */
+public final class ProjectileMotion {
+
+ private ProjectileMotion() {
+ }
+
+ /** Standard Earth gravity constant*/
+ private static final double GRAVITY = 9.80665;
+
+ /**
+ * A simple container for the results of a projectile motion calculation.
+ */
+ public static final class Result {
+ private final double timeOfFlight;
+ private final double horizontalRange;
+ private final double maxHeight;
+
+ public Result(double timeOfFlight, double horizontalRange, double maxHeight) {
+ this.timeOfFlight = timeOfFlight;
+ this.horizontalRange = horizontalRange;
+ this.maxHeight = maxHeight;
+ }
+
+ /** @return The total time the projectile is in the air (seconds). */
+ public double getTimeOfFlight() {
+ return timeOfFlight;
+ }
+
+ /** @return The total horizontal distance traveled (meters). */
+ public double getHorizontalRange() {
+ return horizontalRange;
+ }
+
+ /** @return The maximum vertical height from the ground (meters). */
+ public double getMaxHeight() {
+ return maxHeight;
+ }
+ }
+
+ /**
+ * Calculates projectile trajectory using standard Earth gravity.
+ *
+ * @param initialVelocity Initial speed of the projectile (m/s).
+ * @param launchAngleDegrees Launch angle from the horizontal (degrees).
+ * @param initialHeight Starting height of the projectile (m).
+ * @return A {@link Result} object with the trajectory data.
+ */
+ public static Result calculateTrajectory(double initialVelocity, double launchAngleDegrees, double initialHeight) {
+ return calculateTrajectory(initialVelocity, launchAngleDegrees, initialHeight, GRAVITY);
+ }
+
+ /**
+ * Calculates projectile trajectory with a custom gravity value.
+ *
+ * @param initialVelocity Initial speed (m/s). Must be non-negative.
+ * @param launchAngleDegrees Launch angle (degrees).
+ * @param initialHeight Starting height (m). Must be non-negative.
+ * @param gravity Acceleration due to gravity (m/s^2). Must be positive.
+ * @return A {@link Result} object with the trajectory data.
+ */
+ public static Result calculateTrajectory(double initialVelocity, double launchAngleDegrees, double initialHeight, double gravity) {
+ if (initialVelocity < 0 || initialHeight < 0 || gravity <= 0) {
+ throw new IllegalArgumentException("Velocity, height, and gravity must be non-negative, and gravity must be positive.");
+ }
+
+ double launchAngleRadians = Math.toRadians(launchAngleDegrees);
+ double initialVerticalVelocity = initialVelocity * Math.sin(launchAngleRadians); // Initial vertical velocity
+ double initialHorizontalVelocity = initialVelocity * Math.cos(launchAngleRadians); // Initial horizontal velocity
+
+ // Correctly calculate total time of flight using the quadratic formula for vertical motion.
+ // y(t) = y0 + initialVerticalVelocity*t - 0.5*g*t^2. We solve for t when y(t) = 0.
+ double totalTimeOfFlight = (initialVerticalVelocity + Math.sqrt(initialVerticalVelocity * initialVerticalVelocity + 2 * gravity * initialHeight)) / gravity;
+
+ // Calculate max height. If launched downwards, max height is the initial height.
+ double maxHeight;
+ if (initialVerticalVelocity > 0) {
+ double heightGained = initialVerticalVelocity * initialVerticalVelocity / (2 * gravity);
+ maxHeight = initialHeight + heightGained;
+ } else {
+ maxHeight = initialHeight;
+ }
+
+ double horizontalRange = initialHorizontalVelocity * totalTimeOfFlight;
+
+ return new Result(totalTimeOfFlight, horizontalRange, maxHeight);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/physics/SimplePendulumRK4.java b/src/main/java/com/thealgorithms/physics/SimplePendulumRK4.java
new file mode 100644
index 000000000000..6de69c103b5a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/physics/SimplePendulumRK4.java
@@ -0,0 +1,126 @@
+package com.thealgorithms.physics;
+
+/**
+ * Simulates a simple pendulum using the Runge-Kutta 4th order method.
+ * The pendulum is modeled with the nonlinear differential equation.
+ *
+ * @author [Yash Rajput](https://github.com/the-yash-rajput)
+ */
+public final class SimplePendulumRK4 {
+
+ private SimplePendulumRK4() {
+ throw new AssertionError("No instances.");
+ }
+
+ private final double length; // meters
+ private final double g; // acceleration due to gravity (m/s^2)
+
+ /**
+ * Constructs a simple pendulum simulator.
+ *
+ * @param length the length of the pendulum in meters
+ * @param g the acceleration due to gravity in m/s^2
+ */
+ public SimplePendulumRK4(double length, double g) {
+ if (length <= 0) {
+ throw new IllegalArgumentException("Length must be positive");
+ }
+ if (g <= 0) {
+ throw new IllegalArgumentException("Gravity must be positive");
+ }
+ this.length = length;
+ this.g = g;
+ }
+
+ /**
+ * Computes the derivatives of the state vector.
+ * State: [theta, omega] where theta is angle and omega is angular velocity.
+ *
+ * @param state the current state [theta, omega]
+ * @return the derivatives [dtheta/dt, domega/dt]
+ */
+ private double[] derivatives(double[] state) {
+ double theta = state[0];
+ double omega = state[1];
+ double dtheta = omega;
+ double domega = -(g / length) * Math.sin(theta);
+ return new double[] {dtheta, domega};
+ }
+
+ /**
+ * Performs one time step using the RK4 method.
+ *
+ * @param state the current state [theta, omega]
+ * @param dt the time step size
+ * @return the new state after time dt
+ */
+ public double[] stepRK4(double[] state, double dt) {
+ if (state == null || state.length != 2) {
+ throw new IllegalArgumentException("State must be array of length 2");
+ }
+ if (dt <= 0) {
+ throw new IllegalArgumentException("Time step must be positive");
+ }
+
+ double[] k1 = derivatives(state);
+ double[] s2 = new double[] {state[0] + 0.5 * dt * k1[0], state[1] + 0.5 * dt * k1[1]};
+
+ double[] k2 = derivatives(s2);
+ double[] s3 = new double[] {state[0] + 0.5 * dt * k2[0], state[1] + 0.5 * dt * k2[1]};
+
+ double[] k3 = derivatives(s3);
+ double[] s4 = new double[] {state[0] + dt * k3[0], state[1] + dt * k3[1]};
+
+ double[] k4 = derivatives(s4);
+
+ double thetaNext = state[0] + dt / 6.0 * (k1[0] + 2 * k2[0] + 2 * k3[0] + k4[0]);
+ double omegaNext = state[1] + dt / 6.0 * (k1[1] + 2 * k2[1] + 2 * k3[1] + k4[1]);
+
+ return new double[] {thetaNext, omegaNext};
+ }
+
+ /**
+ * Simulates the pendulum for a given duration.
+ *
+ * @param initialState the initial state [theta, omega]
+ * @param dt the time step size
+ * @param steps the number of steps to simulate
+ * @return array of states at each step
+ */
+ public double[][] simulate(double[] initialState, double dt, int steps) {
+ double[][] trajectory = new double[steps + 1][2];
+ trajectory[0] = initialState.clone();
+
+ double[] currentState = initialState.clone();
+ for (int i = 1; i <= steps; i++) {
+ currentState = stepRK4(currentState, dt);
+ trajectory[i] = currentState.clone();
+ }
+
+ return trajectory;
+ }
+
+ /**
+ * Calculates the total energy of the pendulum.
+ * E = (1/2) * m * L^2 * omega^2 + m * g * L * (1 - cos(theta))
+ * We use m = 1 for simplicity.
+ *
+ * @param state the current state [theta, omega]
+ * @return the total energy
+ */
+ public double calculateEnergy(double[] state) {
+ double theta = state[0];
+ double omega = state[1];
+ double kineticEnergy = 0.5 * length * length * omega * omega;
+ double potentialEnergy = g * length * (1 - Math.cos(theta));
+ return kineticEnergy + potentialEnergy;
+ }
+
+ public double getLength() {
+ return length;
+ }
+
+ public double getGravity() {
+ return g;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/physics/SnellLaw.java b/src/main/java/com/thealgorithms/physics/SnellLaw.java
new file mode 100644
index 000000000000..2736984814fd
--- /dev/null
+++ b/src/main/java/com/thealgorithms/physics/SnellLaw.java
@@ -0,0 +1,33 @@
+package com.thealgorithms.physics;
+
+/**
+ * Calculates refraction angle using Snell's Law:
+ * n1 * sin(theta1) = n2 * sin(theta2)
+ * @see Snell's Law
+ */
+public final class SnellLaw {
+
+ private SnellLaw() {
+ throw new AssertionError("No instances.");
+ }
+
+ /**
+ * Computes the refracted angle (theta2) in radians.
+ *
+ * @param n1 index of refraction of medium 1
+ * @param n2 index of refraction of medium 2
+ * @param theta1 incident angle in radians
+ * @return refracted angle (theta2) in radians
+ * @throws IllegalArgumentException if total internal reflection occurs
+ */
+ public static double refractedAngle(double n1, double n2, double theta1) {
+ double ratio = n1 / n2;
+ double sinTheta2 = ratio * Math.sin(theta1);
+
+ if (Math.abs(sinTheta2) > 1.0) {
+ throw new IllegalArgumentException("Total internal reflection: no refraction possible.");
+ }
+
+ return Math.asin(sinTheta2);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/physics/ThinLens.java b/src/main/java/com/thealgorithms/physics/ThinLens.java
new file mode 100644
index 000000000000..5fb29d8c41e4
--- /dev/null
+++ b/src/main/java/com/thealgorithms/physics/ThinLens.java
@@ -0,0 +1,74 @@
+package com.thealgorithms.physics;
+
+/**
+ * Implements the Thin Lens Formula used in ray optics:
+ *
+ *
+ * 1/f = 1/v + 1/u
+ *
+ *
+ * where:
+ *
+ *
+ *
+ * Uses the Cartesian sign convention.
+ *
+ * @see Thin Lens
+ */
+public final class ThinLens {
+
+ private ThinLens() {
+ throw new AssertionError("No instances.");
+ }
+
+ /**
+ * Computes the image distance using the thin lens formula.
+ *
+ * @param focalLength focal length of the lens (f)
+ * @param objectDistance object distance (u)
+ * @return image distance (v)
+ * @throws IllegalArgumentException if focal length or object distance is zero
+ */
+ public static double imageDistance(double focalLength, double objectDistance) {
+
+ if (focalLength == 0 || objectDistance == 0) {
+ throw new IllegalArgumentException("Focal length and object distance must be non-zero.");
+ }
+
+ return 1.0 / ((1.0 / focalLength) - (1.0 / objectDistance));
+ }
+
+ /**
+ * Computes magnification of the image.
+ *
+ *
+ * m = v / u
+ *
+ *
+ * @param imageDistance image distance (v)
+ * @param objectDistance object distance (u)
+ * @return magnification
+ * @throws IllegalArgumentException if object distance is zero
+ */
+ public static double magnification(double imageDistance, double objectDistance) {
+
+ if (objectDistance == 0) {
+ throw new IllegalArgumentException("Object distance must be non-zero.");
+ }
+
+ return imageDistance / objectDistance;
+ }
+
+ /**
+ * Determines whether the image formed is real or virtual.
+ *
+ * @param imageDistance image distance (v)
+ * @return {@code true} if image is real, {@code false} if virtual
+ */
+ public static boolean isRealImage(double imageDistance) {
+ return imageDistance > 0;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java b/src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java
deleted file mode 100644
index fce665c4de00..000000000000
--- a/src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java
+++ /dev/null
@@ -1,169 +0,0 @@
-package com.thealgorithms.puzzlesandgames;
-
-/**
- * A class that provides methods to solve Sudoku puzzles of any n x n size
- * using a backtracking approach, where n must be a perfect square.
- * The algorithm checks for safe number placements in rows, columns,
- * and subgrids (which are sqrt(n) x sqrt(n) in size) and recursively solves the puzzle.
- * Though commonly used for 9x9 grids, it is adaptable to other valid Sudoku dimensions.
- */
-final class Sudoku {
-
- private Sudoku() {
- }
-
- /**
- * Checks if placing a number in a specific position on the Sudoku board is safe.
- * The number is considered safe if it does not violate any of the Sudoku rules:
- * - It should not be present in the same row.
- * - It should not be present in the same column.
- * - It should not be present in the corresponding 3x3 subgrid.
- * - It should not be present in the corresponding subgrid, which is sqrt(n) x sqrt(n) in size (e.g., for a 9x9 grid, the subgrid will be 3x3).
- *
- * @param board The current state of the Sudoku board.
- * @param row The row index where the number is to be placed.
- * @param col The column index where the number is to be placed.
- * @param num The number to be placed on the board.
- * @return True if the placement is safe, otherwise false.
- */
- public static boolean isSafe(int[][] board, int row, int col, int num) {
- // Check the row for duplicates
- for (int d = 0; d < board.length; d++) {
- if (board[row][d] == num) {
- return false;
- }
- }
-
- // Check the column for duplicates
- for (int r = 0; r < board.length; r++) {
- if (board[r][col] == num) {
- return false;
- }
- }
-
- // Check the corresponding 3x3 subgrid for duplicates
- int sqrt = (int) Math.sqrt(board.length);
- int boxRowStart = row - row % sqrt;
- int boxColStart = col - col % sqrt;
-
- for (int r = boxRowStart; r < boxRowStart + sqrt; r++) {
- for (int d = boxColStart; d < boxColStart + sqrt; d++) {
- if (board[r][d] == num) {
- return false;
- }
- }
- }
-
- return true;
- }
-
- /**
- * Solves the Sudoku puzzle using backtracking.
- * The algorithm finds an empty cell and tries placing numbers
- * from 1 to n, where n is the size of the board
- * (for example, from 1 to 9 in a standard 9x9 Sudoku).
- * The algorithm finds an empty cell and tries placing numbers from 1 to 9.
- * The standard version of Sudoku uses numbers from 1 to 9, so the algorithm can be
- * easily modified for other variations of the game.
- * If a number placement is valid (checked via `isSafe`), the number is
- * placed and the function recursively attempts to solve the rest of the puzzle.
- * If no solution is possible, the number is removed (backtracked),
- * and the process is repeated.
- *
- * @param board The current state of the Sudoku board.
- * @param n The size of the Sudoku board (typically 9 for a standard puzzle).
- * @return True if the Sudoku puzzle is solvable, false otherwise.
- */
- public static boolean solveSudoku(int[][] board, int n) {
- int row = -1;
- int col = -1;
- boolean isEmpty = true;
-
- // Find the next empty cell
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < n; j++) {
- if (board[i][j] == 0) {
- row = i;
- col = j;
- isEmpty = false;
- break;
- }
- }
- if (!isEmpty) {
- break;
- }
- }
-
- // No empty space left
- if (isEmpty) {
- return true;
- }
-
- // Try placing numbers 1 to n in the empty cell (n should be a perfect square)
- // Eg: n=9 for a standard 9x9 Sudoku puzzle, n=16 for a 16x16 puzzle, etc.
- for (int num = 1; num <= n; num++) {
- if (isSafe(board, row, col, num)) {
- board[row][col] = num;
- if (solveSudoku(board, n)) {
- return true;
- } else {
- // replace it
- board[row][col] = 0;
- }
- }
- }
- return false;
- }
-
- /**
- * Prints the current state of the Sudoku board in a readable format.
- * Each row is printed on a new line, with numbers separated by spaces.
- *
- * @param board The current state of the Sudoku board.
- * @param n The size of the Sudoku board (typically 9 for a standard puzzle).
- */
- public static void print(int[][] board, int n) {
- // Print the board in a nxn grid format
- // if n=9, print the board in a 9x9 grid format
- // if n=16, print the board in a 16x16 grid format
- for (int r = 0; r < n; r++) {
- for (int d = 0; d < n; d++) {
- System.out.print(board[r][d]);
- System.out.print(" ");
- }
- System.out.print("\n");
-
- if ((r + 1) % (int) Math.sqrt(n) == 0) {
- System.out.print("");
- }
- }
- }
-
- /**
- * The driver method to demonstrate solving a Sudoku puzzle.
- * A sample 9x9 Sudoku puzzle is provided, and the program attempts to solve it
- * using the `solveSudoku` method. If a solution is found, it is printed to the console.
- *
- * @param args Command-line arguments (not used in this program).
- */
- public static void main(String[] args) {
- int[][] board = new int[][] {
- {3, 0, 6, 5, 0, 8, 4, 0, 0},
- {5, 2, 0, 0, 0, 0, 0, 0, 0},
- {0, 8, 7, 0, 0, 0, 0, 3, 1},
- {0, 0, 3, 0, 1, 0, 0, 8, 0},
- {9, 0, 0, 8, 6, 3, 0, 0, 5},
- {0, 5, 0, 0, 9, 0, 6, 0, 0},
- {1, 3, 0, 0, 0, 0, 2, 5, 0},
- {0, 0, 0, 0, 0, 0, 0, 7, 4},
- {0, 0, 5, 2, 0, 6, 3, 0, 0},
- };
- int n = board.length;
-
- if (solveSudoku(board, n)) {
- print(board, n);
- } else {
- System.out.println("No solution");
- }
- }
-}
diff --git a/src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java b/src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java
index 05d7abbbcd6c..06101295e880 100644
--- a/src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java
+++ b/src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java
@@ -64,13 +64,21 @@ private static double doApproximate(Function
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * {@code
+ * LengthOfLastWord obj = new LengthOfLastWord();
+ * System.out.println(obj.lengthOfLastWord("Hello World")); // Output: 5
+ * System.out.println(obj.lengthOfLastWord(" fly me to the moon ")); // Output: 4
+ * System.out.println(obj.lengthOfLastWord("luffy is still joyboy")); // Output: 6
+ * }
+ *
+ * > norm(Iterable
> x) {
+ List
> y = new ArrayList<>();
+ for (var p : x) {
+ var q = new ArrayList<>(p);
+ q.sort(Integer::compare);
+ y.add(q);
+ }
+ y.sort(Comparator.
>comparingInt(List::size).thenComparing(Object::toString));
+ return y;
+ }
+
+ @Test
+ void sample() {
+ int[] candidates = {2, 3, 6, 7};
+ int target = 7;
+ var expected = List.of(List.of(2, 2, 3), List.of(7));
+ assertEquals(norm(expected), norm(CombinationSum.combinationSum(candidates, target)));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java b/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java
new file mode 100644
index 000000000000..75d3eae08629
--- /dev/null
+++ b/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java
@@ -0,0 +1,53 @@
+package com.thealgorithms.backtracking;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+class SudokuSolverTest {
+
+ @Test
+ void testSolveSudokuEasyPuzzle() {
+ int[][] board = {{5, 3, 0, 0, 7, 0, 0, 0, 0}, {6, 0, 0, 1, 9, 5, 0, 0, 0}, {0, 9, 8, 0, 0, 0, 0, 6, 0}, {8, 0, 0, 0, 6, 0, 0, 0, 3}, {4, 0, 0, 8, 0, 3, 0, 0, 1}, {7, 0, 0, 0, 2, 0, 0, 0, 6}, {0, 6, 0, 0, 0, 0, 2, 8, 0}, {0, 0, 0, 4, 1, 9, 0, 0, 5}, {0, 0, 0, 0, 8, 0, 0, 7, 9}};
+
+ assertTrue(SudokuSolver.solveSudoku(board));
+
+ int[][] expected = {{5, 3, 4, 6, 7, 8, 9, 1, 2}, {6, 7, 2, 1, 9, 5, 3, 4, 8}, {1, 9, 8, 3, 4, 2, 5, 6, 7}, {8, 5, 9, 7, 6, 1, 4, 2, 3}, {4, 2, 6, 8, 5, 3, 7, 9, 1}, {7, 1, 3, 9, 2, 4, 8, 5, 6}, {9, 6, 1, 5, 3, 7, 2, 8, 4}, {2, 8, 7, 4, 1, 9, 6, 3, 5}, {3, 4, 5, 2, 8, 6, 1, 7, 9}};
+
+ assertArrayEquals(expected, board);
+ }
+
+ @Test
+ void testSolveSudokuHardPuzzle() {
+ int[][] board = {{0, 0, 0, 0, 0, 0, 6, 8, 0}, {0, 0, 0, 0, 7, 3, 0, 0, 9}, {3, 0, 9, 0, 0, 0, 0, 4, 5}, {4, 9, 0, 0, 0, 0, 0, 0, 0}, {8, 0, 3, 0, 5, 0, 9, 0, 2}, {0, 0, 0, 0, 0, 0, 0, 3, 6}, {9, 6, 0, 0, 0, 0, 3, 0, 8}, {7, 0, 0, 6, 8, 0, 0, 0, 0}, {0, 2, 8, 0, 0, 0, 0, 0, 0}};
+
+ assertTrue(SudokuSolver.solveSudoku(board));
+ }
+
+ @Test
+ void testSolveSudokuAlreadySolved() {
+ int[][] board = {{5, 3, 4, 6, 7, 8, 9, 1, 2}, {6, 7, 2, 1, 9, 5, 3, 4, 8}, {1, 9, 8, 3, 4, 2, 5, 6, 7}, {8, 5, 9, 7, 6, 1, 4, 2, 3}, {4, 2, 6, 8, 5, 3, 7, 9, 1}, {7, 1, 3, 9, 2, 4, 8, 5, 6}, {9, 6, 1, 5, 3, 7, 2, 8, 4}, {2, 8, 7, 4, 1, 9, 6, 3, 5}, {3, 4, 5, 2, 8, 6, 1, 7, 9}};
+
+ assertTrue(SudokuSolver.solveSudoku(board));
+ }
+
+ @Test
+ void testSolveSudokuInvalidSize() {
+ int[][] board = {{1, 2, 3}, {4, 5, 6}};
+ assertFalse(SudokuSolver.solveSudoku(board));
+ }
+
+ @Test
+ void testSolveSudokuNullBoard() {
+ assertFalse(SudokuSolver.solveSudoku(null));
+ }
+
+ @Test
+ void testSolveSudokuEmptyBoard() {
+ int[][] board = {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}};
+
+ assertTrue(SudokuSolver.solveSudoku(board));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/backtracking/UniquePermutationTest.java b/src/test/java/com/thealgorithms/backtracking/UniquePermutationTest.java
new file mode 100644
index 000000000000..c8e7cd0af0dd
--- /dev/null
+++ b/src/test/java/com/thealgorithms/backtracking/UniquePermutationTest.java
@@ -0,0 +1,31 @@
+package com.thealgorithms.backtracking;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+public class UniquePermutationTest {
+
+ @Test
+ void testUniquePermutationsAab() {
+ List
> graph;
+ private static final int NUM_VERTICES = 6;
+ private static final int MAX_EDGE_WEIGHT = 10;
+
+ @BeforeEach
+ void setUp() {
+ graph = new ArrayList<>();
+ for (int i = 0; i < NUM_VERTICES; i++) {
+ graph.add(new ArrayList<>());
+ }
+ }
+
+ private void addEdge(int u, int v, int weight) {
+ graph.get(u).add(new DialsAlgorithm.Edge(v, weight));
+ }
+
+ @Test
+ @DisplayName("Test with a simple connected graph")
+ void testSimpleGraph() {
+ // Build graph from a standard example
+ addEdge(0, 1, 2);
+ addEdge(0, 2, 4);
+ addEdge(1, 2, 1);
+ addEdge(1, 3, 7);
+ addEdge(2, 4, 3);
+ addEdge(3, 5, 1);
+ addEdge(4, 3, 2);
+ addEdge(4, 5, 5);
+
+ int[] expectedDistances = {0, 2, 3, 8, 6, 9};
+ int[] actualDistances = DialsAlgorithm.run(graph, 0, MAX_EDGE_WEIGHT);
+ assertArrayEquals(expectedDistances, actualDistances);
+ }
+
+ @Test
+ @DisplayName("Test with a disconnected node")
+ void testDisconnectedNode() {
+ addEdge(0, 1, 5);
+ addEdge(1, 2, 5);
+ // Node 3, 4, 5 are disconnected
+
+ int[] expectedDistances = {0, 5, 10, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE};
+ int[] actualDistances = DialsAlgorithm.run(graph, 0, MAX_EDGE_WEIGHT);
+ assertArrayEquals(expectedDistances, actualDistances);
+ }
+
+ @Test
+ @DisplayName("Test with source as destination")
+ void testSourceIsDestination() {
+ addEdge(0, 1, 10);
+ int[] expectedDistances = {0, 10, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE};
+ // Run with source 0
+ int[] actualDistances = DialsAlgorithm.run(graph, 0, MAX_EDGE_WEIGHT);
+ assertArrayEquals(expectedDistances, actualDistances);
+ }
+
+ @Test
+ @DisplayName("Test graph with multiple paths to a node")
+ void testMultiplePaths() {
+ addEdge(0, 1, 10);
+ addEdge(0, 2, 3);
+ addEdge(2, 1, 2); // Shorter path to 1 is via 2 (3+2=5)
+
+ int[] expectedDistances = {0, 5, 3, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE};
+ int[] actualDistances = DialsAlgorithm.run(graph, 0, MAX_EDGE_WEIGHT);
+ assertArrayEquals(expectedDistances, actualDistances);
+ }
+
+ @Test
+ @DisplayName("Test with an invalid source vertex")
+ void testInvalidSource() {
+ assertThrows(IllegalArgumentException.class, () -> DialsAlgorithm.run(graph, -1, MAX_EDGE_WEIGHT));
+ assertThrows(IllegalArgumentException.class, () -> DialsAlgorithm.run(graph, NUM_VERTICES, MAX_EDGE_WEIGHT));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java
index c5df9acdf33b..a189091c17d3 100644
--- a/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java
@@ -1,6 +1,7 @@
package com.thealgorithms.datastructures.graphs;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.BeforeEach;
@@ -61,4 +62,120 @@ void testInvalidSourceVertex() {
assertThrows(IllegalArgumentException.class, () -> dijkstraAlgorithm.run(graph, -1));
assertThrows(IllegalArgumentException.class, () -> dijkstraAlgorithm.run(graph, graph.length));
}
+
+ @Test
+ void testLinearGraph() {
+ // Linear graph: 0 - 1 - 2 - 3
+ // with weights: 2 3 4
+ int[][] linearGraph = {{0, 2, 0, 0}, {2, 0, 3, 0}, {0, 3, 0, 4}, {0, 0, 4, 0}};
+
+ DijkstraAlgorithm dijkstraLinear = new DijkstraAlgorithm(4);
+ int[] distances = dijkstraLinear.run(linearGraph, 0);
+
+ assertArrayEquals(new int[] {0, 2, 5, 9}, distances);
+ }
+
+ @Test
+ void testStarTopology() {
+ // Star graph: center node 0 connected to all others
+ // 1(2)
+ // |
+ // 3(4)-0-2(3)
+ // |
+ // 4(5)
+ int[][] starGraph = {{0, 2, 3, 4, 5}, {2, 0, 0, 0, 0}, {3, 0, 0, 0, 0}, {4, 0, 0, 0, 0}, {5, 0, 0, 0, 0}};
+
+ DijkstraAlgorithm dijkstraStar = new DijkstraAlgorithm(5);
+ int[] distances = dijkstraStar.run(starGraph, 0);
+
+ assertArrayEquals(new int[] {0, 2, 3, 4, 5}, distances);
+ }
+
+ @Test
+ void testCompleteGraphK4() {
+ // Complete graph K4 with varying weights
+ int[][] completeGraph = {{0, 1, 2, 3}, {1, 0, 4, 5}, {2, 4, 0, 6}, {3, 5, 6, 0}};
+
+ DijkstraAlgorithm dijkstraComplete = new DijkstraAlgorithm(4);
+ int[] distances = dijkstraComplete.run(completeGraph, 0);
+
+ // Direct paths from 0 are shortest
+ assertArrayEquals(new int[] {0, 1, 2, 3}, distances);
+ }
+
+ @Test
+ void testDifferentSourceVertex() {
+ // Test running from different source vertices
+ int[][] simpleGraph = {{0, 5, 0, 0}, {5, 0, 3, 0}, {0, 3, 0, 2}, {0, 0, 2, 0}};
+
+ DijkstraAlgorithm dijkstra = new DijkstraAlgorithm(4);
+
+ // From vertex 0
+ int[] distFrom0 = dijkstra.run(simpleGraph, 0);
+ assertArrayEquals(new int[] {0, 5, 8, 10}, distFrom0);
+
+ // From vertex 2
+ int[] distFrom2 = dijkstra.run(simpleGraph, 2);
+ assertArrayEquals(new int[] {8, 3, 0, 2}, distFrom2);
+
+ // From vertex 3
+ int[] distFrom3 = dijkstra.run(simpleGraph, 3);
+ assertArrayEquals(new int[] {10, 5, 2, 0}, distFrom3);
+ }
+
+ @Test
+ void testUnitWeightGraph() {
+ // Graph with all unit weights (like BFS distance)
+ int[][] unitGraph = {{0, 1, 1, 0}, {1, 0, 1, 1}, {1, 1, 0, 1}, {0, 1, 1, 0}};
+
+ DijkstraAlgorithm dijkstraUnit = new DijkstraAlgorithm(4);
+ int[] distances = dijkstraUnit.run(unitGraph, 0);
+
+ assertArrayEquals(new int[] {0, 1, 1, 2}, distances);
+ }
+
+ @Test
+ void testTwoVertexGraph() {
+ int[][] twoVertexGraph = {{0, 7}, {7, 0}};
+
+ DijkstraAlgorithm dijkstraTwo = new DijkstraAlgorithm(2);
+ int[] distances = dijkstraTwo.run(twoVertexGraph, 0);
+
+ assertArrayEquals(new int[] {0, 7}, distances);
+ }
+
+ @Test
+ void testShortcutPath() {
+ // Graph where direct path is longer than indirect path
+ // 0 --(10)--> 2
+ // 0 --(1)--> 1 --(2)--> 2
+ int[][] shortcutGraph = {{0, 1, 10}, {1, 0, 2}, {10, 2, 0}};
+
+ DijkstraAlgorithm dijkstraShortcut = new DijkstraAlgorithm(3);
+ int[] distances = dijkstraShortcut.run(shortcutGraph, 0);
+
+ // The shortest path to vertex 2 should be 3 (via vertex 1), not 10 (direct)
+ assertArrayEquals(new int[] {0, 1, 3}, distances);
+ }
+
+ @Test
+ void testSourceToSourceDistanceIsZero() {
+ // Verify distance from source to itself is always 0
+ int[] distances = dijkstraAlgorithm.run(graph, 0);
+ assertEquals(0, distances[0]);
+
+ distances = dijkstraAlgorithm.run(graph, 5);
+ assertEquals(0, distances[5]);
+ }
+
+ @Test
+ void testLargeWeights() {
+ // Graph with large weights
+ int[][] largeWeightGraph = {{0, 1000, 0}, {1000, 0, 2000}, {0, 2000, 0}};
+
+ DijkstraAlgorithm dijkstraLarge = new DijkstraAlgorithm(3);
+ int[] distances = dijkstraLarge.run(largeWeightGraph, 0);
+
+ assertArrayEquals(new int[] {0, 1000, 3000}, distances);
+ }
}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/MatrixGraphsTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/MatrixGraphsTest.java
index cc8a2df872ce..eaff0222bd36 100644
--- a/src/test/java/com/thealgorithms/datastructures/graphs/MatrixGraphsTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/MatrixGraphsTest.java
@@ -137,4 +137,215 @@ void testDisconnectedGraph() {
assertTrue(dfs.containsAll(Arrays.asList(0, 1)));
assertTrue(bfs.containsAll(Arrays.asList(0, 1)));
}
+
+ @Test
+ void testSingleVertexGraphDfs() {
+ AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(1);
+
+ List