diff --git a/.clang-format b/.clang-format
new file mode 100644
index 000000000000..3d685994a1aa
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,136 @@
+---
+Language: Java
+AccessModifierOffset: -4
+AlignAfterOpenBracket: DontAlign
+AlignConsecutiveMacros: false
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlines: Right
+AlignOperands: false
+AlignTrailingComments: false
+AllowAllArgumentsOnNextLine: true
+AllowAllConstructorInitializersOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+AllowShortLambdasOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: MultiLine
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterCaseLabel: false
+ AfterClass: false
+ AfterControlStatement: false
+ AfterEnum: false
+ AfterFunction: false
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ AfterExternBlock: false
+ BeforeCatch: false
+ BeforeElse: false
+ IndentBraces: false
+ SplitEmptyFunction: true
+ SplitEmptyRecord: true
+ SplitEmptyNamespace: true
+BreakBeforeBinaryOperators: All
+BreakBeforeBraces: Custom
+BreakBeforeInheritanceComma: false
+BreakInheritanceList: BeforeColon
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+BreakConstructorInitializers: BeforeComma
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: true
+ColumnLimit: 300
+CommentPragmas: '^ IWYU pragma:'
+CompactNamespaces: false
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DeriveLineEnding: true
+DerivePointerAlignment: false
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: false
+ForEachMacros:
+ - foreach
+ - Q_FOREACH
+ - BOOST_FOREACH
+IncludeBlocks: Preserve
+IncludeCategories:
+ - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
+ Priority: 2
+ SortPriority: 0
+ - Regex: '^(<|"(gtest|gmock|isl|json)/)'
+ Priority: 3
+ SortPriority: 0
+ - Regex: '.*'
+ Priority: 1
+ SortPriority: 0
+IncludeIsMainRegex: '(Test)?$'
+IncludeIsMainSourceRegex: ''
+IndentCaseLabels: false
+IndentGotoLabels: true
+IndentPPDirectives: None
+IndentWidth: 4
+IndentWrappedFunctionNames: false
+InsertNewlineAtEOF: true
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: Inner
+ObjCBinPackProtocolList: Auto
+ObjCBlockIndentWidth: 4
+ObjCSpaceAfterProperty: true
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakAssignment: 2
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Left
+ReflowComments: true
+SortIncludes: true
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: true
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceInEmptyBlock: false
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInConditionalStatement: false
+SpacesInContainerLiterals: false
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+SpaceBeforeSquareBrackets: false
+Standard: Latest
+StatementMacros:
+ - Q_UNUSED
+ - QT_REQUIRE_VERSION
+TabWidth: 8
+UseCRLF: false
+UseTab: Never
+...
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
new file mode 100644
index 000000000000..bcea8e797ffb
--- /dev/null
+++ b/.devcontainer/Dockerfile
@@ -0,0 +1,25 @@
+# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.238.0/containers/java/.devcontainer/base.Dockerfile
+
+# [Choice] Java version (use -bullseye variants on local arm64/Apple Silicon): 11, 17, 11-bullseye, 17-bullseye, 11-buster, 17-buster
+ARG VARIANT="21-bullseye"
+FROM mcr.microsoft.com/vscode/devcontainers/java:1.1.0-${VARIANT}
+
+# [Option] Install Maven
+ARG INSTALL_MAVEN="false"
+ARG MAVEN_VERSION=""
+# [Option] Install Gradle
+ARG INSTALL_GRADLE="false"
+ARG GRADLE_VERSION=""
+RUN if [ "${INSTALL_MAVEN}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/sdkman/bin/sdkman-init.sh && sdk install maven \"${MAVEN_VERSION}\""; fi \
+ && if [ "${INSTALL_GRADLE}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/sdkman/bin/sdkman-init.sh && sdk install gradle \"${GRADLE_VERSION}\""; fi
+
+# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
+ARG NODE_VERSION="none"
+RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
+
+# [Optional] Uncomment this section to install additional OS packages.
+# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
+# && apt-get -y install --no-install-recommends
+
+# [Optional] Uncomment this line to install global node packages.
+# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g " 2>&1
\ No newline at end of file
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 000000000000..fdc7cdbd25f9
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,47 @@
+// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
+// https://github.com/microsoft/vscode-dev-containers/tree/v0.238.0/containers/java
+{
+ "name": "Java",
+ "build": {
+ "dockerfile": "Dockerfile",
+ "args": {
+ // Update the VARIANT arg to pick a Java version: 11, 17
+ // Append -bullseye or -buster to pin to an OS version.
+ // Use the -bullseye variants on local arm64/Apple Silicon.
+ "VARIANT": "21-bullseye",
+ // Options
+ "INSTALL_MAVEN": "true",
+ "INSTALL_GRADLE": "true",
+ "NODE_VERSION": "lts/*"
+ }
+ },
+
+ // Configure tool-specific properties.
+ "customizations": {
+ // Configure properties specific to VS Code.
+ "vscode": {
+ // Set *default* container specific settings.json values on container create.
+ "settings": {
+ },
+
+ // Add the IDs of extensions you want installed when the container is created.
+ "extensions": [
+ "vscjava.vscode-java-pack",
+ "GitHub.copilot",
+ ]
+ }
+ },
+
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ // "forwardPorts": [],
+
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "java -version",
+
+ // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
+ "remoteUser": "vscode",
+ "features": {
+ "git": "os-provided",
+ "github-cli": "latest"
+ }
+}
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 9bfc524c7c8e..f41af80a3459 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1 +1 @@
-* @siriak @yanglbme
+* @DenizAltunkapan @yanglbme @alxkm
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index ba390fafa659..000000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-title: ""
-labels: ""
-assignees: ""
----
-
-**Describe the bug**
-A clear and concise description of what the bug is.
-
-**To Reproduce**
-Steps to reproduce the behavior:
-
-1. Go to '...'
-2. Click on '....'
-3. Scroll down to '....'
-4. See error
-
-**Expected behavior**
-A clear and concise description of what you expected to happen.
-
-**Screenshots**
-If applicable, add screenshots to help explain your problem.
-
-**Device Specification**
-
-**Additional context**
-Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 000000000000..9c906c381608
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,45 @@
+name: "Bug report"
+description: "Create a report to help us improve"
+title: "[BUG] "
+labels: ["bug"]
+body:
+ - type: textarea
+ id: description
+ attributes:
+ label: "Description"
+ description: "A clear and concise description of what the bug is."
+ validations:
+ required: true
+ - type: textarea
+ id: steps
+ attributes:
+ label: "Steps to reproduce"
+ description: "Steps to reproduce the behavior (if applicable)"
+ placeholder: |
+ 1. Go to '...'
+ 2. Click on '....'
+ 3. Scroll down to '....'
+ 4. See error
+ validations:
+ required: false
+ - type: textarea
+ id: exceptedbhv
+ attributes:
+ label: "Excepted behavior"
+ description: "A clear and concise description of what you expected to happen."
+ validations:
+ required: true
+ - type: textarea
+ id: screenshots
+ attributes:
+ label: "Screenshots"
+ description: "If applicable, add screenshots to help explain your problem."
+ validations:
+ required: false
+ - type: textarea
+ id: context
+ attributes:
+ label: "Additional context"
+ description: "Is there anything else we should know about this bug report?"
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 000000000000..875cc4efab00
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Discord community
+ url: https://the-algorithms.com/discord/
+ about: Have any questions or found any bugs? Please contact us via Discord
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 2bc5d5f71186..000000000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: ""
-labels: ""
-assignees: ""
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Additional context**
-Add any other context or screenshots about the feature request here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 000000000000..98ff394158be
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,34 @@
+name: "Feature Request"
+description: "Suggest an idea for this project"
+title: "[FEATURE REQUEST] "
+labels: ["enhancement"]
+body:
+ - type: textarea
+ id: description
+ attributes:
+ label: What would you like to Propose?
+ description: Provide a clear and concise explanation of your Proposal.
+ validations:
+ required: true
+ - type: markdown
+ attributes:
+ value: |
+ For new implementations, please specify the name and problem statement for the algorithm.
+ For algorithm enhancements, specify what needs to be changed and why. For example:
+ - Adding tests.
+ - Optimizing logic.
+ - Refactoring the file and folders for better structure.
+ - type: textarea
+ id: needdetails
+ attributes:
+ label: "Issue details"
+ description: "Write down all the issue/algorithm details description mentioned above."
+ validations:
+ required: true
+ - type: textarea
+ id: extrainfo
+ attributes:
+ label: "Additional Information"
+ description: "Add any other information or screenshots about the request here."
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/other.yml b/.github/ISSUE_TEMPLATE/other.yml
new file mode 100644
index 000000000000..bf8b29f481c8
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/other.yml
@@ -0,0 +1,19 @@
+name: Other
+description: Use this for any other issues. Do NOT create blank issues
+title: "[OTHER]"
+labels: ["awaiting triage"]
+body:
+ - type: textarea
+ id: issuedescription
+ attributes:
+ label: What would you like to share?
+ description: Provide a clear and concise explanation of your issue.
+ validations:
+ required: true
+ - type: textarea
+ id: extrainfo
+ attributes:
+ label: Additional information
+ description: Is there anything else we should know about this issue?
+ validations:
+ required: false
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000000..2e5622f7b51d
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,18 @@
+---
+version: 2
+updates:
+ - package-ecosystem: "docker"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+
+ - package-ecosystem: "github-actions"
+ directory: "/.github/workflows/"
+ schedule:
+ interval: "daily"
+
+ - package-ecosystem: "maven"
+ directory: "/"
+ schedule:
+ interval: "daily"
+...
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index c805c24b29f3..d9cc4c3c35c5 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,23 +1,16 @@
-### **Describe your change:**
+
-- [ ] Add an algorithm?
-- [ ] Fix a bug or typo in an existing algorithm?
-- [ ] Documentation change?
-
-#### References
-
-
-
-### **Checklist:**
-
-
+
- [ ] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Java/blob/master/CONTRIBUTING.md).
-- [ ] This pull request is all my own work -- I have not plagiarized.
-- [ ] I know that pull requests will not be merged if they fail the automated tests.
-- [ ] This PR only changes one algorithm file. To ease review, please open separate PRs for separate algorithms.
-- [ ] All new Java files are placed inside an existing directory.
-- [ ] All filenames are in all uppercase characters with no spaces or dashes.
+- [ ] This pull request is all my own work -- I have not plagiarized it.
+- [ ] All filenames are in PascalCase.
- [ ] All functions and variable names follow Java naming conventions.
-- [ ] All new algorithms have a URL in its comments that points to Wikipedia or other similar explanation.
-- [ ] If this pull request resolves one or more open issues then the commit message contains `Fixes: #{$ISSUE_NO}`.
+- [ ] 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
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7e3feabdd260..39bde758d68e 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,14 +1,40 @@
name: Build
on: [push, pull_request]
+
+permissions:
+ contents: read
+
jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
- - name: Set up JDK 17
- uses: actions/setup-java@v2
+ - uses: actions/checkout@v5
+ - name: Set up JDK
+ uses: actions/setup-java@v5
with:
- java-version: 17
- distribution: 'adopt'
+ java-version: 21
+ distribution: 'temurin'
- name: Build with Maven
run: mvn --batch-mode --update-snapshots verify
+ - name: Upload coverage to codecov (tokenless)
+ if: >-
+ github.event_name == 'pull_request' &&
+ github.event.pull_request.head.repo.full_name != github.repository
+ uses: codecov/codecov-action@v5
+ with:
+ fail_ci_if_error: true
+ - name: Upload coverage to codecov (with token)
+ if: >
+ github.repository == 'TheAlgorithms/Java' &&
+ (github.event_name != 'pull_request' ||
+ github.event.pull_request.head.repo.full_name == github.repository)
+ uses: codecov/codecov-action@v5
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ fail_ci_if_error: true
+ - name: Checkstyle
+ run: mvn checkstyle:check
+ - name: SpotBugs
+ run: mvn spotbugs:check
+ - name: PMD
+ run: mvn pmd:check
diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml
new file mode 100644
index 000000000000..ca014e115282
--- /dev/null
+++ b/.github/workflows/clang-format-lint.yml
@@ -0,0 +1,19 @@
+name: Clang format linter
+on:
+ push: {}
+ pull_request: {}
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v5
+ - uses: DoozyX/clang-format-lint-action@v0.20
+ with:
+ source: './src'
+ extensions: 'java'
+ clangFormatVersion: 16
diff --git a/.github/workflows/close-failed-prs.yml b/.github/workflows/close-failed-prs.yml
new file mode 100644
index 000000000000..5d54eea07821
--- /dev/null
+++ b/.github/workflows/close-failed-prs.yml
@@ -0,0 +1,154 @@
+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@v7
+ 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 isMergeFromMain = mainBranches.some(branch =>
+ msg.startsWith(`merge branch '${branch}'`) ||
+ msg.includes(`merge remote-tracking branch '${branch}'`)
+ );
+ return !isMergeFromMain;
+ });
+
+ // 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;
+ }
\ No newline at end of file
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 000000000000..3a4cfd829b6b
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,66 @@
+---
+name: "CodeQL"
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - master
+ pull_request:
+ schedule:
+ - cron: '53 3 * * 0'
+
+jobs:
+ analyzeJava:
+ name: AnalyzeJava
+ runs-on: 'ubuntu-latest'
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v5
+
+ - name: Set up JDK
+ uses: actions/setup-java@v5
+ with:
+ java-version: 21
+ distribution: 'temurin'
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v4
+ with:
+ languages: 'java-kotlin'
+
+ - name: Build
+ run: mvn --batch-mode --update-snapshots verify
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v4
+ with:
+ category: "/language:java-kotlin"
+
+ analyzeActions:
+ name: AnalyzeActions
+ runs-on: 'ubuntu-latest'
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v5
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v4
+ with:
+ languages: 'actions'
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v4
+ with:
+ category: "/language:actions"
+...
diff --git a/.github/workflows/infer.yml b/.github/workflows/infer.yml
new file mode 100644
index 000000000000..3df7c4b1fc9e
--- /dev/null
+++ b/.github/workflows/infer.yml
@@ -0,0 +1,64 @@
+---
+name: Infer
+
+'on':
+ workflow_dispatch:
+ push:
+ branches:
+ - master
+ pull_request:
+
+permissions:
+ contents: read
+
+jobs:
+ run_infer:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Set up JDK
+ uses: actions/setup-java@v5
+ with:
+ java-version: 21
+ distribution: 'temurin'
+
+ - name: Set up OCaml
+ uses: ocaml/setup-ocaml@v3
+ with:
+ ocaml-compiler: 5
+
+ - name: Get current year/weak
+ run: echo "year_week=$(date +'%Y_%U')" >> $GITHUB_ENV
+
+ - name: Cache infer build
+ id: cache-infer
+ uses: actions/cache@v4
+ with:
+ path: infer
+ key: ${{ runner.os }}-infer-${{ env.year_week }}
+
+ - name: Build infer
+ if: steps.cache-infer.outputs.cache-hit != 'true'
+ run: |
+ cd ..
+ git clone https://github.com/facebook/infer.git
+ cd infer
+ git checkout 01aaa268f9d38723ba69c139e10f9e2a04b40b1c
+ ./build-infer.sh java
+ cp -r infer ../Java
+
+ - name: Add infer to PATH
+ run: |
+ echo "infer/bin" >> $GITHUB_PATH
+
+ - name: Display infer version
+ run: |
+ which infer
+ infer --version
+
+ - name: Run infer
+ run: |
+ mvn clean
+ infer --fail-on-issue --print-logs --no-progress-bar -- mvn test
+...
diff --git a/.github/workflows/prettify.yml b/.github/workflows/prettify.yml
deleted file mode 100644
index da58f5f06379..000000000000
--- a/.github/workflows/prettify.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-name: Prettify
-on: [push, pull_request]
-jobs:
- prettier:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v2
- with:
- ref: ${{ github.head_ref }}
-
- - name: Prettify code
- uses: creyD/prettier_action@v3.3
- with:
- prettier_options: --write **/*.java
- commit_message: 'Prettify code'
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/project_structure.yml b/.github/workflows/project_structure.yml
new file mode 100644
index 000000000000..f9fb82a2781c
--- /dev/null
+++ b/.github/workflows/project_structure.yml
@@ -0,0 +1,25 @@
+---
+name: ProjectStructure
+
+'on':
+ workflow_dispatch:
+ push:
+ branches:
+ - master
+ pull_request:
+
+permissions:
+ contents: read
+
+jobs:
+ check_structure:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v5
+ - uses: actions/setup-python@v6
+ with:
+ python-version: '3.13'
+
+ - name: Check project structure
+ run: python3 .github/workflows/scripts/check_structure.py
+...
diff --git a/.github/workflows/scripts/check_structure.py b/.github/workflows/scripts/check_structure.py
new file mode 100644
index 000000000000..914f64369207
--- /dev/null
+++ b/.github/workflows/scripts/check_structure.py
@@ -0,0 +1,27 @@
+import pathlib
+import sys
+
+
+def _is_java_file_properly_located(java_file: pathlib.Path) -> bool:
+ main_parents = java_file.parent.parents
+ return (
+ pathlib.Path("src/main/java/com/thealgorithms/") in main_parents
+ or pathlib.Path("src/test/java/com/thealgorithms/") in main_parents
+ )
+
+
+def _find_misplaced_java_files() -> list[pathlib.Path]:
+ return [
+ java_file
+ for java_file in pathlib.Path(".").rglob("*.java")
+ if not _is_java_file_properly_located(java_file)
+ ]
+
+
+if __name__ == "__main__":
+ misplaced_files = _find_misplaced_java_files()
+ if misplaced_files:
+ print("The following java files are not located in the correct directory:")
+ for _ in misplaced_files:
+ print(_)
+ sys.exit(1)
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index 8fbb262b9e36..bb613daf8f1d 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -2,16 +2,21 @@ name: 'Close stale issues and PRs'
on:
schedule:
- cron: '0 0 * * *'
+permissions:
+ contents: read
jobs:
stale:
+ permissions:
+ issues: write
+ pull-requests: write
runs-on: ubuntu-latest
steps:
- - uses: actions/stale@v4
+ - uses: actions/stale@v10
with:
- stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
- close-issue-message: 'Please reopen this issue once you add more information and updates here. If this is not the case and you need some help, feel free to seek help from our [Gitter](https://gitter.im/TheAlgorithms) or ping one of the reviewers. Thank you for your contributions!'
- stale-pr-message: 'This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
- close-pr-message: 'Please reopen this pull request once you commit the changes requested or make improvements on the code. If this is not the case and you need some help, feel free to seek help from our [Gitter](https://gitter.im/TheAlgorithms) or ping one of the reviewers. Thank you for your contributions!'
+ stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution!'
+ close-issue-message: 'Please reopen this issue once you have made the required changes. If you need help, feel free to ask in our [Discord](https://the-algorithms.com/discord) server or ping one of the maintainers here. Thank you for your contribution!'
+ stale-pr-message: 'This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution!'
+ close-pr-message: 'Please reopen this pull request once you have made the required changes. If you need help, feel free to ask in our [Discord](https://the-algorithms.com/discord) server or ping one of the maintainers here. Thank you for your contribution!'
exempt-issue-labels: 'dont-close'
exempt-pr-labels: 'dont-close'
days-before-stale: 30
diff --git a/.github/workflows/update-directorymd.yml b/.github/workflows/update-directorymd.yml
new file mode 100644
index 000000000000..6692a884a867
--- /dev/null
+++ b/.github/workflows/update-directorymd.yml
@@ -0,0 +1,42 @@
+name: Generate Directory Markdown
+
+on:
+ push:
+ branches: [master]
+ workflow_dispatch:
+
+permissions:
+ contents: write
+ pull-requests: write
+
+jobs:
+ generate-directory:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout Repository
+ uses: actions/checkout@v5
+
+ - name: Run Directory Tree Generator
+ uses: DenizAltunkapan/directory-tree-generator@v2
+ with:
+ path: src
+ extensions: .java
+ show-extensions: false
+
+ - name: Commit changes
+ run: |
+ git config --global user.name "$GITHUB_ACTOR"
+ git config --global user.email "$GITHUB_ACTOR@users.noreply.github.com"
+ git add DIRECTORY.md
+ git diff --cached --quiet || git commit -m "Update DIRECTORY.md"
+
+ - name: Create Pull Request
+ uses: peter-evans/create-pull-request@v7
+ with:
+ token: ${{ secrets.REPO_SCOPED_TOKEN }}
+ branch: update-directory
+ base: master
+ title: "Update DIRECTORY.md"
+ body: "Automatically generated update of the directory tree."
+ commit-message: "Update DIRECTORY.md"
+ draft: false
diff --git a/.github/workflows/update_directory.yml b/.github/workflows/update_directory.yml
deleted file mode 100644
index 0a9265c5d801..000000000000
--- a/.github/workflows/update_directory.yml
+++ /dev/null
@@ -1,67 +0,0 @@
-# This GitHub Action updates the DIRECTORY.md file (if needed) when doing a git push
-name: Update Directory
-on: [push, pull_request]
-jobs:
- update_directory_md:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@master
- - uses: actions/setup-python@master
- - name: Update Directory
- shell: python
- run: |
- import os
- from typing import Iterator
-
- URL_BASE = "https://github.com/TheAlgorithms/Java/blob/master"
- g_output = []
-
-
- def good_filepaths(top_dir: str = ".") -> Iterator[str]:
- for dirpath, dirnames, filenames in os.walk(top_dir):
- dirnames[:] = [d for d in dirnames if d[0] not in "._"]
- for filename in filenames:
- if os.path.splitext(filename)[1].lower() == ".java":
- yield os.path.join(dirpath, filename).lstrip("./")
-
-
- def md_prefix(i):
- return f"{i * ' '}*" if i else "\n##"
-
-
- def print_path(old_path: str, new_path: str) -> str:
- global g_output
- old_parts = old_path.split(os.sep)
- for i, new_part in enumerate(new_path.split(os.sep)):
- if i + 1 > len(old_parts) or old_parts[i] != new_part:
- if new_part:
- g_output.append(f"{md_prefix(i)} {new_part.replace('_', ' ')}")
- return new_path
-
-
- def build_directory_md(top_dir: str = ".") -> str:
- global g_output
- old_path = ""
- for filepath in sorted(good_filepaths(), key=str.lower):
- filepath, filename = os.path.split(filepath)
- if filepath != old_path:
- old_path = print_path(old_path, filepath)
- indent = (filepath.count(os.sep) + 1) if filepath else 0
- url = "/".join((URL_BASE, filepath, filename)).replace(" ", "%20")
- filename = os.path.splitext(filename.replace("_", " "))[0]
- g_output.append(f"{md_prefix(indent)} [{filename}]({url})")
- return "\n".join(g_output)
-
-
- with open("DIRECTORY.md", "w") as out_file:
- out_file.write(build_directory_md(".") + "\n")
-
- - name: Update DIRECTORY.md
- run: |
- cat DIRECTORY.md
- git config --global user.name github-actions
- git config --global user.email '${GITHUB_ACTOR}@users.noreply.github.com'
- git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY
- git add DIRECTORY.md
- git commit -am "Update directory" || true
- git push --force origin HEAD:$GITHUB_REF || true
diff --git a/.gitignore b/.gitignore
index e74117ebc9b3..eb9d33c78a33 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,6 @@
/gradle/wrapper/gradle-wrapper.properties
+
##----------Android----------
-# build
*.apk
*.ap_
*.dex
@@ -10,35 +10,37 @@ gen/
build/
out/
-# gradle
+# Ignoring Gradle build artifacts and project files
+##----------Gradle----------
.gradle/
gradle-app.setting
!gradle-wrapper.jar
build/
-# maven
+# Ignoring Maven build artifacts and project files
+##----------Maven----------
*.classpath
*.project
*.settings
/target/
-
local.properties
-##----------idea----------
+# Ignoring IntelliJ IDEA project files and configurations
+##----------IDEA----------
*.iml
.idea/
*.ipr
*.iws
-# Android Studio Navigation editor temp files
+# Ignoring Android Studio Navigation editor temporary files
.navigation/
+# Ignoring common system and editor-generated files
##----------Other----------
-# osx
*~
.DS_Store
gradle.properties
-
.vscode
-
*.log
+
+/infer-out/
diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile
deleted file mode 100644
index f8e49f267475..000000000000
--- a/.gitpod.Dockerfile
+++ /dev/null
@@ -1,7 +0,0 @@
-FROM gitpod/workspace-full
-
-# Install custom tools, runtimes, etc.
-# For example "bastet", a command-line tetris clone:
-# RUN brew install bastet
-#
-# More information: https://www.gitpod.io/docs/config-docker/
diff --git a/.gitpod.dockerfile b/.gitpod.dockerfile
new file mode 100644
index 000000000000..4195f928d1bc
--- /dev/null
+++ b/.gitpod.dockerfile
@@ -0,0 +1,22 @@
+FROM gitpod/workspace-java-21:2025-10-06-13-14-25
+
+ENV LLVM_SCRIPT="tmp_llvm.sh"
+
+RUN test ! -f "$LLVM_SCRIPT" \
+ && wget https://apt.llvm.org/llvm.sh -O "$LLVM_SCRIPT" \
+ && chmod +x "$LLVM_SCRIPT"
+
+USER root
+
+RUN ./"$LLVM_SCRIPT" 16 \
+ && apt-get update \
+ && apt-get install -y --no-install-recommends \
+ clang-format-16=1:16.0.6~++20231112100510+7cbf1a259152-1~exp1~20231112100554.106 \
+ && apt-get clean \
+ && rm -rf /var/lib/apt/lists/*
+
+RUN ln -s "$(command -v clang-format-16)" "/usr/bin/clang-format"
+
+USER gitpod
+
+RUN rm "$LLVM_SCRIPT"
diff --git a/.gitpod.yml b/.gitpod.yml
index 479ecfd1f5e7..21d69f6e2122 100644
--- a/.gitpod.yml
+++ b/.gitpod.yml
@@ -1,6 +1,13 @@
+---
image:
- file: .gitpod.Dockerfile
+ file: .gitpod.dockerfile
tasks:
- - init: 'echo "TODO: Replace with init/build command"'
- command: (e.g. 'npm start', 'yarn watch'...)
+ - init: |
+ mvn dependency:resolve
+ mvn compile
+
+vscode:
+ extensions:
+ - xaver.clang-format
+
diff --git a/.inferconfig b/.inferconfig
new file mode 100644
index 000000000000..6af4f9e2e818
--- /dev/null
+++ b/.inferconfig
@@ -0,0 +1,24 @@
+{
+ "report-block-list-path-regex": [
+ "src/main/java/com/thealgorithms/ciphers/a5/CompositeLFSR.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",
+ "src/main/java/com/thealgorithms/datastructures/heaps/GenericHeap.java",
+ "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/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/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/searches/QuickSelectTest.java",
+ "src/test/java/com/thealgorithms/stacks/PostfixToInfixTest.java",
+ "src/test/java/com/thealgorithms/strings/HorspoolSearchTest.java"
+ ]
+}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d439684a4e14..f2f8dd9ffdea 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,27 +1,31 @@
## How to contribute?
-#### **Did you find a bug?**
+NOTE: *We DO NOT add leetcode problems. They are just applications of basic principles that can be found in other algorithms included in the repository.*
-- **Ensure the bug was not already reported** by searching on GitHub under [Project Issues](https://github.com/TheAlgorithms/Java/issues).
+### Did you find a bug?
-- Please avoid opening issues asking to be "assigned” to a particular algorithm. This merely creates unnecessary noise for maintainers. Instead, please submit your implementation in a pull request and it will be evaluated by project maintainers.
+**Ensure the bug was not already reported** by searching on GitHub under [Project Issues](https://github.com/TheAlgorithms/Java/issues).
+ - If it is mentioned in the issues and you want to fix it, [fork](https://github.com/TheAlgorithms/Java/fork) the repository and submit your implementation in a pull request. The project maintainers will evaluate it.
+ - If the bug is **NOT** mentioned in the issues, [open a new issue](https://github.com/TheAlgorithms/Java/issues/new). Be sure to include a **title**, a clear **description** and a **test case** demonstrating the expected behavior that is not occurring.
-- If you are unable to find an open issue referring to the same problem, depending on the type of issue follow the appropriate steps:
+NOTE: *Please avoid opening issues asking to be "assigned" to a particular algorithm. This merely creates unnecessary noise for maintainers. Instead, please submit your implementation in a pull request and project maintainers will evaluate it.*
-#### **Do you want to contribute to the documentation?**
-- Please read the documentation here [Contributing to the Documentation](https://github.com/TheAlgorithms/Java/blob/master/CONTRIBUTING.md), [open a new issue](https://github.com/TheAlgorithms/Java/issues/new), make changes, and then create a pull request, it will be put under review and accepted if it is appropriate.
-#### **Do you want to add a new feature?**
+### Do you want to contribute to the documentation?
+ - [Fork](https://github.com/TheAlgorithms/Java/fork) the repository and make necessary changes.
+ - Create a pull request.
+ - It will be put under review for approval.
+ - If approved, the requested changes will be merged to the repository.
-- [Open a new issue](https://github.com/TheAlgorithms/Java/issues/new). Be sure to include a **title and a clear description** and a **test case** demonstrating the new feature that you want to add to the project.
+### Do you want to add a new feature?
-#### **Do you want to fix a bug?**
+- [Open a new issue](https://github.com/TheAlgorithms/Java/issues/new).
+- Be sure to include a **title**, a clear **description** and a **test case** demonstrating the new feature you want to add to the project.
-- [Open a new issue](https://github.com/TheAlgorithms/Java/issues/new).Be sure to include a **title and a clear description** and a **test case** demonstrating the expected behavior that is not occurring.
-#### **Do you have questions about the source code?**
+### Do you have questions about the source code?
- Ask any question about how to use the repository in the [TheAlgorithms room in GITTER](https://gitter.im/TheAlgorithms/community?source=orgpage#) or [open a new issue](https://github.com/TheAlgorithms/Java/issues/new)
-:+1::tada: That's all you need to know about the process now it's your turn to help us improve the repository, thank you again! :+1::tada:
+:+1::tada: That's all you need to know about the process now it's your turn to help us improve the repository, thank you again! :+1::tada:
\ No newline at end of file
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 12410c4977f8..47833a3f59f2 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1,417 +1,1526 @@
+# Project Structure
## src
- * main
- * java
- * com
- * thealgorithms
- * audiofilters
- * [IIRFilter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/audiofilters/IIRFilter.java)
- * backtracking
- * [KnightsTour](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/KnightsTour.java)
- * [NQueens](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/NQueens.java)
- * [PowerSum](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/PowerSum.java)
- * ciphers
- * [AES](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AES.java)
- * [AESEncryption](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AESEncryption.java)
- * [AffineCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AffineCipher.java)
- * [Caesar](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Caesar.java)
- * [ColumnarTranspositionCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/ColumnarTranspositionCipher.java)
- * [HillCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/HillCipher.java)
- * [ProductCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/ProductCipher.java)
- * [RSA](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/RSA.java)
- * [SimpleSubCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/SimpleSubCipher.java)
- * [SimpleSubstitutionCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/SimpleSubstitutionCipher.java)
- * [Vigenere](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Vigenere.java)
- * conversions
- * [AnyBaseToAnyBase](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java)
- * [AnyBaseToDecimal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/AnyBaseToDecimal.java)
- * [AnytoAny](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/AnytoAny.java)
- * [BinaryToDecimal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/BinaryToDecimal.java)
- * [BinaryToHexadecimal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/BinaryToHexadecimal.java)
- * [BinaryToOctal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/BinaryToOctal.java)
- * [DecimalToAnyBase](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/DecimalToAnyBase.java)
- * [DecimalToBinary](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/DecimalToBinary.java)
- * [DecimalToHexaDecimal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/DecimalToHexaDecimal.java)
- * [DecimalToOctal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/DecimalToOctal.java)
- * [HexaDecimalToBinary](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/HexaDecimalToBinary.java)
- * [HexaDecimalToDecimal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/HexaDecimalToDecimal.java)
- * [HexToOct](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/HexToOct.java)
- * [IntegerToRoman](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/IntegerToRoman.java)
- * [OctalToDecimal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/OctalToDecimal.java)
- * [OctalToHexadecimal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/OctalToHexadecimal.java)
- * [RgbHsvConversion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/RgbHsvConversion.java)
- * [RomanToInteger](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/RomanToInteger.java)
- * [TurkishToLatinConversion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java)
- * datastructures
- * bags
- * [Bag](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/bags/Bag.java)
- * buffers
- * [CircularBuffer](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/buffers/CircularBuffer.java)
- * caches
- * [LRUCache](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/caches/LRUCache.java)
- * [MRUCache](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/caches/MRUCache.java)
- * disjointsets
- * [DisjointSets](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/disjointsets/DisjointSets.java)
- * [Node](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/disjointsets/Node.java)
- * dynamicarray
- * [DynamicArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/dynamicarray/DynamicArray.java)
- * graphs
- * [A Star](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/A_Star.java)
- * [BellmanFord](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java)
- * [BipartiteGrapfDFS](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/BipartiteGrapfDFS.java)
- * [ConnectedComponent](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/ConnectedComponent.java)
- * [Cycles](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/Cycles.java)
- * [DIJSKSTRAS ALGORITHM](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/DIJSKSTRAS_ALGORITHM.java)
- * [FloydWarshall](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/FloydWarshall.java)
- * [Graphs](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/Graphs.java)
- * [KahnsAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithm.java)
- * [Kruskal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/Kruskal.java)
- * [MatrixGraphs](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java)
- * [PrimMST](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/PrimMST.java)
- * hashmap
- * hashing
- * [HashMap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/HashMap.java)
- * [HashMapLinearProbing](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/HashMapLinearProbing.java)
- * [Main](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/Main.java)
- * [MainLinearProbing](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/MainLinearProbing.java)
- * heaps
- * [EmptyHeapException](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/EmptyHeapException.java)
- * [Heap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/Heap.java)
- * [HeapElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/HeapElement.java)
- * [MaxHeap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/MaxHeap.java)
- * [MinHeap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/MinHeap.java)
- * [MinPriorityQueue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/MinPriorityQueue.java)
- * lists
- * [CircleLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java)
- * [CountSinglyLinkedListRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursion.java)
- * [CreateAndDetectLoop](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoop.java)
- * [CursorLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/CursorLinkedList.java)
- * [DoublyLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/DoublyLinkedList.java)
- * [Merge K SortedLinkedlist](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/Merge_K_SortedLinkedlist.java)
- * [MergeSortedArrayList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/MergeSortedArrayList.java)
- * [MergeSortedSinglyLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/MergeSortedSinglyLinkedList.java)
- * [RandomNode](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/RandomNode.java)
- * [RemoveDuplicateNodes](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/RemoveDuplicateNodes.java)
- * [SearchSinglyLinkedListRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SearchSinglyLinkedListRecursion.java)
- * [SinglyLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedList.java)
- * queues
- * [CircularQueue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/CircularQueue.java)
- * [Deques](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/Deques.java)
- * [GenericArrayListQueue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/GenericArrayListQueue.java)
- * [LinkedQueue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/LinkedQueue.java)
- * [PriorityQueues](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java)
- * [Queues](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/Queues.java)
- * stacks
- * [BalancedBrackets](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/BalancedBrackets.java)
- * [DecimalToAnyUsingStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/DecimalToAnyUsingStack.java)
- * [DuplicateBrackets](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/DuplicateBrackets.java)
- * [InfixToPostfix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/InfixToPostfix.java)
- * [MaximumMinimumWindow](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/MaximumMinimumWindow.java)
- * [NextGraterElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/NextGraterElement.java)
- * [NextSmallerElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/NextSmallerElement.java)
- * [NodeStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/NodeStack.java)
- * [ReverseStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/ReverseStack.java)
- * [StackArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/StackArray.java)
- * [StackArrayList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/StackArrayList.java)
- * [StackOfLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/StackOfLinkedList.java)
- * trees
- * [AVLTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/AVLTree.java)
- * [BinaryTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/BinaryTree.java)
- * [BSTIterative](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/BSTIterative.java)
- * [BSTRecursive](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursive.java)
- * [BSTRecursiveGeneric](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java)
- * [CeilInBinarySearchTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java)
- * [CheckIfBinaryTreeBalanced](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/CheckIfBinaryTreeBalanced.java)
- * [CreateBinaryTreeFromInorderPreorder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/CreateBinaryTreeFromInorderPreorder.java)
- * [CreateBSTFromSortedArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/CreateBSTFromSortedArray.java)
- * [FenwickTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/FenwickTree.java)
- * [GenericTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/GenericTree.java)
- * [LCA](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/LCA.java)
- * [LevelOrderTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/LevelOrderTraversal.java)
- * [LevelOrderTraversalQueue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/LevelOrderTraversalQueue.java)
- * [nearestRightKey](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/nearestRightKey.java)
- * [PrintTopViewofTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/PrintTopViewofTree.java)
- * [RedBlackBST](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/RedBlackBST.java)
- * [SegmentTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/SegmentTree.java)
- * [TreeTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/TreeTraversal.java)
- * [TrieImp](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/TrieImp.java)
- * [ValidBSTOrNot](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/ValidBSTOrNot.java)
- * [VerticalOrderTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/VerticalOrderTraversal.java)
- * devutils
- * nodes
- * [LargeTreeNode](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/devutils/nodes/LargeTreeNode.java)
- * [Node](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/devutils/nodes/Node.java)
- * [SimpleNode](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java)
- * [SimpleTreeNode](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java)
- * [TreeNode](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java)
- * searches
- * [SearchAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/devutils/searches/SearchAlgorithm.java)
- * divideandconquer
- * [BinaryExponentiation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/BinaryExponentiation.java)
- * [ClosestPair](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java)
- * [SkylineAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java)
- * [StrassenMatrixMultiplication](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplication.java)
- * dynamicprogramming
- * [BoardPath](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/BoardPath.java)
- * [BoundaryFill](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java)
- * [BruteForceKnapsack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsack.java)
- * [CatalanNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/CatalanNumber.java)
- * [CoinChange](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/CoinChange.java)
- * [DiceThrow](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/DiceThrow.java)
- * [DyanamicProgrammingKnapsack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/DyanamicProgrammingKnapsack.java)
- * [EditDistance](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/EditDistance.java)
- * [EggDropping](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/EggDropping.java)
- * [Fibonacci](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/Fibonacci.java)
- * [FloodFill](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/FloodFill.java)
- * [FordFulkerson](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/FordFulkerson.java)
- * [KadaneAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithm.java)
- * [Knapsack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/Knapsack.java)
- * [KnapsackMemoization](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/KnapsackMemoization.java)
- * [LevenshteinDistance](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LevenshteinDistance.java)
- * [LongestAlternatingSubsequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LongestAlternatingSubsequence.java)
- * [LongestCommonSubsequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequence.java)
- * [LongestIncreasingSubsequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequence.java)
- * [LongestPalindromicSubsequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubsequence.java)
- * [LongestPalindromicSubstring](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstring.java)
- * [LongestValidParentheses](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LongestValidParentheses.java)
- * [MatrixChainMultiplication](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplication.java)
- * [MatrixChainRecursiveTopDownMemoisation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisation.java)
- * [MemoizationTechniqueKnapsack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/MemoizationTechniqueKnapsack.java)
- * [MinimumPathSum](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/MinimumPathSum.java)
- * [MinimumSumPartition](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/MinimumSumPartition.java)
- * [PalindromicPartitioning](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/PalindromicPartitioning.java)
- * [RegexMatching](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/RegexMatching.java)
- * [RodCutting](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/RodCutting.java)
- * [ShortestCommonSupersequenceLength](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/ShortestCommonSupersequenceLength.java)
- * [SubsetSum](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSum.java)
- * [Sum Of Subset](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/Sum_Of_Subset.java)
- * [WineProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/WineProblem.java)
- * maths
- * [AbsoluteMax](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/AbsoluteMax.java)
- * [AbsoluteMin](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/AbsoluteMin.java)
- * [AbsoluteValue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/AbsoluteValue.java)
- * [ADTFraction](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/ADTFraction.java)
- * [AliquotSum](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/AliquotSum.java)
- * [AmicableNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/AmicableNumber.java)
- * [Area](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Area.java)
- * [Armstrong](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Armstrong.java)
- * [AutomorphicNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/AutomorphicNumber.java)
- * [Average](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Average.java)
- * [BinaryPow](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/BinaryPow.java)
- * [BinomialCoefficient](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/BinomialCoefficient.java)
- * [Ceil](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Ceil.java)
- * [CircularConvolutionFFT](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/CircularConvolutionFFT.java)
- * [Combinations](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Combinations.java)
- * [Convolution](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Convolution.java)
- * [ConvolutionFFT](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/ConvolutionFFT.java)
- * [DeterminantOfMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/DeterminantOfMatrix.java)
- * [DigitalRoot](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/DigitalRoot.java)
- * [DudeneyNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/DudeneyNumber.java)
- * [EulerMethod](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/EulerMethod.java)
- * [Factorial](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Factorial.java)
- * [FactorialRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FactorialRecursion.java)
- * [FFT](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FFT.java)
- * [FFTBluestein](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FFTBluestein.java)
- * [FibonacciJavaStreams](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FibonacciJavaStreams.java)
- * [FibonacciNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FibonacciNumber.java)
- * [FindMax](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FindMax.java)
- * [FindMaxRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FindMaxRecursion.java)
- * [FindMin](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FindMin.java)
- * [FindMinRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FindMinRecursion.java)
- * [Floor](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Floor.java)
- * [Gaussian](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Gaussian.java)
- * [GCD](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/GCD.java)
- * [GCDRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/GCDRecursion.java)
- * [GenericRoot](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/GenericRoot.java)
- * [HarshadNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/HarshadNumber.java)
- * [JugglerSequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/JugglerSequence.java)
- * [KaprekarNumbers](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/KaprekarNumbers.java)
- * [KeithNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/KeithNumber.java)
- * [KrishnamurthyNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/KrishnamurthyNumber.java)
- * [LeonardoNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LeonardoNumber.java)
- * [LinearDiophantineEquationsSolver](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LinearDiophantineEquationsSolver.java)
- * [LucasSeries](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LucasSeries.java)
- * [MagicSquare](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MagicSquare.java)
- * [MatrixUtil](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MatrixUtil.java)
- * [MaxValue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MaxValue.java)
- * [Median](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Median.java)
- * [MinValue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MinValue.java)
- * [Mode](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Mode.java)
- * [NonRepeatingElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/NonRepeatingElement.java)
- * [NthUglyNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/NthUglyNumber.java)
- * [NumberOfDigits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/NumberOfDigits.java)
- * [PalindromeNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PalindromeNumber.java)
- * [ParseInteger](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/ParseInteger.java)
- * [PascalTriangle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PascalTriangle.java)
- * [PerfectCube](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PerfectCube.java)
- * [PerfectNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PerfectNumber.java)
- * [PerfectSquare](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PerfectSquare.java)
- * [PiNilakantha](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PiNilakantha.java)
- * [Pow](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Pow.java)
- * [PowerOfTwoOrNot](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PowerOfTwoOrNot.java)
- * [PowRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PowRecursion.java)
- * [PrimeCheck](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PrimeCheck.java)
- * [PrimeFactorization](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PrimeFactorization.java)
- * [PronicNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PronicNumber.java)
- * [PythagoreanTriple](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PythagoreanTriple.java)
- * [ReverseNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/ReverseNumber.java)
- * [RomanNumeralUtil](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/RomanNumeralUtil.java)
- * [SimpsonIntegration](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SimpsonIntegration.java)
- * [SumOfArithmeticSeries](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SumOfArithmeticSeries.java)
- * [SumOfDigits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SumOfDigits.java)
- * [TrinomialTriangle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/TrinomialTriangle.java)
- * [VampireNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/VampireNumber.java)
- * [VectorCrossProduct](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/VectorCrossProduct.java)
- * [Volume](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Volume.java)
- * matrixexponentiation
- * [Fibonacci](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/matrixexponentiation/Fibonacci.java)
- * minimizinglateness
- * [MinimizingLateness](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/minimizinglateness/MinimizingLateness.java)
- * misc
- * [ColorContrastRatio](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/ColorContrastRatio.java)
- * [InverseOfMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/InverseOfMatrix.java)
- * [matrixTranspose](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/matrixTranspose.java)
- * [MedianOfRunningArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/MedianOfRunningArray.java)
- * [PalindromePrime](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/PalindromePrime.java)
- * [PalindromeSinglyLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/PalindromeSinglyLinkedList.java)
- * [RangeInSortedArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/RangeInSortedArray.java)
- * [Sort012D](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/Sort012D.java)
- * [Sparcity](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/Sparcity.java)
- * [ThreeSumProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/ThreeSumProblem.java)
- * [TwoSumProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/TwoSumProblem.java)
- * [WordBoggle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/WordBoggle.java)
- * others
- * [ArrayLeftRotation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/ArrayLeftRotation.java)
- * [BankersAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/BankersAlgorithm.java)
- * [BestFit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/BestFit.java)
- * [BFPRT](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/BFPRT.java)
- * [BoyerMoore](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/BoyerMoore.java)
- * [BrianKernighanAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/BrianKernighanAlgorithm.java)
- * [CountChar](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/CountChar.java)
- * [CountWords](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/CountWords.java)
- * [CRC32](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/CRC32.java)
- * [CRCAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/CRCAlgorithm.java)
- * [Damm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Damm.java)
- * [Dijkstra](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Dijkstra.java)
- * [EulersFunction](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/EulersFunction.java)
- * [FibbonaciSeries](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/FibbonaciSeries.java)
- * [FirstFit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/FirstFit.java)
- * [FloydTriangle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/FloydTriangle.java)
- * [GuassLegendre](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/GuassLegendre.java)
- * [HappyNumbersSeq](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/HappyNumbersSeq.java)
- * [Huffman](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Huffman.java)
- * [Implementing auto completing features using trie](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java)
- * [InsertDeleteInArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/InsertDeleteInArray.java)
- * [KMP](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/KMP.java)
- * [KochSnowflake](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/KochSnowflake.java)
- * [Krishnamurthy](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Krishnamurthy.java)
- * [LinearCongruentialGenerator](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/LinearCongruentialGenerator.java)
- * [LowestBasePalindrome](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/LowestBasePalindrome.java)
- * [Luhn](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Luhn.java)
- * [Mandelbrot](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Mandelbrot.java)
- * [MiniMaxAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/MiniMaxAlgorithm.java)
- * [PageRank](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/PageRank.java)
- * [PasswordGen](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/PasswordGen.java)
- * [PerlinNoise](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/PerlinNoise.java)
- * [QueueUsingTwoStacks](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/QueueUsingTwoStacks.java)
- * [RabinKarp](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/RabinKarp.java)
- * [RemoveDuplicateFromString](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/RemoveDuplicateFromString.java)
- * [ReturnSubsequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/ReturnSubsequence.java)
- * [ReverseStackUsingRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/ReverseStackUsingRecursion.java)
- * [RootPrecision](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/RootPrecision.java)
- * [RotateMatriceBy90Degree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/RotateMatriceBy90Degree.java)
- * [SieveOfEratosthenes](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/SieveOfEratosthenes.java)
- * [SJF](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/SJF.java)
- * [SkylineProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/SkylineProblem.java)
- * [StackPostfixNotation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/StackPostfixNotation.java)
- * [StringMatchFiniteAutomata](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/StringMatchFiniteAutomata.java)
- * [Sudoku](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Sudoku.java)
- * [ThreeSum](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/ThreeSum.java)
- * [TopKWords](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/TopKWords.java)
- * [TowerOfHanoi](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/TowerOfHanoi.java)
- * [TwoPointers](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/TwoPointers.java)
- * [Verhoeff](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Verhoeff.java)
- * [WorstFit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/WorstFit.java)
- * searches
- * [BinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/BinarySearch.java)
- * [BreadthFirstSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/BreadthFirstSearch.java)
- * [DepthFirstSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/DepthFirstSearch.java)
- * [ExponentalSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/ExponentalSearch.java)
- * [FibonacciSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/FibonacciSearch.java)
- * [HowManyTimesRotated](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/HowManyTimesRotated.java)
- * [InterpolationSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/InterpolationSearch.java)
- * [IterativeBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/IterativeBinarySearch.java)
- * [IterativeTernarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/IterativeTernarySearch.java)
- * [JumpSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/JumpSearch.java)
- * [LinearSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/LinearSearch.java)
- * [LinearSearchThread](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/LinearSearchThread.java)
- * [LowerBound](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/LowerBound.java)
- * [MonteCarloTreeSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/MonteCarloTreeSearch.java)
- * [PerfectBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java)
- * [QuickSelect](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/QuickSelect.java)
- * [SaddlebackSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/SaddlebackSearch.java)
- * [SquareRootBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/SquareRootBinarySearch.java)
- * [TernarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/TernarySearch.java)
- * [UnionFind](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/UnionFind.java)
- * [UpperBound](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/UpperBound.java)
- * sorts
- * [BitonicSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/BitonicSort.java)
- * [BogoSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/BogoSort.java)
- * [BubbleSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/BubbleSort.java)
- * [BubbleSortRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/BubbleSortRecursion.java)
- * [BucketSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/BucketSort.java)
- * [CircleSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CircleSort.java)
- * [CocktailShakerSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CocktailShakerSort.java)
- * [CombSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CombSort.java)
- * [CountingSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CountingSort.java)
- * [CycleSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CycleSort.java)
- * [DNFSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/DNFSort.java)
- * [GnomeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/GnomeSort.java)
- * [HeapSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/HeapSort.java)
- * [InsertionSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/InsertionSort.java)
- * [MergeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/MergeSort.java)
- * [MergeSortNoExtraSpace](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/MergeSortNoExtraSpace.java)
- * [MergeSortRecursive](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/MergeSortRecursive.java)
- * [OddEvenSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/OddEvenSort.java)
- * [PancakeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/PancakeSort.java)
- * [QuickSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/QuickSort.java)
- * [RadixSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/RadixSort.java)
- * [SelectionSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SelectionSort.java)
- * [ShellSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/ShellSort.java)
- * [SimpleSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SimpleSort.java)
- * [SlowSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SlowSort.java)
- * [SortAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SortAlgorithm.java)
- * [SortUtils](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SortUtils.java)
- * [StoogeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/StoogeSort.java)
- * [SwapSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SwapSort.java)
- * [TimSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/TimSort.java)
- * [TreeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/TreeSort.java)
- * strings
- * [Alphabetical](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Alphabetical.java)
- * [Anagrams](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Anagrams.java)
- * [CharactersSame](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/CharactersSame.java)
- * [CheckAnagrams](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/CheckAnagrams.java)
- * [CheckVowels](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/CheckVowels.java)
- * [HorspoolSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/HorspoolSearch.java)
- * [List all Possible Words From Phone Digits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/List_all_Possible_Words_From_Phone_Digits.java)
- * [LongestPalindromicSubstring](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java)
- * [Lower](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Lower.java)
- * [Palindrome](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Palindrome.java)
- * [Pangram](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Pangram.java)
- * [PermuteString](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/PermuteString.java)
- * [ReverseString](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/ReverseString.java)
- * [Rotation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Rotation.java)
- * [Upper](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Upper.java)
- * [WordLadder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/WordLadder.java)
- * test
- * java
- * com
- * thealgorithms
- * maths
- * [KaprekarNumbersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/KaprekarNumbersTest.java)
- * [PascalTriangleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PascalTriangleTest.java)
- * [PronicNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PronicNumberTest.java)
- * others
- * [ArrayLeftRotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ArrayLeftRotationTest.java)
- * searches
- * [QuickSelectTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/QuickSelectTest.java)
+
+- 📁 **main**
+ - 📁 **java**
+ - 📁 **com**
+ - 📁 **thealgorithms**
+ - 📁 **audiofilters**
+ - 📄 [EMAFilter](src/main/java/com/thealgorithms/audiofilters/EMAFilter.java)
+ - 📄 [IIRFilter](src/main/java/com/thealgorithms/audiofilters/IIRFilter.java)
+ - 📁 **backtracking**
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [MColoring](src/main/java/com/thealgorithms/backtracking/MColoring.java)
+ - 📄 [MazeRecursion](src/main/java/com/thealgorithms/backtracking/MazeRecursion.java)
+ - 📄 [NQueens](src/main/java/com/thealgorithms/backtracking/NQueens.java)
+ - 📄 [ParenthesesGenerator](src/main/java/com/thealgorithms/backtracking/ParenthesesGenerator.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [FirstDifferentBit](src/main/java/com/thealgorithms/bitmanipulation/FirstDifferentBit.java)
+ - 📄 [GenerateSubsets](src/main/java/com/thealgorithms/bitmanipulation/GenerateSubsets.java)
+ - 📄 [GrayCodeConversion](src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java)
+ - 📄 [HammingDistance](src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java)
+ - 📄 [HigherLowerPowerOfTwo](src/main/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwo.java)
+ - 📄 [HighestSetBit](src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java)
+ - 📄 [IndexOfRightMostSetBit](src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java)
+ - 📄 [IsEven](src/main/java/com/thealgorithms/bitmanipulation/IsEven.java)
+ - 📄 [IsPowerTwo](src/main/java/com/thealgorithms/bitmanipulation/IsPowerTwo.java)
+ - 📄 [LowestSetBit](src/main/java/com/thealgorithms/bitmanipulation/LowestSetBit.java)
+ - 📄 [ModuloPowerOfTwo](src/main/java/com/thealgorithms/bitmanipulation/ModuloPowerOfTwo.java)
+ - 📄 [NextHigherSameBitCount](src/main/java/com/thealgorithms/bitmanipulation/NextHigherSameBitCount.java)
+ - 📄 [NonRepeatingNumberFinder](src/main/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinder.java)
+ - 📄 [NumberAppearingOddTimes](src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java)
+ - 📄 [NumbersDifferentSigns](src/main/java/com/thealgorithms/bitmanipulation/NumbersDifferentSigns.java)
+ - 📄 [OneBitDifference](src/main/java/com/thealgorithms/bitmanipulation/OneBitDifference.java)
+ - 📄 [OnesComplement](src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java)
+ - 📄 [ParityCheck](src/main/java/com/thealgorithms/bitmanipulation/ParityCheck.java)
+ - 📄 [ReverseBits](src/main/java/com/thealgorithms/bitmanipulation/ReverseBits.java)
+ - 📄 [SingleBitOperations](src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java)
+ - 📄 [SingleElement](src/main/java/com/thealgorithms/bitmanipulation/SingleElement.java)
+ - 📄 [SwapAdjacentBits](src/main/java/com/thealgorithms/bitmanipulation/SwapAdjacentBits.java)
+ - 📄 [TwosComplement](src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java)
+ - 📄 [Xs3Conversion](src/main/java/com/thealgorithms/bitmanipulation/Xs3Conversion.java)
+ - 📁 **ciphers**
+ - 📄 [ADFGVXCipher](src/main/java/com/thealgorithms/ciphers/ADFGVXCipher.java)
+ - 📄 [AES](src/main/java/com/thealgorithms/ciphers/AES.java)
+ - 📄 [AESEncryption](src/main/java/com/thealgorithms/ciphers/AESEncryption.java)
+ - 📄 [AffineCipher](src/main/java/com/thealgorithms/ciphers/AffineCipher.java)
+ - 📄 [AtbashCipher](src/main/java/com/thealgorithms/ciphers/AtbashCipher.java)
+ - 📄 [Autokey](src/main/java/com/thealgorithms/ciphers/Autokey.java)
+ - 📄 [BaconianCipher](src/main/java/com/thealgorithms/ciphers/BaconianCipher.java)
+ - 📄 [Blowfish](src/main/java/com/thealgorithms/ciphers/Blowfish.java)
+ - 📄 [Caesar](src/main/java/com/thealgorithms/ciphers/Caesar.java)
+ - 📄 [ColumnarTranspositionCipher](src/main/java/com/thealgorithms/ciphers/ColumnarTranspositionCipher.java)
+ - 📄 [DES](src/main/java/com/thealgorithms/ciphers/DES.java)
+ - 📄 [DiffieHellman](src/main/java/com/thealgorithms/ciphers/DiffieHellman.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [RSA](src/main/java/com/thealgorithms/ciphers/RSA.java)
+ - 📄 [RailFenceCipher](src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java)
+ - 📄 [SimpleSubCipher](src/main/java/com/thealgorithms/ciphers/SimpleSubCipher.java)
+ - 📄 [Vigenere](src/main/java/com/thealgorithms/ciphers/Vigenere.java)
+ - 📄 [XORCipher](src/main/java/com/thealgorithms/ciphers/XORCipher.java)
+ - 📁 **a5**
+ - 📄 [A5Cipher](src/main/java/com/thealgorithms/ciphers/a5/A5Cipher.java)
+ - 📄 [A5KeyStreamGenerator](src/main/java/com/thealgorithms/ciphers/a5/A5KeyStreamGenerator.java)
+ - 📄 [BaseLFSR](src/main/java/com/thealgorithms/ciphers/a5/BaseLFSR.java)
+ - 📄 [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**
+ - 📄 [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)
+ - 📄 [AnyBaseToDecimal](src/main/java/com/thealgorithms/conversions/AnyBaseToDecimal.java)
+ - 📄 [AnytoAny](src/main/java/com/thealgorithms/conversions/AnytoAny.java)
+ - 📄 [Base64](src/main/java/com/thealgorithms/conversions/Base64.java)
+ - 📄 [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)
+ - 📄 [DecimalToOctal](src/main/java/com/thealgorithms/conversions/DecimalToOctal.java)
+ - 📄 [EndianConverter](src/main/java/com/thealgorithms/conversions/EndianConverter.java)
+ - 📄 [HexToOct](src/main/java/com/thealgorithms/conversions/HexToOct.java)
+ - 📄 [HexaDecimalToBinary](src/main/java/com/thealgorithms/conversions/HexaDecimalToBinary.java)
+ - 📄 [HexaDecimalToDecimal](src/main/java/com/thealgorithms/conversions/HexaDecimalToDecimal.java)
+ - 📄 [IPConverter](src/main/java/com/thealgorithms/conversions/IPConverter.java)
+ - 📄 [IPv6Converter](src/main/java/com/thealgorithms/conversions/IPv6Converter.java)
+ - 📄 [IntegerToEnglish](src/main/java/com/thealgorithms/conversions/IntegerToEnglish.java)
+ - 📄 [IntegerToRoman](src/main/java/com/thealgorithms/conversions/IntegerToRoman.java)
+ - 📄 [MorseCodeConverter](src/main/java/com/thealgorithms/conversions/MorseCodeConverter.java)
+ - 📄 [NumberToWords](src/main/java/com/thealgorithms/conversions/NumberToWords.java)
+ - 📄 [OctalToBinary](src/main/java/com/thealgorithms/conversions/OctalToBinary.java)
+ - 📄 [OctalToDecimal](src/main/java/com/thealgorithms/conversions/OctalToDecimal.java)
+ - 📄 [OctalToHexadecimal](src/main/java/com/thealgorithms/conversions/OctalToHexadecimal.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [WordsToNumber](src/main/java/com/thealgorithms/conversions/WordsToNumber.java)
+ - 📁 **datastructures**
+ - 📄 [Node](src/main/java/com/thealgorithms/datastructures/Node.java)
+ - 📁 **bags**
+ - 📄 [Bag](src/main/java/com/thealgorithms/datastructures/bags/Bag.java)
+ - 📁 **bloomfilter**
+ - 📄 [BloomFilter](src/main/java/com/thealgorithms/datastructures/bloomfilter/BloomFilter.java)
+ - 📁 **buffers**
+ - 📄 [CircularBuffer](src/main/java/com/thealgorithms/datastructures/buffers/CircularBuffer.java)
+ - 📁 **caches**
+ - 📄 [FIFOCache](src/main/java/com/thealgorithms/datastructures/caches/FIFOCache.java)
+ - 📄 [LFUCache](src/main/java/com/thealgorithms/datastructures/caches/LFUCache.java)
+ - 📄 [LIFOCache](src/main/java/com/thealgorithms/datastructures/caches/LIFOCache.java)
+ - 📄 [LRUCache](src/main/java/com/thealgorithms/datastructures/caches/LRUCache.java)
+ - 📄 [MRUCache](src/main/java/com/thealgorithms/datastructures/caches/MRUCache.java)
+ - 📄 [RRCache](src/main/java/com/thealgorithms/datastructures/caches/RRCache.java)
+ - 📁 **crdt**
+ - 📄 [GCounter](src/main/java/com/thealgorithms/datastructures/crdt/GCounter.java)
+ - 📄 [GSet](src/main/java/com/thealgorithms/datastructures/crdt/GSet.java)
+ - 📄 [LWWElementSet](src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java)
+ - 📄 [ORSet](src/main/java/com/thealgorithms/datastructures/crdt/ORSet.java)
+ - 📄 [PNCounter](src/main/java/com/thealgorithms/datastructures/crdt/PNCounter.java)
+ - 📄 [TwoPSet](src/main/java/com/thealgorithms/datastructures/crdt/TwoPSet.java)
+ - 📁 **disjointsetunion**
+ - 📄 [DisjointSetUnion](src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnion.java)
+ - 📄 [DisjointSetUnionBySize](src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionBySize.java)
+ - 📄 [Node](src/main/java/com/thealgorithms/datastructures/disjointsetunion/Node.java)
+ - 📁 **dynamicarray**
+ - 📄 [DynamicArray](src/main/java/com/thealgorithms/datastructures/dynamicarray/DynamicArray.java)
+ - 📁 **graphs**
+ - 📄 [AStar](src/main/java/com/thealgorithms/datastructures/graphs/AStar.java)
+ - 📄 [BellmanFord](src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java)
+ - 📄 [BipartiteGraphDFS](src/main/java/com/thealgorithms/datastructures/graphs/BipartiteGraphDFS.java)
+ - 📄 [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)
+ - 📄 [FloydWarshall](src/main/java/com/thealgorithms/datastructures/graphs/FloydWarshall.java)
+ - 📄 [FordFulkerson](src/main/java/com/thealgorithms/datastructures/graphs/FordFulkerson.java)
+ - 📄 [Graphs](src/main/java/com/thealgorithms/datastructures/graphs/Graphs.java)
+ - 📄 [HamiltonianCycle](src/main/java/com/thealgorithms/datastructures/graphs/HamiltonianCycle.java)
+ - 📄 [JohnsonsAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java)
+ - 📄 [KahnsAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithm.java)
+ - 📄 [Kosaraju](src/main/java/com/thealgorithms/datastructures/graphs/Kosaraju.java)
+ - 📄 [Kruskal](src/main/java/com/thealgorithms/datastructures/graphs/Kruskal.java)
+ - 📄 [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**
+ - 📁 **hashing**
+ - 📄 [GenericHashMapUsingArray](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [MajorityElement](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/MajorityElement.java)
+ - 📄 [Map](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/Map.java)
+ - 📁 **heaps**
+ - 📄 [EmptyHeapException](src/main/java/com/thealgorithms/datastructures/heaps/EmptyHeapException.java)
+ - 📄 [FibonacciHeap](src/main/java/com/thealgorithms/datastructures/heaps/FibonacciHeap.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [MedianFinder](src/main/java/com/thealgorithms/datastructures/heaps/MedianFinder.java)
+ - 📄 [MergeKSortedArrays](src/main/java/com/thealgorithms/datastructures/heaps/MergeKSortedArrays.java)
+ - 📄 [MinHeap](src/main/java/com/thealgorithms/datastructures/heaps/MinHeap.java)
+ - 📄 [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)
+ - 📄 [QuickSortLinkedList](src/main/java/com/thealgorithms/datastructures/lists/QuickSortLinkedList.java)
+ - 📄 [RandomNode](src/main/java/com/thealgorithms/datastructures/lists/RandomNode.java)
+ - 📄 [ReverseKGroup](src/main/java/com/thealgorithms/datastructures/lists/ReverseKGroup.java)
+ - 📄 [RotateSinglyLinkedLists](src/main/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedLists.java)
+ - 📄 [SearchSinglyLinkedListRecursion](src/main/java/com/thealgorithms/datastructures/lists/SearchSinglyLinkedListRecursion.java)
+ - 📄 [SinglyLinkedList](src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedList.java)
+ - 📄 [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)
+ - 📄 [GenericArrayListQueue](src/main/java/com/thealgorithms/datastructures/queues/GenericArrayListQueue.java)
+ - 📄 [LinkedQueue](src/main/java/com/thealgorithms/datastructures/queues/LinkedQueue.java)
+ - 📄 [PriorityQueues](src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java)
+ - 📄 [Queue](src/main/java/com/thealgorithms/datastructures/queues/Queue.java)
+ - 📄 [QueueByTwoStacks](src/main/java/com/thealgorithms/datastructures/queues/QueueByTwoStacks.java)
+ - 📄 [SlidingWindowMaximum](src/main/java/com/thealgorithms/datastructures/queues/SlidingWindowMaximum.java)
+ - 📄 [TokenBucket](src/main/java/com/thealgorithms/datastructures/queues/TokenBucket.java)
+ - 📁 **stacks**
+ - 📄 [NodeStack](src/main/java/com/thealgorithms/datastructures/stacks/NodeStack.java)
+ - 📄 [ReverseStack](src/main/java/com/thealgorithms/datastructures/stacks/ReverseStack.java)
+ - 📄 [Stack](src/main/java/com/thealgorithms/datastructures/stacks/Stack.java)
+ - 📄 [StackArray](src/main/java/com/thealgorithms/datastructures/stacks/StackArray.java)
+ - 📄 [StackArrayList](src/main/java/com/thealgorithms/datastructures/stacks/StackArrayList.java)
+ - 📄 [StackOfLinkedList](src/main/java/com/thealgorithms/datastructures/stacks/StackOfLinkedList.java)
+ - 📁 **trees**
+ - 📄 [AVLSimple](src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java)
+ - 📄 [AVLTree](src/main/java/com/thealgorithms/datastructures/trees/AVLTree.java)
+ - 📄 [BSTFromSortedArray](src/main/java/com/thealgorithms/datastructures/trees/BSTFromSortedArray.java)
+ - 📄 [BSTIterative](src/main/java/com/thealgorithms/datastructures/trees/BSTIterative.java)
+ - 📄 [BSTRecursive](src/main/java/com/thealgorithms/datastructures/trees/BSTRecursive.java)
+ - 📄 [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)
+ - 📄 [BoundaryTraversal](src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java)
+ - 📄 [CeilInBinarySearchTree](src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.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)
+ - 📄 [CreateBinaryTreeFromInorderPreorder](src/main/java/com/thealgorithms/datastructures/trees/CreateBinaryTreeFromInorderPreorder.java)
+ - 📄 [FenwickTree](src/main/java/com/thealgorithms/datastructures/trees/FenwickTree.java)
+ - 📄 [GenericTree](src/main/java/com/thealgorithms/datastructures/trees/GenericTree.java)
+ - 📄 [InorderTraversal](src/main/java/com/thealgorithms/datastructures/trees/InorderTraversal.java)
+ - 📄 [KDTree](src/main/java/com/thealgorithms/datastructures/trees/KDTree.java)
+ - 📄 [LCA](src/main/java/com/thealgorithms/datastructures/trees/LCA.java)
+ - 📄 [LazySegmentTree](src/main/java/com/thealgorithms/datastructures/trees/LazySegmentTree.java)
+ - 📄 [LevelOrderTraversal](src/main/java/com/thealgorithms/datastructures/trees/LevelOrderTraversal.java)
+ - 📄 [PostOrderTraversal](src/main/java/com/thealgorithms/datastructures/trees/PostOrderTraversal.java)
+ - 📄 [PreOrderTraversal](src/main/java/com/thealgorithms/datastructures/trees/PreOrderTraversal.java)
+ - 📄 [PrintTopViewofTree](src/main/java/com/thealgorithms/datastructures/trees/PrintTopViewofTree.java)
+ - 📄 [QuadTree](src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java)
+ - 📄 [RedBlackBST](src/main/java/com/thealgorithms/datastructures/trees/RedBlackBST.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [VerticalOrderTraversal](src/main/java/com/thealgorithms/datastructures/trees/VerticalOrderTraversal.java)
+ - 📄 [ZigzagTraversal](src/main/java/com/thealgorithms/datastructures/trees/ZigzagTraversal.java)
+ - 📄 [nearestRightKey](src/main/java/com/thealgorithms/datastructures/trees/nearestRightKey.java)
+ - 📁 **devutils**
+ - 📁 **entities**
+ - 📄 [ProcessDetails](src/main/java/com/thealgorithms/devutils/entities/ProcessDetails.java)
+ - 📁 **nodes**
+ - 📄 [LargeTreeNode](src/main/java/com/thealgorithms/devutils/nodes/LargeTreeNode.java)
+ - 📄 [Node](src/main/java/com/thealgorithms/devutils/nodes/Node.java)
+ - 📄 [SimpleNode](src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java)
+ - 📄 [SimpleTreeNode](src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java)
+ - 📄 [TreeNode](src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java)
+ - 📁 **searches**
+ - 📄 [MatrixSearchAlgorithm](src/main/java/com/thealgorithms/devutils/searches/MatrixSearchAlgorithm.java)
+ - 📄 [SearchAlgorithm](src/main/java/com/thealgorithms/devutils/searches/SearchAlgorithm.java)
+ - 📁 **divideandconquer**
+ - 📄 [BinaryExponentiation](src/main/java/com/thealgorithms/divideandconquer/BinaryExponentiation.java)
+ - 📄 [ClosestPair](src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java)
+ - 📄 [CountingInversions](src/main/java/com/thealgorithms/divideandconquer/CountingInversions.java)
+ - 📄 [MedianOfTwoSortedArrays](src/main/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArrays.java)
+ - 📄 [SkylineAlgorithm](src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java)
+ - 📄 [StrassenMatrixMultiplication](src/main/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplication.java)
+ - 📄 [TilingProblem](src/main/java/com/thealgorithms/divideandconquer/TilingProblem.java)
+ - 📁 **dynamicprogramming**
+ - 📄 [Abbreviation](src/main/java/com/thealgorithms/dynamicprogramming/Abbreviation.java)
+ - 📄 [AllConstruct](src/main/java/com/thealgorithms/dynamicprogramming/AllConstruct.java)
+ - 📄 [AssignmentUsingBitmask](src/main/java/com/thealgorithms/dynamicprogramming/AssignmentUsingBitmask.java)
+ - 📄 [BoardPath](src/main/java/com/thealgorithms/dynamicprogramming/BoardPath.java)
+ - 📄 [BoundaryFill](src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java)
+ - 📄 [BruteForceKnapsack](src/main/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsack.java)
+ - 📄 [CatalanNumber](src/main/java/com/thealgorithms/dynamicprogramming/CatalanNumber.java)
+ - 📄 [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)
+ - 📄 [Fibonacci](src/main/java/com/thealgorithms/dynamicprogramming/Fibonacci.java)
+ - 📄 [KadaneAlgorithm](src/main/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithm.java)
+ - 📄 [Knapsack](src/main/java/com/thealgorithms/dynamicprogramming/Knapsack.java)
+ - 📄 [KnapsackMemoization](src/main/java/com/thealgorithms/dynamicprogramming/KnapsackMemoization.java)
+ - 📄 [KnapsackZeroOne](src/main/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOne.java)
+ - 📄 [KnapsackZeroOneTabulation](src/main/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTabulation.java)
+ - 📄 [LevenshteinDistance](src/main/java/com/thealgorithms/dynamicprogramming/LevenshteinDistance.java)
+ - 📄 [LongestAlternatingSubsequence](src/main/java/com/thealgorithms/dynamicprogramming/LongestAlternatingSubsequence.java)
+ - 📄 [LongestArithmeticSubsequence](src/main/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequence.java)
+ - 📄 [LongestCommonSubsequence](src/main/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequence.java)
+ - 📄 [LongestIncreasingSubsequence](src/main/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequence.java)
+ - 📄 [LongestIncreasingSubsequenceNLogN](src/main/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceNLogN.java)
+ - 📄 [LongestPalindromicSubsequence](src/main/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubsequence.java)
+ - 📄 [LongestPalindromicSubstring](src/main/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstring.java)
+ - 📄 [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)
+ - 📄 [PartitionProblem](src/main/java/com/thealgorithms/dynamicprogramming/PartitionProblem.java)
+ - 📄 [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)
+ - 📄 [SumOfSubset](src/main/java/com/thealgorithms/dynamicprogramming/SumOfSubset.java)
+ - 📄 [TreeMatching](src/main/java/com/thealgorithms/dynamicprogramming/TreeMatching.java)
+ - 📄 [Tribonacci](src/main/java/com/thealgorithms/dynamicprogramming/Tribonacci.java)
+ - 📄 [UniquePaths](src/main/java/com/thealgorithms/dynamicprogramming/UniquePaths.java)
+ - 📄 [UniqueSubsequencesCount](src/main/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCount.java)
+ - 📄 [WildcardMatching](src/main/java/com/thealgorithms/dynamicprogramming/WildcardMatching.java)
+ - 📄 [WineProblem](src/main/java/com/thealgorithms/dynamicprogramming/WineProblem.java)
+ - 📁 **geometry**
+ - 📄 [BresenhamLine](src/main/java/com/thealgorithms/geometry/BresenhamLine.java)
+ - 📄 [ConvexHull](src/main/java/com/thealgorithms/geometry/ConvexHull.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)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [BinaryAddition](src/main/java/com/thealgorithms/greedyalgorithms/BinaryAddition.java)
+ - 📄 [CoinChange](src/main/java/com/thealgorithms/greedyalgorithms/CoinChange.java)
+ - 📄 [DigitSeparation](src/main/java/com/thealgorithms/greedyalgorithms/DigitSeparation.java)
+ - 📄 [EgyptianFraction](src/main/java/com/thealgorithms/greedyalgorithms/EgyptianFraction.java)
+ - 📄 [FractionalKnapsack](src/main/java/com/thealgorithms/greedyalgorithms/FractionalKnapsack.java)
+ - 📄 [GaleShapley](src/main/java/com/thealgorithms/greedyalgorithms/GaleShapley.java)
+ - 📄 [JobSequencing](src/main/java/com/thealgorithms/greedyalgorithms/JobSequencing.java)
+ - 📄 [KCenters](src/main/java/com/thealgorithms/greedyalgorithms/KCenters.java)
+ - 📄 [MergeIntervals](src/main/java/com/thealgorithms/greedyalgorithms/MergeIntervals.java)
+ - 📄 [MinimizingLateness](src/main/java/com/thealgorithms/greedyalgorithms/MinimizingLateness.java)
+ - 📄 [MinimumWaitingTime](src/main/java/com/thealgorithms/greedyalgorithms/MinimumWaitingTime.java)
+ - 📄 [OptimalFileMerging](src/main/java/com/thealgorithms/greedyalgorithms/OptimalFileMerging.java)
+ - 📄 [StockProfitCalculator](src/main/java/com/thealgorithms/greedyalgorithms/StockProfitCalculator.java)
+ - 📁 **io**
+ - 📄 [BufferedReader](src/main/java/com/thealgorithms/io/BufferedReader.java)
+ - 📁 **lineclipping**
+ - 📄 [CohenSutherland](src/main/java/com/thealgorithms/lineclipping/CohenSutherland.java)
+ - 📄 [LiangBarsky](src/main/java/com/thealgorithms/lineclipping/LiangBarsky.java)
+ - 📁 **utils**
+ - 📄 [Line](src/main/java/com/thealgorithms/lineclipping/utils/Line.java)
+ - 📄 [Point](src/main/java/com/thealgorithms/lineclipping/utils/Point.java)
+ - 📁 **maths**
+ - 📄 [ADTFraction](src/main/java/com/thealgorithms/maths/ADTFraction.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [Armstrong](src/main/java/com/thealgorithms/maths/Armstrong.java)
+ - 📄 [AutoCorrelation](src/main/java/com/thealgorithms/maths/AutoCorrelation.java)
+ - 📄 [AutomorphicNumber](src/main/java/com/thealgorithms/maths/AutomorphicNumber.java)
+ - 📄 [Average](src/main/java/com/thealgorithms/maths/Average.java)
+ - 📄 [BinaryPow](src/main/java/com/thealgorithms/maths/BinaryPow.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [Combinations](src/main/java/com/thealgorithms/maths/Combinations.java)
+ - 📄 [Convolution](src/main/java/com/thealgorithms/maths/Convolution.java)
+ - 📄 [ConvolutionFFT](src/main/java/com/thealgorithms/maths/ConvolutionFFT.java)
+ - 📄 [CrossCorrelation](src/main/java/com/thealgorithms/maths/CrossCorrelation.java)
+ - 📄 [DeterminantOfMatrix](src/main/java/com/thealgorithms/maths/DeterminantOfMatrix.java)
+ - 📄 [DigitalRoot](src/main/java/com/thealgorithms/maths/DigitalRoot.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [FibonacciLoop](src/main/java/com/thealgorithms/maths/FibonacciLoop.java)
+ - 📄 [FibonacciNumberCheck](src/main/java/com/thealgorithms/maths/FibonacciNumberCheck.java)
+ - 📄 [FibonacciNumberGoldenRation](src/main/java/com/thealgorithms/maths/FibonacciNumberGoldenRation.java)
+ - 📄 [FindKthNumber](src/main/java/com/thealgorithms/maths/FindKthNumber.java)
+ - 📄 [FindMax](src/main/java/com/thealgorithms/maths/FindMax.java)
+ - 📄 [FindMaxRecursion](src/main/java/com/thealgorithms/maths/FindMaxRecursion.java)
+ - 📄 [FindMin](src/main/java/com/thealgorithms/maths/FindMin.java)
+ - 📄 [FindMinRecursion](src/main/java/com/thealgorithms/maths/FindMinRecursion.java)
+ - 📄 [Floor](src/main/java/com/thealgorithms/maths/Floor.java)
+ - 📄 [FrizzyNumber](src/main/java/com/thealgorithms/maths/FrizzyNumber.java)
+ - 📄 [GCD](src/main/java/com/thealgorithms/maths/GCD.java)
+ - 📄 [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)
+ - 📄 [JugglerSequence](src/main/java/com/thealgorithms/maths/JugglerSequence.java)
+ - 📄 [KaprekarNumbers](src/main/java/com/thealgorithms/maths/KaprekarNumbers.java)
+ - 📄 [KaratsubaMultiplication](src/main/java/com/thealgorithms/maths/KaratsubaMultiplication.java)
+ - 📄 [KeithNumber](src/main/java/com/thealgorithms/maths/KeithNumber.java)
+ - 📄 [KrishnamurthyNumber](src/main/java/com/thealgorithms/maths/KrishnamurthyNumber.java)
+ - 📄 [LeastCommonMultiple](src/main/java/com/thealgorithms/maths/LeastCommonMultiple.java)
+ - 📄 [LeonardoNumber](src/main/java/com/thealgorithms/maths/LeonardoNumber.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [Means](src/main/java/com/thealgorithms/maths/Means.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [PerfectCube](src/main/java/com/thealgorithms/maths/PerfectCube.java)
+ - 📄 [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)
+ - 📄 [PowerOfTwoOrNot](src/main/java/com/thealgorithms/maths/PowerOfTwoOrNot.java)
+ - 📄 [PowerUsingRecursion](src/main/java/com/thealgorithms/maths/PowerUsingRecursion.java)
+ - 📁 **Prime**
+ - 📄 [LiouvilleLambdaFunction](src/main/java/com/thealgorithms/maths/Prime/LiouvilleLambdaFunction.java)
+ - 📄 [MillerRabinPrimalityCheck](src/main/java/com/thealgorithms/maths/Prime/MillerRabinPrimalityCheck.java)
+ - 📄 [MobiusFunction](src/main/java/com/thealgorithms/maths/Prime/MobiusFunction.java)
+ - 📄 [PrimeCheck](src/main/java/com/thealgorithms/maths/Prime/PrimeCheck.java)
+ - 📄 [PrimeFactorization](src/main/java/com/thealgorithms/maths/Prime/PrimeFactorization.java)
+ - 📄 [SquareFreeInteger](src/main/java/com/thealgorithms/maths/Prime/SquareFreeInteger.java)
+ - 📄 [PronicNumber](src/main/java/com/thealgorithms/maths/PronicNumber.java)
+ - 📄 [PythagoreanTriple](src/main/java/com/thealgorithms/maths/PythagoreanTriple.java)
+ - 📄 [QuadraticEquationSolver](src/main/java/com/thealgorithms/maths/QuadraticEquationSolver.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [StandardDeviation](src/main/java/com/thealgorithms/maths/StandardDeviation.java)
+ - 📄 [StandardScore](src/main/java/com/thealgorithms/maths/StandardScore.java)
+ - 📄 [StrobogrammaticNumber](src/main/java/com/thealgorithms/maths/StrobogrammaticNumber.java)
+ - 📄 [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)
+ - 📄 [UniformNumbers](src/main/java/com/thealgorithms/maths/UniformNumbers.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [MedianOfMatrix](src/main/java/com/thealgorithms/matrix/MedianOfMatrix.java)
+ - 📄 [MirrorOfMatrix](src/main/java/com/thealgorithms/matrix/MirrorOfMatrix.java)
+ - 📄 [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)
+ - 📁 **matrixexponentiation**
+ - 📄 [Fibonacci](src/main/java/com/thealgorithms/matrix/matrixexponentiation/Fibonacci.java)
+ - 📁 **utils**
+ - 📄 [MatrixUtil](src/main/java/com/thealgorithms/matrix/utils/MatrixUtil.java)
+ - 📁 **misc**
+ - 📄 [ColorContrastRatio](src/main/java/com/thealgorithms/misc/ColorContrastRatio.java)
+ - 📄 [MapReduce](src/main/java/com/thealgorithms/misc/MapReduce.java)
+ - 📄 [MedianOfRunningArray](src/main/java/com/thealgorithms/misc/MedianOfRunningArray.java)
+ - 📄 [MedianOfRunningArrayByte](src/main/java/com/thealgorithms/misc/MedianOfRunningArrayByte.java)
+ - 📄 [MedianOfRunningArrayDouble](src/main/java/com/thealgorithms/misc/MedianOfRunningArrayDouble.java)
+ - 📄 [MedianOfRunningArrayFloat](src/main/java/com/thealgorithms/misc/MedianOfRunningArrayFloat.java)
+ - 📄 [MedianOfRunningArrayInteger](src/main/java/com/thealgorithms/misc/MedianOfRunningArrayInteger.java)
+ - 📄 [MedianOfRunningArrayLong](src/main/java/com/thealgorithms/misc/MedianOfRunningArrayLong.java)
+ - 📄 [PalindromePrime](src/main/java/com/thealgorithms/misc/PalindromePrime.java)
+ - 📄 [PalindromeSinglyLinkedList](src/main/java/com/thealgorithms/misc/PalindromeSinglyLinkedList.java)
+ - 📄 [RangeInSortedArray](src/main/java/com/thealgorithms/misc/RangeInSortedArray.java)
+ - 📄 [ShuffleArray](src/main/java/com/thealgorithms/misc/ShuffleArray.java)
+ - 📄 [Sparsity](src/main/java/com/thealgorithms/misc/Sparsity.java)
+ - 📄 [ThreeSumProblem](src/main/java/com/thealgorithms/misc/ThreeSumProblem.java)
+ - 📄 [TwoSumProblem](src/main/java/com/thealgorithms/misc/TwoSumProblem.java)
+ - 📁 **others**
+ - 📄 [ArrayLeftRotation](src/main/java/com/thealgorithms/others/ArrayLeftRotation.java)
+ - 📄 [ArrayRightRotation](src/main/java/com/thealgorithms/others/ArrayRightRotation.java)
+ - 📄 [BFPRT](src/main/java/com/thealgorithms/others/BFPRT.java)
+ - 📄 [BankersAlgorithm](src/main/java/com/thealgorithms/others/BankersAlgorithm.java)
+ - 📄 [BoyerMoore](src/main/java/com/thealgorithms/others/BoyerMoore.java)
+ - 📄 [BrianKernighanAlgorithm](src/main/java/com/thealgorithms/others/BrianKernighanAlgorithm.java)
+ - 📄 [CRC16](src/main/java/com/thealgorithms/others/CRC16.java)
+ - 📄 [CRC32](src/main/java/com/thealgorithms/others/CRC32.java)
+ - 📄 [CRCAlgorithm](src/main/java/com/thealgorithms/others/CRCAlgorithm.java)
+ - 📄 [Conway](src/main/java/com/thealgorithms/others/Conway.java)
+ - 📄 [Damm](src/main/java/com/thealgorithms/others/Damm.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [Luhn](src/main/java/com/thealgorithms/others/Luhn.java)
+ - 📄 [Mandelbrot](src/main/java/com/thealgorithms/others/Mandelbrot.java)
+ - 📄 [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**
+ - 📄 [GroundToGroundProjectileMotion](src/main/java/com/thealgorithms/physics/GroundToGroundProjectileMotion.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**
+ - 📄 [KargerMinCut](src/main/java/com/thealgorithms/randomized/KargerMinCut.java)
+ - 📄 [MonteCarloIntegration](src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java)
+ - 📄 [RandomizedClosestPair](src/main/java/com/thealgorithms/randomized/RandomizedClosestPair.java)
+ - 📄 [RandomizedMatrixMultiplicationVerification](src/main/java/com/thealgorithms/randomized/RandomizedMatrixMultiplicationVerification.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [FCFSScheduling](src/main/java/com/thealgorithms/scheduling/FCFSScheduling.java)
+ - 📄 [FairShareScheduling](src/main/java/com/thealgorithms/scheduling/FairShareScheduling.java)
+ - 📄 [GangScheduling](src/main/java/com/thealgorithms/scheduling/GangScheduling.java)
+ - 📄 [HighestResponseRatioNextScheduling](src/main/java/com/thealgorithms/scheduling/HighestResponseRatioNextScheduling.java)
+ - 📄 [JobSchedulingWithDeadline](src/main/java/com/thealgorithms/scheduling/JobSchedulingWithDeadline.java)
+ - 📄 [LotteryScheduling](src/main/java/com/thealgorithms/scheduling/LotteryScheduling.java)
+ - 📄 [MLFQScheduler](src/main/java/com/thealgorithms/scheduling/MLFQScheduler.java)
+ - 📄 [MultiAgentScheduling](src/main/java/com/thealgorithms/scheduling/MultiAgentScheduling.java)
+ - 📄 [NonPreemptivePriorityScheduling](src/main/java/com/thealgorithms/scheduling/NonPreemptivePriorityScheduling.java)
+ - 📄 [PreemptivePriorityScheduling](src/main/java/com/thealgorithms/scheduling/PreemptivePriorityScheduling.java)
+ - 📄 [ProportionalFairScheduling](src/main/java/com/thealgorithms/scheduling/ProportionalFairScheduling.java)
+ - 📄 [RRScheduling](src/main/java/com/thealgorithms/scheduling/RRScheduling.java)
+ - 📄 [RandomScheduling](src/main/java/com/thealgorithms/scheduling/RandomScheduling.java)
+ - 📄 [SJFScheduling](src/main/java/com/thealgorithms/scheduling/SJFScheduling.java)
+ - 📄 [SRTFScheduling](src/main/java/com/thealgorithms/scheduling/SRTFScheduling.java)
+ - 📄 [SelfAdjustingScheduling](src/main/java/com/thealgorithms/scheduling/SelfAdjustingScheduling.java)
+ - 📄 [SlackTimeScheduling](src/main/java/com/thealgorithms/scheduling/SlackTimeScheduling.java)
+ - 📁 **diskscheduling**
+ - 📄 [CircularLookScheduling](src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularLookScheduling.java)
+ - 📄 [CircularScanScheduling](src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularScanScheduling.java)
+ - 📄 [LookScheduling](src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java)
+ - 📄 [SSFScheduling](src/main/java/com/thealgorithms/scheduling/diskscheduling/SSFScheduling.java)
+ - 📄 [ScanScheduling](src/main/java/com/thealgorithms/scheduling/diskscheduling/ScanScheduling.java)
+ - 📁 **searches**
+ - 📄 [BM25InvertedIndex](src/main/java/com/thealgorithms/searches/BM25InvertedIndex.java)
+ - 📄 [BinarySearch](src/main/java/com/thealgorithms/searches/BinarySearch.java)
+ - 📄 [BinarySearch2dArray](src/main/java/com/thealgorithms/searches/BinarySearch2dArray.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [IterativeBinarySearch](src/main/java/com/thealgorithms/searches/IterativeBinarySearch.java)
+ - 📄 [IterativeTernarySearch](src/main/java/com/thealgorithms/searches/IterativeTernarySearch.java)
+ - 📄 [JumpSearch](src/main/java/com/thealgorithms/searches/JumpSearch.java)
+ - 📄 [KMPSearch](src/main/java/com/thealgorithms/searches/KMPSearch.java)
+ - 📄 [LinearSearch](src/main/java/com/thealgorithms/searches/LinearSearch.java)
+ - 📄 [LinearSearchThread](src/main/java/com/thealgorithms/searches/LinearSearchThread.java)
+ - 📄 [LowerBound](src/main/java/com/thealgorithms/searches/LowerBound.java)
+ - 📄 [MonteCarloTreeSearch](src/main/java/com/thealgorithms/searches/MonteCarloTreeSearch.java)
+ - 📄 [OrderAgnosticBinarySearch](src/main/java/com/thealgorithms/searches/OrderAgnosticBinarySearch.java)
+ - 📄 [PerfectBinarySearch](src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java)
+ - 📄 [QuickSelect](src/main/java/com/thealgorithms/searches/QuickSelect.java)
+ - 📄 [RabinKarpAlgorithm](src/main/java/com/thealgorithms/searches/RabinKarpAlgorithm.java)
+ - 📄 [RandomSearch](src/main/java/com/thealgorithms/searches/RandomSearch.java)
+ - 📄 [RecursiveBinarySearch](src/main/java/com/thealgorithms/searches/RecursiveBinarySearch.java)
+ - 📄 [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)
+ - 📄 [UnionFind](src/main/java/com/thealgorithms/searches/UnionFind.java)
+ - 📄 [UpperBound](src/main/java/com/thealgorithms/searches/UpperBound.java)
+ - 📁 **slidingwindow**
+ - 📄 [LongestSubarrayWithSumLessOrEqualToK](src/main/java/com/thealgorithms/slidingwindow/LongestSubarrayWithSumLessOrEqualToK.java)
+ - 📄 [LongestSubstringWithoutRepeatingCharacters](src/main/java/com/thealgorithms/slidingwindow/LongestSubstringWithoutRepeatingCharacters.java)
+ - 📄 [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)
+ - 📄 [BeadSort](src/main/java/com/thealgorithms/sorts/BeadSort.java)
+ - 📄 [BinaryInsertionSort](src/main/java/com/thealgorithms/sorts/BinaryInsertionSort.java)
+ - 📄 [BitonicSort](src/main/java/com/thealgorithms/sorts/BitonicSort.java)
+ - 📄 [BogoSort](src/main/java/com/thealgorithms/sorts/BogoSort.java)
+ - 📄 [BubbleSort](src/main/java/com/thealgorithms/sorts/BubbleSort.java)
+ - 📄 [BubbleSortRecursive](src/main/java/com/thealgorithms/sorts/BubbleSortRecursive.java)
+ - 📄 [BucketSort](src/main/java/com/thealgorithms/sorts/BucketSort.java)
+ - 📄 [CircleSort](src/main/java/com/thealgorithms/sorts/CircleSort.java)
+ - 📄 [CocktailShakerSort](src/main/java/com/thealgorithms/sorts/CocktailShakerSort.java)
+ - 📄 [CombSort](src/main/java/com/thealgorithms/sorts/CombSort.java)
+ - 📄 [CountingSort](src/main/java/com/thealgorithms/sorts/CountingSort.java)
+ - 📄 [CycleSort](src/main/java/com/thealgorithms/sorts/CycleSort.java)
+ - 📄 [DarkSort](src/main/java/com/thealgorithms/sorts/DarkSort.java)
+ - 📄 [DualPivotQuickSort](src/main/java/com/thealgorithms/sorts/DualPivotQuickSort.java)
+ - 📄 [DutchNationalFlagSort](src/main/java/com/thealgorithms/sorts/DutchNationalFlagSort.java)
+ - 📄 [ExchangeSort](src/main/java/com/thealgorithms/sorts/ExchangeSort.java)
+ - 📄 [FlashSort](src/main/java/com/thealgorithms/sorts/FlashSort.java)
+ - 📄 [GnomeSort](src/main/java/com/thealgorithms/sorts/GnomeSort.java)
+ - 📄 [HeapSort](src/main/java/com/thealgorithms/sorts/HeapSort.java)
+ - 📄 [InsertionSort](src/main/java/com/thealgorithms/sorts/InsertionSort.java)
+ - 📄 [IntrospectiveSort](src/main/java/com/thealgorithms/sorts/IntrospectiveSort.java)
+ - 📄 [LinkListSort](src/main/java/com/thealgorithms/sorts/LinkListSort.java)
+ - 📄 [MergeSort](src/main/java/com/thealgorithms/sorts/MergeSort.java)
+ - 📄 [MergeSortNoExtraSpace](src/main/java/com/thealgorithms/sorts/MergeSortNoExtraSpace.java)
+ - 📄 [MergeSortRecursive](src/main/java/com/thealgorithms/sorts/MergeSortRecursive.java)
+ - 📄 [OddEvenSort](src/main/java/com/thealgorithms/sorts/OddEvenSort.java)
+ - 📄 [PancakeSort](src/main/java/com/thealgorithms/sorts/PancakeSort.java)
+ - 📄 [PatienceSort](src/main/java/com/thealgorithms/sorts/PatienceSort.java)
+ - 📄 [PigeonholeSort](src/main/java/com/thealgorithms/sorts/PigeonholeSort.java)
+ - 📄 [PriorityQueueSort](src/main/java/com/thealgorithms/sorts/PriorityQueueSort.java)
+ - 📄 [QuickSort](src/main/java/com/thealgorithms/sorts/QuickSort.java)
+ - 📄 [RadixSort](src/main/java/com/thealgorithms/sorts/RadixSort.java)
+ - 📄 [SelectionSort](src/main/java/com/thealgorithms/sorts/SelectionSort.java)
+ - 📄 [SelectionSortRecursive](src/main/java/com/thealgorithms/sorts/SelectionSortRecursive.java)
+ - 📄 [ShellSort](src/main/java/com/thealgorithms/sorts/ShellSort.java)
+ - 📄 [SlowSort](src/main/java/com/thealgorithms/sorts/SlowSort.java)
+ - 📄 [SortAlgorithm](src/main/java/com/thealgorithms/sorts/SortAlgorithm.java)
+ - 📄 [SortUtils](src/main/java/com/thealgorithms/sorts/SortUtils.java)
+ - 📄 [SortUtilsRandomGenerator](src/main/java/com/thealgorithms/sorts/SortUtilsRandomGenerator.java)
+ - 📄 [SpreadSort](src/main/java/com/thealgorithms/sorts/SpreadSort.java)
+ - 📄 [StalinSort](src/main/java/com/thealgorithms/sorts/StalinSort.java)
+ - 📄 [StoogeSort](src/main/java/com/thealgorithms/sorts/StoogeSort.java)
+ - 📄 [StrandSort](src/main/java/com/thealgorithms/sorts/StrandSort.java)
+ - 📄 [SwapSort](src/main/java/com/thealgorithms/sorts/SwapSort.java)
+ - 📄 [TimSort](src/main/java/com/thealgorithms/sorts/TimSort.java)
+ - 📄 [TopologicalSort](src/main/java/com/thealgorithms/sorts/TopologicalSort.java)
+ - 📄 [TreeSort](src/main/java/com/thealgorithms/sorts/TreeSort.java)
+ - 📄 [WaveSort](src/main/java/com/thealgorithms/sorts/WaveSort.java)
+ - 📄 [WiggleSort](src/main/java/com/thealgorithms/sorts/WiggleSort.java)
+ - 📁 **stacks**
+ - 📄 [BalancedBrackets](src/main/java/com/thealgorithms/stacks/BalancedBrackets.java)
+ - 📄 [CelebrityFinder](src/main/java/com/thealgorithms/stacks/CelebrityFinder.java)
+ - 📄 [DecimalToAnyUsingStack](src/main/java/com/thealgorithms/stacks/DecimalToAnyUsingStack.java)
+ - 📄 [DuplicateBrackets](src/main/java/com/thealgorithms/stacks/DuplicateBrackets.java)
+ - 📄 [GreatestElementConstantTime](src/main/java/com/thealgorithms/stacks/GreatestElementConstantTime.java)
+ - 📄 [InfixToPostfix](src/main/java/com/thealgorithms/stacks/InfixToPostfix.java)
+ - 📄 [InfixToPrefix](src/main/java/com/thealgorithms/stacks/InfixToPrefix.java)
+ - 📄 [LargestRectangle](src/main/java/com/thealgorithms/stacks/LargestRectangle.java)
+ - 📄 [MaximumMinimumWindow](src/main/java/com/thealgorithms/stacks/MaximumMinimumWindow.java)
+ - 📄 [MinStackUsingSingleStack](src/main/java/com/thealgorithms/stacks/MinStackUsingSingleStack.java)
+ - 📄 [MinStackUsingTwoStacks](src/main/java/com/thealgorithms/stacks/MinStackUsingTwoStacks.java)
+ - 📄 [NextGreaterElement](src/main/java/com/thealgorithms/stacks/NextGreaterElement.java)
+ - 📄 [NextSmallerElement](src/main/java/com/thealgorithms/stacks/NextSmallerElement.java)
+ - 📄 [PalindromeWithStack](src/main/java/com/thealgorithms/stacks/PalindromeWithStack.java)
+ - 📄 [PostfixEvaluator](src/main/java/com/thealgorithms/stacks/PostfixEvaluator.java)
+ - 📄 [PostfixToInfix](src/main/java/com/thealgorithms/stacks/PostfixToInfix.java)
+ - 📄 [PrefixEvaluator](src/main/java/com/thealgorithms/stacks/PrefixEvaluator.java)
+ - 📄 [PrefixToInfix](src/main/java/com/thealgorithms/stacks/PrefixToInfix.java)
+ - 📄 [SmallestElementConstantTime](src/main/java/com/thealgorithms/stacks/SmallestElementConstantTime.java)
+ - 📄 [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)
+ - 📁 **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)
+ - 📄 [CountChar](src/main/java/com/thealgorithms/strings/CountChar.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [LongestPalindromicSubstring](src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java)
+ - 📄 [Lower](src/main/java/com/thealgorithms/strings/Lower.java)
+ - 📄 [Manacher](src/main/java/com/thealgorithms/strings/Manacher.java)
+ - 📄 [MyAtoi](src/main/java/com/thealgorithms/strings/MyAtoi.java)
+ - 📄 [Palindrome](src/main/java/com/thealgorithms/strings/Palindrome.java)
+ - 📄 [Pangram](src/main/java/com/thealgorithms/strings/Pangram.java)
+ - 📄 [PermuteString](src/main/java/com/thealgorithms/strings/PermuteString.java)
+ - 📄 [RabinKarp](src/main/java/com/thealgorithms/strings/RabinKarp.java)
+ - 📄 [RemoveDuplicateFromString](src/main/java/com/thealgorithms/strings/RemoveDuplicateFromString.java)
+ - 📄 [ReturnSubsequence](src/main/java/com/thealgorithms/strings/ReturnSubsequence.java)
+ - 📄 [ReverseString](src/main/java/com/thealgorithms/strings/ReverseString.java)
+ - 📄 [ReverseWordsInString](src/main/java/com/thealgorithms/strings/ReverseWordsInString.java)
+ - 📄 [Rotation](src/main/java/com/thealgorithms/strings/Rotation.java)
+ - 📄 [StringCompression](src/main/java/com/thealgorithms/strings/StringCompression.java)
+ - 📄 [StringMatchFiniteAutomata](src/main/java/com/thealgorithms/strings/StringMatchFiniteAutomata.java)
+ - 📄 [SuffixArray](src/main/java/com/thealgorithms/strings/SuffixArray.java)
+ - 📄 [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)
+ - 📁 **zigZagPattern**
+ - 📄 [ZigZagPattern](src/main/java/com/thealgorithms/strings/zigZagPattern/ZigZagPattern.java)
+ - 📁 **tree**
+ - 📄 [HeavyLightDecomposition](src/main/java/com/thealgorithms/tree/HeavyLightDecomposition.java)
+- 📁 **test**
+ - 📁 **java**
+ - 📁 **com**
+ - 📁 **thealgorithms**
+ - 📁 **audiofilters**
+ - 📄 [EMAFilterTest](src/test/java/com/thealgorithms/audiofilters/EMAFilterTest.java)
+ - 📄 [IIRFilterTest](src/test/java/com/thealgorithms/audiofilters/IIRFilterTest.java)
+ - 📁 **backtracking**
+ - 📄 [AllPathsFromSourceToTargetTest](src/test/java/com/thealgorithms/backtracking/AllPathsFromSourceToTargetTest.java)
+ - 📄 [ArrayCombinationTest](src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.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)
+ - 📄 [KnightsTourTest](src/test/java/com/thealgorithms/backtracking/KnightsTourTest.java)
+ - 📄 [MColoringTest](src/test/java/com/thealgorithms/backtracking/MColoringTest.java)
+ - 📄 [MazeRecursionTest](src/test/java/com/thealgorithms/backtracking/MazeRecursionTest.java)
+ - 📄 [NQueensTest](src/test/java/com/thealgorithms/backtracking/NQueensTest.java)
+ - 📄 [ParenthesesGeneratorTest](src/test/java/com/thealgorithms/backtracking/ParenthesesGeneratorTest.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [FirstDifferentBitTest](src/test/java/com/thealgorithms/bitmanipulation/FirstDifferentBitTest.java)
+ - 📄 [GenerateSubsetsTest](src/test/java/com/thealgorithms/bitmanipulation/GenerateSubsetsTest.java)
+ - 📄 [GrayCodeConversionTest](src/test/java/com/thealgorithms/bitmanipulation/GrayCodeConversionTest.java)
+ - 📄 [HammingDistanceTest](src/test/java/com/thealgorithms/bitmanipulation/HammingDistanceTest.java)
+ - 📄 [HigherLowerPowerOfTwoTest](src/test/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwoTest.java)
+ - 📄 [HighestSetBitTest](src/test/java/com/thealgorithms/bitmanipulation/HighestSetBitTest.java)
+ - 📄 [IndexOfRightMostSetBitTest](src/test/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBitTest.java)
+ - 📄 [IsEvenTest](src/test/java/com/thealgorithms/bitmanipulation/IsEvenTest.java)
+ - 📄 [IsPowerTwoTest](src/test/java/com/thealgorithms/bitmanipulation/IsPowerTwoTest.java)
+ - 📄 [LowestSetBitTest](src/test/java/com/thealgorithms/bitmanipulation/LowestSetBitTest.java)
+ - 📄 [ModuloPowerOfTwoTest](src/test/java/com/thealgorithms/bitmanipulation/ModuloPowerOfTwoTest.java)
+ - 📄 [NextHigherSameBitCountTest](src/test/java/com/thealgorithms/bitmanipulation/NextHigherSameBitCountTest.java)
+ - 📄 [NonRepeatingNumberFinderTest](src/test/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinderTest.java)
+ - 📄 [NumberAppearingOddTimesTest](src/test/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimesTest.java)
+ - 📄 [NumbersDifferentSignsTest](src/test/java/com/thealgorithms/bitmanipulation/NumbersDifferentSignsTest.java)
+ - 📄 [OneBitDifferenceTest](src/test/java/com/thealgorithms/bitmanipulation/OneBitDifferenceTest.java)
+ - 📄 [OnesComplementTest](src/test/java/com/thealgorithms/bitmanipulation/OnesComplementTest.java)
+ - 📄 [ParityCheckTest](src/test/java/com/thealgorithms/bitmanipulation/ParityCheckTest.java)
+ - 📄 [ReverseBitsTest](src/test/java/com/thealgorithms/bitmanipulation/ReverseBitsTest.java)
+ - 📄 [SingleBitOperationsTest](src/test/java/com/thealgorithms/bitmanipulation/SingleBitOperationsTest.java)
+ - 📄 [SingleElementTest](src/test/java/com/thealgorithms/bitmanipulation/SingleElementTest.java)
+ - 📄 [SwapAdjacentBitsTest](src/test/java/com/thealgorithms/bitmanipulation/SwapAdjacentBitsTest.java)
+ - 📄 [TwosComplementTest](src/test/java/com/thealgorithms/bitmanipulation/TwosComplementTest.java)
+ - 📄 [Xs3ConversionTest](src/test/java/com/thealgorithms/bitmanipulation/Xs3ConversionTest.java)
+ - 📁 **ciphers**
+ - 📄 [ADFGVXCipherTest](src/test/java/com/thealgorithms/ciphers/ADFGVXCipherTest.java)
+ - 📄 [AESEncryptionTest](src/test/java/com/thealgorithms/ciphers/AESEncryptionTest.java)
+ - 📄 [AffineCipherTest](src/test/java/com/thealgorithms/ciphers/AffineCipherTest.java)
+ - 📄 [AtbashTest](src/test/java/com/thealgorithms/ciphers/AtbashTest.java)
+ - 📄 [AutokeyTest](src/test/java/com/thealgorithms/ciphers/AutokeyTest.java)
+ - 📄 [BaconianCipherTest](src/test/java/com/thealgorithms/ciphers/BaconianCipherTest.java)
+ - 📄 [BlowfishTest](src/test/java/com/thealgorithms/ciphers/BlowfishTest.java)
+ - 📄 [CaesarTest](src/test/java/com/thealgorithms/ciphers/CaesarTest.java)
+ - 📄 [ColumnarTranspositionCipherTest](src/test/java/com/thealgorithms/ciphers/ColumnarTranspositionCipherTest.java)
+ - 📄 [DESTest](src/test/java/com/thealgorithms/ciphers/DESTest.java)
+ - 📄 [DiffieHellmanTest](src/test/java/com/thealgorithms/ciphers/DiffieHellmanTest.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [RailFenceTest](src/test/java/com/thealgorithms/ciphers/RailFenceTest.java)
+ - 📄 [SimpleSubCipherTest](src/test/java/com/thealgorithms/ciphers/SimpleSubCipherTest.java)
+ - 📄 [VigenereTest](src/test/java/com/thealgorithms/ciphers/VigenereTest.java)
+ - 📄 [XORCipherTest](src/test/java/com/thealgorithms/ciphers/XORCipherTest.java)
+ - 📁 **a5**
+ - 📄 [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**
+ - 📄 [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)
+ - 📄 [AnytoAnyTest](src/test/java/com/thealgorithms/conversions/AnytoAnyTest.java)
+ - 📄 [Base64Test](src/test/java/com/thealgorithms/conversions/Base64Test.java)
+ - 📄 [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)
+ - 📄 [DecimalToOctalTest](src/test/java/com/thealgorithms/conversions/DecimalToOctalTest.java)
+ - 📄 [EndianConverterTest](src/test/java/com/thealgorithms/conversions/EndianConverterTest.java)
+ - 📄 [HexToOctTest](src/test/java/com/thealgorithms/conversions/HexToOctTest.java)
+ - 📄 [HexaDecimalToBinaryTest](src/test/java/com/thealgorithms/conversions/HexaDecimalToBinaryTest.java)
+ - 📄 [HexaDecimalToDecimalTest](src/test/java/com/thealgorithms/conversions/HexaDecimalToDecimalTest.java)
+ - 📄 [IPConverterTest](src/test/java/com/thealgorithms/conversions/IPConverterTest.java)
+ - 📄 [IPv6ConverterTest](src/test/java/com/thealgorithms/conversions/IPv6ConverterTest.java)
+ - 📄 [IntegerToEnglishTest](src/test/java/com/thealgorithms/conversions/IntegerToEnglishTest.java)
+ - 📄 [IntegerToRomanTest](src/test/java/com/thealgorithms/conversions/IntegerToRomanTest.java)
+ - 📄 [MorseCodeConverterTest](src/test/java/com/thealgorithms/conversions/MorseCodeConverterTest.java)
+ - 📄 [NumberToWordsTest](src/test/java/com/thealgorithms/conversions/NumberToWordsTest.java)
+ - 📄 [OctalToBinaryTest](src/test/java/com/thealgorithms/conversions/OctalToBinaryTest.java)
+ - 📄 [OctalToDecimalTest](src/test/java/com/thealgorithms/conversions/OctalToDecimalTest.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [WordsToNumberTest](src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java)
+ - 📁 **datastructures**
+ - 📁 **bag**
+ - 📄 [BagTest](src/test/java/com/thealgorithms/datastructures/bag/BagTest.java)
+ - 📁 **bloomfilter**
+ - 📄 [BloomFilterTest](src/test/java/com/thealgorithms/datastructures/bloomfilter/BloomFilterTest.java)
+ - 📁 **buffers**
+ - 📄 [CircularBufferTest](src/test/java/com/thealgorithms/datastructures/buffers/CircularBufferTest.java)
+ - 📁 **caches**
+ - 📄 [FIFOCacheTest](src/test/java/com/thealgorithms/datastructures/caches/FIFOCacheTest.java)
+ - 📄 [LFUCacheTest](src/test/java/com/thealgorithms/datastructures/caches/LFUCacheTest.java)
+ - 📄 [LIFOCacheTest](src/test/java/com/thealgorithms/datastructures/caches/LIFOCacheTest.java)
+ - 📄 [LRUCacheTest](src/test/java/com/thealgorithms/datastructures/caches/LRUCacheTest.java)
+ - 📄 [MRUCacheTest](src/test/java/com/thealgorithms/datastructures/caches/MRUCacheTest.java)
+ - 📄 [RRCacheTest](src/test/java/com/thealgorithms/datastructures/caches/RRCacheTest.java)
+ - 📁 **crdt**
+ - 📄 [GCounterTest](src/test/java/com/thealgorithms/datastructures/crdt/GCounterTest.java)
+ - 📄 [GSetTest](src/test/java/com/thealgorithms/datastructures/crdt/GSetTest.java)
+ - 📄 [LWWElementSetTest](src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java)
+ - 📄 [ORSetTest](src/test/java/com/thealgorithms/datastructures/crdt/ORSetTest.java)
+ - 📄 [PNCounterTest](src/test/java/com/thealgorithms/datastructures/crdt/PNCounterTest.java)
+ - 📄 [TwoPSetTest](src/test/java/com/thealgorithms/datastructures/crdt/TwoPSetTest.java)
+ - 📁 **disjointsetunion**
+ - 📄 [DisjointSetUnionBySizeTest](src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionBySizeTest.java)
+ - 📄 [DisjointSetUnionTest](src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionTest.java)
+ - 📁 **dynamicarray**
+ - 📄 [DynamicArrayTest](src/test/java/com/thealgorithms/datastructures/dynamicarray/DynamicArrayTest.java)
+ - 📁 **graphs**
+ - 📄 [AStarTest](src/test/java/com/thealgorithms/datastructures/graphs/AStarTest.java)
+ - 📄 [BipartiteGraphDFSTest](src/test/java/com/thealgorithms/datastructures/graphs/BipartiteGraphDFSTest.java)
+ - 📄 [BoruvkaAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/BoruvkaAlgorithmTest.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)
+ - 📄 [FloydWarshallTest](src/test/java/com/thealgorithms/datastructures/graphs/FloydWarshallTest.java)
+ - 📄 [FordFulkersonTest](src/test/java/com/thealgorithms/datastructures/graphs/FordFulkersonTest.java)
+ - 📄 [HamiltonianCycleTest](src/test/java/com/thealgorithms/datastructures/graphs/HamiltonianCycleTest.java)
+ - 📄 [JohnsonsAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithmTest.java)
+ - 📄 [KahnsAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithmTest.java)
+ - 📄 [KosarajuTest](src/test/java/com/thealgorithms/datastructures/graphs/KosarajuTest.java)
+ - 📄 [KruskalTest](src/test/java/com/thealgorithms/datastructures/graphs/KruskalTest.java)
+ - 📄 [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**
+ - 📄 [GenericHashMapUsingArrayListTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayListTest.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [MapTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/MapTest.java)
+ - 📁 **heaps**
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [MedianFinderTest](src/test/java/com/thealgorithms/datastructures/heaps/MedianFinderTest.java)
+ - 📄 [MergeKSortedArraysTest](src/test/java/com/thealgorithms/datastructures/heaps/MergeKSortedArraysTest.java)
+ - 📄 [MinHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/MinHeapTest.java)
+ - 📄 [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)
+ - 📄 [QuickSortLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/QuickSortLinkedListTest.java)
+ - 📄 [ReverseKGroupTest](src/test/java/com/thealgorithms/datastructures/lists/ReverseKGroupTest.java)
+ - 📄 [RotateSinglyLinkedListsTest](src/test/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedListsTest.java)
+ - 📄 [SearchSinglyLinkedListRecursionTest](src/test/java/com/thealgorithms/datastructures/lists/SearchSinglyLinkedListRecursionTest.java)
+ - 📄 [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)
+ - 📄 [GenericArrayListQueueTest](src/test/java/com/thealgorithms/datastructures/queues/GenericArrayListQueueTest.java)
+ - 📄 [LinkedQueueTest](src/test/java/com/thealgorithms/datastructures/queues/LinkedQueueTest.java)
+ - 📄 [PriorityQueuesTest](src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java)
+ - 📄 [QueueByTwoStacksTest](src/test/java/com/thealgorithms/datastructures/queues/QueueByTwoStacksTest.java)
+ - 📄 [QueueTest](src/test/java/com/thealgorithms/datastructures/queues/QueueTest.java)
+ - 📄 [SlidingWindowMaximumTest](src/test/java/com/thealgorithms/datastructures/queues/SlidingWindowMaximumTest.java)
+ - 📄 [TokenBucketTest](src/test/java/com/thealgorithms/datastructures/queues/TokenBucketTest.java)
+ - 📁 **stacks**
+ - 📄 [NodeStackTest](src/test/java/com/thealgorithms/datastructures/stacks/NodeStackTest.java)
+ - 📄 [ReverseStackTest](src/test/java/com/thealgorithms/datastructures/stacks/ReverseStackTest.java)
+ - 📄 [StackArrayListTest](src/test/java/com/thealgorithms/datastructures/stacks/StackArrayListTest.java)
+ - 📄 [StackArrayTest](src/test/java/com/thealgorithms/datastructures/stacks/StackArrayTest.java)
+ - 📄 [StackOfLinkedListTest](src/test/java/com/thealgorithms/datastructures/stacks/StackOfLinkedListTest.java)
+ - 📁 **trees**
+ - 📄 [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)
+ - 📄 [BoundaryTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java)
+ - 📄 [CeilInBinarySearchTreeTest](src/test/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTreeTest.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)
+ - 📄 [CreateBinaryTreeFromInorderPreorderTest](src/test/java/com/thealgorithms/datastructures/trees/CreateBinaryTreeFromInorderPreorderTest.java)
+ - 📄 [InorderTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/InorderTraversalTest.java)
+ - 📄 [KDTreeTest](src/test/java/com/thealgorithms/datastructures/trees/KDTreeTest.java)
+ - 📄 [LazySegmentTreeTest](src/test/java/com/thealgorithms/datastructures/trees/LazySegmentTreeTest.java)
+ - 📄 [LevelOrderTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/LevelOrderTraversalTest.java)
+ - 📄 [PostOrderTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/PostOrderTraversalTest.java)
+ - 📄 [PreOrderTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/PreOrderTraversalTest.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [CountingInversionsTest](src/test/java/com/thealgorithms/divideandconquer/CountingInversionsTest.java)
+ - 📄 [MedianOfTwoSortedArraysTest](src/test/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArraysTest.java)
+ - 📄 [SkylineAlgorithmTest](src/test/java/com/thealgorithms/divideandconquer/SkylineAlgorithmTest.java)
+ - 📄 [StrassenMatrixMultiplicationTest](src/test/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplicationTest.java)
+ - 📄 [TilingProblemTest](src/test/java/com/thealgorithms/divideandconquer/TilingProblemTest.java)
+ - 📁 **dynamicprogramming**
+ - 📄 [AbbreviationTest](src/test/java/com/thealgorithms/dynamicprogramming/AbbreviationTest.java)
+ - 📄 [AllConstructTest](src/test/java/com/thealgorithms/dynamicprogramming/AllConstructTest.java)
+ - 📄 [AssignmentUsingBitmaskTest](src/test/java/com/thealgorithms/dynamicprogramming/AssignmentUsingBitmaskTest.java)
+ - 📄 [BoardPathTest](src/test/java/com/thealgorithms/dynamicprogramming/BoardPathTest.java)
+ - 📄 [BoundaryFillTest](src/test/java/com/thealgorithms/dynamicprogramming/BoundaryFillTest.java)
+ - 📄 [BruteForceKnapsackTest](src/test/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsackTest.java)
+ - 📄 [CatalanNumberTest](src/test/java/com/thealgorithms/dynamicprogramming/CatalanNumberTest.java)
+ - 📄 [ClimbStairsTest](src/test/java/com/thealgorithms/dynamicprogramming/ClimbStairsTest.java)
+ - 📄 [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)
+ - 📄 [KadaneAlgorithmTest](src/test/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithmTest.java)
+ - 📄 [KnapsackMemoizationTest](src/test/java/com/thealgorithms/dynamicprogramming/KnapsackMemoizationTest.java)
+ - 📄 [KnapsackTest](src/test/java/com/thealgorithms/dynamicprogramming/KnapsackTest.java)
+ - 📄 [KnapsackZeroOneTabulationTest](src/test/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTabulationTest.java)
+ - 📄 [KnapsackZeroOneTest](src/test/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTest.java)
+ - 📄 [LevenshteinDistanceTests](src/test/java/com/thealgorithms/dynamicprogramming/LevenshteinDistanceTests.java)
+ - 📄 [LongestAlternatingSubsequenceTest](src/test/java/com/thealgorithms/dynamicprogramming/LongestAlternatingSubsequenceTest.java)
+ - 📄 [LongestArithmeticSubsequenceTest](src/test/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequenceTest.java)
+ - 📄 [LongestCommonSubsequenceTest](src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java)
+ - 📄 [LongestIncreasingSubsequenceNLogNTest](src/test/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceNLogNTest.java)
+ - 📄 [LongestIncreasingSubsequenceTests](src/test/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceTests.java)
+ - 📄 [LongestPalindromicSubstringTest](src/test/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstringTest.java)
+ - 📄 [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)
+ - 📄 [PartitionProblemTest](src/test/java/com/thealgorithms/dynamicprogramming/PartitionProblemTest.java)
+ - 📄 [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)
+ - 📄 [SumOfSubsetTest](src/test/java/com/thealgorithms/dynamicprogramming/SumOfSubsetTest.java)
+ - 📄 [TreeMatchingTest](src/test/java/com/thealgorithms/dynamicprogramming/TreeMatchingTest.java)
+ - 📄 [TribonacciTest](src/test/java/com/thealgorithms/dynamicprogramming/TribonacciTest.java)
+ - 📄 [UniquePathsTests](src/test/java/com/thealgorithms/dynamicprogramming/UniquePathsTests.java)
+ - 📄 [UniqueSubsequencesCountTest](src/test/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCountTest.java)
+ - 📄 [WildcardMatchingTest](src/test/java/com/thealgorithms/dynamicprogramming/WildcardMatchingTest.java)
+ - 📄 [WineProblemTest](src/test/java/com/thealgorithms/dynamicprogramming/WineProblemTest.java)
+ - 📁 **geometry**
+ - 📄 [BresenhamLineTest](src/test/java/com/thealgorithms/geometry/BresenhamLineTest.java)
+ - 📄 [ConvexHullTest](src/test/java/com/thealgorithms/geometry/ConvexHullTest.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)
+ - 📄 [HopcroftKarpTest](src/test/java/com/thealgorithms/graph/HopcroftKarpTest.java)
+ - 📄 [PredecessorConstrainedDfsTest](src/test/java/com/thealgorithms/graph/PredecessorConstrainedDfsTest.java)
+ - 📄 [PushRelabelTest](src/test/java/com/thealgorithms/graph/PushRelabelTest.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)
+ - 📄 [BinaryAdditionTest](src/test/java/com/thealgorithms/greedyalgorithms/BinaryAdditionTest.java)
+ - 📄 [CoinChangeTest](src/test/java/com/thealgorithms/greedyalgorithms/CoinChangeTest.java)
+ - 📄 [DigitSeparationTest](src/test/java/com/thealgorithms/greedyalgorithms/DigitSeparationTest.java)
+ - 📄 [EgyptianFractionTest](src/test/java/com/thealgorithms/greedyalgorithms/EgyptianFractionTest.java)
+ - 📄 [FractionalKnapsackTest](src/test/java/com/thealgorithms/greedyalgorithms/FractionalKnapsackTest.java)
+ - 📄 [GaleShapleyTest](src/test/java/com/thealgorithms/greedyalgorithms/GaleShapleyTest.java)
+ - 📄 [JobSequencingTest](src/test/java/com/thealgorithms/greedyalgorithms/JobSequencingTest.java)
+ - 📄 [KCentersTest](src/test/java/com/thealgorithms/greedyalgorithms/KCentersTest.java)
+ - 📄 [MergeIntervalsTest](src/test/java/com/thealgorithms/greedyalgorithms/MergeIntervalsTest.java)
+ - 📄 [MinimizingLatenessTest](src/test/java/com/thealgorithms/greedyalgorithms/MinimizingLatenessTest.java)
+ - 📄 [MinimumWaitingTimeTest](src/test/java/com/thealgorithms/greedyalgorithms/MinimumWaitingTimeTest.java)
+ - 📄 [OptimalFileMergingTest](src/test/java/com/thealgorithms/greedyalgorithms/OptimalFileMergingTest.java)
+ - 📄 [StockProfitCalculatorTest](src/test/java/com/thealgorithms/greedyalgorithms/StockProfitCalculatorTest.java)
+ - 📁 **io**
+ - 📄 [BufferedReaderTest](src/test/java/com/thealgorithms/io/BufferedReaderTest.java)
+ - 📁 **lineclipping**
+ - 📄 [CohenSutherlandTest](src/test/java/com/thealgorithms/lineclipping/CohenSutherlandTest.java)
+ - 📄 [LiangBarskyTest](src/test/java/com/thealgorithms/lineclipping/LiangBarskyTest.java)
+ - 📁 **maths**
+ - 📄 [ADTFractionTest](src/test/java/com/thealgorithms/maths/ADTFractionTest.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [ArmstrongTest](src/test/java/com/thealgorithms/maths/ArmstrongTest.java)
+ - 📄 [AutoCorrelationTest](src/test/java/com/thealgorithms/maths/AutoCorrelationTest.java)
+ - 📄 [AutomorphicNumberTest](src/test/java/com/thealgorithms/maths/AutomorphicNumberTest.java)
+ - 📄 [AverageTest](src/test/java/com/thealgorithms/maths/AverageTest.java)
+ - 📄 [BinaryPowTest](src/test/java/com/thealgorithms/maths/BinaryPowTest.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [ConvolutionFFTTest](src/test/java/com/thealgorithms/maths/ConvolutionFFTTest.java)
+ - 📄 [ConvolutionTest](src/test/java/com/thealgorithms/maths/ConvolutionTest.java)
+ - 📄 [CrossCorrelationTest](src/test/java/com/thealgorithms/maths/CrossCorrelationTest.java)
+ - 📄 [DeterminantOfMatrixTest](src/test/java/com/thealgorithms/maths/DeterminantOfMatrixTest.java)
+ - 📄 [DigitalRootTest](src/test/java/com/thealgorithms/maths/DigitalRootTest.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [FibonacciJavaStreamsTest](src/test/java/com/thealgorithms/maths/FibonacciJavaStreamsTest.java)
+ - 📄 [FibonacciLoopTest](src/test/java/com/thealgorithms/maths/FibonacciLoopTest.java)
+ - 📄 [FibonacciNumberCheckTest](src/test/java/com/thealgorithms/maths/FibonacciNumberCheckTest.java)
+ - 📄 [FibonacciNumberGoldenRationTest](src/test/java/com/thealgorithms/maths/FibonacciNumberGoldenRationTest.java)
+ - 📄 [FindKthNumberTest](src/test/java/com/thealgorithms/maths/FindKthNumberTest.java)
+ - 📄 [FindMaxRecursionTest](src/test/java/com/thealgorithms/maths/FindMaxRecursionTest.java)
+ - 📄 [FindMaxTest](src/test/java/com/thealgorithms/maths/FindMaxTest.java)
+ - 📄 [FindMinRecursionTest](src/test/java/com/thealgorithms/maths/FindMinRecursionTest.java)
+ - 📄 [FindMinTest](src/test/java/com/thealgorithms/maths/FindMinTest.java)
+ - 📄 [FloorTest](src/test/java/com/thealgorithms/maths/FloorTest.java)
+ - 📄 [FrizzyNumberTest](src/test/java/com/thealgorithms/maths/FrizzyNumberTest.java)
+ - 📄 [GCDRecursionTest](src/test/java/com/thealgorithms/maths/GCDRecursionTest.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [PerfectCubeTest](src/test/java/com/thealgorithms/maths/PerfectCubeTest.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [PythagoreanTripleTest](src/test/java/com/thealgorithms/maths/PythagoreanTripleTest.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [SquareRootwithBabylonianMethodTest](src/test/java/com/thealgorithms/maths/SquareRootwithBabylonianMethodTest.java)
+ - 📄 [StandardDeviationTest](src/test/java/com/thealgorithms/maths/StandardDeviationTest.java)
+ - 📄 [StandardScoreTest](src/test/java/com/thealgorithms/maths/StandardScoreTest.java)
+ - 📄 [StrobogrammaticNumberTest](src/test/java/com/thealgorithms/maths/StrobogrammaticNumberTest.java)
+ - 📄 [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)
+ - 📄 [MobiusFunctionTest](src/test/java/com/thealgorithms/maths/prime/MobiusFunctionTest.java)
+ - 📄 [PrimeCheckTest](src/test/java/com/thealgorithms/maths/prime/PrimeCheckTest.java)
+ - 📄 [PrimeFactorizationTest](src/test/java/com/thealgorithms/maths/prime/PrimeFactorizationTest.java)
+ - 📁 **matrix**
+ - 📄 [InverseOfMatrixTest](src/test/java/com/thealgorithms/matrix/InverseOfMatrixTest.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)
+ - 📄 [SolveSystemTest](src/test/java/com/thealgorithms/matrix/SolveSystemTest.java)
+ - 📄 [TestPrintMatrixInSpiralOrder](src/test/java/com/thealgorithms/matrix/TestPrintMatrixInSpiralOrder.java)
+ - 📁 **misc**
+ - 📄 [ColorContrastRatioTest](src/test/java/com/thealgorithms/misc/ColorContrastRatioTest.java)
+ - 📄 [MapReduceTest](src/test/java/com/thealgorithms/misc/MapReduceTest.java)
+ - 📄 [MedianOfRunningArrayTest](src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java)
+ - 📄 [PalindromePrimeTest](src/test/java/com/thealgorithms/misc/PalindromePrimeTest.java)
+ - 📄 [PalindromeSinglyLinkedListTest](src/test/java/com/thealgorithms/misc/PalindromeSinglyLinkedListTest.java)
+ - 📄 [RangeInSortedArrayTest](src/test/java/com/thealgorithms/misc/RangeInSortedArrayTest.java)
+ - 📄 [ShuffleArrayTest](src/test/java/com/thealgorithms/misc/ShuffleArrayTest.java)
+ - 📄 [SparsityTest](src/test/java/com/thealgorithms/misc/SparsityTest.java)
+ - 📄 [ThreeSumProblemTest](src/test/java/com/thealgorithms/misc/ThreeSumProblemTest.java)
+ - 📄 [TwoSumProblemTest](src/test/java/com/thealgorithms/misc/TwoSumProblemTest.java)
+ - 📁 **others**
+ - 📄 [ArrayLeftRotationTest](src/test/java/com/thealgorithms/others/ArrayLeftRotationTest.java)
+ - 📄 [ArrayRightRotationTest](src/test/java/com/thealgorithms/others/ArrayRightRotationTest.java)
+ - 📄 [BFPRTTest](src/test/java/com/thealgorithms/others/BFPRTTest.java)
+ - 📄 [BestFitCPUTest](src/test/java/com/thealgorithms/others/BestFitCPUTest.java)
+ - 📄 [BoyerMooreTest](src/test/java/com/thealgorithms/others/BoyerMooreTest.java)
+ - 📄 [CRC16Test](src/test/java/com/thealgorithms/others/CRC16Test.java)
+ - 📄 [CRCAlgorithmTest](src/test/java/com/thealgorithms/others/CRCAlgorithmTest.java)
+ - 📄 [ConwayTest](src/test/java/com/thealgorithms/others/ConwayTest.java)
+ - 📄 [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**
+ - 📄 [GroundToGroundProjectileMotionTest](src/test/java/com/thealgorithms/physics/GroundToGroundProjectileMotionTest.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**
+ - 📄 [KargerMinCutTest](src/test/java/com/thealgorithms/randomized/KargerMinCutTest.java)
+ - 📄 [MonteCarloIntegrationTest](src/test/java/com/thealgorithms/randomized/MonteCarloIntegrationTest.java)
+ - 📄 [RandomizedClosestPairTest](src/test/java/com/thealgorithms/randomized/RandomizedClosestPairTest.java)
+ - 📄 [RandomizedMatrixMultiplicationVerificationTest](src/test/java/com/thealgorithms/randomized/RandomizedMatrixMultiplicationVerificationTest.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [FCFSSchedulingTest](src/test/java/com/thealgorithms/scheduling/FCFSSchedulingTest.java)
+ - 📄 [FairShareSchedulingTest](src/test/java/com/thealgorithms/scheduling/FairShareSchedulingTest.java)
+ - 📄 [GangSchedulingTest](src/test/java/com/thealgorithms/scheduling/GangSchedulingTest.java)
+ - 📄 [HighestResponseRatioNextSchedulingTest](src/test/java/com/thealgorithms/scheduling/HighestResponseRatioNextSchedulingTest.java)
+ - 📄 [JobSchedulingWithDeadlineTest](src/test/java/com/thealgorithms/scheduling/JobSchedulingWithDeadlineTest.java)
+ - 📄 [LotterySchedulingTest](src/test/java/com/thealgorithms/scheduling/LotterySchedulingTest.java)
+ - 📄 [MLFQSchedulerTest](src/test/java/com/thealgorithms/scheduling/MLFQSchedulerTest.java)
+ - 📄 [MultiAgentSchedulingTest](src/test/java/com/thealgorithms/scheduling/MultiAgentSchedulingTest.java)
+ - 📄 [NonPreemptivePrioritySchedulingTest](src/test/java/com/thealgorithms/scheduling/NonPreemptivePrioritySchedulingTest.java)
+ - 📄 [PreemptivePrioritySchedulingTest](src/test/java/com/thealgorithms/scheduling/PreemptivePrioritySchedulingTest.java)
+ - 📄 [ProportionalFairSchedulingTest](src/test/java/com/thealgorithms/scheduling/ProportionalFairSchedulingTest.java)
+ - 📄 [RRSchedulingTest](src/test/java/com/thealgorithms/scheduling/RRSchedulingTest.java)
+ - 📄 [RandomSchedulingTest](src/test/java/com/thealgorithms/scheduling/RandomSchedulingTest.java)
+ - 📄 [SJFSchedulingTest](src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java)
+ - 📄 [SRTFSchedulingTest](src/test/java/com/thealgorithms/scheduling/SRTFSchedulingTest.java)
+ - 📄 [SelfAdjustingSchedulingTest](src/test/java/com/thealgorithms/scheduling/SelfAdjustingSchedulingTest.java)
+ - 📄 [SlackTimeSchedulingTest](src/test/java/com/thealgorithms/scheduling/SlackTimeSchedulingTest.java)
+ - 📁 **diskscheduling**
+ - 📄 [CircularLookSchedulingTest](src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularLookSchedulingTest.java)
+ - 📄 [CircularScanSchedulingTest](src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularScanSchedulingTest.java)
+ - 📄 [LookSchedulingTest](src/test/java/com/thealgorithms/scheduling/diskscheduling/LookSchedulingTest.java)
+ - 📄 [SSFSchedulingTest](src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java)
+ - 📄 [ScanSchedulingTest](src/test/java/com/thealgorithms/scheduling/diskscheduling/ScanSchedulingTest.java)
+ - 📁 **searches**
+ - 📄 [BM25InvertedIndexTest](src/test/java/com/thealgorithms/searches/BM25InvertedIndexTest.java)
+ - 📄 [BinarySearch2dArrayTest](src/test/java/com/thealgorithms/searches/BinarySearch2dArrayTest.java)
+ - 📄 [BinarySearchTest](src/test/java/com/thealgorithms/searches/BinarySearchTest.java)
+ - 📄 [BoyerMooreTest](src/test/java/com/thealgorithms/searches/BoyerMooreTest.java)
+ - 📄 [BreadthFirstSearchTest](src/test/java/com/thealgorithms/searches/BreadthFirstSearchTest.java)
+ - 📄 [DepthFirstSearchTest](src/test/java/com/thealgorithms/searches/DepthFirstSearchTest.java)
+ - 📄 [ExponentialSearchTest](src/test/java/com/thealgorithms/searches/ExponentialSearchTest.java)
+ - 📄 [FibonacciSearchTest](src/test/java/com/thealgorithms/searches/FibonacciSearchTest.java)
+ - 📄 [HowManyTimesRotatedTest](src/test/java/com/thealgorithms/searches/HowManyTimesRotatedTest.java)
+ - 📄 [InterpolationSearchTest](src/test/java/com/thealgorithms/searches/InterpolationSearchTest.java)
+ - 📄 [IterativeBinarySearchTest](src/test/java/com/thealgorithms/searches/IterativeBinarySearchTest.java)
+ - 📄 [IterativeTernarySearchTest](src/test/java/com/thealgorithms/searches/IterativeTernarySearchTest.java)
+ - 📄 [JumpSearchTest](src/test/java/com/thealgorithms/searches/JumpSearchTest.java)
+ - 📄 [KMPSearchTest](src/test/java/com/thealgorithms/searches/KMPSearchTest.java)
+ - 📄 [LinearSearchTest](src/test/java/com/thealgorithms/searches/LinearSearchTest.java)
+ - 📄 [LinearSearchThreadTest](src/test/java/com/thealgorithms/searches/LinearSearchThreadTest.java)
+ - 📄 [LowerBoundTest](src/test/java/com/thealgorithms/searches/LowerBoundTest.java)
+ - 📄 [MonteCarloTreeSearchTest](src/test/java/com/thealgorithms/searches/MonteCarloTreeSearchTest.java)
+ - 📄 [OrderAgnosticBinarySearchTest](src/test/java/com/thealgorithms/searches/OrderAgnosticBinarySearchTest.java)
+ - 📄 [PerfectBinarySearchTest](src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java)
+ - 📄 [QuickSelectTest](src/test/java/com/thealgorithms/searches/QuickSelectTest.java)
+ - 📄 [RabinKarpAlgorithmTest](src/test/java/com/thealgorithms/searches/RabinKarpAlgorithmTest.java)
+ - 📄 [RandomSearchTest](src/test/java/com/thealgorithms/searches/RandomSearchTest.java)
+ - 📄 [RecursiveBinarySearchTest](src/test/java/com/thealgorithms/searches/RecursiveBinarySearchTest.java)
+ - 📄 [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)
+ - 📄 [TestSearchInARowAndColWiseSortedMatrix](src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java)
+ - 📄 [UnionFindTest](src/test/java/com/thealgorithms/searches/UnionFindTest.java)
+ - 📄 [UpperBoundTest](src/test/java/com/thealgorithms/searches/UpperBoundTest.java)
+ - 📁 **slidingwindow**
+ - 📄 [LongestSubarrayWithSumLessOrEqualToKTest](src/test/java/com/thealgorithms/slidingwindow/LongestSubarrayWithSumLessOrEqualToKTest.java)
+ - 📄 [LongestSubstringWithoutRepeatingCharactersTest](src/test/java/com/thealgorithms/slidingwindow/LongestSubstringWithoutRepeatingCharactersTest.java)
+ - 📄 [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)
+ - 📄 [BeadSortTest](src/test/java/com/thealgorithms/sorts/BeadSortTest.java)
+ - 📄 [BinaryInsertionSortTest](src/test/java/com/thealgorithms/sorts/BinaryInsertionSortTest.java)
+ - 📄 [BitonicSortTest](src/test/java/com/thealgorithms/sorts/BitonicSortTest.java)
+ - 📄 [BogoSortTest](src/test/java/com/thealgorithms/sorts/BogoSortTest.java)
+ - 📄 [BubbleSortRecursiveTest](src/test/java/com/thealgorithms/sorts/BubbleSortRecursiveTest.java)
+ - 📄 [BubbleSortTest](src/test/java/com/thealgorithms/sorts/BubbleSortTest.java)
+ - 📄 [BucketSortTest](src/test/java/com/thealgorithms/sorts/BucketSortTest.java)
+ - 📄 [CircleSortTest](src/test/java/com/thealgorithms/sorts/CircleSortTest.java)
+ - 📄 [CocktailShakerSortTest](src/test/java/com/thealgorithms/sorts/CocktailShakerSortTest.java)
+ - 📄 [CombSortTest](src/test/java/com/thealgorithms/sorts/CombSortTest.java)
+ - 📄 [CountingSortTest](src/test/java/com/thealgorithms/sorts/CountingSortTest.java)
+ - 📄 [CycleSortTest](src/test/java/com/thealgorithms/sorts/CycleSortTest.java)
+ - 📄 [DarkSortTest](src/test/java/com/thealgorithms/sorts/DarkSortTest.java)
+ - 📄 [DualPivotQuickSortTest](src/test/java/com/thealgorithms/sorts/DualPivotQuickSortTest.java)
+ - 📄 [DutchNationalFlagSortTest](src/test/java/com/thealgorithms/sorts/DutchNationalFlagSortTest.java)
+ - 📄 [ExchangeSortTest](src/test/java/com/thealgorithms/sorts/ExchangeSortTest.java)
+ - 📄 [FlashSortTest](src/test/java/com/thealgorithms/sorts/FlashSortTest.java)
+ - 📄 [GnomeSortTest](src/test/java/com/thealgorithms/sorts/GnomeSortTest.java)
+ - 📄 [HeapSortTest](src/test/java/com/thealgorithms/sorts/HeapSortTest.java)
+ - 📄 [InsertionSortTest](src/test/java/com/thealgorithms/sorts/InsertionSortTest.java)
+ - 📄 [IntrospectiveSortTest](src/test/java/com/thealgorithms/sorts/IntrospectiveSortTest.java)
+ - 📄 [MergeSortNoExtraSpaceTest](src/test/java/com/thealgorithms/sorts/MergeSortNoExtraSpaceTest.java)
+ - 📄 [MergeSortRecursiveTest](src/test/java/com/thealgorithms/sorts/MergeSortRecursiveTest.java)
+ - 📄 [MergeSortTest](src/test/java/com/thealgorithms/sorts/MergeSortTest.java)
+ - 📄 [OddEvenSortTest](src/test/java/com/thealgorithms/sorts/OddEvenSortTest.java)
+ - 📄 [PancakeSortTest](src/test/java/com/thealgorithms/sorts/PancakeSortTest.java)
+ - 📄 [PatienceSortTest](src/test/java/com/thealgorithms/sorts/PatienceSortTest.java)
+ - 📄 [PigeonholeSortTest](src/test/java/com/thealgorithms/sorts/PigeonholeSortTest.java)
+ - 📄 [PriorityQueueSortTest](src/test/java/com/thealgorithms/sorts/PriorityQueueSortTest.java)
+ - 📄 [QuickSortTest](src/test/java/com/thealgorithms/sorts/QuickSortTest.java)
+ - 📄 [RadixSortTest](src/test/java/com/thealgorithms/sorts/RadixSortTest.java)
+ - 📄 [SelectionSortRecursiveTest](src/test/java/com/thealgorithms/sorts/SelectionSortRecursiveTest.java)
+ - 📄 [SelectionSortTest](src/test/java/com/thealgorithms/sorts/SelectionSortTest.java)
+ - 📄 [ShellSortTest](src/test/java/com/thealgorithms/sorts/ShellSortTest.java)
+ - 📄 [SlowSortTest](src/test/java/com/thealgorithms/sorts/SlowSortTest.java)
+ - 📄 [SortUtilsRandomGeneratorTest](src/test/java/com/thealgorithms/sorts/SortUtilsRandomGeneratorTest.java)
+ - 📄 [SortUtilsTest](src/test/java/com/thealgorithms/sorts/SortUtilsTest.java)
+ - 📄 [SortingAlgorithmTest](src/test/java/com/thealgorithms/sorts/SortingAlgorithmTest.java)
+ - 📄 [SpreadSortTest](src/test/java/com/thealgorithms/sorts/SpreadSortTest.java)
+ - 📄 [StalinSortTest](src/test/java/com/thealgorithms/sorts/StalinSortTest.java)
+ - 📄 [StoogeSortTest](src/test/java/com/thealgorithms/sorts/StoogeSortTest.java)
+ - 📄 [StrandSortTest](src/test/java/com/thealgorithms/sorts/StrandSortTest.java)
+ - 📄 [SwapSortTest](src/test/java/com/thealgorithms/sorts/SwapSortTest.java)
+ - 📄 [TimSortTest](src/test/java/com/thealgorithms/sorts/TimSortTest.java)
+ - 📄 [TopologicalSortTest](src/test/java/com/thealgorithms/sorts/TopologicalSortTest.java)
+ - 📄 [TreeSortTest](src/test/java/com/thealgorithms/sorts/TreeSortTest.java)
+ - 📄 [WaveSortTest](src/test/java/com/thealgorithms/sorts/WaveSortTest.java)
+ - 📄 [WiggleSortTest](src/test/java/com/thealgorithms/sorts/WiggleSortTest.java)
+ - 📁 **stacks**
+ - 📄 [BalancedBracketsTest](src/test/java/com/thealgorithms/stacks/BalancedBracketsTest.java)
+ - 📄 [CelebrityFinderTest](src/test/java/com/thealgorithms/stacks/CelebrityFinderTest.java)
+ - 📄 [DecimalToAnyUsingStackTest](src/test/java/com/thealgorithms/stacks/DecimalToAnyUsingStackTest.java)
+ - 📄 [DuplicateBracketsTest](src/test/java/com/thealgorithms/stacks/DuplicateBracketsTest.java)
+ - 📄 [GreatestElementConstantTimeTest](src/test/java/com/thealgorithms/stacks/GreatestElementConstantTimeTest.java)
+ - 📄 [InfixToPostfixTest](src/test/java/com/thealgorithms/stacks/InfixToPostfixTest.java)
+ - 📄 [InfixToPrefixTest](src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java)
+ - 📄 [LargestRectangleTest](src/test/java/com/thealgorithms/stacks/LargestRectangleTest.java)
+ - 📄 [MinStackUsingSingleStackTest](src/test/java/com/thealgorithms/stacks/MinStackUsingSingleStackTest.java)
+ - 📄 [MinStackUsingTwoStacksTest](src/test/java/com/thealgorithms/stacks/MinStackUsingTwoStacksTest.java)
+ - 📄 [NextGreaterElementTest](src/test/java/com/thealgorithms/stacks/NextGreaterElementTest.java)
+ - 📄 [NextSmallerElementTest](src/test/java/com/thealgorithms/stacks/NextSmallerElementTest.java)
+ - 📄 [PalindromeWithStackTest](src/test/java/com/thealgorithms/stacks/PalindromeWithStackTest.java)
+ - 📄 [PostfixEvaluatorTest](src/test/java/com/thealgorithms/stacks/PostfixEvaluatorTest.java)
+ - 📄 [PostfixToInfixTest](src/test/java/com/thealgorithms/stacks/PostfixToInfixTest.java)
+ - 📄 [PrefixEvaluatorTest](src/test/java/com/thealgorithms/stacks/PrefixEvaluatorTest.java)
+ - 📄 [PrefixToInfixTest](src/test/java/com/thealgorithms/stacks/PrefixToInfixTest.java)
+ - 📄 [SmallestElementConstantTimeTest](src/test/java/com/thealgorithms/stacks/SmallestElementConstantTimeTest.java)
+ - 📄 [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)
+ - 📁 **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)
+ - 📄 [CountCharTest](src/test/java/com/thealgorithms/strings/CountCharTest.java)
+ - 📄 [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)
+ - 📄 [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)
+ - 📄 [LongestPalindromicSubstringTest](src/test/java/com/thealgorithms/strings/LongestPalindromicSubstringTest.java)
+ - 📄 [LowerTest](src/test/java/com/thealgorithms/strings/LowerTest.java)
+ - 📄 [ManacherTest](src/test/java/com/thealgorithms/strings/ManacherTest.java)
+ - 📄 [MyAtoiTest](src/test/java/com/thealgorithms/strings/MyAtoiTest.java)
+ - 📄 [PalindromeTest](src/test/java/com/thealgorithms/strings/PalindromeTest.java)
+ - 📄 [PangramTest](src/test/java/com/thealgorithms/strings/PangramTest.java)
+ - 📄 [PermuteStringTest](src/test/java/com/thealgorithms/strings/PermuteStringTest.java)
+ - 📄 [RemoveDuplicateFromStringTest](src/test/java/com/thealgorithms/strings/RemoveDuplicateFromStringTest.java)
+ - 📄 [ReturnSubsequenceTest](src/test/java/com/thealgorithms/strings/ReturnSubsequenceTest.java)
+ - 📄 [ReverseStringTest](src/test/java/com/thealgorithms/strings/ReverseStringTest.java)
+ - 📄 [ReverseWordsInStringTest](src/test/java/com/thealgorithms/strings/ReverseWordsInStringTest.java)
+ - 📄 [RotationTest](src/test/java/com/thealgorithms/strings/RotationTest.java)
+ - 📄 [StringCompressionTest](src/test/java/com/thealgorithms/strings/StringCompressionTest.java)
+ - 📄 [StringMatchFiniteAutomataTest](src/test/java/com/thealgorithms/strings/StringMatchFiniteAutomataTest.java)
+ - 📄 [SuffixArrayTest](src/test/java/com/thealgorithms/strings/SuffixArrayTest.java)
+ - 📄 [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)
+ - 📁 **zigZagPattern**
+ - 📄 [ZigZagPatternTest](src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java)
+ - 📁 **tree**
+ - 📄 [HeavyLightDecompositionTest](src/test/java/com/thealgorithms/tree/HeavyLightDecompositionTest.java)
diff --git a/README-ko.md b/README-ko.md
index 487d80e94e19..4f8cab92fc42 100644
--- a/README-ko.md
+++ b/README-ko.md
@@ -26,7 +26,7 @@ From [Wikipedia][bubble-wiki]: 버블 소트(sinking sor라고도 불리움)는
![alt text][insertion-image]
-From [Wikipedia][insertion-wiki]: 삽입 정렬은 최종 정렬된 배열(또는 리스트)을 한번에 하나씩 구축하는 알고리즘이다. 이것은 큰 리스트에서 더 나은 알고리즘인 퀵 소트, 힙 소트, 또는 머지 소트보다 훨씬 안좋은 효율을 가진다. 그림에서 각 막대는 정렬해야 하는 배열의 요소를 나타낸다. 상단과 두 번째 상단 막대의 첫 번째 교차점에서 발생하는 것은 두 번째 요소가 첫 번째 요소보다 더 높은 우선 순위를 가지기 떄문에 막대로 표시되는 이러한 요소를 교환한 것이다. 이 방법을 반복하면 삽입 정렬이 완료된다.
+From [Wikipedia][insertion-wiki]: 삽입 정렬은 최종 정렬된 배열(또는 리스트)을 한번에 하나씩 구축하는 알고리즘이다. 이것은 큰 리스트에서 더 나은 알고리즘인 퀵 소트, 힙 소트, 또는 머지 소트보다 훨씬 안좋은 효율을 가진다. 그림에서 각 막대는 정렬해야 하는 배열의 요소를 나타낸다. 상단과 두 번째 상단 막대의 첫 번째 교차점에서 발생하는 것은 두 번째 요소가 첫 번째 요소보다 더 높은 우선 순위를 가지기 때문에 막대로 표시되는 이러한 요소를 교환한 것이다. 이 방법을 반복하면 삽입 정렬이 완료된다.
**속성**
@@ -82,7 +82,7 @@ From [Wikipedia][selection-wiki]: 알고리즘 입력 리스트를 두 부분으
![alt text][shell-image]
-From [Wikipedia][shell-wiki]: 쉘 정렬은 멀리 떨어져 있는 항목의 교환을 허용하는 삽입 종류의 일반화이다. 그 아이디어는 모든 n번째 요소가 정렬된 목록을 제공한다는 것을 고려하여 어느 곳에서든지 시작하도록 요소의 목록을 배열하는 것이다. 이러한 목록은 h-sorted로 알려져 있다. 마찬가지로, 각각 개별적으로 정렬된 h 인터리브 목록으로 간주될 수 있다.
+From [Wikipedia][shell-wiki]: 쉘 정렬은 멀리 떨어져 있는 항목의 교환을 허용하는 삽입 종류의 일반화이다. 그 아이디어는 모든 n번째 요소가 정렬된 목록을 제공한다는 것을 고려하여 어느 곳에서든지 시작하도록 요소의 목록을 배열하는 것이다. 이러한 목록은 h-sorted로 알려져 있다. 마찬가지로, 각각 개별적으로 정렬된 h 인터리브 목록으로 간주할 수 있다.
**속성**
@@ -120,7 +120,7 @@ From [Wikipedia][linear-wiki]: 선형 탐색 또는 순차 탐색은 목록 내
![alt text][binary-image]
-From [Wikipedia][binary-wiki]: 이진 탐색, (also known as half-interval search or logarithmic search), 은 정렬된 배열 내에서 목표값의 위치를 찾는 검색 알고리즘이다. 목표값을 배열의 중간 요소와 비교한다; 만약 목표값이 동일하지 않으면, 목표물의 절반이 제거되고 검색이 성공할 때까지 나머지 절반에서 게속된다.
+From [Wikipedia][binary-wiki]: 이진 탐색, (also known as half-interval search or logarithmic search), 은 정렬된 배열 내에서 목표값의 위치를 찾는 검색 알고리즘이다. 목표값을 배열의 중간 요소와 비교한다; 만약 목표값이 동일하지 않으면, 목표물의 절반이 제거되고 검색이 성공할 때까지 나머지 절반에서 속된다.
**속성**
diff --git a/README.md b/README.md
index 59930fded1d3..d60d5104c385 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
# The Algorithms - Java
[](https://github.com/TheAlgorithms/Java/actions/workflows/build.yml)
+[](https://codecov.io/gh/TheAlgorithms/Java)
[](https://discord.gg/c7MnfGFGa6)
[](https://gitpod.io/#https://github.com/TheAlgorithms/Java)
@@ -15,8 +16,5 @@ These implementations are intended for learning purposes. As such, they may be l
## Contribution Guidelines
Please read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute to this project.
-## Community Channel
-We're on [Gitter](https://gitter.im/TheAlgorithms)! Come join us.
-
## Algorithms
Our [directory](DIRECTORY.md) has the full list of applications.
diff --git a/checkstyle.xml b/checkstyle.xml
new file mode 100644
index 000000000000..d78724455af7
--- /dev/null
+++ b/checkstyle.xml
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pmd-custom_ruleset.xml b/pmd-custom_ruleset.xml
new file mode 100644
index 000000000000..19bb1c7968f0
--- /dev/null
+++ b/pmd-custom_ruleset.xml
@@ -0,0 +1,28 @@
+
+
+
+ Custom PMD checks for TheAlgorithms/Java
+
+
+
+ Avoid using the main method.
+
+ 3
+
+
+
+
+
+
+
+
+
diff --git a/pmd-exclude.properties b/pmd-exclude.properties
new file mode 100644
index 000000000000..a3c95b12fa4b
--- /dev/null
+++ b/pmd-exclude.properties
@@ -0,0 +1,122 @@
+com.thealgorithms.ciphers.AES=UselessMainMethod
+com.thealgorithms.ciphers.AESEncryption=UselessMainMethod
+com.thealgorithms.ciphers.AffineCipher=UselessParentheses
+com.thealgorithms.ciphers.DES=UselessParentheses
+com.thealgorithms.ciphers.ProductCipher=UselessMainMethod
+com.thealgorithms.ciphers.RSA=UselessParentheses
+com.thealgorithms.conversions.AnyBaseToAnyBase=UselessMainMethod,UselessParentheses
+com.thealgorithms.conversions.AnytoAny=UselessParentheses
+com.thealgorithms.conversions.RgbHsvConversion=UselessMainMethod
+com.thealgorithms.datastructures.crdt.Pair=UnusedPrivateField
+com.thealgorithms.datastructures.graphs.AStar=UselessParentheses
+com.thealgorithms.datastructures.graphs.AdjacencyMatrixGraph=CollapsibleIfStatements,UnnecessaryFullyQualifiedName,UselessParentheses
+com.thealgorithms.datastructures.graphs.BellmanFord=UselessMainMethod
+com.thealgorithms.datastructures.graphs.BipartiteGraphDFS=CollapsibleIfStatements
+com.thealgorithms.datastructures.graphs.ConnectedComponent=UselessMainMethod
+com.thealgorithms.datastructures.graphs.Cycles=UselessMainMethod
+com.thealgorithms.datastructures.graphs.Graphs=UselessMainMethod
+com.thealgorithms.datastructures.graphs.KahnsAlgorithm=UselessMainMethod
+com.thealgorithms.datastructures.graphs.MatrixGraphs=UselessMainMethod
+com.thealgorithms.datastructures.hashmap.hashing.HashMapCuckooHashing=UselessParentheses
+com.thealgorithms.datastructures.hashmap.hashing.MainCuckooHashing=UselessMainMethod
+com.thealgorithms.datastructures.heaps.FibonacciHeap=UselessParentheses
+com.thealgorithms.datastructures.heaps.HeapNode=UselessParentheses
+com.thealgorithms.datastructures.lists.DoublyLinkedList=UselessParentheses
+com.thealgorithms.datastructures.lists.Link=UselessMainMethod
+com.thealgorithms.datastructures.lists.RandomNode=UselessMainMethod
+com.thealgorithms.datastructures.lists.SearchSinglyLinkedListRecursion=UselessParentheses
+com.thealgorithms.datastructures.lists.SinglyLinkedList=UnusedLocalVariable,UselessMainMethod
+com.thealgorithms.datastructures.queues.Deque=UselessMainMethod
+com.thealgorithms.datastructures.queues.PriorityQueue=UselessParentheses
+com.thealgorithms.datastructures.trees.BSTRecursiveGeneric=UselessMainMethod
+com.thealgorithms.datastructures.trees.CheckBinaryTreeIsValidBST=UselessParentheses
+com.thealgorithms.datastructures.trees.LCA=UselessMainMethod
+com.thealgorithms.datastructures.trees.NearestRightKey=UselessMainMethod
+com.thealgorithms.datastructures.trees.PrintTopViewofTree=UselessMainMethod
+com.thealgorithms.datastructures.trees.SegmentTree=UselessParentheses
+com.thealgorithms.devutils.nodes.LargeTreeNode=UselessParentheses
+com.thealgorithms.devutils.nodes.SimpleNode=UselessParentheses
+com.thealgorithms.devutils.nodes.SimpleTreeNode=UselessParentheses
+com.thealgorithms.devutils.nodes.TreeNode=UselessParentheses
+com.thealgorithms.divideandconquer.ClosestPair=UnnecessaryFullyQualifiedName,UselessMainMethod,UselessParentheses
+com.thealgorithms.divideandconquer.Point=UselessParentheses
+com.thealgorithms.dynamicprogramming.CatalanNumber=UselessMainMethod
+com.thealgorithms.dynamicprogramming.EggDropping=UselessMainMethod
+com.thealgorithms.dynamicprogramming.LongestPalindromicSubsequence=UselessMainMethod
+com.thealgorithms.dynamicprogramming.WineProblem=UselessParentheses
+com.thealgorithms.maths.BinomialCoefficient=UselessParentheses
+com.thealgorithms.maths.Complex=UselessParentheses
+com.thealgorithms.maths.DistanceFormulaTest=UnnecessaryFullyQualifiedName
+com.thealgorithms.maths.EulerMethod=UselessMainMethod
+com.thealgorithms.maths.GCDRecursion=UselessMainMethod
+com.thealgorithms.maths.Gaussian=UselessParentheses
+com.thealgorithms.maths.GcdSolutionWrapper=UselessParentheses
+com.thealgorithms.maths.HeronsFormula=UselessParentheses
+com.thealgorithms.maths.JugglerSequence=UselessMainMethod
+com.thealgorithms.maths.KaprekarNumbers=UselessParentheses
+com.thealgorithms.maths.KeithNumber=UselessMainMethod,UselessParentheses
+com.thealgorithms.maths.LeonardoNumber=UselessParentheses
+com.thealgorithms.maths.LinearDiophantineEquationsSolver=UselessMainMethod,UselessParentheses
+com.thealgorithms.maths.MagicSquare=UselessMainMethod
+com.thealgorithms.maths.PiNilakantha=UselessMainMethod
+com.thealgorithms.maths.Prime.PrimeCheck=UselessMainMethod
+com.thealgorithms.maths.PythagoreanTriple=UselessMainMethod
+com.thealgorithms.maths.RomanNumeralUtil=UselessParentheses
+com.thealgorithms.maths.SecondMinMax=UselessParentheses
+com.thealgorithms.maths.SecondMinMaxTest=UnnecessaryFullyQualifiedName
+com.thealgorithms.maths.SimpsonIntegration=UselessMainMethod
+com.thealgorithms.maths.StandardDeviation=UselessParentheses
+com.thealgorithms.maths.SumOfArithmeticSeries=UselessParentheses
+com.thealgorithms.maths.TrinomialTriangle=UselessMainMethod,UselessParentheses
+com.thealgorithms.maths.VectorCrossProduct=UselessMainMethod
+com.thealgorithms.maths.Volume=UselessParentheses
+com.thealgorithms.matrix.RotateMatrixBy90Degrees=UselessMainMethod
+com.thealgorithms.misc.Sparsity=UselessParentheses
+com.thealgorithms.others.BankersAlgorithm=UselessMainMethod
+com.thealgorithms.others.BrianKernighanAlgorithm=UselessMainMethod
+com.thealgorithms.others.CRC16=UselessMainMethod,UselessParentheses
+com.thealgorithms.others.CRC32=UselessMainMethod
+com.thealgorithms.others.Damm=UnnecessaryFullyQualifiedName,UselessMainMethod
+com.thealgorithms.others.Dijkstra=UselessMainMethod
+com.thealgorithms.others.GaussLegendre=UselessMainMethod
+com.thealgorithms.others.HappyNumbersSeq=UselessMainMethod
+com.thealgorithms.others.Huffman=UselessMainMethod
+com.thealgorithms.others.InsertDeleteInArray=UselessMainMethod
+com.thealgorithms.others.KochSnowflake=UselessMainMethod
+com.thealgorithms.others.Krishnamurthy=UselessMainMethod
+com.thealgorithms.others.LinearCongruentialGenerator=UselessMainMethod
+com.thealgorithms.others.Luhn=UnnecessaryFullyQualifiedName,UselessMainMethod
+com.thealgorithms.others.Mandelbrot=UselessMainMethod,UselessParentheses
+com.thealgorithms.others.MiniMaxAlgorithm=UselessMainMethod,UselessParentheses
+com.thealgorithms.others.MosAlgorithm=UselessMainMethod
+com.thealgorithms.others.PageRank=UselessMainMethod,UselessParentheses
+com.thealgorithms.others.PerlinNoise=UselessMainMethod,UselessParentheses
+com.thealgorithms.others.QueueUsingTwoStacks=UselessParentheses
+com.thealgorithms.others.Trieac=UselessMainMethod,UselessParentheses
+com.thealgorithms.others.Verhoeff=UnnecessaryFullyQualifiedName,UselessMainMethod
+com.thealgorithms.puzzlesandgames.Sudoku=UselessMainMethod
+com.thealgorithms.recursion.DiceThrower=UselessMainMethod
+com.thealgorithms.searches.HowManyTimesRotated=UselessMainMethod
+com.thealgorithms.searches.InterpolationSearch=UselessParentheses
+com.thealgorithms.searches.KMPSearch=UselessParentheses
+com.thealgorithms.searches.RabinKarpAlgorithm=UselessParentheses
+com.thealgorithms.searches.RecursiveBinarySearch=UselessMainMethod
+com.thealgorithms.sorts.BogoSort=UselessMainMethod
+com.thealgorithms.sorts.CircleSort=EmptyControlStatement
+com.thealgorithms.sorts.DutchNationalFlagSort=UselessParentheses
+com.thealgorithms.sorts.MergeSortNoExtraSpace=UselessParentheses
+com.thealgorithms.sorts.RadixSort=UselessParentheses
+com.thealgorithms.sorts.TreeSort=UselessMainMethod
+com.thealgorithms.sorts.WiggleSort=UselessParentheses
+com.thealgorithms.stacks.LargestRectangle=UselessMainMethod
+com.thealgorithms.stacks.MaximumMinimumWindow=UselessMainMethod
+com.thealgorithms.stacks.PostfixToInfix=UselessParentheses
+com.thealgorithms.strings.Alphabetical=UselessMainMethod
+com.thealgorithms.strings.HorspoolSearch=UnnecessaryFullyQualifiedName,UselessParentheses
+com.thealgorithms.strings.KMP=UselessMainMethod
+com.thealgorithms.strings.Lower=UselessMainMethod
+com.thealgorithms.strings.Palindrome=UselessParentheses
+com.thealgorithms.strings.Pangram=UselessMainMethod
+com.thealgorithms.strings.RabinKarp=UselessMainMethod
+com.thealgorithms.strings.Rotation=UselessMainMethod
+com.thealgorithms.strings.Upper=UselessMainMethod
diff --git a/pom.xml b/pom.xml
index 48f9e1cbbbc6..116c7bb27e40 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,16 +1,18 @@
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0%20http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
com.thealgorithms
Java
1.0-SNAPSHOT
jar
+
UTF-8
- 17
- 17
+ 21
+ 21
+ 3.27.6
@@ -18,7 +20,7 @@
org.junit
junit-bom
- 5.8.2
+ 6.0.0
pom
import
@@ -31,18 +33,126 @@
junit-jupiter
test
+
+ org.assertj
+ assertj-core
+ ${assertj.version}
+ test
+
+
+ org.mockito
+ mockito-core
+ 5.20.0
+ test
+
+
+ org.apache.commons
+ commons-lang3
+ 3.19.0
+
+
+ org.apache.commons
+ commons-collections4
+ 4.5.0
+
+ maven-surefire-plugin
+ 3.5.4
+
+
+
+
+
+ org.apache.maven.plugins
maven-compiler-plugin
- 3.8.1
+ 3.14.1
+
+ 21
+
+ -Xlint:all
+ -Xlint:-auxiliaryclass
+ -Werror
+
+
- maven-surefire-plugin
- 2.22.2
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.14
+
+
+
+ prepare-agent
+
+
+
+ generate-code-coverage-report
+ test
+
+ report
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+ 3.6.0
+
+ checkstyle.xml
+ true
+ true
+ warning
+
+
+
+ com.puppycrawl.tools
+ checkstyle
+ 12.1.0
+
+
+
+
+ com.github.spotbugs
+ spotbugs-maven-plugin
+ 4.9.8.1
+
+ spotbugs-exclude.xml
+ true
+
+
+ com.mebigfatguy.fb-contrib
+ fb-contrib
+ 7.6.15
+
+
+ com.h3xstream.findsecbugs
+ findsecbugs-plugin
+ 1.14.0
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-pmd-plugin
+ 3.28.0
+
+
+ /rulesets/java/maven-pmd-plugin-default.xml
+ /category/java/security.xml
+ file://${basedir}/pmd-custom_ruleset.xml
+
+ true
+ true
+ false
+ pmd-exclude.properties
+
-
\ No newline at end of file
+
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
new file mode 100644
index 000000000000..d2e094556d61
--- /dev/null
+++ b/spotbugs-exclude.xml
@@ -0,0 +1,211 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/thealgorithms/audiofilters/EMAFilter.java b/src/main/java/com/thealgorithms/audiofilters/EMAFilter.java
new file mode 100644
index 000000000000..0dd23e937953
--- /dev/null
+++ b/src/main/java/com/thealgorithms/audiofilters/EMAFilter.java
@@ -0,0 +1,48 @@
+package com.thealgorithms.audiofilters;
+
+/**
+ * Exponential Moving Average (EMA) Filter for smoothing audio signals.
+ *
+ * This filter applies an exponential moving average to a sequence of audio
+ * signal values, making it useful for smoothing out rapid fluctuations.
+ * The smoothing factor (alpha) controls the degree of smoothing.
+ *
+ *
Based on the definition from
+ * Wikipedia link.
+ */
+public class EMAFilter {
+ private final double alpha;
+ private double emaValue;
+ /**
+ * Constructs an EMA filter with a given smoothing factor.
+ *
+ * @param alpha Smoothing factor (0 < alpha <= 1)
+ * @throws IllegalArgumentException if alpha is not in (0, 1]
+ */
+ public EMAFilter(double alpha) {
+ if (alpha <= 0 || alpha > 1) {
+ throw new IllegalArgumentException("Alpha must be between 0 and 1.");
+ }
+ this.alpha = alpha;
+ this.emaValue = 0.0;
+ }
+ /**
+ * Applies the EMA filter to an audio signal array.
+ *
+ * @param audioSignal Array of audio samples to process
+ * @return Array of processed (smoothed) samples
+ */
+ public double[] apply(double[] audioSignal) {
+ if (audioSignal.length == 0) {
+ return new double[0];
+ }
+ double[] emaSignal = new double[audioSignal.length];
+ emaValue = audioSignal[0];
+ emaSignal[0] = emaValue;
+ for (int i = 1; i < audioSignal.length; i++) {
+ emaValue = alpha * audioSignal[i] + (1 - alpha) * emaValue;
+ emaSignal[i] = emaValue;
+ }
+ return emaSignal;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/audiofilters/IIRFilter.java b/src/main/java/com/thealgorithms/audiofilters/IIRFilter.java
index 0de145f60c67..fbc095909541 100644
--- a/src/main/java/com/thealgorithms/audiofilters/IIRFilter.java
+++ b/src/main/java/com/thealgorithms/audiofilters/IIRFilter.java
@@ -4,7 +4,7 @@
* N-Order IIR Filter Assumes inputs are normalized to [-1, 1]
*
* Based on the difference equation from
- * https://en.wikipedia.org/wiki/Infinite_impulse_response
+ * Wikipedia link
*/
public class IIRFilter {
@@ -58,7 +58,7 @@ public void setCoeffs(double[] aCoeffs, double[] bCoeffs) throws IllegalArgument
throw new IllegalArgumentException("bCoeffs must be of size " + order + ", got " + bCoeffs.length);
}
- for (int i = 0; i <= order; i++) {
+ for (int i = 0; i < order; i++) {
coeffsA[i] = aCoeffs[i];
coeffsB[i] = bCoeffs[i];
}
diff --git a/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java b/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java
new file mode 100644
index 000000000000..c35a36d97a57
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java
@@ -0,0 +1,101 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Program description - To find all possible paths from source to destination
+ * Wikipedia
+ *
+ * @author Siddhant Swarup Mallick
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class AllPathsFromSourceToTarget {
+
+ // No. of vertices in graph
+ private final int v;
+
+ // To store the paths from source to destination
+ static List> nm = new ArrayList<>();
+ // adjacency list
+ private ArrayList[] adjList;
+
+ // Constructor
+ public AllPathsFromSourceToTarget(int vertices) {
+
+ // initialise vertex count
+ this.v = vertices;
+
+ // initialise adjacency list
+ initAdjList();
+ }
+
+ // utility method to initialise adjacency list
+ private void initAdjList() {
+ adjList = new ArrayList[v];
+
+ for (int i = 0; i < v; i++) {
+ adjList[i] = new ArrayList<>();
+ }
+ }
+
+ // add edge from u to v
+ public void addEdge(int u, int v) {
+ // Add v to u's list.
+ adjList[u].add(v);
+ }
+
+ public void storeAllPaths(int s, int d) {
+ boolean[] isVisited = new boolean[v];
+ ArrayList pathList = new ArrayList<>();
+
+ // add source to path[]
+ pathList.add(s);
+ // Call recursive utility
+ storeAllPathsUtil(s, d, isVisited, pathList);
+ }
+
+ // A recursive function to print all paths from 'u' to 'd'.
+ // isVisited[] keeps track of vertices in current path.
+ // localPathList<> stores actual vertices in the current path
+ private void storeAllPathsUtil(Integer u, Integer d, boolean[] isVisited, List localPathList) {
+
+ if (u.equals(d)) {
+ nm.add(new ArrayList<>(localPathList));
+ return;
+ }
+
+ // Mark the current node
+ isVisited[u] = true;
+
+ // Recursion for all the vertices adjacent to current vertex
+
+ for (Integer i : adjList[u]) {
+ if (!isVisited[i]) {
+ // store current node in path[]
+ localPathList.add(i);
+ storeAllPathsUtil(i, d, isVisited, localPathList);
+
+ // remove current node in path[]
+ localPathList.remove(i);
+ }
+ }
+
+ // Mark the current node
+ isVisited[u] = false;
+ }
+
+ // Driver program
+ public static List> allPathsFromSourceToTarget(int vertices, int[][] a, int source, int destination) {
+ // Create a sample graph
+ AllPathsFromSourceToTarget g = new AllPathsFromSourceToTarget(vertices);
+ for (int[] i : a) {
+ g.addEdge(i[0], i[1]);
+ // edges are added
+ }
+ g.storeAllPaths(source, destination);
+ // method call to store all possible paths
+ return nm;
+ // returns all possible paths from source to destination
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java
new file mode 100644
index 000000000000..f8cd0c40c20e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java
@@ -0,0 +1,54 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides methods to find all combinations of integers from 0 to n-1
+ * of a specified length k using backtracking.
+ */
+public final class ArrayCombination {
+ private ArrayCombination() {
+ }
+
+ /**
+ * Generates all possible combinations of length k from the integers 0 to n-1.
+ *
+ * @param n The total number of elements (0 to n-1).
+ * @param k The desired length of each combination.
+ * @return A list containing all combinations of length k.
+ * @throws IllegalArgumentException if n or k are negative, or if k is greater than n.
+ */
+ public static List> combination(int n, int k) {
+ if (n < 0 || k < 0 || k > n) {
+ throw new IllegalArgumentException("Invalid input: n must be non-negative, k must be non-negative and less than or equal to n.");
+ }
+
+ List> combinations = new ArrayList<>();
+ combine(combinations, new ArrayList<>(), 0, n, k);
+ return combinations;
+ }
+
+ /**
+ * A helper method that uses backtracking to find combinations.
+ *
+ * @param combinations The list to store all valid combinations found.
+ * @param current The current combination being built.
+ * @param start The starting index for the current recursion.
+ * @param n The total number of elements (0 to n-1).
+ * @param k The desired length of each combination.
+ */
+ private static void combine(List> combinations, List current, int start, int n, int k) {
+ // Base case: combination found
+ if (current.size() == k) {
+ combinations.add(new ArrayList<>(current));
+ return;
+ }
+
+ for (int i = start; i < n; i++) {
+ current.add(i);
+ combine(combinations, current, i + 1, n, k);
+ current.remove(current.size() - 1); // Backtrack
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/Combination.java b/src/main/java/com/thealgorithms/backtracking/Combination.java
new file mode 100644
index 000000000000..ecaf7428f986
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/Combination.java
@@ -0,0 +1,67 @@
+package com.thealgorithms.backtracking;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.TreeSet;
+
+/**
+ * Finds all permutations of given array
+ * @author Alan Piao (git-Alan Piao)
+ */
+public final class Combination {
+ private Combination() {
+ }
+
+ /**
+ * Find all combinations of given array using backtracking
+ * @param arr the array.
+ * @param n length of combination
+ * @param the type of elements in the array.
+ * @return a list of all combinations of length n. If n == 0, return null.
+ */
+ public static List> combination(T[] arr, int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("The combination length cannot be negative.");
+ }
+
+ if (n == 0) {
+ return Collections.emptyList();
+ }
+ T[] array = arr.clone();
+ Arrays.sort(array);
+
+ List> result = new LinkedList<>();
+ backtracking(array, n, 0, new TreeSet(), result);
+ return result;
+ }
+
+ /**
+ * Backtrack all possible combinations of a given array
+ * @param arr the array.
+ * @param n length of the combination
+ * @param index the starting index.
+ * @param currSet set that tracks current combination
+ * @param result the list contains all combination.
+ * @param the type of elements in the array.
+ */
+ private static void backtracking(T[] arr, int n, int index, TreeSet currSet, List> result) {
+ if (index + n - currSet.size() > arr.length) {
+ return;
+ }
+ if (currSet.size() == n - 1) {
+ for (int i = index; i < arr.length; i++) {
+ currSet.add(arr[i]);
+ result.add(new TreeSet<>(currSet));
+ currSet.remove(arr[i]);
+ }
+ return;
+ }
+ for (int i = index; i < arr.length; i++) {
+ currSet.add(arr[i]);
+ backtracking(arr, n, i + 1, currSet, result);
+ currSet.remove(arr[i]);
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java b/src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java
new file mode 100644
index 000000000000..6bfb026c7de9
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java
@@ -0,0 +1,125 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * A class to solve a crossword puzzle using backtracking.
+ * Example:
+ * Input:
+ * puzzle = {
+ * {' ', ' ', ' '},
+ * {' ', ' ', ' '},
+ * {' ', ' ', ' '}
+ * }
+ * words = List.of("cat", "dog")
+ *
+ * Output:
+ * {
+ * {'c', 'a', 't'},
+ * {' ', ' ', ' '},
+ * {'d', 'o', 'g'}
+ * }
+ */
+public final class CrosswordSolver {
+ private CrosswordSolver() {
+ }
+
+ /**
+ * Checks if a word can be placed at the specified position in the crossword.
+ *
+ * @param puzzle The crossword puzzle represented as a 2D char array.
+ * @param word The word to be placed.
+ * @param row The row index where the word might be placed.
+ * @param col The column index where the word might be placed.
+ * @param vertical If true, the word is placed vertically; otherwise, horizontally.
+ * @return true if the word can be placed, false otherwise.
+ */
+ public static boolean isValid(char[][] puzzle, String word, int row, int col, boolean vertical) {
+ for (int i = 0; i < word.length(); i++) {
+ if (vertical) {
+ if (row + i >= puzzle.length || puzzle[row + i][col] != ' ') {
+ return false;
+ }
+ } else {
+ if (col + i >= puzzle[0].length || puzzle[row][col + i] != ' ') {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Places a word at the specified position in the crossword.
+ *
+ * @param puzzle The crossword puzzle represented as a 2D char array.
+ * @param word The word to be placed.
+ * @param row The row index where the word will be placed.
+ * @param col The column index where the word will be placed.
+ * @param vertical If true, the word is placed vertically; otherwise, horizontally.
+ */
+ public static void placeWord(char[][] puzzle, String word, int row, int col, boolean vertical) {
+ for (int i = 0; i < word.length(); i++) {
+ if (vertical) {
+ puzzle[row + i][col] = word.charAt(i);
+ } else {
+ puzzle[row][col + i] = word.charAt(i);
+ }
+ }
+ }
+
+ /**
+ * Removes a word from the specified position in the crossword.
+ *
+ * @param puzzle The crossword puzzle represented as a 2D char array.
+ * @param word The word to be removed.
+ * @param row The row index where the word is placed.
+ * @param col The column index where the word is placed.
+ * @param vertical If true, the word was placed vertically; otherwise, horizontally.
+ */
+ public static void removeWord(char[][] puzzle, String word, int row, int col, boolean vertical) {
+ for (int i = 0; i < word.length(); i++) {
+ if (vertical) {
+ puzzle[row + i][col] = ' ';
+ } else {
+ puzzle[row][col + i] = ' ';
+ }
+ }
+ }
+
+ /**
+ * Solves the crossword puzzle using backtracking.
+ *
+ * @param puzzle The crossword puzzle represented as a 2D char array.
+ * @param words The list of words to be placed.
+ * @return true if the crossword is solved, false otherwise.
+ */
+ public static boolean solveCrossword(char[][] puzzle, Collection words) {
+ // Create a mutable copy of the words list
+ List remainingWords = new ArrayList<>(words);
+
+ for (int row = 0; row < puzzle.length; row++) {
+ for (int col = 0; col < puzzle[0].length; col++) {
+ if (puzzle[row][col] == ' ') {
+ for (String word : new ArrayList<>(remainingWords)) {
+ for (boolean vertical : new boolean[] {true, false}) {
+ if (isValid(puzzle, word, row, col, vertical)) {
+ placeWord(puzzle, word, row, col, vertical);
+ remainingWords.remove(word);
+ if (solveCrossword(puzzle, remainingWords)) {
+ return true;
+ }
+ remainingWords.add(word);
+ removeWord(puzzle, word, row, col, vertical);
+ }
+ }
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/FloodFill.java b/src/main/java/com/thealgorithms/backtracking/FloodFill.java
new file mode 100644
index 000000000000..c8219ca8ba7e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/FloodFill.java
@@ -0,0 +1,62 @@
+package com.thealgorithms.backtracking;
+
+/**
+ * Java program for Flood fill algorithm.
+ * @author Akshay Dubey (Git-Akshay Dubey)
+ */
+public final class FloodFill {
+ 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
+ */
+
+ public static int getPixel(final int[][] image, final int x, final int y) {
+ return image[x][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
+ */
+ public static void putPixel(final int[][] image, final int x, final int y, final int newColor) {
+ image[x][y] = newColor;
+ }
+
+ /**
+ * 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 newColor The new color which to be filled in the image
+ * @param oldColor The old color which is to be replaced in the image
+ */
+ public static void floodFill(final int[][] image, final int x, final int y, final int newColor, final int oldColor) {
+ if (newColor == oldColor || x < 0 || x >= image.length || y < 0 || y >= image[x].length || getPixel(image, x, y) != oldColor) {
+ return;
+ }
+
+ putPixel(image, x, y, newColor);
+
+ /* Recursively check for horizontally & vertically adjacent coordinates */
+ floodFill(image, x + 1, y, newColor, oldColor);
+ floodFill(image, x - 1, y, newColor, oldColor);
+ floodFill(image, x, y + 1, newColor, oldColor);
+ floodFill(image, x, y - 1, newColor, oldColor);
+
+ /* Recursively check for diagonally adjacent coordinates */
+ floodFill(image, x + 1, y - 1, newColor, oldColor);
+ floodFill(image, x - 1, y + 1, newColor, oldColor);
+ floodFill(image, x + 1, y + 1, newColor, oldColor);
+ floodFill(image, x - 1, y - 1, newColor, oldColor);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/KnightsTour.java b/src/main/java/com/thealgorithms/backtracking/KnightsTour.java
index e337df8f6e8e..2c2da659f3aa 100644
--- a/src/main/java/com/thealgorithms/backtracking/KnightsTour.java
+++ b/src/main/java/com/thealgorithms/backtracking/KnightsTour.java
@@ -1,62 +1,72 @@
package com.thealgorithms.backtracking;
-import java.util.*;
-
-/*
- * Problem Statement: -
-
- Given a N*N board with the Knight placed on the first block of an empty board. Moving according to the rules of
- chess knight must visit each square exactly once. Print the order of each cell in which they are visited.
-
- Example: -
-
- Input : N = 8
-
- Output:
- 0 59 38 33 30 17 8 63
- 37 34 31 60 9 62 29 16
- 58 1 36 39 32 27 18 7
- 35 48 41 26 61 10 15 28
- 42 57 2 49 40 23 6 19
- 47 50 45 54 25 20 11 14
- 56 43 52 3 22 13 24 5
- 51 46 55 44 53 4 21 12
-
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * The KnightsTour class solves the Knight's Tour problem using backtracking.
+ *
+ * Problem Statement:
+ * Given an N*N board with a knight placed on the first block, the knight must
+ * move according to chess rules and visit each square on the board exactly once.
+ * The class outputs the sequence of moves for the knight.
+ *
+ * Example:
+ * Input: N = 8 (8x8 chess board)
+ * Output: The sequence of numbers representing the order in which the knight visits each square.
*/
-public class KnightsTour {
-
- private final static int base = 12;
- private final static int[][] moves = {{1, -2}, {2, -1}, {2, 1}, {1, 2}, {-1, 2}, {-2, 1}, {-2, -1}, {-1, -2}}; // Possible moves by knight on chess
- private static int[][] grid; // chess grid
- private static int total; // total squares in chess
-
- public static void main(String[] args) {
- grid = new int[base][base];
- total = (base - 4) * (base - 4);
+public final class KnightsTour {
+ private KnightsTour() {
+ }
- for (int r = 0; r < base; r++) {
- for (int c = 0; c < base; c++) {
- if (r < 2 || r > base - 3 || c < 2 || c > base - 3) {
- grid[r][c] = -1;
+ // The size of the chess board (12x12 grid, with 2 extra rows/columns as a buffer around a 8x8 area)
+ private static final int BASE = 12;
+
+ // Possible moves for a knight in chess
+ private static final int[][] MOVES = {
+ {1, -2},
+ {2, -1},
+ {2, 1},
+ {1, 2},
+ {-1, 2},
+ {-2, 1},
+ {-2, -1},
+ {-1, -2},
+ };
+
+ // Chess grid representing the board
+ static int[][] grid;
+
+ // Total number of cells the knight needs to visit
+ static int total;
+
+ /**
+ * Resets the chess board to its initial state.
+ * Initializes the grid with boundary cells marked as -1 and internal cells as 0.
+ * Sets the total number of cells the knight needs to visit.
+ */
+ public static void resetBoard() {
+ grid = new int[BASE][BASE];
+ total = (BASE - 4) * (BASE - 4);
+ for (int r = 0; r < BASE; r++) {
+ for (int c = 0; c < BASE; c++) {
+ if (r < 2 || r > BASE - 3 || c < 2 || c > BASE - 3) {
+ grid[r][c] = -1; // Mark boundary cells
}
}
}
-
- int row = 2 + (int) (Math.random() * (base - 4));
- int col = 2 + (int) (Math.random() * (base - 4));
-
- grid[row][col] = 1;
-
- if (solve(row, col, 2)) {
- printResult();
- } else {
- System.out.println("no result");
- }
-
}
- // Return True when solvable
- private static boolean solve(int row, int column, int count) {
+ /**
+ * Recursive method to solve the Knight's Tour problem.
+ *
+ * @param row The current row of the knight
+ * @param column The current column of the knight
+ * @param count The current move number
+ * @return True if a solution is found, False otherwise
+ */
+ static boolean solve(int row, int column, int count) {
if (count > total) {
return true;
}
@@ -67,53 +77,72 @@ private static boolean solve(int row, int column, int count) {
return false;
}
- Collections.sort(neighbor, new Comparator() {
- public int compare(int[] a, int[] b) {
- return a[2] - b[2];
- }
- });
+ // Sort neighbors by Warnsdorff's rule (fewest onward moves)
+ neighbor.sort(Comparator.comparingInt(a -> a[2]));
for (int[] nb : neighbor) {
- row = nb[0];
- column = nb[1];
- grid[row][column] = count;
- if (!orphanDetected(count, row, column) && solve(row, column, count + 1)) {
+ int nextRow = nb[0];
+ int nextCol = nb[1];
+ grid[nextRow][nextCol] = count;
+ if (!orphanDetected(count, nextRow, nextCol) && solve(nextRow, nextCol, count + 1)) {
return true;
}
- grid[row][column] = 0;
+ grid[nextRow][nextCol] = 0; // Backtrack
}
return false;
}
- // Returns List of neighbours
- private static List neighbors(int row, int column) {
+ /**
+ * Returns a list of valid neighboring cells where the knight can move.
+ *
+ * @param row The current row of the knight
+ * @param column The current column of the knight
+ * @return A list of arrays representing valid moves, where each array contains:
+ * {nextRow, nextCol, numberOfPossibleNextMoves}
+ */
+ static List neighbors(int row, int column) {
List neighbour = new ArrayList<>();
- for (int[] m : moves) {
+ for (int[] m : MOVES) {
int x = m[0];
int y = m[1];
- if (grid[row + y][column + x] == 0) {
+ if (row + y >= 0 && row + y < BASE && column + x >= 0 && column + x < BASE && grid[row + y][column + x] == 0) {
int num = countNeighbors(row + y, column + x);
- neighbour.add(new int[]{row + y, column + x, num});
+ neighbour.add(new int[] {row + y, column + x, num});
}
}
return neighbour;
}
- // Returns the total count of neighbors
- private static int countNeighbors(int row, int column) {
+ /**
+ * Counts the number of possible valid moves for a knight from a given position.
+ *
+ * @param row The row of the current position
+ * @param column The column of the current position
+ * @return The number of valid neighboring moves
+ */
+ static int countNeighbors(int row, int column) {
int num = 0;
- for (int[] m : moves) {
- if (grid[row + m[1]][column + m[0]] == 0) {
+ for (int[] m : MOVES) {
+ int x = m[0];
+ int y = m[1];
+ if (row + y >= 0 && row + y < BASE && column + x >= 0 && column + x < BASE && grid[row + y][column + x] == 0) {
num++;
}
}
return num;
}
- // Returns true if it is orphan
- private static boolean orphanDetected(int count, int row, int column) {
+ /**
+ * Detects if moving to a given position will create an orphan (a position with no further valid moves).
+ *
+ * @param count The current move number
+ * @param row The row of the current position
+ * @param column The column of the current position
+ * @return True if an orphan is detected, False otherwise
+ */
+ static boolean orphanDetected(int count, int row, int column) {
if (count < total - 1) {
List neighbor = neighbors(row, column);
for (int[] nb : neighbor) {
@@ -124,17 +153,4 @@ private static boolean orphanDetected(int count, int row, int column) {
}
return false;
}
-
- // Prints the result grid
- private static void printResult() {
- for (int[] row : grid) {
- for (int i : row) {
- if (i == -1) {
- continue;
- }
- System.out.printf("%2d ", i);
- }
- System.out.println();
- }
- }
}
diff --git a/src/main/java/com/thealgorithms/backtracking/MColoring.java b/src/main/java/com/thealgorithms/backtracking/MColoring.java
new file mode 100644
index 000000000000..d0188dfd13aa
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/MColoring.java
@@ -0,0 +1,96 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Set;
+
+/**
+ * Node class represents a graph node. Each node is associated with a color
+ * (initially 1) and contains a set of edges representing its adjacent nodes.
+ *
+ * @author Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ */
+class Node {
+ int color = 1; // Initial color for each node
+ Set edges = new HashSet(); // Set of edges representing adjacent nodes
+}
+
+/**
+ * MColoring class solves the M-Coloring problem where the goal is to determine
+ * if it's possible to color a graph using at most M colors such that no two
+ * adjacent nodes have the same color.
+ */
+public final class MColoring {
+
+ private MColoring() {
+ } // Prevent instantiation of utility class
+
+ /**
+ * Determines whether it is possible to color the graph using at most M colors.
+ *
+ * @param nodes List of nodes representing the graph.
+ * @param n The total number of nodes in the graph.
+ * @param m The maximum number of allowed colors.
+ * @return true if the graph can be colored using M colors, false otherwise.
+ */
+ static boolean isColoringPossible(ArrayList nodes, int n, int m) {
+
+ // Visited array keeps track of whether each node has been processed.
+ ArrayList visited = new ArrayList();
+ for (int i = 0; i < n + 1; i++) {
+ visited.add(0); // Initialize all nodes as unvisited (0)
+ }
+
+ // The number of colors used so far (initially set to 1, since all nodes
+ // start with color 1).
+ int maxColors = 1;
+
+ // Loop through all the nodes to ensure every node is visited, in case the
+ // graph is disconnected.
+ for (int sv = 1; sv <= n; sv++) {
+ if (visited.get(sv) > 0) {
+ continue; // Skip nodes that are already visited
+ }
+
+ // If the node is unvisited, mark it as visited and add it to the queue for BFS.
+ visited.set(sv, 1);
+ Queue q = new LinkedList<>();
+ q.add(sv);
+
+ // Perform BFS to process all nodes and their adjacent nodes
+ while (q.size() != 0) {
+ int top = q.peek(); // Get the current node from the queue
+ q.remove();
+
+ // Check all adjacent nodes of the current node
+ for (int it : nodes.get(top).edges) {
+
+ // If the adjacent node has the same color as the current node, increment its
+ // color to avoid conflict.
+ if (nodes.get(top).color == nodes.get(it).color) {
+ nodes.get(it).color += 1;
+ }
+
+ // Keep track of the maximum number of colors used so far
+ maxColors = Math.max(maxColors, Math.max(nodes.get(top).color, nodes.get(it).color));
+
+ // If the number of colors used exceeds the allowed limit M, return false.
+ if (maxColors > m) {
+ return false;
+ }
+
+ // If the adjacent node hasn't been visited yet, mark it as visited and add it
+ // to the queue for further processing.
+ if (visited.get(it) == 0) {
+ visited.set(it, 1);
+ q.add(it);
+ }
+ }
+ }
+ }
+
+ return true; // Possible to color the entire graph with M or fewer colors.
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/MazeRecursion.java b/src/main/java/com/thealgorithms/backtracking/MazeRecursion.java
new file mode 100644
index 000000000000..8247172e7ee0
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/MazeRecursion.java
@@ -0,0 +1,125 @@
+package com.thealgorithms.backtracking;
+
+/**
+ * This class contains methods to solve a maze using recursive backtracking.
+ * The maze is represented as a 2D array where walls, paths, and visited/dead
+ * ends are marked with different integers.
+ *
+ * The goal is to find a path from a starting position to the target position
+ * (map[6][5]) while navigating through the maze.
+ */
+public final class MazeRecursion {
+
+ private MazeRecursion() {
+ }
+
+ /**
+ * This method solves the maze using the "down -> right -> up -> left"
+ * movement strategy.
+ *
+ * @param map The 2D array representing the maze (walls, paths, etc.)
+ * @return The solved maze with paths marked, or null if no solution exists.
+ */
+ public static int[][] solveMazeUsingFirstStrategy(int[][] map) {
+ if (setWay(map, 1, 1)) {
+ return map;
+ }
+ return null;
+ }
+
+ /**
+ * This method solves the maze using the "up -> right -> down -> left"
+ * movement strategy.
+ *
+ * @param map The 2D array representing the maze (walls, paths, etc.)
+ * @return The solved maze with paths marked, or null if no solution exists.
+ */
+ public static int[][] solveMazeUsingSecondStrategy(int[][] map) {
+ if (setWay2(map, 1, 1)) {
+ return map;
+ }
+ return null;
+ }
+
+ /**
+ * Attempts to find a path through the maze using a "down -> right -> up -> left"
+ * movement strategy. The path is marked with '2' for valid paths and '3' for dead ends.
+ *
+ * @param map The 2D array representing the maze (walls, paths, etc.)
+ * @param i The current x-coordinate of the ball (row index)
+ * @param j The current y-coordinate of the ball (column index)
+ * @return True if a path is found to (6,5), otherwise false
+ */
+ private static boolean setWay(int[][] map, int i, int j) {
+ if (map[6][5] == 2) {
+ return true;
+ }
+
+ // If the current position is unvisited (0), explore it
+ if (map[i][j] == 0) {
+ // Mark the current position as '2'
+ map[i][j] = 2;
+
+ // Move down
+ if (setWay(map, i + 1, j)) {
+ return true;
+ }
+ // Move right
+ else if (setWay(map, i, j + 1)) {
+ return true;
+ }
+ // Move up
+ else if (setWay(map, i - 1, j)) {
+ return true;
+ }
+ // Move left
+ else if (setWay(map, i, j - 1)) {
+ return true;
+ }
+
+ map[i][j] = 3; // Mark as dead end (3) if no direction worked
+ return false;
+ }
+ return false;
+ }
+
+ /**
+ * Attempts to find a path through the maze using an alternative movement
+ * strategy "up -> right -> down -> left".
+ *
+ * @param map The 2D array representing the maze (walls, paths, etc.)
+ * @param i The current x-coordinate of the ball (row index)
+ * @param j The current y-coordinate of the ball (column index)
+ * @return True if a path is found to (6,5), otherwise false
+ */
+ private static boolean setWay2(int[][] map, int i, int j) {
+ if (map[6][5] == 2) {
+ return true;
+ }
+
+ if (map[i][j] == 0) {
+ map[i][j] = 2;
+
+ // Move up
+ if (setWay2(map, i - 1, j)) {
+ return true;
+ }
+ // Move right
+ else if (setWay2(map, i, j + 1)) {
+ return true;
+ }
+ // Move down
+ else if (setWay2(map, i + 1, j)) {
+ return true;
+ }
+ // Move left
+ else if (setWay2(map, i, j - 1)) {
+ return true;
+ }
+
+ map[i][j] = 3; // Mark as dead end (3) if no direction worked
+ return false;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/NQueens.java b/src/main/java/com/thealgorithms/backtracking/NQueens.java
index fb0138d10d20..1a8e453e34cb 100644
--- a/src/main/java/com/thealgorithms/backtracking/NQueens.java
+++ b/src/main/java/com/thealgorithms/backtracking/NQueens.java
@@ -8,18 +8,18 @@
* which N queens can be placed on the board such no two queens attack each
* other. Ex. N = 6 Solution= There are 4 possible ways Arrangement: 1 ".Q....",
* "...Q..", ".....Q", "Q.....", "..Q...", "....Q."
- *
+ *
* Arrangement: 2 "..Q...", ".....Q", ".Q....", "....Q.", "Q.....", "...Q.."
- *
+ *
* Arrangement: 3 "...Q..", "Q.....", "....Q.", ".Q....", ".....Q", "..Q..."
- *
+ *
* Arrangement: 4 "....Q.", "..Q...", "Q.....", ".....Q", "...Q..", ".Q...."
*
* Solution: Brute Force approach:
*
* Generate all possible arrangement to place N queens on N*N board. Check each
* board if queens are placed safely. If it is safe, include arrangement in
- * solution set. Otherwise ignore it
+ * solution set. Otherwise, ignore it
*
* Optimized solution: This can be solved using backtracking in below steps
*
@@ -32,15 +32,14 @@
* queen is not placed safely. If there is no such way then return an empty list
* as solution
*/
-public class NQueens {
+public final class NQueens {
+ private NQueens() {
+ }
- public static void main(String[] args) {
- placeQueens(1);
- placeQueens(2);
- placeQueens(3);
- placeQueens(4);
- placeQueens(5);
- placeQueens(6);
+ public static List> getNQueensArrangements(int queens) {
+ List> arrangements = new ArrayList<>();
+ getSolution(queens, arrangements, new int[queens], 0);
+ return arrangements;
}
public static void placeQueens(final int queens) {
@@ -51,10 +50,10 @@ public static void placeQueens(final int queens) {
} else {
System.out.println("Arrangement for placing " + queens + " queens");
}
- arrangements.forEach(arrangement -> {
- arrangement.forEach(row -> System.out.println(row));
+ for (List arrangement : arrangements) {
+ arrangement.forEach(System.out::println);
System.out.println();
- });
+ }
}
/**
@@ -84,7 +83,8 @@ private static void getSolution(int boardSize, List> solutions, int
for (int rowIndex = 0; rowIndex < boardSize; rowIndex++) {
columns[columnIndex] = rowIndex;
if (isPlacedCorrectly(columns, rowIndex, columnIndex)) {
- // If queen is placed successfully at rowIndex in column=columnIndex then try placing queen in next column
+ // If queen is placed successfully at rowIndex in column=columnIndex then try
+ // placing queen in next column
getSolution(boardSize, solutions, columns, columnIndex + 1);
}
}
diff --git a/src/main/java/com/thealgorithms/backtracking/ParenthesesGenerator.java b/src/main/java/com/thealgorithms/backtracking/ParenthesesGenerator.java
new file mode 100644
index 000000000000..bf93f946ab7b
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/ParenthesesGenerator.java
@@ -0,0 +1,50 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class generates all valid combinations of parentheses for a given number of pairs using backtracking.
+ */
+public final class ParenthesesGenerator {
+ private ParenthesesGenerator() {
+ }
+
+ /**
+ * Generates all valid combinations of parentheses for a given number of pairs.
+ *
+ * @param n The number of pairs of parentheses.
+ * @return A list of strings representing valid combinations of parentheses.
+ * @throws IllegalArgumentException if n is less than 0.
+ */
+ public static List generateParentheses(final int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("The number of pairs of parentheses cannot be negative");
+ }
+ List result = new ArrayList<>();
+ generateParenthesesHelper(result, "", 0, 0, n);
+ return result;
+ }
+
+ /**
+ * Helper function for generating all valid combinations of parentheses recursively.
+ *
+ * @param result The list to store valid combinations.
+ * @param current The current combination being formed.
+ * @param open The number of open parentheses.
+ * @param close The number of closed parentheses.
+ * @param n The total number of pairs of parentheses.
+ */
+ private static void generateParenthesesHelper(List result, final String current, final int open, final int close, final int n) {
+ if (current.length() == n * 2) {
+ result.add(current);
+ return;
+ }
+ if (open < n) {
+ generateParenthesesHelper(result, current + "(", open + 1, close, n);
+ }
+ if (close < open) {
+ generateParenthesesHelper(result, current + ")", open, close + 1, n);
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/Permutation.java b/src/main/java/com/thealgorithms/backtracking/Permutation.java
new file mode 100644
index 000000000000..21d26e53980f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/Permutation.java
@@ -0,0 +1,57 @@
+package com.thealgorithms.backtracking;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Finds all permutations of given array
+ * @author Alan Piao (Git-Alan Piao)
+ */
+public final class Permutation {
+ private Permutation() {
+ }
+
+ /**
+ * Find all permutations of given array using backtracking
+ * @param arr the array.
+ * @param the type of elements in the array.
+ * @return a list of all permutations.
+ */
+ public static List permutation(T[] arr) {
+ T[] array = arr.clone();
+ List result = new LinkedList<>();
+ backtracking(array, 0, result);
+ return result;
+ }
+
+ /**
+ * Backtrack all possible orders of a given array
+ * @param arr the array.
+ * @param index the starting index.
+ * @param result the list contains all permutations.
+ * @param the type of elements in the array.
+ */
+ private static void backtracking(T[] arr, int index, List result) {
+ if (index == arr.length) {
+ result.add(arr.clone());
+ }
+ for (int i = index; i < arr.length; i++) {
+ swap(index, i, arr);
+ backtracking(arr, index + 1, result);
+ swap(index, i, arr);
+ }
+ }
+
+ /**
+ * Swap two element for a given array
+ * @param a first index
+ * @param b second index
+ * @param arr the array.
+ * @param the type of elements in the array.
+ */
+ private static void swap(int a, int b, T[] arr) {
+ T temp = arr[a];
+ arr[a] = arr[b];
+ arr[b] = temp;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/PowerSum.java b/src/main/java/com/thealgorithms/backtracking/PowerSum.java
index bbaf83ecaa98..b34ba660ebd7 100644
--- a/src/main/java/com/thealgorithms/backtracking/PowerSum.java
+++ b/src/main/java/com/thealgorithms/backtracking/PowerSum.java
@@ -1,55 +1,51 @@
package com.thealgorithms.backtracking;
-import java.util.Scanner;
-
-/*
- * Problem Statement :
- * Find the number of ways that a given integer, N , can be expressed as the sum of the Xth powers of unique, natural numbers.
- * For example, if N=100 and X=3, we have to find all combinations of unique cubes adding up to 100. The only solution is 1^3+2^3+3^3+4^3.
- * Therefore output will be 1.
+/**
+ * Problem Statement:
+ * Find the number of ways that a given integer, N, can be expressed as the sum of the Xth powers
+ * of unique, natural numbers.
+ * For example, if N=100 and X=3, we have to find all combinations of unique cubes adding up to 100.
+ * The only solution is 1^3 + 2^3 + 3^3 + 4^3. Therefore, the output will be 1.
+ *
+ * N is represented by the parameter 'targetSum' in the code.
+ * X is represented by the parameter 'power' in the code.
*/
public class PowerSum {
- public static void main(String[] args) {
- Scanner sc = new Scanner(System.in);
- System.out.println("Enter the number and the power");
- int N = sc.nextInt();
- int X = sc.nextInt();
- PowerSum ps = new PowerSum();
- int count = ps.powSum(N, X);
- //printing the answer.
- System.out.println("Number of combinations of different natural number's raised to " + X + " having sum " + N + " are : ");
- System.out.println(count);
- sc.close();
+ /**
+ * Calculates the number of ways to express the target sum as a sum of Xth powers of unique natural numbers.
+ *
+ * @param targetSum The target sum to achieve (N in the problem statement)
+ * @param power The power to raise natural numbers to (X in the problem statement)
+ * @return The number of ways to express the target sum
+ */
+ public int powSum(int targetSum, int power) {
+ // Special case: when both targetSum and power are zero
+ if (targetSum == 0 && power == 0) {
+ return 1; // by convention, one way to sum to zero: use nothing
+ }
+ return sumRecursive(targetSum, power, 1, 0);
}
- private int count = 0, sum = 0;
- public int powSum(int N, int X) {
- Sum(N, X, 1);
- return count;
- }
+ /**
+ * Recursively calculates the number of ways to express the remaining sum as a sum of Xth powers.
+ *
+ * @param remainingSum The remaining sum to achieve
+ * @param power The power to raise natural numbers to (X in the problem statement)
+ * @param currentNumber The current natural number being considered
+ * @param currentSum The current sum of powered numbers
+ * @return The number of valid combinations
+ */
+ private int sumRecursive(int remainingSum, int power, int currentNumber, int currentSum) {
+ int newSum = currentSum + (int) Math.pow(currentNumber, power);
- //here i is the natural number which will be raised by X and added in sum.
- public void Sum(int N, int X, int i) {
- //if sum is equal to N that is one of our answer and count is increased.
- if (sum == N) {
- count++;
- return;
- } //we will be adding next natural number raised to X only if on adding it in sum the result is less than N.
- else if (sum + power(i, X) <= N) {
- sum += power(i, X);
- Sum(N, X, i + 1);
- //backtracking and removing the number added last since no possible combination is there with it.
- sum -= power(i, X);
+ if (newSum == remainingSum) {
+ return 1;
}
- if (power(i, X) < N) {
- //calling the sum function with next natural number after backtracking if when it is raised to X is still less than X.
- Sum(N, X, i + 1);
+ if (newSum > remainingSum) {
+ return 0;
}
- }
- //creating a separate power function so that it can be used again and again when required.
- private int power(int a, int b) {
- return (int) Math.pow(a, b);
+ return sumRecursive(remainingSum, power, currentNumber + 1, newSum) + sumRecursive(remainingSum, power, currentNumber + 1, currentSum);
}
}
diff --git a/src/main/java/com/thealgorithms/backtracking/SubsequenceFinder.java b/src/main/java/com/thealgorithms/backtracking/SubsequenceFinder.java
new file mode 100644
index 000000000000..4a159dbfe0b1
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/SubsequenceFinder.java
@@ -0,0 +1,54 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class generates all subsequences for a given list of elements using backtracking
+ */
+public final class SubsequenceFinder {
+ private SubsequenceFinder() {
+ }
+
+ /**
+ * Find all subsequences of given list using backtracking
+ *
+ * @param sequence a list of items on the basis of which we need to generate all subsequences
+ * @param the type of elements in the array
+ * @return a list of all subsequences
+ */
+ public static List> generateAll(List sequence) {
+ List> allSubSequences = new ArrayList<>();
+ if (sequence.isEmpty()) {
+ allSubSequences.add(new ArrayList<>());
+ return allSubSequences;
+ }
+ List currentSubsequence = new ArrayList<>();
+ backtrack(sequence, currentSubsequence, 0, allSubSequences);
+ return allSubSequences;
+ }
+
+ /**
+ * Iterate through each branch of states
+ * We know that each state has exactly two branching
+ * It terminates when it reaches the end of the given sequence
+ *
+ * @param sequence all elements
+ * @param currentSubsequence current subsequence
+ * @param index current index
+ * @param allSubSequences contains all sequences
+ * @param the type of elements which we generate
+ */
+ private static void backtrack(List sequence, List currentSubsequence, final int index, List> allSubSequences) {
+ assert index <= sequence.size();
+ if (index == sequence.size()) {
+ allSubSequences.add(new ArrayList<>(currentSubsequence));
+ return;
+ }
+
+ backtrack(sequence, currentSubsequence, index + 1, allSubSequences);
+ currentSubsequence.add(sequence.get(index));
+ backtrack(sequence, currentSubsequence, index + 1, allSubSequences);
+ currentSubsequence.removeLast();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java b/src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java
new file mode 100644
index 000000000000..1854cab20a7f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java
@@ -0,0 +1,86 @@
+package com.thealgorithms.backtracking;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Class to determine if a pattern matches a string using backtracking.
+ *
+ * Example:
+ * Pattern: "abab"
+ * Input String: "JavaPythonJavaPython"
+ * Output: true
+ *
+ * Pattern: "aaaa"
+ * Input String: "JavaJavaJavaJava"
+ * Output: true
+ *
+ * Pattern: "aabb"
+ * Input String: "JavaPythonPythonJava"
+ * Output: false
+ */
+public final class WordPatternMatcher {
+ private WordPatternMatcher() {
+ }
+
+ /**
+ * Determines if the given pattern matches the input string using backtracking.
+ *
+ * @param pattern The pattern to match.
+ * @param inputString The string to match against the pattern.
+ * @return True if the pattern matches the string, False otherwise.
+ */
+ public static boolean matchWordPattern(String pattern, String inputString) {
+ Map patternMap = new HashMap<>();
+ Map strMap = new HashMap<>();
+ return backtrack(pattern, inputString, 0, 0, patternMap, strMap);
+ }
+
+ /**
+ * Backtracking helper function to check if the pattern matches the string.
+ *
+ * @param pattern The pattern string.
+ * @param inputString The string to match against the pattern.
+ * @param patternIndex Current index in the pattern.
+ * @param strIndex Current index in the input string.
+ * @param patternMap Map to store pattern characters to string mappings.
+ * @param strMap Map to store string to pattern character mappings.
+ * @return True if the pattern matches, False otherwise.
+ */
+ private static boolean backtrack(String pattern, String inputString, int patternIndex, int strIndex, Map patternMap, Map strMap) {
+ if (patternIndex == pattern.length() && strIndex == inputString.length()) {
+ return true;
+ }
+ if (patternIndex == pattern.length() || strIndex == inputString.length()) {
+ return false;
+ }
+
+ char currentChar = pattern.charAt(patternIndex);
+ if (patternMap.containsKey(currentChar)) {
+ String mappedStr = patternMap.get(currentChar);
+ if (inputString.startsWith(mappedStr, strIndex)) {
+ return backtrack(pattern, inputString, patternIndex + 1, strIndex + mappedStr.length(), patternMap, strMap);
+ } else {
+ return false;
+ }
+ }
+
+ for (int end = strIndex + 1; end <= inputString.length(); end++) {
+ String substring = inputString.substring(strIndex, end);
+ if (strMap.containsKey(substring)) {
+ continue;
+ }
+
+ patternMap.put(currentChar, substring);
+ strMap.put(substring, currentChar);
+ if (backtrack(pattern, inputString, patternIndex + 1, end, patternMap, strMap)) {
+ return true;
+ }
+
+ patternMap.remove(currentChar);
+ strMap.remove(substring);
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/WordSearch.java b/src/main/java/com/thealgorithms/backtracking/WordSearch.java
new file mode 100644
index 000000000000..174ca90ccaab
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/WordSearch.java
@@ -0,0 +1,109 @@
+package com.thealgorithms.backtracking;
+
+/**
+ * Word Search Problem
+ *
+ * This class solves the word search problem where given an m x n grid of characters (board)
+ * and a target word, the task is to check if the word exists in the grid.
+ * The word can be constructed from sequentially adjacent cells (horizontally or vertically),
+ * and the same cell may not be used more than once in constructing the word.
+ *
+ * Example:
+ * - For board =
+ * [
+ * ['A','B','C','E'],
+ * ['S','F','C','S'],
+ * ['A','D','E','E']
+ * ]
+ * and word = "ABCCED", -> returns true
+ * and word = "SEE", -> returns true
+ * and word = "ABCB", -> returns false
+ *
+ * Solution:
+ * - Depth First Search (DFS) with backtracking is used to explore possible paths from any cell
+ * matching the first letter of the word. DFS ensures that we search all valid paths, while
+ * backtracking helps in reverting decisions when a path fails to lead to a solution.
+ *
+ * Time Complexity: O(m * n * 3^L)
+ * - m = number of rows in the board
+ * - n = number of columns in the board
+ * - L = length of the word
+ * - For each cell, we look at 3 possible directions (since we exclude the previously visited direction),
+ * and we do this for L letters.
+ *
+ * Space Complexity: O(L)
+ * - Stack space for the recursive DFS function, where L is the maximum depth of recursion (length of the word).
+ */
+public class WordSearch {
+ private final int[] dx = {0, 0, 1, -1};
+ private final int[] dy = {1, -1, 0, 0};
+ private boolean[][] visited;
+ private char[][] board;
+ private String word;
+
+ /**
+ * Checks if the given (x, y) coordinates are valid positions in the board.
+ *
+ * @param x The row index.
+ * @param y The column index.
+ * @return True if the coordinates are within the bounds of the board; false otherwise.
+ */
+ private boolean isValid(int x, int y) {
+ return x >= 0 && x < board.length && y >= 0 && y < board[0].length;
+ }
+
+ /**
+ * Performs Depth First Search (DFS) from the cell (x, y)
+ * to search for the next character in the word.
+ *
+ * @param x The current row index.
+ * @param y The current column index.
+ * @param nextIdx The index of the next character in the word to be matched.
+ * @return True if a valid path is found to match the remaining characters of the word; false otherwise.
+ */
+ private boolean doDFS(int x, int y, int nextIdx) {
+ visited[x][y] = true;
+ if (nextIdx == word.length()) {
+ return true;
+ }
+
+ for (int i = 0; i < 4; ++i) {
+ int xi = x + dx[i];
+ int yi = y + dy[i];
+ if (isValid(xi, yi) && board[xi][yi] == word.charAt(nextIdx) && !visited[xi][yi]) {
+ boolean exists = doDFS(xi, yi, nextIdx + 1);
+ if (exists) {
+ return true;
+ }
+ }
+ }
+
+ visited[x][y] = false; // Backtrack
+ return false;
+ }
+
+ /**
+ * Main function to check if the word exists in the board. It initiates DFS from any
+ * cell that matches the first character of the word.
+ *
+ * @param board The 2D grid of characters (the board).
+ * @param word The target word to search for in the board.
+ * @return True if the word exists in the board; false otherwise.
+ */
+ public boolean exist(char[][] board, String word) {
+ this.board = board;
+ this.word = word;
+ for (int i = 0; i < board.length; ++i) {
+ for (int j = 0; j < board[0].length; ++j) {
+ if (board[i][j] == word.charAt(0)) {
+ visited = new boolean[board.length][board[0].length];
+ boolean exists = doDFS(i, j, 1);
+ if (exists) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BcdConversion.java b/src/main/java/com/thealgorithms/bitmanipulation/BcdConversion.java
new file mode 100644
index 000000000000..e6bd35720d9f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/BcdConversion.java
@@ -0,0 +1,82 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides methods to convert between BCD (Binary-Coded Decimal) and decimal numbers.
+ *
+ * BCD is a class of binary encodings of decimal numbers where each decimal digit is represented by a fixed number of binary digits, usually four or eight.
+ *
+ * For more information, refer to the
+ * Binary-Coded Decimal Wikipedia page.
+ *
+ * Example usage:
+ *
+ * int decimal = BcdConversion.bcdToDecimal(0x1234);
+ * System.out.println("BCD 0x1234 to decimal: " + decimal); // Output: 1234
+ *
+ * int bcd = BcdConversion.decimalToBcd(1234);
+ * System.out.println("Decimal 1234 to BCD: " + Integer.toHexString(bcd)); // Output: 0x1234
+ *
+ */
+public final class BcdConversion {
+ private BcdConversion() {
+ }
+
+ /**
+ * Converts a BCD (Binary-Coded Decimal) number to a decimal number.
+ * Steps:
+ *
1. Validate the BCD number to ensure all digits are between 0 and 9.
+ *
2. Extract the last 4 bits (one BCD digit) from the BCD number.
+ *
3. Multiply the extracted digit by the corresponding power of 10 and add it to the decimal number.
+ *
4. Shift the BCD number right by 4 bits to process the next BCD digit.
+ *
5. Repeat steps 1-4 until the BCD number is zero.
+ *
+ * @param bcd The BCD number.
+ * @return The corresponding decimal number.
+ * @throws IllegalArgumentException if the BCD number contains invalid digits.
+ */
+ public static int bcdToDecimal(int bcd) {
+ int decimal = 0;
+ int multiplier = 1;
+
+ // Validate BCD digits
+ while (bcd > 0) {
+ int digit = bcd & 0xF;
+ if (digit > 9) {
+ throw new IllegalArgumentException("Invalid BCD digit: " + digit);
+ }
+ decimal += digit * multiplier;
+ multiplier *= 10;
+ bcd >>= 4;
+ }
+ return decimal;
+ }
+
+ /**
+ * Converts a decimal number to BCD (Binary-Coded Decimal).
+ *
Steps:
+ *
1. Check if the decimal number is within the valid range for BCD (0 to 9999).
+ *
2. Extract the last decimal digit from the decimal number.
+ *
3. Shift the digit to the correct BCD position and add it to the BCD number.
+ *
4. Remove the last decimal digit from the decimal number.
+ *
5. Repeat steps 2-4 until the decimal number is zero.
+ *
+ * @param decimal The decimal number.
+ * @return The corresponding BCD number.
+ * @throws IllegalArgumentException if the decimal number is greater than 9999.
+ */
+ public static int decimalToBcd(int decimal) {
+ if (decimal < 0 || decimal > 9999) {
+ throw new IllegalArgumentException("Value out of bounds for BCD representation: " + decimal);
+ }
+
+ int bcd = 0;
+ int shift = 0;
+ while (decimal > 0) {
+ int digit = decimal % 10;
+ bcd |= (digit << (shift * 4));
+ decimal /= 10;
+ shift++;
+ }
+ return bcd;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java b/src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java
new file mode 100644
index 000000000000..0d6fd140c720
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java
@@ -0,0 +1,43 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class contains a method to check if the binary representation of a number is a palindrome.
+ *
+ * A binary palindrome is a number whose binary representation is the same when read from left to right and right to left.
+ * For example, the number 9 has a binary representation of 1001, which is a palindrome.
+ * The number 10 has a binary representation of 1010, which is not a palindrome.
+ *
+ *
+ * @author Hardvan
+ */
+public final class BinaryPalindromeCheck {
+ private BinaryPalindromeCheck() {
+ }
+
+ /**
+ * Checks if the binary representation of a number is a palindrome.
+ *
+ * @param x The number to check.
+ * @return True if the binary representation is a palindrome, otherwise false.
+ */
+ public static boolean isBinaryPalindrome(int x) {
+ int reversed = reverseBits(x);
+ return x == reversed;
+ }
+
+ /**
+ * Helper function to reverse all the bits of an integer.
+ *
+ * @param x The number to reverse the bits of.
+ * @return The number with reversed bits.
+ */
+ private static int reverseBits(int x) {
+ int result = 0;
+ while (x > 0) {
+ result <<= 1;
+ result |= (x & 1);
+ x >>= 1;
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java b/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java
new file mode 100644
index 000000000000..634c9e7b3b44
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java
@@ -0,0 +1,33 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Utility class for performing bit-swapping operations on integers.
+ * This class cannot be instantiated.
+ */
+public final class BitSwap {
+ private BitSwap() {
+ }
+
+ /**
+ * Swaps two bits at specified positions in an integer.
+ *
+ * @param data The input integer whose bits need to be swapped
+ * @param posA The position of the first bit (0-based, from least significant)
+ * @param posB The position of the second bit (0-based, from least significant)
+ * @return The modified value with swapped bits
+ * @throws IllegalArgumentException if either position is negative or ≥ 32
+ */
+
+ public static int bitSwap(int data, final int posA, final int posB) {
+ if (posA < 0 || posA >= Integer.SIZE || posB < 0 || posB >= Integer.SIZE) {
+ throw new IllegalArgumentException("Bit positions must be between 0 and 31");
+ }
+
+ boolean bitA = ((data >> posA) & 1) != 0;
+ boolean bitB = ((data >> posB) & 1) != 0;
+ if (bitA != bitB) {
+ data ^= (1 << posA) ^ (1 << posB);
+ }
+ return data;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BitwiseGCD.java b/src/main/java/com/thealgorithms/bitmanipulation/BitwiseGCD.java
new file mode 100644
index 000000000000..516563459256
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/BitwiseGCD.java
@@ -0,0 +1,147 @@
+package com.thealgorithms.bitmanipulation;
+
+import java.math.BigInteger;
+
+/**
+ * Bitwise GCD implementation with full-range support utilities.
+ *
+ * This class provides a fast binary (Stein's) GCD implementation for {@code long}
+ * inputs and a BigInteger-backed API for full 2's-complement range support (including
+ * {@code Long.MIN_VALUE}). The {@code long} implementation is efficient and avoids
+ * division/modulo operations. For edge-cases that overflow signed-64-bit ranges
+ * (e.g., gcd(Long.MIN_VALUE, 0) = 2^63), use the BigInteger API {@code gcdBig}.
+ *
+ *
Behaviour:
+ *
+ * - {@code gcd(long,long)} : returns non-negative {@code long} gcd for inputs whose
+ * absolute values fit in signed {@code long} (i.e., not causing an unsigned 2^63 result).
+ * If the true gcd does not fit in a signed {@code long} (for example gcd(Long.MIN_VALUE,0) = 2^63)
+ * this method will delegate to BigInteger and throw {@link ArithmeticException} if the
+ * BigInteger result does not fit into a signed {@code long}.
+ * - {@code gcdBig(BigInteger, BigInteger)} : returns the exact gcd as a {@link BigInteger}
+ * and works for the full signed-64-bit range and beyond.
+ *
+ */
+public final class BitwiseGCD {
+
+ private BitwiseGCD() {
+ }
+
+ /**
+ * Computes GCD of two long values using Stein's algorithm (binary GCD).
+ * Handles negative inputs. If either input is {@code Long.MIN_VALUE} the
+ * method delegates to the BigInteger implementation and will throw {@link ArithmeticException}
+ * if the result cannot be represented as a signed {@code long}.
+ *
+ * @param a first value (may be negative)
+ * @param b second value (may be negative)
+ * @return non-negative gcd as a {@code long}
+ * @throws ArithmeticException when the exact gcd does not fit into a signed {@code long}
+ */
+ public static long gcd(long a, long b) {
+ // Trivial cases
+ if (a == 0L) {
+ return absOrThrowIfOverflow(b);
+ }
+ if (b == 0L) {
+ return absOrThrowIfOverflow(a);
+ }
+
+ // If either is Long.MIN_VALUE, absolute value doesn't fit into signed long.
+ if (a == Long.MIN_VALUE || b == Long.MIN_VALUE) {
+ // Delegate to BigInteger and try to return a long if it fits
+ BigInteger g = gcdBig(BigInteger.valueOf(a), BigInteger.valueOf(b));
+ return g.longValueExact();
+ }
+
+ // Work with non-negative long values now (safe because we excluded Long.MIN_VALUE)
+ a = (a < 0) ? -a : a;
+ b = (b < 0) ? -b : b;
+
+ // Count common factors of 2
+ int commonTwos = Long.numberOfTrailingZeros(a | b);
+
+ // Remove all factors of 2 from a
+ a >>= Long.numberOfTrailingZeros(a);
+
+ while (b != 0L) {
+ // Remove all factors of 2 from b
+ b >>= Long.numberOfTrailingZeros(b);
+
+ // Now both a and b are odd. Ensure a <= b
+ if (a > b) {
+ long tmp = a;
+ a = b;
+ b = tmp;
+ }
+
+ // b >= a; subtract a from b (result is even)
+ b = b - a;
+ }
+
+ // Restore common powers of two
+ return a << commonTwos;
+ }
+
+ /**
+ * Helper to return absolute value of x unless x == Long.MIN_VALUE, in which
+ * case we delegate to BigInteger and throw to indicate overflow.
+ */
+ private static long absOrThrowIfOverflow(long x) {
+ if (x == Long.MIN_VALUE) {
+ // |Long.MIN_VALUE| = 2^63 which does not fit into signed long
+ throw new ArithmeticException("Absolute value of Long.MIN_VALUE does not fit into signed long. Use gcdBig() for full-range support.");
+ }
+ return (x < 0) ? -x : x;
+ }
+
+ /**
+ * Computes GCD for an array of {@code long} values. Returns 0 for empty/null arrays.
+ * If any intermediate gcd cannot be represented in signed long (rare), an ArithmeticException
+ * will be thrown.
+ */
+ public static long gcd(long... values) {
+
+ if (values == null || values.length == 0) {
+ return 0L;
+ }
+ long result = values[0];
+ for (int i = 1; i < values.length; i++) {
+ result = gcd(result, values[i]);
+ if (result == 1L) {
+ return 1L; // early exit
+ }
+ }
+ return result;
+ }
+
+ /**
+ * BigInteger-backed gcd that works for the full integer range (and beyond).
+ * This is the recommended method when inputs may be Long.MIN_VALUE or when you
+ * need an exact result even if it is greater than Long.MAX_VALUE.
+ * @param a first value (may be negative)
+ * @param b second value (may be negative)
+ * @return non-negative gcd as a {@link BigInteger}
+ */
+ public static BigInteger gcdBig(BigInteger a, BigInteger b) {
+
+ if (a == null || b == null) {
+ throw new NullPointerException("Arguments must not be null");
+ }
+ return a.abs().gcd(b.abs());
+ }
+
+ /**
+ * Convenience overload that accepts signed-64 inputs and returns BigInteger gcd.
+ */
+ public static BigInteger gcdBig(long a, long b) {
+ return gcdBig(BigInteger.valueOf(a), BigInteger.valueOf(b));
+ }
+
+ /**
+ * int overload for convenience.
+ */
+ public static int gcd(int a, int b) {
+ return (int) gcd((long) a, (long) b);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java b/src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java
new file mode 100644
index 000000000000..869466320831
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java
@@ -0,0 +1,111 @@
+package com.thealgorithms.bitmanipulation;
+
+import java.util.List;
+
+/**
+ * Implements various Boolean algebra gates (AND, OR, NOT, XOR, NAND, NOR)
+ */
+public final class BooleanAlgebraGates {
+
+ private BooleanAlgebraGates() {
+ // Prevent instantiation
+ }
+
+ /**
+ * Represents a Boolean gate that takes multiple inputs and returns a result.
+ */
+ interface BooleanGate {
+ /**
+ * Evaluates the gate with the given inputs.
+ *
+ * @param inputs The input values for the gate.
+ * @return The result of the evaluation.
+ */
+ boolean evaluate(List inputs);
+ }
+
+ /**
+ * AND Gate implementation.
+ * Returns true if all inputs are true; otherwise, false.
+ */
+ static class ANDGate implements BooleanGate {
+ @Override
+ public boolean evaluate(List inputs) {
+ for (boolean input : inputs) {
+ if (!input) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * OR Gate implementation.
+ * Returns true if at least one input is true; otherwise, false.
+ */
+ static class ORGate implements BooleanGate {
+ @Override
+ public boolean evaluate(List inputs) {
+ for (boolean input : inputs) {
+ if (input) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * NOT Gate implementation (Unary operation).
+ * Negates a single input value.
+ */
+ static class NOTGate {
+ /**
+ * Evaluates the negation of the input.
+ *
+ * @param input The input value to be negated.
+ * @return The negated value.
+ */
+ public boolean evaluate(boolean input) {
+ return !input;
+ }
+ }
+
+ /**
+ * XOR Gate implementation.
+ * Returns true if an odd number of inputs are true; otherwise, false.
+ */
+ static class XORGate implements BooleanGate {
+ @Override
+ public boolean evaluate(List inputs) {
+ boolean result = false;
+ for (boolean input : inputs) {
+ result ^= input;
+ }
+ return result;
+ }
+ }
+
+ /**
+ * NAND Gate implementation.
+ * Returns true if at least one input is false; otherwise, false.
+ */
+ static class NANDGate implements BooleanGate {
+ @Override
+ public boolean evaluate(List inputs) {
+ return !new ANDGate().evaluate(inputs); // Equivalent to negation of AND
+ }
+ }
+
+ /**
+ * NOR Gate implementation.
+ * Returns true if all inputs are false; otherwise, false.
+ */
+ static class NORGate implements BooleanGate {
+ @Override
+ public boolean evaluate(List inputs) {
+ return !new ORGate().evaluate(inputs); // Equivalent to negation of OR
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java b/src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java
new file mode 100644
index 000000000000..3e9a4a21183f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java
@@ -0,0 +1,39 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * ClearLeftmostSetBit class contains a method to clear the leftmost set bit of a number.
+ * The leftmost set bit is the leftmost bit that is set to 1 in the binary representation of a number.
+ *
+ * Example:
+ * 26 (11010) -> 10 (01010)
+ * 1 (1) -> 0 (0)
+ * 7 (111) -> 3 (011)
+ * 6 (0110) -> 2 (0010)
+ *
+ * @author Hardvan
+ */
+public final class ClearLeftmostSetBit {
+ private ClearLeftmostSetBit() {
+ }
+
+ /**
+ * Clears the leftmost set bit (1) of a given number.
+ * Step 1: Find the position of the leftmost set bit
+ * Step 2: Create a mask with all bits set except for the leftmost set bit
+ * Step 3: Clear the leftmost set bit using AND with the mask
+ *
+ * @param num The input number.
+ * @return The number after clearing the leftmost set bit.
+ */
+ public static int clearLeftmostSetBit(int num) {
+ int pos = 0;
+ int temp = num;
+ while (temp > 0) {
+ temp >>= 1;
+ pos++;
+ }
+
+ int mask = ~(1 << (pos - 1));
+ return num & mask;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/CountBitsFlip.java b/src/main/java/com/thealgorithms/bitmanipulation/CountBitsFlip.java
new file mode 100644
index 000000000000..8d2c757e5e0a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/CountBitsFlip.java
@@ -0,0 +1,63 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Implementation to count number of bits to be flipped to convert A to B
+ *
+ * Problem: Given two numbers A and B, count the number of bits needed to be
+ * flipped to convert A to B.
+ *
+ * Example:
+ * A = 10 (01010 in binary)
+ * B = 20 (10100 in binary)
+ * XOR = 30 (11110 in binary) - positions where bits differ
+ * Answer: 4 bits need to be flipped
+ *
+ * Time Complexity: O(log n) - where n is the number of set bits
+ * Space Complexity: O(1)
+ *
+ *@author [Yash Rajput](https://github.com/the-yash-rajput)
+ */
+public final class CountBitsFlip {
+
+ private CountBitsFlip() {
+ throw new AssertionError("No instances.");
+ }
+
+ /**
+ * Counts the number of bits that need to be flipped to convert a to b
+ *
+ * Algorithm:
+ * 1. XOR a and b to get positions where bits differ
+ * 2. Count the number of set bits in the XOR result
+ * 3. Use Brian Kernighan's algorithm: n & (n-1) removes rightmost set bit
+ *
+ * @param a the source number
+ * @param b the target number
+ * @return the number of bits to flip to convert A to B
+ */
+ public static long countBitsFlip(long a, long b) {
+ int count = 0;
+
+ // XOR gives us positions where bits differ
+ long xorResult = a ^ b;
+
+ // Count set bits using Brian Kernighan's algorithm
+ while (xorResult != 0) {
+ xorResult = xorResult & (xorResult - 1); // Remove rightmost set bit
+ count++;
+ }
+
+ return count;
+ }
+
+ /**
+ * Alternative implementation using Long.bitCount().
+ *
+ * @param a the source number
+ * @param b the target number
+ * @return the number of bits to flip to convert a to b
+ */
+ public static long countBitsFlipAlternative(long a, long b) {
+ return Long.bitCount(a ^ b);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java b/src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java
new file mode 100644
index 000000000000..318334f0b951
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java
@@ -0,0 +1,39 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * CountLeadingZeros class contains a method to count the number of leading zeros in the binary representation of a number.
+ * The number of leading zeros is the number of zeros before the leftmost 1 bit.
+ * For example, the number 5 has 29 leading zeros in its 32-bit binary representation.
+ * The number 0 has 32 leading zeros.
+ * The number 1 has 31 leading zeros.
+ * The number -1 has no leading zeros.
+ *
+ * @author Hardvan
+ */
+public final class CountLeadingZeros {
+ private CountLeadingZeros() {
+ }
+
+ /**
+ * Counts the number of leading zeros in the binary representation of a number.
+ * Method: Keep shifting the mask to the right until the leftmost bit is 1.
+ * The number of shifts is the number of leading zeros.
+ *
+ * @param num The input number.
+ * @return The number of leading zeros.
+ */
+ public static int countLeadingZeros(int num) {
+ if (num == 0) {
+ return 32;
+ }
+
+ int count = 0;
+ int mask = 1 << 31;
+ while ((mask & num) == 0) {
+ count++;
+ mask >>>= 1;
+ }
+
+ return count;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java b/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java
new file mode 100644
index 000000000000..242f35fc35f2
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java
@@ -0,0 +1,79 @@
+package com.thealgorithms.bitmanipulation;
+
+public class CountSetBits {
+
+ /**
+ * The below algorithm is called as Brian Kernighan's algorithm
+ * We can use Brian Kernighan’s algorithm to improve the above naive algorithm’s performance.
+ The idea is to only consider the set bits of an integer by turning off its rightmost set bit
+ (after counting it), so the next iteration of the loop considers the next rightmost bit.
+
+ The expression n & (n-1) can be used to turn off the rightmost set bit of a number n. This
+ works as the expression n-1 flips all the bits after the rightmost set bit of n, including the
+ rightmost set bit itself. Therefore, n & (n-1) results in the last bit flipped of n.
+
+ For example, consider number 52, which is 00110100 in binary, and has a total 3 bits set.
+
+ 1st iteration of the loop: n = 52
+
+ 00110100 & (n)
+ 00110011 (n-1)
+ ~~~~~~~~
+ 00110000
+
+
+ 2nd iteration of the loop: n = 48
+
+ 00110000 & (n)
+ 00101111 (n-1)
+ ~~~~~~~~
+ 00100000
+
+
+ 3rd iteration of the loop: n = 32
+
+ 00100000 & (n)
+ 00011111 (n-1)
+ ~~~~~~~~
+ 00000000 (n = 0)
+
+ * @param num takes Long number whose number of set bit is to be found
+ * @return the count of set bits in the binary equivalent
+ */
+ public long countSetBits(long num) {
+ long cnt = 0;
+ while (num > 0) {
+ cnt++;
+ num &= (num - 1);
+ }
+ return cnt;
+ }
+
+ /**
+ * This approach takes O(1) running time to count the set bits, but requires a pre-processing.
+ *
+ * So, we divide our 32-bit input into 8-bit chunks, with four chunks. We have 8 bits in each chunk.
+ *
+ * Then the range is from 0-255 (0 to 2^7).
+ * So, we may need to count set bits from 0 to 255 in individual chunks.
+ *
+ * @param num takes a long number
+ * @return the count of set bits in the binary equivalent
+ */
+ public int lookupApproach(int num) {
+ int[] table = new int[256];
+ table[0] = 0;
+
+ for (int i = 1; i < 256; i++) {
+ table[i] = (i & 1) + table[i >> 1]; // i >> 1 equals to i/2
+ }
+
+ int res = 0;
+ for (int i = 0; i < 4; i++) {
+ res += table[num & 0xff];
+ num >>= 8;
+ }
+
+ return res;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/FindNthBit.java b/src/main/java/com/thealgorithms/bitmanipulation/FindNthBit.java
new file mode 100644
index 000000000000..7a35fc3feebf
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/FindNthBit.java
@@ -0,0 +1,46 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * A utility class to find the Nth bit of a given number.
+ *
+ * This class provides a method to extract the value of the Nth bit (either 0 or 1)
+ * from the binary representation of a given integer.
+ *
+ *
Example:
+ *
{@code
+ * int result = FindNthBit.findNthBit(5, 2); // returns 0 as the 2nd bit of 5 (binary 101) is 0.
+ * }
+ *
+ * Author: Tuhinm2002
+ */
+public final class FindNthBit {
+
+ /**
+ * Private constructor to prevent instantiation.
+ *
+ *
This is a utility class, and it should not be instantiated.
+ * Attempting to instantiate this class will throw an UnsupportedOperationException.
+ */
+ private FindNthBit() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ /**
+ * Finds the value of the Nth bit of the given number.
+ *
+ *
This method uses bitwise operations to extract the Nth bit from the
+ * binary representation of the given integer.
+ *
+ * @param num the integer number whose Nth bit is to be found
+ * @param n the bit position (1-based) to retrieve
+ * @return the value of the Nth bit (0 or 1)
+ * @throws IllegalArgumentException if the bit position is less than 1
+ */
+ public static int findNthBit(int num, int n) {
+ if (n < 1) {
+ throw new IllegalArgumentException("Bit position must be greater than or equal to 1.");
+ }
+ // Shifting the number to the right by (n - 1) positions and checking the last bit
+ return (num & (1 << (n - 1))) >> (n - 1);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/FirstDifferentBit.java b/src/main/java/com/thealgorithms/bitmanipulation/FirstDifferentBit.java
new file mode 100644
index 000000000000..9a761c572e2c
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/FirstDifferentBit.java
@@ -0,0 +1,33 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to find the first differing bit
+ * between two integers.
+ *
+ * Example:
+ * x = 10 (1010 in binary)
+ * y = 12 (1100 in binary)
+ * The first differing bit is at index 1 (0-based)
+ * So, the output will be 1
+ *
+ * @author Hardvan
+ */
+public final class FirstDifferentBit {
+ private FirstDifferentBit() {
+ }
+
+ /**
+ * Identifies the index of the first differing bit between two integers.
+ * Steps:
+ * 1. XOR the two integers to get the differing bits
+ * 2. Find the index of the first set bit in XOR result
+ *
+ * @param x the first integer
+ * @param y the second integer
+ * @return the index of the first differing bit (0-based)
+ */
+ public static int firstDifferentBit(int x, int y) {
+ int diff = x ^ y;
+ return Integer.numberOfTrailingZeros(diff);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/GenerateSubsets.java b/src/main/java/com/thealgorithms/bitmanipulation/GenerateSubsets.java
new file mode 100644
index 000000000000..f1b812495c1b
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/GenerateSubsets.java
@@ -0,0 +1,44 @@
+package com.thealgorithms.bitmanipulation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides a method to generate all subsets (power set)
+ * of a given set using bit manipulation.
+ *
+ * @author Hardvan
+ */
+public final class GenerateSubsets {
+ private GenerateSubsets() {
+ }
+
+ /**
+ * Generates all subsets of a given set using bit manipulation.
+ * Steps:
+ * 1. Iterate over all numbers from 0 to 2^n - 1.
+ * 2. For each number, iterate over all bits from 0 to n - 1.
+ * 3. If the i-th bit of the number is set, add the i-th element of the set to the current subset.
+ * 4. Add the current subset to the list of subsets.
+ * 5. Return the list of subsets.
+ *
+ * @param set the input set of integers
+ * @return a list of all subsets represented as lists of integers
+ */
+ public static List> generateSubsets(int[] set) {
+ int n = set.length;
+ List> subsets = new ArrayList<>();
+
+ for (int mask = 0; mask < (1 << n); mask++) {
+ List subset = new ArrayList<>();
+ for (int i = 0; i < n; i++) {
+ if ((mask & (1 << i)) != 0) {
+ subset.add(set[i]);
+ }
+ }
+ subsets.add(subset);
+ }
+
+ return subsets;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java b/src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java
new file mode 100644
index 000000000000..83cd30c7d50a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java
@@ -0,0 +1,44 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Gray code is a binary numeral system where two successive values differ in only one bit.
+ * This is a simple conversion between binary and Gray code.
+ * Example:
+ * 7 -> 0111 -> 0100 -> 4
+ * 4 -> 0100 -> 0111 -> 7
+ * 0 -> 0000 -> 0000 -> 0
+ * 1 -> 0001 -> 0000 -> 0
+ * 2 -> 0010 -> 0011 -> 3
+ * 3 -> 0011 -> 0010 -> 2
+ *
+ * @author Hardvan
+ */
+public final class GrayCodeConversion {
+ private GrayCodeConversion() {
+ }
+
+ /**
+ * Converts a binary number to Gray code.
+ *
+ * @param num The binary number.
+ * @return The corresponding Gray code.
+ */
+ public static int binaryToGray(int num) {
+ return num ^ (num >> 1);
+ }
+
+ /**
+ * Converts a Gray code number back to binary.
+ *
+ * @param gray The Gray code number.
+ * @return The corresponding binary number.
+ */
+ public static int grayToBinary(int gray) {
+ int binary = gray;
+ while (gray > 0) {
+ gray >>= 1;
+ binary ^= gray;
+ }
+ return binary;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java b/src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java
new file mode 100644
index 000000000000..4c24909ef234
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java
@@ -0,0 +1,29 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * The Hamming distance between two integers is the number of positions at which the corresponding bits are different.
+ * Given two integers x and y, calculate the Hamming distance.
+ * Example:
+ * Input: x = 1, y = 4
+ * Output: 2
+ * Explanation: 1 (0001) and 4 (0100) have 2 differing bits.
+ *
+ * @author Hardvan
+ */
+public final class HammingDistance {
+ private HammingDistance() {
+ }
+
+ /**
+ * Calculates the Hamming distance between two integers.
+ * The Hamming distance is the number of differing bits between the two integers.
+ *
+ * @param x The first integer.
+ * @param y The second integer.
+ * @return The Hamming distance (number of differing bits).
+ */
+ public static int hammingDistance(int x, int y) {
+ int xor = x ^ y;
+ return Integer.bitCount(xor);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwo.java b/src/main/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwo.java
new file mode 100644
index 000000000000..0fb058b2b8a3
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwo.java
@@ -0,0 +1,54 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * HigherLowerPowerOfTwo class has two methods to find the next higher and lower power of two.
+ *
+ * nextHigherPowerOfTwo method finds the next higher power of two.
+ * nextLowerPowerOfTwo method finds the next lower power of two.
+ * Both methods take an integer as input and return the next higher or lower power of two.
+ * If the input is less than 1, the next higher power of two is 1.
+ * If the input is less than or equal to 1, the next lower power of two is 0.
+ * nextHigherPowerOfTwo method uses bitwise operations to find the next higher power of two.
+ * nextLowerPowerOfTwo method uses Integer.highestOneBit method to find the next lower power of two.
+ * The time complexity of both methods is O(1).
+ * The space complexity of both methods is O(1).
+ *
+ *
+ * @author Hardvan
+ */
+public final class HigherLowerPowerOfTwo {
+ private HigherLowerPowerOfTwo() {
+ }
+
+ /**
+ * Finds the next higher power of two.
+ *
+ * @param x The given number.
+ * @return The next higher power of two.
+ */
+ public static int nextHigherPowerOfTwo(int x) {
+ if (x < 1) {
+ return 1;
+ }
+ x--;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ return x + 1;
+ }
+
+ /**
+ * Finds the next lower power of two.
+ *
+ * @param x The given number.
+ * @return The next lower power of two.
+ */
+ public static int nextLowerPowerOfTwo(int x) {
+ if (x < 1) {
+ return 0;
+ }
+ return Integer.highestOneBit(x);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java b/src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java
new file mode 100644
index 000000000000..2398b8214371
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java
@@ -0,0 +1,54 @@
+package com.thealgorithms.bitmanipulation;
+
+import java.util.Optional;
+
+/**
+ * Find Highest Set Bit
+ *
+ * This class provides a utility method to calculate the position of the highest
+ * (most significant) bit that is set to 1 in a given non-negative integer.
+ * It is often used in bit manipulation tasks to find the left-most set bit in binary
+ * representation of a number.
+ *
+ * Example:
+ * - For input 18 (binary 10010), the highest set bit is at position 4 (zero-based index).
+ *
+ * @author Bama Charan Chhandogi
+ * @version 1.0
+ * @since 2021-06-23
+ */
+public final class HighestSetBit {
+
+ private HighestSetBit() {
+ }
+
+ /**
+ * Finds the highest (most significant) set bit in the given integer.
+ * The method returns the position (index) of the highest set bit as an {@link Optional}.
+ *
+ * - If the number is 0, no bits are set, and the method returns {@link Optional#empty()}.
+ * - If the number is negative, the method throws {@link IllegalArgumentException}.
+ *
+ * @param num The input integer for which the highest set bit is to be found. It must be non-negative.
+ * @return An {@link Optional} containing the index of the highest set bit (zero-based).
+ * Returns {@link Optional#empty()} if the number is 0.
+ * @throws IllegalArgumentException if the input number is negative.
+ */
+ public static Optional findHighestSetBit(int num) {
+ if (num < 0) {
+ throw new IllegalArgumentException("Input cannot be negative");
+ }
+
+ if (num == 0) {
+ return Optional.empty();
+ }
+
+ int position = 0;
+ while (num > 0) {
+ num >>= 1;
+ position++;
+ }
+
+ return Optional.of(position - 1); // Subtract 1 to convert to zero-based index
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java b/src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java
new file mode 100644
index 000000000000..1b8962344ea7
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java
@@ -0,0 +1,44 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Utility class for bit manipulation operations.
+ * This class provides methods to work with bitwise operations.
+ * Specifically, it includes a method to find the index of the rightmost set bit
+ * in an integer.
+ * This class is not meant to be instantiated.
+ *
+ * Author: Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ */
+public final class IndexOfRightMostSetBit {
+
+ private IndexOfRightMostSetBit() {
+ }
+
+ /**
+ * Finds the index of the rightmost set bit in the given integer.
+ * The index is zero-based, meaning the rightmost bit has an index of 0.
+ *
+ * @param n the integer to check for the rightmost set bit
+ * @return the index of the rightmost set bit; -1 if there are no set bits
+ * (i.e., the input integer is 0)
+ */
+ public static int indexOfRightMostSetBit(int n) {
+ if (n == 0) {
+ return -1; // No set bits
+ }
+
+ // Handle negative numbers by finding the two's complement
+ if (n < 0) {
+ n = -n;
+ n = n & (~n + 1); // Isolate the rightmost set bit
+ }
+
+ int index = 0;
+ while ((n & 1) == 0) {
+ n = n >> 1;
+ index++;
+ }
+
+ return index;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/IsEven.java b/src/main/java/com/thealgorithms/bitmanipulation/IsEven.java
new file mode 100644
index 000000000000..09d5383322ff
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/IsEven.java
@@ -0,0 +1,14 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Checks whether a number is even
+ * @author Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ */
+
+public final class IsEven {
+ private IsEven() {
+ }
+ public static boolean isEven(int number) {
+ return (number & 1) == 0;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/IsPowerTwo.java b/src/main/java/com/thealgorithms/bitmanipulation/IsPowerTwo.java
new file mode 100644
index 000000000000..4cdf3c6faa3e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/IsPowerTwo.java
@@ -0,0 +1,32 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Utility class for checking if a number is a power of two.
+ * A power of two is a number that can be expressed as 2^n where n is a non-negative integer.
+ * This class provides a method to determine if a given integer is a power of two using bit manipulation.
+ *
+ * @author Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ */
+public final class IsPowerTwo {
+ private IsPowerTwo() {
+ }
+
+ /**
+ * Checks if the given integer is a power of two.
+ *
+ * A number is considered a power of two if it is greater than zero and
+ * has exactly one '1' bit in its binary representation. This method
+ * uses the property that for any power of two (n), the expression
+ * (n & (n - 1)) will be zero.
+ *
+ * @param number the integer to check
+ * @return true if the number is a power of two, false otherwise
+ */
+ public static boolean isPowerTwo(int number) {
+ if (number <= 0) {
+ return false;
+ }
+ int ans = number & (number - 1);
+ return ans == 0;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/LowestSetBit.java b/src/main/java/com/thealgorithms/bitmanipulation/LowestSetBit.java
new file mode 100644
index 000000000000..127b6fa2c0b1
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/LowestSetBit.java
@@ -0,0 +1,34 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Lowest Set Bit
+ * @author Prayas Kumar (https://github.com/prayas7102)
+ */
+
+public final class LowestSetBit {
+ // Private constructor to hide the default public one
+ private LowestSetBit() {
+ }
+ /**
+ * Isolates the lowest set bit of the given number. For example, if n = 18
+ * (binary: 10010), the result will be 2 (binary: 00010).
+ *
+ * @param n the number whose lowest set bit will be isolated
+ * @return the isolated lowest set bit of n
+ */
+ public static int isolateLowestSetBit(int n) {
+ // Isolate the lowest set bit using n & -n
+ return n & -n;
+ }
+ /**
+ * Clears the lowest set bit of the given number.
+ * For example, if n = 18 (binary: 10010), the result will be 16 (binary: 10000).
+ *
+ * @param n the number whose lowest set bit will be cleared
+ * @return the number after clearing its lowest set bit
+ */
+ public static int clearLowestSetBit(int n) {
+ // Clear the lowest set bit using n & (n - 1)
+ return n & (n - 1);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/ModuloPowerOfTwo.java b/src/main/java/com/thealgorithms/bitmanipulation/ModuloPowerOfTwo.java
new file mode 100644
index 000000000000..537a046f77e4
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/ModuloPowerOfTwo.java
@@ -0,0 +1,28 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to compute the remainder
+ * of a number when divided by a power of two (2^n)
+ * without using division or modulo operations.
+ *
+ * @author Hardvan
+ */
+public final class ModuloPowerOfTwo {
+ private ModuloPowerOfTwo() {
+ }
+
+ /**
+ * Computes the remainder of a given integer when divided by 2^n.
+ *
+ * @param x the input number
+ * @param n the exponent (power of two)
+ * @return the remainder of x divided by 2^n
+ */
+ public static int moduloPowerOfTwo(int x, int n) {
+ if (n <= 0) {
+ throw new IllegalArgumentException("The exponent must be positive");
+ }
+
+ return x & ((1 << n) - 1);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/NextHigherSameBitCount.java b/src/main/java/com/thealgorithms/bitmanipulation/NextHigherSameBitCount.java
new file mode 100644
index 000000000000..6a764d806279
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/NextHigherSameBitCount.java
@@ -0,0 +1,30 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to find the next higher number
+ * with the same number of set bits as the given number.
+ *
+ * @author Hardvan
+ */
+public final class NextHigherSameBitCount {
+ private NextHigherSameBitCount() {
+ }
+
+ /**
+ * Finds the next higher integer with the same number of set bits.
+ * Steps:
+ * 1. Find {@code c}, the rightmost set bit of {@code n}.
+ * 2. Find {@code r}, the rightmost set bit of {@code n + c}.
+ * 3. Swap the bits of {@code r} and {@code n} to the right of {@code c}.
+ * 4. Shift the bits of {@code r} and {@code n} to the right of {@code c} to the rightmost.
+ * 5. Combine the results of steps 3 and 4.
+ *
+ * @param n the input number
+ * @return the next higher integer with the same set bit count
+ */
+ public static int nextHigherSameBitCount(int n) {
+ int c = n & -n;
+ int r = n + c;
+ return (((r ^ n) >> 2) / c) | r;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinder.java b/src/main/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinder.java
new file mode 100644
index 000000000000..17e1a73ec062
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinder.java
@@ -0,0 +1,35 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * A utility class to find the non-repeating number in an array where every other number repeats.
+ * This class contains a method to identify the single unique number using bit manipulation.
+ *
+ * The solution leverages the properties of the XOR operation, which states that:
+ * - x ^ x = 0 for any integer x (a number XORed with itself is zero)
+ * - x ^ 0 = x for any integer x (a number XORed with zero is the number itself)
+ *
+ * Using these properties, we can find the non-repeating number in linear time with constant space.
+ *
+ * Example:
+ * Given the input array [2, 3, 5, 2, 3], the output will be 5 since it does not repeat.
+ *
+ * @author Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ */
+public final class NonRepeatingNumberFinder {
+ private NonRepeatingNumberFinder() {
+ }
+
+ /**
+ * Finds the non-repeating number in the given array.
+ *
+ * @param arr an array of integers where every number except one appears twice
+ * @return the integer that appears only once in the array or 0 if the array is empty
+ */
+ public static int findNonRepeatingNumber(int[] arr) {
+ int result = 0;
+ for (int num : arr) {
+ result ^= num;
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java b/src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java
new file mode 100644
index 000000000000..bd4868d4dbd5
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java
@@ -0,0 +1,41 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to find the element that appears an
+ * odd number of times in an array. All other elements in the array
+ * must appear an even number of times for the logic to work.
+ *
+ * The solution uses the XOR operation, which has the following properties:
+ * - a ^ a = 0 (XOR-ing the same numbers cancels them out)
+ * - a ^ 0 = a
+ * - XOR is commutative and associative.
+ *
+ * Time Complexity: O(n), where n is the size of the array.
+ * Space Complexity: O(1), as no extra space is used.
+ *
+ * Usage Example:
+ * int result = NumberAppearingOddTimes.findOddOccurrence(new int[]{1, 2, 1, 2, 3});
+ * // result will be 3
+ *
+ * @author Lakshyajeet Singh Goyal (https://github.com/DarkMatter-999)
+ */
+
+public final class NumberAppearingOddTimes {
+ private NumberAppearingOddTimes() {
+ }
+
+ /**
+ * Finds the element in the array that appears an odd number of times.
+ *
+ * @param arr the input array containing integers, where all elements
+ * except one appear an even number of times.
+ * @return the integer that appears an odd number of times.
+ */
+ public static int findOddOccurrence(int[] arr) {
+ int result = 0;
+ for (int num : arr) {
+ result ^= num;
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/NumbersDifferentSigns.java b/src/main/java/com/thealgorithms/bitmanipulation/NumbersDifferentSigns.java
new file mode 100644
index 000000000000..a2da37aa81ee
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/NumbersDifferentSigns.java
@@ -0,0 +1,30 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to determine whether two integers have
+ * different signs. It utilizes the XOR operation on the two numbers:
+ *
+ * - If two numbers have different signs, their most significant bits
+ * (sign bits) will differ, resulting in a negative XOR result.
+ * - If two numbers have the same sign, the XOR result will be non-negative.
+ *
+ * Time Complexity: O(1) - Constant time operation.
+ * Space Complexity: O(1) - No extra space used.
+ *
+ * @author Bama Charan Chhandogi
+ */
+public final class NumbersDifferentSigns {
+ private NumbersDifferentSigns() {
+ }
+
+ /**
+ * Determines if two integers have different signs using bitwise XOR.
+ *
+ * @param num1 the first integer
+ * @param num2 the second integer
+ * @return true if the two numbers have different signs, false otherwise
+ */
+ public static boolean differentSigns(int num1, int num2) {
+ return (num1 ^ num2) < 0;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/OneBitDifference.java b/src/main/java/com/thealgorithms/bitmanipulation/OneBitDifference.java
new file mode 100644
index 000000000000..afec0188e299
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/OneBitDifference.java
@@ -0,0 +1,32 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to detect if two integers
+ * differ by exactly one bit flip.
+ *
+ * Example:
+ * 1 (0001) and 2 (0010) differ by exactly one bit flip.
+ * 7 (0111) and 3 (0011) differ by exactly one bit flip.
+ *
+ * @author Hardvan
+ */
+public final class OneBitDifference {
+ private OneBitDifference() {
+ }
+
+ /**
+ * Checks if two integers differ by exactly one bit.
+ *
+ * @param x the first integer
+ * @param y the second integer
+ * @return true if x and y differ by exactly one bit, false otherwise
+ */
+ public static boolean differByOneBit(int x, int y) {
+ if (x == y) {
+ return false;
+ }
+
+ int xor = x ^ y;
+ return (xor & (xor - 1)) == 0;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java b/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java
new file mode 100644
index 000000000000..aae3a996e49d
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java
@@ -0,0 +1,37 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * @author - https://github.com/Monk-AbhinayVerma
+ * @Wikipedia - https://en.wikipedia.org/wiki/Ones%27_complement
+ * The class OnesComplement computes the complement of binary number
+ * and returns
+ * the complemented binary string.
+ * @return the complimented binary string
+ */
+public final class OnesComplement {
+ private OnesComplement() {
+ }
+
+ /**
+ * Returns the 1's complement of a binary string.
+ *
+ * @param binary A string representing a binary number (e.g., "1010").
+ * @return A string representing the 1's complement.
+ * @throws IllegalArgumentException if the input is null or contains characters other than '0' or '1'.
+ */
+ public static String onesComplement(String binary) {
+ if (binary == null || binary.isEmpty()) {
+ throw new IllegalArgumentException("Input must be a non-empty binary string.");
+ }
+
+ StringBuilder complement = new StringBuilder(binary.length());
+ for (char bit : binary.toCharArray()) {
+ switch (bit) {
+ case '0' -> complement.append('1');
+ case '1' -> complement.append('0');
+ default -> throw new IllegalArgumentException("Input must contain only '0' and '1'. Found: " + bit);
+ }
+ }
+ return complement.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/ParityCheck.java b/src/main/java/com/thealgorithms/bitmanipulation/ParityCheck.java
new file mode 100644
index 000000000000..5acab4d4a362
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/ParityCheck.java
@@ -0,0 +1,34 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * The ParityCheck class provides a method to check the parity of a given number.
+ *
+ * Parity is a mathematical term that describes the property of an integer's binary representation.
+ * The parity of a binary number is the number of 1s in its binary representation.
+ * If the number of 1s is even, the parity is even; otherwise, it is odd.
+ *
+ * For example, the binary representation of 5 is 101, which has two 1s, so the parity of 5 is even.
+ * The binary representation of 6 is 110, which has two 1s, so the parity of 6 is even.
+ * The binary representation of 7 is 111, which has three 1s, so the parity of 7 is odd.
+ *
+ * @author Hardvan
+ */
+public final class ParityCheck {
+ private ParityCheck() {
+ }
+
+ /**
+ * This method checks the parity of the given number.
+ *
+ * @param n the number to check the parity of
+ * @return true if the number has even parity, false otherwise
+ */
+ public static boolean checkParity(int n) {
+ int count = 0;
+ while (n > 0) {
+ count += n & 1;
+ n >>= 1;
+ }
+ return count % 2 == 0;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/ReverseBits.java b/src/main/java/com/thealgorithms/bitmanipulation/ReverseBits.java
new file mode 100644
index 000000000000..12c269d9be48
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/ReverseBits.java
@@ -0,0 +1,41 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to reverse the bits of a 32-bit integer.
+ * Reversing the bits means that the least significant bit (LSB) becomes
+ * the most significant bit (MSB) and vice versa.
+ *
+ * Example:
+ * Input (binary): 00000010100101000001111010011100 (43261596)
+ * Output (binary): 00111001011110000010100101000000 (964176192)
+ *
+ * Time Complexity: O(32) - A fixed number of 32 iterations
+ * Space Complexity: O(1) - No extra space used
+ *
+ * Note:
+ * - If the input is negative, Java handles it using two’s complement representation.
+ * - This function works on 32-bit integers by default.
+ *
+ * @author Bama Charan Chhandogi
+ */
+public final class ReverseBits {
+ private ReverseBits() {
+ }
+
+ /**
+ * Reverses the bits of a 32-bit integer.
+ *
+ * @param n the integer whose bits are to be reversed
+ * @return the integer obtained by reversing the bits of the input
+ */
+ public static int reverseBits(int n) {
+ int result = 0;
+ int bitCount = 32;
+ for (int i = 0; i < bitCount; i++) {
+ result <<= 1; // Left shift the result to make space for the next bit
+ result |= (n & 1); // OR operation to set the least significant bit of result with the current bit of n
+ n >>= 1; // Right shift n to move on to the next bit
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java b/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java
new file mode 100644
index 000000000000..624a4e2b858a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java
@@ -0,0 +1,68 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * A utility class for performing single-bit operations on integers.
+ * These operations include flipping, setting, clearing, and getting
+ * individual bits at specified positions.
+ *
+ * Bit positions are zero-indexed (i.e., the least significant bit is at position 0).
+ * These methods leverage bitwise operations for optimal performance.
+ *
+ * Examples:
+ * - `flipBit(3, 1)` flips the bit at index 1 in binary `11` (result: `1`).
+ * - `setBit(4, 0)` sets the bit at index 0 in `100` (result: `101` or 5).
+ * - `clearBit(7, 1)` clears the bit at index 1 in `111` (result: `101` or 5).
+ * - `getBit(6, 0)` checks if the least significant bit is set (result: `0`).
+ *
+ * Time Complexity: O(1) for all operations.
+ *
+ * Author: lukasb1b (https://github.com/lukasb1b)
+ */
+public final class SingleBitOperations {
+ private SingleBitOperations() {
+ }
+
+ /**
+ * Flips (toggles) the bit at the specified position.
+ *
+ * @param num the input number
+ * @param bit the position of the bit to flip (0-indexed)
+ * @return the new number after flipping the specified bit
+ */
+ public static int flipBit(final int num, final int bit) {
+ return num ^ (1 << bit);
+ }
+
+ /**
+ * Sets the bit at the specified position to 1.
+ *
+ * @param num the input number
+ * @param bit the position of the bit to set (0-indexed)
+ * @return the new number after setting the specified bit to 1
+ */
+ public static int setBit(final int num, final int bit) {
+ return num | (1 << bit);
+ }
+
+ /**
+ * Clears the bit at the specified position (sets it to 0).
+ *
+ * @param num the input number
+ * @param bit the position of the bit to clear (0-indexed)
+ * @return the new number after clearing the specified bit
+ */
+ public static int clearBit(final int num, final int bit) {
+ return num & ~(1 << bit);
+ }
+
+ /**
+ * Gets the bit value (0 or 1) at the specified position.
+ *
+ * @param num the input number
+ * @param bit the position of the bit to retrieve (0-indexed)
+ * @return 1 if the bit is set, 0 otherwise
+ */
+ public static int getBit(final int num, final int bit) {
+ return (num >> bit) & 1;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/SingleElement.java b/src/main/java/com/thealgorithms/bitmanipulation/SingleElement.java
new file mode 100644
index 000000000000..85ebdf02db25
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/SingleElement.java
@@ -0,0 +1,39 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Utility class to find the single non-duplicate element from an array
+ * where all other elements appear twice.
+ *
+ * The algorithm runs in O(n) time complexity and O(1) space complexity
+ * using bitwise XOR.
+ *
+ *
+ * @author Tuhin M
+ */
+public final class SingleElement {
+
+ /**
+ * Private constructor to prevent instantiation of this utility class.
+ * Throws an UnsupportedOperationException if attempted.
+ */
+ private SingleElement() {
+ throw new UnsupportedOperationException("Utility Class");
+ }
+
+ /**
+ * Finds the single non-duplicate element in an array where every other
+ * element appears exactly twice. Uses bitwise XOR to achieve O(n) time
+ * complexity and O(1) space complexity.
+ *
+ * @param arr the input array containing integers where every element
+ * except one appears exactly twice
+ * @return the single non-duplicate element
+ */
+ public static int findSingleElement(int[] arr) {
+ int ele = 0;
+ for (int i = 0; i < arr.length; i++) {
+ ele ^= arr[i];
+ }
+ return ele;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/SwapAdjacentBits.java b/src/main/java/com/thealgorithms/bitmanipulation/SwapAdjacentBits.java
new file mode 100644
index 000000000000..98a7de8bdf1a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/SwapAdjacentBits.java
@@ -0,0 +1,57 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * A utility class to swap every pair of adjacent bits in a given integer.
+ * This operation shifts the even-positioned bits to odd positions and vice versa.
+ *
+ * Example:
+ * - Input: 2 (binary: `10`) → Output: 1 (binary: `01`)
+ * - Input: 43 (binary: `101011`) → Output: 23 (binary: `010111`)
+ *
+ * **Explanation of the Algorithm:**
+ * 1. Mask even-positioned bits: Using `0xAAAAAAAA` (binary: `101010...`),
+ * which selects bits in even positions.
+ * 2. Mask odd-positioned bits: Using `0x55555555` (binary: `010101...`),
+ * which selects bits in odd positions.
+ * 3. Shift bits:
+ * - Right-shift even-positioned bits by 1 to move them to odd positions.
+ * - Left-shift odd-positioned bits by 1 to move them to even positions.
+ * 4. Combine both shifted results using bitwise OR (`|`) to produce the final result.
+ *
+ * Use Case: This algorithm can be useful in applications involving low-level bit manipulation,
+ * such as encoding, data compression, or cryptographic transformations.
+ *
+ * Time Complexity: O(1) (constant time, since operations are bitwise).
+ *
+ * Author: Lakshyajeet Singh Goyal (https://github.com/DarkMatter-999)
+ */
+public final class SwapAdjacentBits {
+ private SwapAdjacentBits() {
+ }
+
+ /**
+ * Swaps every pair of adjacent bits of a given integer.
+ * Steps:
+ * 1. Mask the even-positioned bits.
+ * 2. Mask the odd-positioned bits.
+ * 3. Shift the even bits to the right and the odd bits to the left.
+ * 4. Combine the shifted bits.
+ *
+ * @param num the integer whose bits are to be swapped
+ * @return the integer after swapping every pair of adjacent bits
+ */
+ public static int swapAdjacentBits(int num) {
+ // mask the even bits (0xAAAAAAAA => 10101010...)
+ int evenBits = num & 0xAAAAAAAA;
+
+ // mask the odd bits (0x55555555 => 01010101...)
+ int oddBits = num & 0x55555555;
+
+ // right shift even bits and left shift odd bits
+ evenBits >>= 1;
+ oddBits <<= 1;
+
+ // combine shifted bits
+ return evenBits | oddBits;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java b/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java
new file mode 100644
index 000000000000..9b8cecd791a6
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java
@@ -0,0 +1,62 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to compute the Two's Complement of a given binary number.
+ *
+ * In two's complement representation, a binary number's negative value is obtained
+ * by taking the one's complement (inverting all bits) and then adding 1 to the result.
+ * This method handles both small and large binary strings and ensures the output is
+ * correct for all binary inputs, including edge cases like all zeroes and all ones.
+ *
+ *
For more information on Two's Complement:
+ * @see Wikipedia - Two's Complement
+ *
+ *
Algorithm originally suggested by Jon von Neumann.
+ *
+ * @author Abhinay Verma (https://github.com/Monk-AbhinayVerma)
+ */
+public final class TwosComplement {
+ private TwosComplement() {
+ }
+
+ /**
+ * Computes the Two's Complement of the given binary string.
+ * Steps:
+ * 1. Compute the One's Complement (invert all bits).
+ * 2. Add 1 to the One's Complement to get the Two's Complement.
+ * 3. Iterate from the rightmost bit to the left, adding 1 and carrying over as needed.
+ * 4. If a carry is still present after the leftmost bit, prepend '1' to handle overflow.
+ *
+ * @param binary The binary number as a string (only '0' and '1' characters allowed).
+ * @return The two's complement of the input binary string as a new binary string.
+ * @throws IllegalArgumentException If the input contains non-binary characters.
+ */
+ public static String twosComplement(String binary) {
+ if (!binary.matches("[01]+")) {
+ throw new IllegalArgumentException("Input must contain only '0' and '1'.");
+ }
+
+ StringBuilder onesComplement = new StringBuilder();
+ for (char bit : binary.toCharArray()) {
+ onesComplement.append(bit == '0' ? '1' : '0');
+ }
+
+ StringBuilder twosComplement = new StringBuilder(onesComplement);
+ boolean carry = true;
+
+ for (int i = onesComplement.length() - 1; i >= 0 && carry; i--) {
+ if (onesComplement.charAt(i) == '1') {
+ twosComplement.setCharAt(i, '0');
+ } else {
+ twosComplement.setCharAt(i, '1');
+ carry = false;
+ }
+ }
+
+ if (carry) {
+ twosComplement.insert(0, '1');
+ }
+
+ return twosComplement.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/Xs3Conversion.java b/src/main/java/com/thealgorithms/bitmanipulation/Xs3Conversion.java
new file mode 100644
index 000000000000..b22abc0c04ff
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/Xs3Conversion.java
@@ -0,0 +1,58 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides methods to convert between XS-3 (Excess-3) and binary.
+ *
+ * Excess-3, also called XS-3, is a binary-coded decimal (BCD) code in which each decimal digit is represented by its corresponding 4-bit binary value plus 3.
+ *
+ * For more information, refer to the
+ * Excess-3 Wikipedia page.
+ *
+ * Example usage:
+ *
+ * int binary = Xs3Conversion.xs3ToBinary(0x4567);
+ * System.out.println("XS-3 0x4567 to binary: " + binary); // Output: 1234
+ *
+ * int xs3 = Xs3Conversion.binaryToXs3(1234);
+ * System.out.println("Binary 1234 to XS-3: " + Integer.toHexString(xs3)); // Output: 0x4567
+ *
+ */
+public final class Xs3Conversion {
+ private Xs3Conversion() {
+ }
+ /**
+ * Converts an XS-3 (Excess-3) number to binary.
+ *
+ * @param xs3 The XS-3 number.
+ * @return The corresponding binary number.
+ */
+ public static int xs3ToBinary(int xs3) {
+ int binary = 0;
+ int multiplier = 1;
+ while (xs3 > 0) {
+ int digit = (xs3 & 0xF) - 3; // Extract the last 4 bits (one XS-3 digit) and subtract 3
+ binary += digit * multiplier;
+ multiplier *= 10;
+ xs3 >>= 4; // Shift right by 4 bits to process the next XS-3 digit
+ }
+ return binary;
+ }
+
+ /**
+ * Converts a binary number to XS-3 (Excess-3).
+ *
+ * @param binary The binary number.
+ * @return The corresponding XS-3 number.
+ */
+ public static int binaryToXs3(int binary) {
+ int xs3 = 0;
+ int shift = 0;
+ while (binary > 0) {
+ int digit = (binary % 10) + 3; // Extract the last decimal digit and add 3
+ xs3 |= (digit << (shift * 4)); // Shift the digit to the correct XS-3 position
+ binary /= 10; // Remove the last decimal digit
+ shift++;
+ }
+ return xs3;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/ADFGVXCipher.java b/src/main/java/com/thealgorithms/ciphers/ADFGVXCipher.java
new file mode 100644
index 000000000000..d915858f9e6f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/ADFGVXCipher.java
@@ -0,0 +1,167 @@
+package com.thealgorithms.ciphers;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The ADFGVX cipher is a fractionating transposition cipher that was used by
+ * the German Army during World War I. It combines a **Polybius square substitution**
+ * with a **columnar transposition** to enhance encryption strength.
+ *
+ * The name "ADFGVX" refers to the six letters (A, D, F, G, V, X) used as row and
+ * column labels in the Polybius square. This cipher was designed to secure
+ * communication and create complex, hard-to-break ciphertexts.
+ *
+ * Learn more: ADFGVX Cipher - Wikipedia.
+ *
+ * Example usage:
+ *
+ * ADFGVXCipher cipher = new ADFGVXCipher();
+ * String encrypted = cipher.encrypt("attack at 1200am", "PRIVACY");
+ * String decrypted = cipher.decrypt(encrypted, "PRIVACY");
+ *
+ *
+ * @author bennybebo
+ */
+public class ADFGVXCipher {
+
+ // Constants used in the Polybius square
+ private static final char[] POLYBIUS_LETTERS = {'A', 'D', 'F', 'G', 'V', 'X'};
+ private static final char[][] POLYBIUS_SQUARE = {{'N', 'A', '1', 'C', '3', 'H'}, {'8', 'T', 'B', '2', 'O', 'M'}, {'E', '5', 'W', 'R', 'P', 'D'}, {'4', 'F', '6', 'G', '7', 'I'}, {'9', 'J', '0', 'K', 'L', 'Q'}, {'S', 'U', 'V', 'X', 'Y', 'Z'}};
+
+ // Maps for fast substitution lookups
+ private static final Map POLYBIUS_MAP = new HashMap<>();
+ private static final Map REVERSE_POLYBIUS_MAP = new HashMap<>();
+
+ // Static block to initialize the lookup tables from the Polybius square
+ static {
+ for (int i = 0; i < POLYBIUS_SQUARE.length; i++) {
+ for (int j = 0; j < POLYBIUS_SQUARE[i].length; j++) {
+ String key = "" + POLYBIUS_LETTERS[i] + POLYBIUS_LETTERS[j];
+ POLYBIUS_MAP.put(key, POLYBIUS_SQUARE[i][j]);
+ REVERSE_POLYBIUS_MAP.put(POLYBIUS_SQUARE[i][j], key);
+ }
+ }
+ }
+
+ /**
+ * Encrypts a given plaintext using the ADFGVX cipher with the provided keyword.
+ * Steps:
+ * 1. Substitute each letter in the plaintext with a pair of ADFGVX letters.
+ * 2. Perform a columnar transposition on the fractionated text using the keyword.
+ *
+ * @param plaintext The message to be encrypted (can contain letters and digits).
+ * @param key The keyword for columnar transposition.
+ * @return The encrypted message as ciphertext.
+ */
+ public String encrypt(String plaintext, String key) {
+ plaintext = plaintext.toUpperCase().replaceAll("[^A-Z0-9]", ""); // Sanitize input
+ StringBuilder fractionatedText = new StringBuilder();
+
+ for (char c : plaintext.toCharArray()) {
+ fractionatedText.append(REVERSE_POLYBIUS_MAP.get(c));
+ }
+
+ return columnarTransposition(fractionatedText.toString(), key);
+ }
+
+ /**
+ * Decrypts a given ciphertext using the ADFGVX cipher with the provided keyword.
+ * Steps:
+ * 1. Reverse the columnar transposition performed during encryption.
+ * 2. Substitute each pair of ADFGVX letters with the corresponding plaintext letter.
+ * The resulting text is the decrypted message.
+ *
+ * @param ciphertext The encrypted message.
+ * @param key The keyword used during encryption.
+ * @return The decrypted plaintext message.
+ */
+ public String decrypt(String ciphertext, String key) {
+ String fractionatedText = reverseColumnarTransposition(ciphertext, key);
+
+ StringBuilder plaintext = new StringBuilder();
+ for (int i = 0; i < fractionatedText.length(); i += 2) {
+ String pair = fractionatedText.substring(i, i + 2);
+ plaintext.append(POLYBIUS_MAP.get(pair));
+ }
+
+ return plaintext.toString();
+ }
+
+ /**
+ * Helper method: Performs columnar transposition during encryption
+ *
+ * @param text The fractionated text to be transposed
+ * @param key The keyword for columnar transposition
+ * @return The transposed text
+ */
+ private String columnarTransposition(String text, String key) {
+ int numRows = (int) Math.ceil((double) text.length() / key.length());
+ char[][] table = new char[numRows][key.length()];
+ for (char[] row : table) { // Fill empty cells with underscores
+ Arrays.fill(row, '_');
+ }
+
+ // Populate the table row by row
+ for (int i = 0; i < text.length(); i++) {
+ table[i / key.length()][i % key.length()] = text.charAt(i);
+ }
+
+ // Read columns based on the alphabetical order of the key
+ StringBuilder ciphertext = new StringBuilder();
+ char[] sortedKey = key.toCharArray();
+ Arrays.sort(sortedKey);
+
+ for (char keyChar : sortedKey) {
+ int column = key.indexOf(keyChar);
+ for (char[] row : table) {
+ if (row[column] != '_') {
+ ciphertext.append(row[column]);
+ }
+ }
+ }
+
+ return ciphertext.toString();
+ }
+
+ /**
+ * Helper method: Reverses the columnar transposition during decryption
+ *
+ * @param ciphertext The transposed text to be reversed
+ * @param key The keyword used during encryption
+ * @return The reversed text
+ */
+ private String reverseColumnarTransposition(String ciphertext, String key) {
+ int numRows = (int) Math.ceil((double) ciphertext.length() / key.length());
+ char[][] table = new char[numRows][key.length()];
+
+ char[] sortedKey = key.toCharArray();
+ Arrays.sort(sortedKey);
+
+ int index = 0;
+ // Populate the table column by column according to the sorted key
+ for (char keyChar : sortedKey) {
+ int column = key.indexOf(keyChar);
+ for (int row = 0; row < numRows; row++) {
+ if (index < ciphertext.length()) {
+ table[row][column] = ciphertext.charAt(index++);
+ } else {
+ table[row][column] = '_';
+ }
+ }
+ }
+
+ // Read the table row by row to reconstruct the fractionated text
+ StringBuilder fractionatedText = new StringBuilder();
+ for (char[] row : table) {
+ for (char cell : row) {
+ if (cell != '_') {
+ fractionatedText.append(cell);
+ }
+ }
+ }
+
+ return fractionatedText.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/AES.java b/src/main/java/com/thealgorithms/ciphers/AES.java
index 879523af37bc..1c283f6b7655 100644
--- a/src/main/java/com/thealgorithms/ciphers/AES.java
+++ b/src/main/java/com/thealgorithms/ciphers/AES.java
@@ -7,29 +7,271 @@
* This class is build to demonstrate the application of the AES-algorithm on a
* single 128-Bit block of data.
*/
-public class AES {
+public final class AES {
+ private AES() {
+ }
/**
* Precalculated values for x to the power of 2 in Rijndaels galois field.
* Used as 'RCON' during the key expansion.
*/
private static final int[] RCON = {
- 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
- 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
- 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
- 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
- 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
- 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
- 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
- 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
- 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
- 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
- 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
- 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
- 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
- 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
- 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
- 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d
+ 0x8d,
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x40,
+ 0x80,
+ 0x1b,
+ 0x36,
+ 0x6c,
+ 0xd8,
+ 0xab,
+ 0x4d,
+ 0x9a,
+ 0x2f,
+ 0x5e,
+ 0xbc,
+ 0x63,
+ 0xc6,
+ 0x97,
+ 0x35,
+ 0x6a,
+ 0xd4,
+ 0xb3,
+ 0x7d,
+ 0xfa,
+ 0xef,
+ 0xc5,
+ 0x91,
+ 0x39,
+ 0x72,
+ 0xe4,
+ 0xd3,
+ 0xbd,
+ 0x61,
+ 0xc2,
+ 0x9f,
+ 0x25,
+ 0x4a,
+ 0x94,
+ 0x33,
+ 0x66,
+ 0xcc,
+ 0x83,
+ 0x1d,
+ 0x3a,
+ 0x74,
+ 0xe8,
+ 0xcb,
+ 0x8d,
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x40,
+ 0x80,
+ 0x1b,
+ 0x36,
+ 0x6c,
+ 0xd8,
+ 0xab,
+ 0x4d,
+ 0x9a,
+ 0x2f,
+ 0x5e,
+ 0xbc,
+ 0x63,
+ 0xc6,
+ 0x97,
+ 0x35,
+ 0x6a,
+ 0xd4,
+ 0xb3,
+ 0x7d,
+ 0xfa,
+ 0xef,
+ 0xc5,
+ 0x91,
+ 0x39,
+ 0x72,
+ 0xe4,
+ 0xd3,
+ 0xbd,
+ 0x61,
+ 0xc2,
+ 0x9f,
+ 0x25,
+ 0x4a,
+ 0x94,
+ 0x33,
+ 0x66,
+ 0xcc,
+ 0x83,
+ 0x1d,
+ 0x3a,
+ 0x74,
+ 0xe8,
+ 0xcb,
+ 0x8d,
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x40,
+ 0x80,
+ 0x1b,
+ 0x36,
+ 0x6c,
+ 0xd8,
+ 0xab,
+ 0x4d,
+ 0x9a,
+ 0x2f,
+ 0x5e,
+ 0xbc,
+ 0x63,
+ 0xc6,
+ 0x97,
+ 0x35,
+ 0x6a,
+ 0xd4,
+ 0xb3,
+ 0x7d,
+ 0xfa,
+ 0xef,
+ 0xc5,
+ 0x91,
+ 0x39,
+ 0x72,
+ 0xe4,
+ 0xd3,
+ 0xbd,
+ 0x61,
+ 0xc2,
+ 0x9f,
+ 0x25,
+ 0x4a,
+ 0x94,
+ 0x33,
+ 0x66,
+ 0xcc,
+ 0x83,
+ 0x1d,
+ 0x3a,
+ 0x74,
+ 0xe8,
+ 0xcb,
+ 0x8d,
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x40,
+ 0x80,
+ 0x1b,
+ 0x36,
+ 0x6c,
+ 0xd8,
+ 0xab,
+ 0x4d,
+ 0x9a,
+ 0x2f,
+ 0x5e,
+ 0xbc,
+ 0x63,
+ 0xc6,
+ 0x97,
+ 0x35,
+ 0x6a,
+ 0xd4,
+ 0xb3,
+ 0x7d,
+ 0xfa,
+ 0xef,
+ 0xc5,
+ 0x91,
+ 0x39,
+ 0x72,
+ 0xe4,
+ 0xd3,
+ 0xbd,
+ 0x61,
+ 0xc2,
+ 0x9f,
+ 0x25,
+ 0x4a,
+ 0x94,
+ 0x33,
+ 0x66,
+ 0xcc,
+ 0x83,
+ 0x1d,
+ 0x3a,
+ 0x74,
+ 0xe8,
+ 0xcb,
+ 0x8d,
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x40,
+ 0x80,
+ 0x1b,
+ 0x36,
+ 0x6c,
+ 0xd8,
+ 0xab,
+ 0x4d,
+ 0x9a,
+ 0x2f,
+ 0x5e,
+ 0xbc,
+ 0x63,
+ 0xc6,
+ 0x97,
+ 0x35,
+ 0x6a,
+ 0xd4,
+ 0xb3,
+ 0x7d,
+ 0xfa,
+ 0xef,
+ 0xc5,
+ 0x91,
+ 0x39,
+ 0x72,
+ 0xe4,
+ 0xd3,
+ 0xbd,
+ 0x61,
+ 0xc2,
+ 0x9f,
+ 0x25,
+ 0x4a,
+ 0x94,
+ 0x33,
+ 0x66,
+ 0xcc,
+ 0x83,
+ 0x1d,
+ 0x3a,
+ 0x74,
+ 0xe8,
+ 0xcb,
+ 0x8d,
};
/**
@@ -37,22 +279,262 @@ public class AES {
* step, as well as the key expansion.
*/
private static final int[] SBOX = {
- 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
- 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
- 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
- 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
- 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
- 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
- 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
- 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
- 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
- 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
- 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
- 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
- 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
- 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
- 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
- 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
+ 0x63,
+ 0x7C,
+ 0x77,
+ 0x7B,
+ 0xF2,
+ 0x6B,
+ 0x6F,
+ 0xC5,
+ 0x30,
+ 0x01,
+ 0x67,
+ 0x2B,
+ 0xFE,
+ 0xD7,
+ 0xAB,
+ 0x76,
+ 0xCA,
+ 0x82,
+ 0xC9,
+ 0x7D,
+ 0xFA,
+ 0x59,
+ 0x47,
+ 0xF0,
+ 0xAD,
+ 0xD4,
+ 0xA2,
+ 0xAF,
+ 0x9C,
+ 0xA4,
+ 0x72,
+ 0xC0,
+ 0xB7,
+ 0xFD,
+ 0x93,
+ 0x26,
+ 0x36,
+ 0x3F,
+ 0xF7,
+ 0xCC,
+ 0x34,
+ 0xA5,
+ 0xE5,
+ 0xF1,
+ 0x71,
+ 0xD8,
+ 0x31,
+ 0x15,
+ 0x04,
+ 0xC7,
+ 0x23,
+ 0xC3,
+ 0x18,
+ 0x96,
+ 0x05,
+ 0x9A,
+ 0x07,
+ 0x12,
+ 0x80,
+ 0xE2,
+ 0xEB,
+ 0x27,
+ 0xB2,
+ 0x75,
+ 0x09,
+ 0x83,
+ 0x2C,
+ 0x1A,
+ 0x1B,
+ 0x6E,
+ 0x5A,
+ 0xA0,
+ 0x52,
+ 0x3B,
+ 0xD6,
+ 0xB3,
+ 0x29,
+ 0xE3,
+ 0x2F,
+ 0x84,
+ 0x53,
+ 0xD1,
+ 0x00,
+ 0xED,
+ 0x20,
+ 0xFC,
+ 0xB1,
+ 0x5B,
+ 0x6A,
+ 0xCB,
+ 0xBE,
+ 0x39,
+ 0x4A,
+ 0x4C,
+ 0x58,
+ 0xCF,
+ 0xD0,
+ 0xEF,
+ 0xAA,
+ 0xFB,
+ 0x43,
+ 0x4D,
+ 0x33,
+ 0x85,
+ 0x45,
+ 0xF9,
+ 0x02,
+ 0x7F,
+ 0x50,
+ 0x3C,
+ 0x9F,
+ 0xA8,
+ 0x51,
+ 0xA3,
+ 0x40,
+ 0x8F,
+ 0x92,
+ 0x9D,
+ 0x38,
+ 0xF5,
+ 0xBC,
+ 0xB6,
+ 0xDA,
+ 0x21,
+ 0x10,
+ 0xFF,
+ 0xF3,
+ 0xD2,
+ 0xCD,
+ 0x0C,
+ 0x13,
+ 0xEC,
+ 0x5F,
+ 0x97,
+ 0x44,
+ 0x17,
+ 0xC4,
+ 0xA7,
+ 0x7E,
+ 0x3D,
+ 0x64,
+ 0x5D,
+ 0x19,
+ 0x73,
+ 0x60,
+ 0x81,
+ 0x4F,
+ 0xDC,
+ 0x22,
+ 0x2A,
+ 0x90,
+ 0x88,
+ 0x46,
+ 0xEE,
+ 0xB8,
+ 0x14,
+ 0xDE,
+ 0x5E,
+ 0x0B,
+ 0xDB,
+ 0xE0,
+ 0x32,
+ 0x3A,
+ 0x0A,
+ 0x49,
+ 0x06,
+ 0x24,
+ 0x5C,
+ 0xC2,
+ 0xD3,
+ 0xAC,
+ 0x62,
+ 0x91,
+ 0x95,
+ 0xE4,
+ 0x79,
+ 0xE7,
+ 0xC8,
+ 0x37,
+ 0x6D,
+ 0x8D,
+ 0xD5,
+ 0x4E,
+ 0xA9,
+ 0x6C,
+ 0x56,
+ 0xF4,
+ 0xEA,
+ 0x65,
+ 0x7A,
+ 0xAE,
+ 0x08,
+ 0xBA,
+ 0x78,
+ 0x25,
+ 0x2E,
+ 0x1C,
+ 0xA6,
+ 0xB4,
+ 0xC6,
+ 0xE8,
+ 0xDD,
+ 0x74,
+ 0x1F,
+ 0x4B,
+ 0xBD,
+ 0x8B,
+ 0x8A,
+ 0x70,
+ 0x3E,
+ 0xB5,
+ 0x66,
+ 0x48,
+ 0x03,
+ 0xF6,
+ 0x0E,
+ 0x61,
+ 0x35,
+ 0x57,
+ 0xB9,
+ 0x86,
+ 0xC1,
+ 0x1D,
+ 0x9E,
+ 0xE1,
+ 0xF8,
+ 0x98,
+ 0x11,
+ 0x69,
+ 0xD9,
+ 0x8E,
+ 0x94,
+ 0x9B,
+ 0x1E,
+ 0x87,
+ 0xE9,
+ 0xCE,
+ 0x55,
+ 0x28,
+ 0xDF,
+ 0x8C,
+ 0xA1,
+ 0x89,
+ 0x0D,
+ 0xBF,
+ 0xE6,
+ 0x42,
+ 0x68,
+ 0x41,
+ 0x99,
+ 0x2D,
+ 0x0F,
+ 0xB0,
+ 0x54,
+ 0xBB,
+ 0x16,
};
/**
@@ -60,22 +542,262 @@ public class AES {
* subBytesDec step.
*/
private static final int[] INVERSE_SBOX = {
- 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
- 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
- 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
- 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
- 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
- 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
- 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
- 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
- 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
- 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
- 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
- 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
- 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
- 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
- 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
- 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
+ 0x52,
+ 0x09,
+ 0x6A,
+ 0xD5,
+ 0x30,
+ 0x36,
+ 0xA5,
+ 0x38,
+ 0xBF,
+ 0x40,
+ 0xA3,
+ 0x9E,
+ 0x81,
+ 0xF3,
+ 0xD7,
+ 0xFB,
+ 0x7C,
+ 0xE3,
+ 0x39,
+ 0x82,
+ 0x9B,
+ 0x2F,
+ 0xFF,
+ 0x87,
+ 0x34,
+ 0x8E,
+ 0x43,
+ 0x44,
+ 0xC4,
+ 0xDE,
+ 0xE9,
+ 0xCB,
+ 0x54,
+ 0x7B,
+ 0x94,
+ 0x32,
+ 0xA6,
+ 0xC2,
+ 0x23,
+ 0x3D,
+ 0xEE,
+ 0x4C,
+ 0x95,
+ 0x0B,
+ 0x42,
+ 0xFA,
+ 0xC3,
+ 0x4E,
+ 0x08,
+ 0x2E,
+ 0xA1,
+ 0x66,
+ 0x28,
+ 0xD9,
+ 0x24,
+ 0xB2,
+ 0x76,
+ 0x5B,
+ 0xA2,
+ 0x49,
+ 0x6D,
+ 0x8B,
+ 0xD1,
+ 0x25,
+ 0x72,
+ 0xF8,
+ 0xF6,
+ 0x64,
+ 0x86,
+ 0x68,
+ 0x98,
+ 0x16,
+ 0xD4,
+ 0xA4,
+ 0x5C,
+ 0xCC,
+ 0x5D,
+ 0x65,
+ 0xB6,
+ 0x92,
+ 0x6C,
+ 0x70,
+ 0x48,
+ 0x50,
+ 0xFD,
+ 0xED,
+ 0xB9,
+ 0xDA,
+ 0x5E,
+ 0x15,
+ 0x46,
+ 0x57,
+ 0xA7,
+ 0x8D,
+ 0x9D,
+ 0x84,
+ 0x90,
+ 0xD8,
+ 0xAB,
+ 0x00,
+ 0x8C,
+ 0xBC,
+ 0xD3,
+ 0x0A,
+ 0xF7,
+ 0xE4,
+ 0x58,
+ 0x05,
+ 0xB8,
+ 0xB3,
+ 0x45,
+ 0x06,
+ 0xD0,
+ 0x2C,
+ 0x1E,
+ 0x8F,
+ 0xCA,
+ 0x3F,
+ 0x0F,
+ 0x02,
+ 0xC1,
+ 0xAF,
+ 0xBD,
+ 0x03,
+ 0x01,
+ 0x13,
+ 0x8A,
+ 0x6B,
+ 0x3A,
+ 0x91,
+ 0x11,
+ 0x41,
+ 0x4F,
+ 0x67,
+ 0xDC,
+ 0xEA,
+ 0x97,
+ 0xF2,
+ 0xCF,
+ 0xCE,
+ 0xF0,
+ 0xB4,
+ 0xE6,
+ 0x73,
+ 0x96,
+ 0xAC,
+ 0x74,
+ 0x22,
+ 0xE7,
+ 0xAD,
+ 0x35,
+ 0x85,
+ 0xE2,
+ 0xF9,
+ 0x37,
+ 0xE8,
+ 0x1C,
+ 0x75,
+ 0xDF,
+ 0x6E,
+ 0x47,
+ 0xF1,
+ 0x1A,
+ 0x71,
+ 0x1D,
+ 0x29,
+ 0xC5,
+ 0x89,
+ 0x6F,
+ 0xB7,
+ 0x62,
+ 0x0E,
+ 0xAA,
+ 0x18,
+ 0xBE,
+ 0x1B,
+ 0xFC,
+ 0x56,
+ 0x3E,
+ 0x4B,
+ 0xC6,
+ 0xD2,
+ 0x79,
+ 0x20,
+ 0x9A,
+ 0xDB,
+ 0xC0,
+ 0xFE,
+ 0x78,
+ 0xCD,
+ 0x5A,
+ 0xF4,
+ 0x1F,
+ 0xDD,
+ 0xA8,
+ 0x33,
+ 0x88,
+ 0x07,
+ 0xC7,
+ 0x31,
+ 0xB1,
+ 0x12,
+ 0x10,
+ 0x59,
+ 0x27,
+ 0x80,
+ 0xEC,
+ 0x5F,
+ 0x60,
+ 0x51,
+ 0x7F,
+ 0xA9,
+ 0x19,
+ 0xB5,
+ 0x4A,
+ 0x0D,
+ 0x2D,
+ 0xE5,
+ 0x7A,
+ 0x9F,
+ 0x93,
+ 0xC9,
+ 0x9C,
+ 0xEF,
+ 0xA0,
+ 0xE0,
+ 0x3B,
+ 0x4D,
+ 0xAE,
+ 0x2A,
+ 0xF5,
+ 0xB0,
+ 0xC8,
+ 0xEB,
+ 0xBB,
+ 0x3C,
+ 0x83,
+ 0x53,
+ 0x99,
+ 0x61,
+ 0x17,
+ 0x2B,
+ 0x04,
+ 0x7E,
+ 0xBA,
+ 0x77,
+ 0xD6,
+ 0x26,
+ 0xE1,
+ 0x69,
+ 0x14,
+ 0x63,
+ 0x55,
+ 0x21,
+ 0x0C,
+ 0x7D,
};
/**
@@ -83,22 +805,262 @@ public class AES {
* the MixColums step during encryption.
*/
private static final int[] MULT2 = {
- 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
- 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
- 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
- 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
- 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
- 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
- 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
- 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
- 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,
- 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25,
- 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45,
- 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,
- 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85,
- 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5,
- 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,
- 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
+ 0x00,
+ 0x02,
+ 0x04,
+ 0x06,
+ 0x08,
+ 0x0a,
+ 0x0c,
+ 0x0e,
+ 0x10,
+ 0x12,
+ 0x14,
+ 0x16,
+ 0x18,
+ 0x1a,
+ 0x1c,
+ 0x1e,
+ 0x20,
+ 0x22,
+ 0x24,
+ 0x26,
+ 0x28,
+ 0x2a,
+ 0x2c,
+ 0x2e,
+ 0x30,
+ 0x32,
+ 0x34,
+ 0x36,
+ 0x38,
+ 0x3a,
+ 0x3c,
+ 0x3e,
+ 0x40,
+ 0x42,
+ 0x44,
+ 0x46,
+ 0x48,
+ 0x4a,
+ 0x4c,
+ 0x4e,
+ 0x50,
+ 0x52,
+ 0x54,
+ 0x56,
+ 0x58,
+ 0x5a,
+ 0x5c,
+ 0x5e,
+ 0x60,
+ 0x62,
+ 0x64,
+ 0x66,
+ 0x68,
+ 0x6a,
+ 0x6c,
+ 0x6e,
+ 0x70,
+ 0x72,
+ 0x74,
+ 0x76,
+ 0x78,
+ 0x7a,
+ 0x7c,
+ 0x7e,
+ 0x80,
+ 0x82,
+ 0x84,
+ 0x86,
+ 0x88,
+ 0x8a,
+ 0x8c,
+ 0x8e,
+ 0x90,
+ 0x92,
+ 0x94,
+ 0x96,
+ 0x98,
+ 0x9a,
+ 0x9c,
+ 0x9e,
+ 0xa0,
+ 0xa2,
+ 0xa4,
+ 0xa6,
+ 0xa8,
+ 0xaa,
+ 0xac,
+ 0xae,
+ 0xb0,
+ 0xb2,
+ 0xb4,
+ 0xb6,
+ 0xb8,
+ 0xba,
+ 0xbc,
+ 0xbe,
+ 0xc0,
+ 0xc2,
+ 0xc4,
+ 0xc6,
+ 0xc8,
+ 0xca,
+ 0xcc,
+ 0xce,
+ 0xd0,
+ 0xd2,
+ 0xd4,
+ 0xd6,
+ 0xd8,
+ 0xda,
+ 0xdc,
+ 0xde,
+ 0xe0,
+ 0xe2,
+ 0xe4,
+ 0xe6,
+ 0xe8,
+ 0xea,
+ 0xec,
+ 0xee,
+ 0xf0,
+ 0xf2,
+ 0xf4,
+ 0xf6,
+ 0xf8,
+ 0xfa,
+ 0xfc,
+ 0xfe,
+ 0x1b,
+ 0x19,
+ 0x1f,
+ 0x1d,
+ 0x13,
+ 0x11,
+ 0x17,
+ 0x15,
+ 0x0b,
+ 0x09,
+ 0x0f,
+ 0x0d,
+ 0x03,
+ 0x01,
+ 0x07,
+ 0x05,
+ 0x3b,
+ 0x39,
+ 0x3f,
+ 0x3d,
+ 0x33,
+ 0x31,
+ 0x37,
+ 0x35,
+ 0x2b,
+ 0x29,
+ 0x2f,
+ 0x2d,
+ 0x23,
+ 0x21,
+ 0x27,
+ 0x25,
+ 0x5b,
+ 0x59,
+ 0x5f,
+ 0x5d,
+ 0x53,
+ 0x51,
+ 0x57,
+ 0x55,
+ 0x4b,
+ 0x49,
+ 0x4f,
+ 0x4d,
+ 0x43,
+ 0x41,
+ 0x47,
+ 0x45,
+ 0x7b,
+ 0x79,
+ 0x7f,
+ 0x7d,
+ 0x73,
+ 0x71,
+ 0x77,
+ 0x75,
+ 0x6b,
+ 0x69,
+ 0x6f,
+ 0x6d,
+ 0x63,
+ 0x61,
+ 0x67,
+ 0x65,
+ 0x9b,
+ 0x99,
+ 0x9f,
+ 0x9d,
+ 0x93,
+ 0x91,
+ 0x97,
+ 0x95,
+ 0x8b,
+ 0x89,
+ 0x8f,
+ 0x8d,
+ 0x83,
+ 0x81,
+ 0x87,
+ 0x85,
+ 0xbb,
+ 0xb9,
+ 0xbf,
+ 0xbd,
+ 0xb3,
+ 0xb1,
+ 0xb7,
+ 0xb5,
+ 0xab,
+ 0xa9,
+ 0xaf,
+ 0xad,
+ 0xa3,
+ 0xa1,
+ 0xa7,
+ 0xa5,
+ 0xdb,
+ 0xd9,
+ 0xdf,
+ 0xdd,
+ 0xd3,
+ 0xd1,
+ 0xd7,
+ 0xd5,
+ 0xcb,
+ 0xc9,
+ 0xcf,
+ 0xcd,
+ 0xc3,
+ 0xc1,
+ 0xc7,
+ 0xc5,
+ 0xfb,
+ 0xf9,
+ 0xff,
+ 0xfd,
+ 0xf3,
+ 0xf1,
+ 0xf7,
+ 0xf5,
+ 0xeb,
+ 0xe9,
+ 0xef,
+ 0xed,
+ 0xe3,
+ 0xe1,
+ 0xe7,
+ 0xe5,
};
/**
@@ -106,22 +1068,262 @@ public class AES {
* the MixColums step during encryption.
*/
private static final int[] MULT3 = {
- 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
- 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
- 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
- 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41,
- 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1,
- 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,
- 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1,
- 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81,
- 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,
- 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba,
- 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea,
- 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,
- 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a,
- 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a,
- 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,
- 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
+ 0x00,
+ 0x03,
+ 0x06,
+ 0x05,
+ 0x0c,
+ 0x0f,
+ 0x0a,
+ 0x09,
+ 0x18,
+ 0x1b,
+ 0x1e,
+ 0x1d,
+ 0x14,
+ 0x17,
+ 0x12,
+ 0x11,
+ 0x30,
+ 0x33,
+ 0x36,
+ 0x35,
+ 0x3c,
+ 0x3f,
+ 0x3a,
+ 0x39,
+ 0x28,
+ 0x2b,
+ 0x2e,
+ 0x2d,
+ 0x24,
+ 0x27,
+ 0x22,
+ 0x21,
+ 0x60,
+ 0x63,
+ 0x66,
+ 0x65,
+ 0x6c,
+ 0x6f,
+ 0x6a,
+ 0x69,
+ 0x78,
+ 0x7b,
+ 0x7e,
+ 0x7d,
+ 0x74,
+ 0x77,
+ 0x72,
+ 0x71,
+ 0x50,
+ 0x53,
+ 0x56,
+ 0x55,
+ 0x5c,
+ 0x5f,
+ 0x5a,
+ 0x59,
+ 0x48,
+ 0x4b,
+ 0x4e,
+ 0x4d,
+ 0x44,
+ 0x47,
+ 0x42,
+ 0x41,
+ 0xc0,
+ 0xc3,
+ 0xc6,
+ 0xc5,
+ 0xcc,
+ 0xcf,
+ 0xca,
+ 0xc9,
+ 0xd8,
+ 0xdb,
+ 0xde,
+ 0xdd,
+ 0xd4,
+ 0xd7,
+ 0xd2,
+ 0xd1,
+ 0xf0,
+ 0xf3,
+ 0xf6,
+ 0xf5,
+ 0xfc,
+ 0xff,
+ 0xfa,
+ 0xf9,
+ 0xe8,
+ 0xeb,
+ 0xee,
+ 0xed,
+ 0xe4,
+ 0xe7,
+ 0xe2,
+ 0xe1,
+ 0xa0,
+ 0xa3,
+ 0xa6,
+ 0xa5,
+ 0xac,
+ 0xaf,
+ 0xaa,
+ 0xa9,
+ 0xb8,
+ 0xbb,
+ 0xbe,
+ 0xbd,
+ 0xb4,
+ 0xb7,
+ 0xb2,
+ 0xb1,
+ 0x90,
+ 0x93,
+ 0x96,
+ 0x95,
+ 0x9c,
+ 0x9f,
+ 0x9a,
+ 0x99,
+ 0x88,
+ 0x8b,
+ 0x8e,
+ 0x8d,
+ 0x84,
+ 0x87,
+ 0x82,
+ 0x81,
+ 0x9b,
+ 0x98,
+ 0x9d,
+ 0x9e,
+ 0x97,
+ 0x94,
+ 0x91,
+ 0x92,
+ 0x83,
+ 0x80,
+ 0x85,
+ 0x86,
+ 0x8f,
+ 0x8c,
+ 0x89,
+ 0x8a,
+ 0xab,
+ 0xa8,
+ 0xad,
+ 0xae,
+ 0xa7,
+ 0xa4,
+ 0xa1,
+ 0xa2,
+ 0xb3,
+ 0xb0,
+ 0xb5,
+ 0xb6,
+ 0xbf,
+ 0xbc,
+ 0xb9,
+ 0xba,
+ 0xfb,
+ 0xf8,
+ 0xfd,
+ 0xfe,
+ 0xf7,
+ 0xf4,
+ 0xf1,
+ 0xf2,
+ 0xe3,
+ 0xe0,
+ 0xe5,
+ 0xe6,
+ 0xef,
+ 0xec,
+ 0xe9,
+ 0xea,
+ 0xcb,
+ 0xc8,
+ 0xcd,
+ 0xce,
+ 0xc7,
+ 0xc4,
+ 0xc1,
+ 0xc2,
+ 0xd3,
+ 0xd0,
+ 0xd5,
+ 0xd6,
+ 0xdf,
+ 0xdc,
+ 0xd9,
+ 0xda,
+ 0x5b,
+ 0x58,
+ 0x5d,
+ 0x5e,
+ 0x57,
+ 0x54,
+ 0x51,
+ 0x52,
+ 0x43,
+ 0x40,
+ 0x45,
+ 0x46,
+ 0x4f,
+ 0x4c,
+ 0x49,
+ 0x4a,
+ 0x6b,
+ 0x68,
+ 0x6d,
+ 0x6e,
+ 0x67,
+ 0x64,
+ 0x61,
+ 0x62,
+ 0x73,
+ 0x70,
+ 0x75,
+ 0x76,
+ 0x7f,
+ 0x7c,
+ 0x79,
+ 0x7a,
+ 0x3b,
+ 0x38,
+ 0x3d,
+ 0x3e,
+ 0x37,
+ 0x34,
+ 0x31,
+ 0x32,
+ 0x23,
+ 0x20,
+ 0x25,
+ 0x26,
+ 0x2f,
+ 0x2c,
+ 0x29,
+ 0x2a,
+ 0x0b,
+ 0x08,
+ 0x0d,
+ 0x0e,
+ 0x07,
+ 0x04,
+ 0x01,
+ 0x02,
+ 0x13,
+ 0x10,
+ 0x15,
+ 0x16,
+ 0x1f,
+ 0x1c,
+ 0x19,
+ 0x1a,
};
/**
@@ -129,22 +1331,262 @@ public class AES {
* the MixColums step during decryption.
*/
private static final int[] MULT9 = {
- 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
- 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,
- 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
- 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc,
- 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01,
- 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91,
- 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a,
- 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa,
- 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b,
- 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b,
- 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0,
- 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30,
- 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed,
- 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d,
- 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6,
- 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
+ 0x00,
+ 0x09,
+ 0x12,
+ 0x1b,
+ 0x24,
+ 0x2d,
+ 0x36,
+ 0x3f,
+ 0x48,
+ 0x41,
+ 0x5a,
+ 0x53,
+ 0x6c,
+ 0x65,
+ 0x7e,
+ 0x77,
+ 0x90,
+ 0x99,
+ 0x82,
+ 0x8b,
+ 0xb4,
+ 0xbd,
+ 0xa6,
+ 0xaf,
+ 0xd8,
+ 0xd1,
+ 0xca,
+ 0xc3,
+ 0xfc,
+ 0xf5,
+ 0xee,
+ 0xe7,
+ 0x3b,
+ 0x32,
+ 0x29,
+ 0x20,
+ 0x1f,
+ 0x16,
+ 0x0d,
+ 0x04,
+ 0x73,
+ 0x7a,
+ 0x61,
+ 0x68,
+ 0x57,
+ 0x5e,
+ 0x45,
+ 0x4c,
+ 0xab,
+ 0xa2,
+ 0xb9,
+ 0xb0,
+ 0x8f,
+ 0x86,
+ 0x9d,
+ 0x94,
+ 0xe3,
+ 0xea,
+ 0xf1,
+ 0xf8,
+ 0xc7,
+ 0xce,
+ 0xd5,
+ 0xdc,
+ 0x76,
+ 0x7f,
+ 0x64,
+ 0x6d,
+ 0x52,
+ 0x5b,
+ 0x40,
+ 0x49,
+ 0x3e,
+ 0x37,
+ 0x2c,
+ 0x25,
+ 0x1a,
+ 0x13,
+ 0x08,
+ 0x01,
+ 0xe6,
+ 0xef,
+ 0xf4,
+ 0xfd,
+ 0xc2,
+ 0xcb,
+ 0xd0,
+ 0xd9,
+ 0xae,
+ 0xa7,
+ 0xbc,
+ 0xb5,
+ 0x8a,
+ 0x83,
+ 0x98,
+ 0x91,
+ 0x4d,
+ 0x44,
+ 0x5f,
+ 0x56,
+ 0x69,
+ 0x60,
+ 0x7b,
+ 0x72,
+ 0x05,
+ 0x0c,
+ 0x17,
+ 0x1e,
+ 0x21,
+ 0x28,
+ 0x33,
+ 0x3a,
+ 0xdd,
+ 0xd4,
+ 0xcf,
+ 0xc6,
+ 0xf9,
+ 0xf0,
+ 0xeb,
+ 0xe2,
+ 0x95,
+ 0x9c,
+ 0x87,
+ 0x8e,
+ 0xb1,
+ 0xb8,
+ 0xa3,
+ 0xaa,
+ 0xec,
+ 0xe5,
+ 0xfe,
+ 0xf7,
+ 0xc8,
+ 0xc1,
+ 0xda,
+ 0xd3,
+ 0xa4,
+ 0xad,
+ 0xb6,
+ 0xbf,
+ 0x80,
+ 0x89,
+ 0x92,
+ 0x9b,
+ 0x7c,
+ 0x75,
+ 0x6e,
+ 0x67,
+ 0x58,
+ 0x51,
+ 0x4a,
+ 0x43,
+ 0x34,
+ 0x3d,
+ 0x26,
+ 0x2f,
+ 0x10,
+ 0x19,
+ 0x02,
+ 0x0b,
+ 0xd7,
+ 0xde,
+ 0xc5,
+ 0xcc,
+ 0xf3,
+ 0xfa,
+ 0xe1,
+ 0xe8,
+ 0x9f,
+ 0x96,
+ 0x8d,
+ 0x84,
+ 0xbb,
+ 0xb2,
+ 0xa9,
+ 0xa0,
+ 0x47,
+ 0x4e,
+ 0x55,
+ 0x5c,
+ 0x63,
+ 0x6a,
+ 0x71,
+ 0x78,
+ 0x0f,
+ 0x06,
+ 0x1d,
+ 0x14,
+ 0x2b,
+ 0x22,
+ 0x39,
+ 0x30,
+ 0x9a,
+ 0x93,
+ 0x88,
+ 0x81,
+ 0xbe,
+ 0xb7,
+ 0xac,
+ 0xa5,
+ 0xd2,
+ 0xdb,
+ 0xc0,
+ 0xc9,
+ 0xf6,
+ 0xff,
+ 0xe4,
+ 0xed,
+ 0x0a,
+ 0x03,
+ 0x18,
+ 0x11,
+ 0x2e,
+ 0x27,
+ 0x3c,
+ 0x35,
+ 0x42,
+ 0x4b,
+ 0x50,
+ 0x59,
+ 0x66,
+ 0x6f,
+ 0x74,
+ 0x7d,
+ 0xa1,
+ 0xa8,
+ 0xb3,
+ 0xba,
+ 0x85,
+ 0x8c,
+ 0x97,
+ 0x9e,
+ 0xe9,
+ 0xe0,
+ 0xfb,
+ 0xf2,
+ 0xcd,
+ 0xc4,
+ 0xdf,
+ 0xd6,
+ 0x31,
+ 0x38,
+ 0x23,
+ 0x2a,
+ 0x15,
+ 0x1c,
+ 0x07,
+ 0x0e,
+ 0x79,
+ 0x70,
+ 0x6b,
+ 0x62,
+ 0x5d,
+ 0x54,
+ 0x4f,
+ 0x46,
};
/**
@@ -152,22 +1594,262 @@ public class AES {
* the MixColums step during decryption.
*/
private static final int[] MULT11 = {
- 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,
- 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,
- 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12,
- 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2,
- 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f,
- 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f,
- 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4,
- 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54,
- 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e,
- 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e,
- 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5,
- 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55,
- 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68,
- 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8,
- 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13,
- 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
+ 0x00,
+ 0x0b,
+ 0x16,
+ 0x1d,
+ 0x2c,
+ 0x27,
+ 0x3a,
+ 0x31,
+ 0x58,
+ 0x53,
+ 0x4e,
+ 0x45,
+ 0x74,
+ 0x7f,
+ 0x62,
+ 0x69,
+ 0xb0,
+ 0xbb,
+ 0xa6,
+ 0xad,
+ 0x9c,
+ 0x97,
+ 0x8a,
+ 0x81,
+ 0xe8,
+ 0xe3,
+ 0xfe,
+ 0xf5,
+ 0xc4,
+ 0xcf,
+ 0xd2,
+ 0xd9,
+ 0x7b,
+ 0x70,
+ 0x6d,
+ 0x66,
+ 0x57,
+ 0x5c,
+ 0x41,
+ 0x4a,
+ 0x23,
+ 0x28,
+ 0x35,
+ 0x3e,
+ 0x0f,
+ 0x04,
+ 0x19,
+ 0x12,
+ 0xcb,
+ 0xc0,
+ 0xdd,
+ 0xd6,
+ 0xe7,
+ 0xec,
+ 0xf1,
+ 0xfa,
+ 0x93,
+ 0x98,
+ 0x85,
+ 0x8e,
+ 0xbf,
+ 0xb4,
+ 0xa9,
+ 0xa2,
+ 0xf6,
+ 0xfd,
+ 0xe0,
+ 0xeb,
+ 0xda,
+ 0xd1,
+ 0xcc,
+ 0xc7,
+ 0xae,
+ 0xa5,
+ 0xb8,
+ 0xb3,
+ 0x82,
+ 0x89,
+ 0x94,
+ 0x9f,
+ 0x46,
+ 0x4d,
+ 0x50,
+ 0x5b,
+ 0x6a,
+ 0x61,
+ 0x7c,
+ 0x77,
+ 0x1e,
+ 0x15,
+ 0x08,
+ 0x03,
+ 0x32,
+ 0x39,
+ 0x24,
+ 0x2f,
+ 0x8d,
+ 0x86,
+ 0x9b,
+ 0x90,
+ 0xa1,
+ 0xaa,
+ 0xb7,
+ 0xbc,
+ 0xd5,
+ 0xde,
+ 0xc3,
+ 0xc8,
+ 0xf9,
+ 0xf2,
+ 0xef,
+ 0xe4,
+ 0x3d,
+ 0x36,
+ 0x2b,
+ 0x20,
+ 0x11,
+ 0x1a,
+ 0x07,
+ 0x0c,
+ 0x65,
+ 0x6e,
+ 0x73,
+ 0x78,
+ 0x49,
+ 0x42,
+ 0x5f,
+ 0x54,
+ 0xf7,
+ 0xfc,
+ 0xe1,
+ 0xea,
+ 0xdb,
+ 0xd0,
+ 0xcd,
+ 0xc6,
+ 0xaf,
+ 0xa4,
+ 0xb9,
+ 0xb2,
+ 0x83,
+ 0x88,
+ 0x95,
+ 0x9e,
+ 0x47,
+ 0x4c,
+ 0x51,
+ 0x5a,
+ 0x6b,
+ 0x60,
+ 0x7d,
+ 0x76,
+ 0x1f,
+ 0x14,
+ 0x09,
+ 0x02,
+ 0x33,
+ 0x38,
+ 0x25,
+ 0x2e,
+ 0x8c,
+ 0x87,
+ 0x9a,
+ 0x91,
+ 0xa0,
+ 0xab,
+ 0xb6,
+ 0xbd,
+ 0xd4,
+ 0xdf,
+ 0xc2,
+ 0xc9,
+ 0xf8,
+ 0xf3,
+ 0xee,
+ 0xe5,
+ 0x3c,
+ 0x37,
+ 0x2a,
+ 0x21,
+ 0x10,
+ 0x1b,
+ 0x06,
+ 0x0d,
+ 0x64,
+ 0x6f,
+ 0x72,
+ 0x79,
+ 0x48,
+ 0x43,
+ 0x5e,
+ 0x55,
+ 0x01,
+ 0x0a,
+ 0x17,
+ 0x1c,
+ 0x2d,
+ 0x26,
+ 0x3b,
+ 0x30,
+ 0x59,
+ 0x52,
+ 0x4f,
+ 0x44,
+ 0x75,
+ 0x7e,
+ 0x63,
+ 0x68,
+ 0xb1,
+ 0xba,
+ 0xa7,
+ 0xac,
+ 0x9d,
+ 0x96,
+ 0x8b,
+ 0x80,
+ 0xe9,
+ 0xe2,
+ 0xff,
+ 0xf4,
+ 0xc5,
+ 0xce,
+ 0xd3,
+ 0xd8,
+ 0x7a,
+ 0x71,
+ 0x6c,
+ 0x67,
+ 0x56,
+ 0x5d,
+ 0x40,
+ 0x4b,
+ 0x22,
+ 0x29,
+ 0x34,
+ 0x3f,
+ 0x0e,
+ 0x05,
+ 0x18,
+ 0x13,
+ 0xca,
+ 0xc1,
+ 0xdc,
+ 0xd7,
+ 0xe6,
+ 0xed,
+ 0xf0,
+ 0xfb,
+ 0x92,
+ 0x99,
+ 0x84,
+ 0x8f,
+ 0xbe,
+ 0xb5,
+ 0xa8,
+ 0xa3,
};
/**
@@ -175,22 +1857,262 @@ public class AES {
* the MixColums step during decryption.
*/
private static final int[] MULT13 = {
- 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,
- 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,
- 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0,
- 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20,
- 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26,
- 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6,
- 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d,
- 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d,
- 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91,
- 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41,
- 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a,
- 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa,
- 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc,
- 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c,
- 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47,
- 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
+ 0x00,
+ 0x0d,
+ 0x1a,
+ 0x17,
+ 0x34,
+ 0x39,
+ 0x2e,
+ 0x23,
+ 0x68,
+ 0x65,
+ 0x72,
+ 0x7f,
+ 0x5c,
+ 0x51,
+ 0x46,
+ 0x4b,
+ 0xd0,
+ 0xdd,
+ 0xca,
+ 0xc7,
+ 0xe4,
+ 0xe9,
+ 0xfe,
+ 0xf3,
+ 0xb8,
+ 0xb5,
+ 0xa2,
+ 0xaf,
+ 0x8c,
+ 0x81,
+ 0x96,
+ 0x9b,
+ 0xbb,
+ 0xb6,
+ 0xa1,
+ 0xac,
+ 0x8f,
+ 0x82,
+ 0x95,
+ 0x98,
+ 0xd3,
+ 0xde,
+ 0xc9,
+ 0xc4,
+ 0xe7,
+ 0xea,
+ 0xfd,
+ 0xf0,
+ 0x6b,
+ 0x66,
+ 0x71,
+ 0x7c,
+ 0x5f,
+ 0x52,
+ 0x45,
+ 0x48,
+ 0x03,
+ 0x0e,
+ 0x19,
+ 0x14,
+ 0x37,
+ 0x3a,
+ 0x2d,
+ 0x20,
+ 0x6d,
+ 0x60,
+ 0x77,
+ 0x7a,
+ 0x59,
+ 0x54,
+ 0x43,
+ 0x4e,
+ 0x05,
+ 0x08,
+ 0x1f,
+ 0x12,
+ 0x31,
+ 0x3c,
+ 0x2b,
+ 0x26,
+ 0xbd,
+ 0xb0,
+ 0xa7,
+ 0xaa,
+ 0x89,
+ 0x84,
+ 0x93,
+ 0x9e,
+ 0xd5,
+ 0xd8,
+ 0xcf,
+ 0xc2,
+ 0xe1,
+ 0xec,
+ 0xfb,
+ 0xf6,
+ 0xd6,
+ 0xdb,
+ 0xcc,
+ 0xc1,
+ 0xe2,
+ 0xef,
+ 0xf8,
+ 0xf5,
+ 0xbe,
+ 0xb3,
+ 0xa4,
+ 0xa9,
+ 0x8a,
+ 0x87,
+ 0x90,
+ 0x9d,
+ 0x06,
+ 0x0b,
+ 0x1c,
+ 0x11,
+ 0x32,
+ 0x3f,
+ 0x28,
+ 0x25,
+ 0x6e,
+ 0x63,
+ 0x74,
+ 0x79,
+ 0x5a,
+ 0x57,
+ 0x40,
+ 0x4d,
+ 0xda,
+ 0xd7,
+ 0xc0,
+ 0xcd,
+ 0xee,
+ 0xe3,
+ 0xf4,
+ 0xf9,
+ 0xb2,
+ 0xbf,
+ 0xa8,
+ 0xa5,
+ 0x86,
+ 0x8b,
+ 0x9c,
+ 0x91,
+ 0x0a,
+ 0x07,
+ 0x10,
+ 0x1d,
+ 0x3e,
+ 0x33,
+ 0x24,
+ 0x29,
+ 0x62,
+ 0x6f,
+ 0x78,
+ 0x75,
+ 0x56,
+ 0x5b,
+ 0x4c,
+ 0x41,
+ 0x61,
+ 0x6c,
+ 0x7b,
+ 0x76,
+ 0x55,
+ 0x58,
+ 0x4f,
+ 0x42,
+ 0x09,
+ 0x04,
+ 0x13,
+ 0x1e,
+ 0x3d,
+ 0x30,
+ 0x27,
+ 0x2a,
+ 0xb1,
+ 0xbc,
+ 0xab,
+ 0xa6,
+ 0x85,
+ 0x88,
+ 0x9f,
+ 0x92,
+ 0xd9,
+ 0xd4,
+ 0xc3,
+ 0xce,
+ 0xed,
+ 0xe0,
+ 0xf7,
+ 0xfa,
+ 0xb7,
+ 0xba,
+ 0xad,
+ 0xa0,
+ 0x83,
+ 0x8e,
+ 0x99,
+ 0x94,
+ 0xdf,
+ 0xd2,
+ 0xc5,
+ 0xc8,
+ 0xeb,
+ 0xe6,
+ 0xf1,
+ 0xfc,
+ 0x67,
+ 0x6a,
+ 0x7d,
+ 0x70,
+ 0x53,
+ 0x5e,
+ 0x49,
+ 0x44,
+ 0x0f,
+ 0x02,
+ 0x15,
+ 0x18,
+ 0x3b,
+ 0x36,
+ 0x21,
+ 0x2c,
+ 0x0c,
+ 0x01,
+ 0x16,
+ 0x1b,
+ 0x38,
+ 0x35,
+ 0x22,
+ 0x2f,
+ 0x64,
+ 0x69,
+ 0x7e,
+ 0x73,
+ 0x50,
+ 0x5d,
+ 0x4a,
+ 0x47,
+ 0xdc,
+ 0xd1,
+ 0xc6,
+ 0xcb,
+ 0xe8,
+ 0xe5,
+ 0xf2,
+ 0xff,
+ 0xb4,
+ 0xb9,
+ 0xae,
+ 0xa3,
+ 0x80,
+ 0x8d,
+ 0x9a,
+ 0x97,
};
/**
@@ -198,22 +2120,262 @@ public class AES {
* the MixColums step during decryption.
*/
private static final int[] MULT14 = {
- 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,
- 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,
- 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81,
- 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61,
- 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7,
- 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17,
- 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c,
- 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc,
- 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b,
- 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb,
- 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0,
- 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20,
- 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6,
- 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56,
- 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d,
- 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
+ 0x00,
+ 0x0e,
+ 0x1c,
+ 0x12,
+ 0x38,
+ 0x36,
+ 0x24,
+ 0x2a,
+ 0x70,
+ 0x7e,
+ 0x6c,
+ 0x62,
+ 0x48,
+ 0x46,
+ 0x54,
+ 0x5a,
+ 0xe0,
+ 0xee,
+ 0xfc,
+ 0xf2,
+ 0xd8,
+ 0xd6,
+ 0xc4,
+ 0xca,
+ 0x90,
+ 0x9e,
+ 0x8c,
+ 0x82,
+ 0xa8,
+ 0xa6,
+ 0xb4,
+ 0xba,
+ 0xdb,
+ 0xd5,
+ 0xc7,
+ 0xc9,
+ 0xe3,
+ 0xed,
+ 0xff,
+ 0xf1,
+ 0xab,
+ 0xa5,
+ 0xb7,
+ 0xb9,
+ 0x93,
+ 0x9d,
+ 0x8f,
+ 0x81,
+ 0x3b,
+ 0x35,
+ 0x27,
+ 0x29,
+ 0x03,
+ 0x0d,
+ 0x1f,
+ 0x11,
+ 0x4b,
+ 0x45,
+ 0x57,
+ 0x59,
+ 0x73,
+ 0x7d,
+ 0x6f,
+ 0x61,
+ 0xad,
+ 0xa3,
+ 0xb1,
+ 0xbf,
+ 0x95,
+ 0x9b,
+ 0x89,
+ 0x87,
+ 0xdd,
+ 0xd3,
+ 0xc1,
+ 0xcf,
+ 0xe5,
+ 0xeb,
+ 0xf9,
+ 0xf7,
+ 0x4d,
+ 0x43,
+ 0x51,
+ 0x5f,
+ 0x75,
+ 0x7b,
+ 0x69,
+ 0x67,
+ 0x3d,
+ 0x33,
+ 0x21,
+ 0x2f,
+ 0x05,
+ 0x0b,
+ 0x19,
+ 0x17,
+ 0x76,
+ 0x78,
+ 0x6a,
+ 0x64,
+ 0x4e,
+ 0x40,
+ 0x52,
+ 0x5c,
+ 0x06,
+ 0x08,
+ 0x1a,
+ 0x14,
+ 0x3e,
+ 0x30,
+ 0x22,
+ 0x2c,
+ 0x96,
+ 0x98,
+ 0x8a,
+ 0x84,
+ 0xae,
+ 0xa0,
+ 0xb2,
+ 0xbc,
+ 0xe6,
+ 0xe8,
+ 0xfa,
+ 0xf4,
+ 0xde,
+ 0xd0,
+ 0xc2,
+ 0xcc,
+ 0x41,
+ 0x4f,
+ 0x5d,
+ 0x53,
+ 0x79,
+ 0x77,
+ 0x65,
+ 0x6b,
+ 0x31,
+ 0x3f,
+ 0x2d,
+ 0x23,
+ 0x09,
+ 0x07,
+ 0x15,
+ 0x1b,
+ 0xa1,
+ 0xaf,
+ 0xbd,
+ 0xb3,
+ 0x99,
+ 0x97,
+ 0x85,
+ 0x8b,
+ 0xd1,
+ 0xdf,
+ 0xcd,
+ 0xc3,
+ 0xe9,
+ 0xe7,
+ 0xf5,
+ 0xfb,
+ 0x9a,
+ 0x94,
+ 0x86,
+ 0x88,
+ 0xa2,
+ 0xac,
+ 0xbe,
+ 0xb0,
+ 0xea,
+ 0xe4,
+ 0xf6,
+ 0xf8,
+ 0xd2,
+ 0xdc,
+ 0xce,
+ 0xc0,
+ 0x7a,
+ 0x74,
+ 0x66,
+ 0x68,
+ 0x42,
+ 0x4c,
+ 0x5e,
+ 0x50,
+ 0x0a,
+ 0x04,
+ 0x16,
+ 0x18,
+ 0x32,
+ 0x3c,
+ 0x2e,
+ 0x20,
+ 0xec,
+ 0xe2,
+ 0xf0,
+ 0xfe,
+ 0xd4,
+ 0xda,
+ 0xc8,
+ 0xc6,
+ 0x9c,
+ 0x92,
+ 0x80,
+ 0x8e,
+ 0xa4,
+ 0xaa,
+ 0xb8,
+ 0xb6,
+ 0x0c,
+ 0x02,
+ 0x10,
+ 0x1e,
+ 0x34,
+ 0x3a,
+ 0x28,
+ 0x26,
+ 0x7c,
+ 0x72,
+ 0x60,
+ 0x6e,
+ 0x44,
+ 0x4a,
+ 0x58,
+ 0x56,
+ 0x37,
+ 0x39,
+ 0x2b,
+ 0x25,
+ 0x0f,
+ 0x01,
+ 0x13,
+ 0x1d,
+ 0x47,
+ 0x49,
+ 0x5b,
+ 0x55,
+ 0x7f,
+ 0x71,
+ 0x63,
+ 0x6d,
+ 0xd7,
+ 0xd9,
+ 0xcb,
+ 0xc5,
+ 0xef,
+ 0xe1,
+ 0xf3,
+ 0xfd,
+ 0xa7,
+ 0xa9,
+ 0xbb,
+ 0xb5,
+ 0x9f,
+ 0x91,
+ 0x83,
+ 0x8d,
};
/**
@@ -256,8 +2418,6 @@ public static BigInteger scheduleCore(BigInteger t, int rconCounter) {
rBytes = new StringBuilder(rBytes.substring(0, i * 2) + currentByteBits + rBytes.substring((i + 1) * 2));
}
- // t = new BigInteger(rBytes, 16);
- // return t;
return new BigInteger(rBytes.toString(), 16);
}
@@ -270,35 +2430,32 @@ public static BigInteger scheduleCore(BigInteger t, int rconCounter) {
public static BigInteger[] keyExpansion(BigInteger initialKey) {
BigInteger[] roundKeys = {
initialKey,
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),};
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ };
// initialize rcon iteration
int rconCounter = 1;
for (int i = 1; i < 11; i++) {
-
// get the previous 32 bits the key
BigInteger t = roundKeys[i - 1].remainder(new BigInteger("100000000", 16));
// split previous key into 8-bit segments
BigInteger[] prevKey = {
roundKeys[i - 1].remainder(new BigInteger("100000000", 16)),
- roundKeys[i - 1]
- .remainder(new BigInteger("10000000000000000", 16))
- .divide(new BigInteger("100000000", 16)),
- roundKeys[i - 1]
- .remainder(new BigInteger("1000000000000000000000000", 16))
- .divide(new BigInteger("10000000000000000", 16)),
- roundKeys[i - 1].divide(new BigInteger("1000000000000000000000000", 16)),};
+ roundKeys[i - 1].remainder(new BigInteger("10000000000000000", 16)).divide(new BigInteger("100000000", 16)),
+ roundKeys[i - 1].remainder(new BigInteger("1000000000000000000000000", 16)).divide(new BigInteger("10000000000000000", 16)),
+ roundKeys[i - 1].divide(new BigInteger("1000000000000000000000000", 16)),
+ };
// run schedule core
t = scheduleCore(t, rconCounter);
@@ -326,7 +2483,6 @@ public static BigInteger[] keyExpansion(BigInteger initialKey) {
* @return array of 8-bit integers
*/
public static int[] splitBlockIntoCells(BigInteger block) {
-
int[] cells = new int[16];
StringBuilder blockBits = new StringBuilder(block.toString(2));
@@ -352,7 +2508,6 @@ public static int[] splitBlockIntoCells(BigInteger block) {
* @return block of merged cells
*/
public static BigInteger mergeCellsIntoBlock(int[] cells) {
-
StringBuilder blockBits = new StringBuilder();
for (int i = 0; i < 16; i++) {
StringBuilder cellBits = new StringBuilder(Integer.toBinaryString(cells[i]));
@@ -382,7 +2537,6 @@ public static BigInteger addRoundKey(BigInteger ciphertext, BigInteger key) {
* @return subtraction Output
*/
public static BigInteger subBytes(BigInteger ciphertext) {
-
int[] cells = splitBlockIntoCells(ciphertext);
for (int i = 0; i < 16; i++) {
@@ -399,7 +2553,6 @@ public static BigInteger subBytes(BigInteger ciphertext) {
* @return subtraction Output
*/
public static BigInteger subBytesDec(BigInteger ciphertext) {
-
int[] cells = splitBlockIntoCells(ciphertext);
for (int i = 0; i < 16; i++) {
@@ -483,12 +2636,16 @@ public static BigInteger shiftRowsDec(BigInteger ciphertext) {
* Applies the Rijndael MixColumns to the input and returns the result.
*/
public static BigInteger mixColumns(BigInteger ciphertext) {
-
int[] cells = splitBlockIntoCells(ciphertext);
int[] outputCells = new int[16];
for (int i = 0; i < 4; i++) {
- int[] row = {cells[i * 4], cells[i * 4 + 1], cells[i * 4 + 2], cells[i * 4 + 3]};
+ int[] row = {
+ cells[i * 4],
+ cells[i * 4 + 1],
+ cells[i * 4 + 2],
+ cells[i * 4 + 3],
+ };
outputCells[i * 4] = MULT2[row[0]] ^ MULT3[row[1]] ^ row[2] ^ row[3];
outputCells[i * 4 + 1] = row[0] ^ MULT2[row[1]] ^ MULT3[row[2]] ^ row[3];
@@ -503,12 +2660,16 @@ public static BigInteger mixColumns(BigInteger ciphertext) {
* returns the result.
*/
public static BigInteger mixColumnsDec(BigInteger ciphertext) {
-
int[] cells = splitBlockIntoCells(ciphertext);
int[] outputCells = new int[16];
for (int i = 0; i < 4; i++) {
- int[] row = {cells[i * 4], cells[i * 4 + 1], cells[i * 4 + 2], cells[i * 4 + 3]};
+ int[] row = {
+ cells[i * 4],
+ cells[i * 4 + 1],
+ cells[i * 4 + 2],
+ cells[i * 4 + 3],
+ };
outputCells[i * 4] = MULT14[row[0]] ^ MULT11[row[1]] ^ MULT13[row[2]] ^ MULT9[row[3]];
outputCells[i * 4 + 1] = MULT9[row[0]] ^ MULT14[row[1]] ^ MULT11[row[2]] ^ MULT13[row[3]];
@@ -554,7 +2715,6 @@ public static BigInteger encrypt(BigInteger plainText, BigInteger key) {
* @return decryptedText
*/
public static BigInteger decrypt(BigInteger cipherText, BigInteger key) {
-
BigInteger[] roundKeys = keyExpansion(key);
// Invert final round
@@ -577,34 +2737,44 @@ public static BigInteger decrypt(BigInteger cipherText, BigInteger key) {
}
public static void main(String[] args) {
-
try (Scanner input = new Scanner(System.in)) {
System.out.println("Enter (e) letter for encrpyt or (d) letter for decrypt :");
char choice = input.nextLine().charAt(0);
String in;
switch (choice) {
case 'E', 'e' -> {
- System.out.println("Choose a plaintext block (128-Bit Integer in base 16):");
+ System.out.println(
+ "Choose a plaintext block (128-Bit Integer in base 16):"
+ );
in = input.nextLine();
BigInteger plaintext = new BigInteger(in, 16);
- System.out.println("Choose a Key (128-Bit Integer in base 16):");
+ System.out.println(
+ "Choose a Key (128-Bit Integer in base 16):"
+ );
in = input.nextLine();
BigInteger encryptionKey = new BigInteger(in, 16);
System.out.println(
- "The encrypted message is: \n" + encrypt(plaintext, encryptionKey).toString(16));
+ "The encrypted message is: \n"
+ + encrypt(plaintext, encryptionKey).toString(16)
+ );
}
case 'D', 'd' -> {
- System.out.println("Enter your ciphertext block (128-Bit Integer in base 16):");
+ System.out.println(
+ "Enter your ciphertext block (128-Bit Integer in base 16):"
+ );
in = input.nextLine();
BigInteger ciphertext = new BigInteger(in, 16);
- System.out.println("Choose a Key (128-Bit Integer in base 16):");
+ System.out.println(
+ "Choose a Key (128-Bit Integer in base 16):"
+ );
in = input.nextLine();
BigInteger decryptionKey = new BigInteger(in, 16);
System.out.println(
- "The deciphered message is:\n" + decrypt(ciphertext, decryptionKey).toString(16));
+ "The deciphered message is:\n"
+ + decrypt(ciphertext, decryptionKey).toString(16)
+ );
}
- default ->
- System.out.println("** End **");
+ default -> System.out.println("** End **");
}
}
}
diff --git a/src/main/java/com/thealgorithms/ciphers/AESEncryption.java b/src/main/java/com/thealgorithms/ciphers/AESEncryption.java
index 81fa79cc90f4..14582205442f 100644
--- a/src/main/java/com/thealgorithms/ciphers/AESEncryption.java
+++ b/src/main/java/com/thealgorithms/ciphers/AESEncryption.java
@@ -1,8 +1,15 @@
package com.thealgorithms.ciphers;
-import javax.crypto.*;
+import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
/**
* This example program shows how AES encryption and decryption can be done in
@@ -10,13 +17,16 @@
* hence in the following program we display it in hexadecimal format of the
* underlying bytes.
*/
-public class AESEncryption {
+public final class AESEncryption {
+ private AESEncryption() {
+ }
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+ private static Cipher aesCipher;
/**
* 1. Generate a plain text for encryption 2. Get a secret key (printed in
- * hexadecimal form). In actual use this must by encrypted and kept safe.
+ * hexadecimal form). In actual use this must be encrypted and kept safe.
* The same key is required for decryption.
*/
public static void main(String[] args) throws Exception {
@@ -54,11 +64,9 @@ public static SecretKey getSecretEncryptionKey() throws NoSuchAlgorithmException
* @throws BadPaddingException (from Cipher)
* @throws IllegalBlockSizeException (from Cipher)
*/
- public static byte[] encryptText(String plainText, SecretKey secKey)
- throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
- IllegalBlockSizeException, BadPaddingException {
+ public static byte[] encryptText(String plainText, SecretKey secKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
// AES defaults to AES/ECB/PKCS5Padding in Java 7
- Cipher aesCipher = Cipher.getInstance("AES");
+ aesCipher = Cipher.getInstance("AES/GCM/NoPadding");
aesCipher.init(Cipher.ENCRYPT_MODE, secKey);
return aesCipher.doFinal(plainText.getBytes());
}
@@ -68,13 +76,12 @@ public static byte[] encryptText(String plainText, SecretKey secKey)
*
* @return plainText
*/
- public static String decryptText(byte[] byteCipherText, SecretKey secKey)
- throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
- IllegalBlockSizeException, BadPaddingException {
+ public static String decryptText(byte[] byteCipherText, SecretKey secKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
// AES defaults to AES/ECB/PKCS5Padding in Java 7
- Cipher aesCipher = Cipher.getInstance("AES");
- aesCipher.init(Cipher.DECRYPT_MODE, secKey);
- byte[] bytePlainText = aesCipher.doFinal(byteCipherText);
+ Cipher decryptionCipher = Cipher.getInstance("AES/GCM/NoPadding");
+ GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, aesCipher.getIV());
+ decryptionCipher.init(Cipher.DECRYPT_MODE, secKey, gcmParameterSpec);
+ byte[] bytePlainText = decryptionCipher.doFinal(byteCipherText);
return new String(bytePlainText);
}
diff --git a/src/main/java/com/thealgorithms/ciphers/AffineCipher.java b/src/main/java/com/thealgorithms/ciphers/AffineCipher.java
index d08c50533fd7..979f18532eaa 100644
--- a/src/main/java/com/thealgorithms/ciphers/AffineCipher.java
+++ b/src/main/java/com/thealgorithms/ciphers/AffineCipher.java
@@ -1,72 +1,87 @@
package com.thealgorithms.ciphers;
-class AffineCipher {
+/**
+ * The AffineCipher class implements the Affine cipher, a type of monoalphabetic substitution cipher.
+ * It encrypts and decrypts messages using a linear transformation defined by the formula:
+ *
+ * E(x) = (a * x + b) mod m
+ * D(y) = a^-1 * (y - b) mod m
+ *
+ * where:
+ * - E(x) is the encrypted character,
+ * - D(y) is the decrypted character,
+ * - a is the multiplicative key (must be coprime to m),
+ * - b is the additive key,
+ * - x is the index of the plaintext character,
+ * - y is the index of the ciphertext character,
+ * - m is the size of the alphabet (26 for the English alphabet).
+ *
+ * The class provides methods for encrypting and decrypting messages, as well as a main method to demonstrate its usage.
+ */
+final class AffineCipher {
+ private AffineCipher() {
+ }
// Key values of a and b
static int a = 17;
static int b = 20;
+ /**
+ * Encrypts a message using the Affine cipher.
+ *
+ * @param msg the plaintext message as a character array
+ * @return the encrypted ciphertext
+ */
static String encryptMessage(char[] msg) {
- /// Cipher Text initially empty
- String cipher = "";
+ // Cipher Text initially empty
+ StringBuilder cipher = new StringBuilder();
for (int i = 0; i < msg.length; i++) {
// Avoid space to be encrypted
- /* applying encryption formula ( a x + b ) mod m
+ /* applying encryption formula ( a * x + b ) mod m
{here x is msg[i] and m is 26} and added 'A' to
- bring it in range of ascii alphabet[ 65-90 | A-Z ] */
+ bring it in the range of ASCII alphabet [65-90 | A-Z] */
if (msg[i] != ' ') {
- cipher = cipher
- + (char) ((((a * (msg[i] - 'A')) + b) % 26) + 'A');
- } else // else simply append space character
- {
- cipher += msg[i];
+ cipher.append((char) ((((a * (msg[i] - 'A')) + b) % 26) + 'A'));
+ } else { // else simply append space character
+ cipher.append(msg[i]);
}
}
- return cipher;
+ return cipher.toString();
}
+ /**
+ * Decrypts a ciphertext using the Affine cipher.
+ *
+ * @param cipher the ciphertext to decrypt
+ * @return the decrypted plaintext message
+ */
static String decryptCipher(String cipher) {
- String msg = "";
- int a_inv = 0;
- int flag = 0;
+ StringBuilder msg = new StringBuilder();
+ int aInv = 0;
+ int flag;
- //Find a^-1 (the multiplicative inverse of a
- //in the group of integers modulo m.)
+ // Find a^-1 (the multiplicative inverse of a in the group of integers modulo m.)
for (int i = 0; i < 26; i++) {
flag = (a * i) % 26;
- // Check if (a*i)%26 == 1,
+ // Check if (a * i) % 26 == 1,
// then i will be the multiplicative inverse of a
if (flag == 1) {
- a_inv = i;
+ aInv = i;
+ break;
}
}
for (int i = 0; i < cipher.length(); i++) {
- /*Applying decryption formula a^-1 ( x - b ) mod m
+ /* Applying decryption formula a^-1 * (x - b) mod m
{here x is cipher[i] and m is 26} and added 'A'
- to bring it in range of ASCII alphabet[ 65-90 | A-Z ] */
+ to bring it in the range of ASCII alphabet [65-90 | A-Z] */
if (cipher.charAt(i) != ' ') {
- msg = msg + (char) (((a_inv
- * ((cipher.charAt(i) + 'A' - b)) % 26)) + 'A');
- } else //else simply append space character
- {
- msg += cipher.charAt(i);
+ msg.append((char) (((aInv * ((cipher.charAt(i) - 'A') - b + 26)) % 26) + 'A'));
+ } else { // else simply append space character
+ msg.append(cipher.charAt(i));
}
}
- return msg;
- }
-
- // Driver code
- public static void main(String[] args) {
- String msg = "AFFINE CIPHER";
-
- // Calling encryption function
- String cipherText = encryptMessage(msg.toCharArray());
- System.out.println("Encrypted Message is : " + cipherText);
-
- // Calling Decryption function
- System.out.println("Decrypted Message is: " + decryptCipher(cipherText));
-
+ return msg.toString();
}
}
diff --git a/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java b/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java
new file mode 100644
index 000000000000..9169aa82bd75
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java
@@ -0,0 +1,101 @@
+package com.thealgorithms.ciphers;
+
+/**
+ * The Atbash cipher is a classic substitution cipher that substitutes each letter
+ * with its opposite letter in the alphabet.
+ *
+ * For example:
+ * - 'A' becomes 'Z', 'B' becomes 'Y', 'C' becomes 'X', and so on.
+ * - Similarly, 'a' becomes 'z', 'b' becomes 'y', and so on.
+ *
+ * The cipher works identically for both uppercase and lowercase letters.
+ * Non-alphabetical characters remain unchanged in the output.
+ *
+ * This cipher is symmetric, meaning that applying the cipher twice will return
+ * the original text. Therefore, the same function is used for both encryption and decryption.
+ *
+ * Usage Example:
+ *
+ * AtbashCipher cipher = new AtbashCipher("Hello World!");
+ * String encrypted = cipher.convert(); // Output: "Svool Dliow!"
+ *
+ *
+ * @author Krounosity
+ * @see Atbash Cipher (Wikipedia)
+ */
+public class AtbashCipher {
+
+ private String toConvert;
+
+ public AtbashCipher() {
+ }
+
+ /**
+ * Constructor with a string parameter.
+ *
+ * @param str The string to be converted using the Atbash cipher
+ */
+ public AtbashCipher(String str) {
+ this.toConvert = str;
+ }
+
+ /**
+ * Returns the current string set for conversion.
+ *
+ * @return The string to be converted
+ */
+ public String getString() {
+ return toConvert;
+ }
+
+ /**
+ * Sets the string to be converted using the Atbash cipher.
+ *
+ * @param str The new string to convert
+ */
+ public void setString(String str) {
+ this.toConvert = str;
+ }
+
+ /**
+ * Checks if a character is uppercase.
+ *
+ * @param ch The character to check
+ * @return {@code true} if the character is uppercase, {@code false} otherwise
+ */
+ private boolean isCapital(char ch) {
+ return ch >= 'A' && ch <= 'Z';
+ }
+
+ /**
+ * Checks if a character is lowercase.
+ *
+ * @param ch The character to check
+ * @return {@code true} if the character is lowercase, {@code false} otherwise
+ */
+ private boolean isSmall(char ch) {
+ return ch >= 'a' && ch <= 'z';
+ }
+
+ /**
+ * Converts the input string using the Atbash cipher.
+ * Alphabetic characters are substituted with their opposite in the alphabet,
+ * while non-alphabetic characters remain unchanged.
+ *
+ * @return The converted string after applying the Atbash cipher
+ */
+ public String convert() {
+ StringBuilder convertedString = new StringBuilder();
+
+ for (char ch : toConvert.toCharArray()) {
+ if (isSmall(ch)) {
+ convertedString.append((char) ('z' - (ch - 'a')));
+ } else if (isCapital(ch)) {
+ convertedString.append((char) ('Z' - (ch - 'A')));
+ } else {
+ convertedString.append(ch);
+ }
+ }
+ return convertedString.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/Autokey.java b/src/main/java/com/thealgorithms/ciphers/Autokey.java
new file mode 100644
index 000000000000..bb67f512accf
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/Autokey.java
@@ -0,0 +1,55 @@
+package com.thealgorithms.ciphers;
+
+/**
+ * The Autokey Cipher is an interesting and historically significant encryption method,
+ * as it improves upon the classic Vigenère Cipher by using the plaintext itself to
+ * extend the key. This makes it harder to break using frequency analysis, as it
+ * doesn’t rely solely on a repeated key.
+ * https://en.wikipedia.org/wiki/Autokey_cipher
+ *
+ * @author bennybebo
+ */
+public class Autokey {
+
+ // Encrypts the plaintext using the Autokey cipher
+ public String encrypt(String plaintext, String keyword) {
+ plaintext = plaintext.toUpperCase().replaceAll("[^A-Z]", ""); // Sanitize input
+ keyword = keyword.toUpperCase();
+
+ StringBuilder extendedKey = new StringBuilder(keyword);
+ extendedKey.append(plaintext); // Extend key with plaintext
+
+ StringBuilder ciphertext = new StringBuilder();
+
+ for (int i = 0; i < plaintext.length(); i++) {
+ char plainChar = plaintext.charAt(i);
+ char keyChar = extendedKey.charAt(i);
+
+ int encryptedChar = (plainChar - 'A' + keyChar - 'A') % 26 + 'A';
+ ciphertext.append((char) encryptedChar);
+ }
+
+ return ciphertext.toString();
+ }
+
+ // Decrypts the ciphertext using the Autokey cipher
+ public String decrypt(String ciphertext, String keyword) {
+ ciphertext = ciphertext.toUpperCase().replaceAll("[^A-Z]", ""); // Sanitize input
+ keyword = keyword.toUpperCase();
+
+ StringBuilder plaintext = new StringBuilder();
+ StringBuilder extendedKey = new StringBuilder(keyword);
+
+ for (int i = 0; i < ciphertext.length(); i++) {
+ char cipherChar = ciphertext.charAt(i);
+ char keyChar = extendedKey.charAt(i);
+
+ int decryptedChar = (cipherChar - 'A' - (keyChar - 'A') + 26) % 26 + 'A';
+ plaintext.append((char) decryptedChar);
+
+ extendedKey.append((char) decryptedChar); // Extend key with each decrypted char
+ }
+
+ return plaintext.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/BaconianCipher.java b/src/main/java/com/thealgorithms/ciphers/BaconianCipher.java
new file mode 100644
index 000000000000..16dfd6e674af
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/BaconianCipher.java
@@ -0,0 +1,71 @@
+package com.thealgorithms.ciphers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The Baconian Cipher is a substitution cipher where each letter is represented
+ * by a group of five binary digits (A's and B's). It can also be used to hide
+ * messages within other texts, making it a simple form of steganography.
+ * https://en.wikipedia.org/wiki/Bacon%27s_cipher
+ *
+ * @author Bennybebo
+ */
+public class BaconianCipher {
+
+ private static final Map BACONIAN_MAP = new HashMap<>();
+ private static final Map REVERSE_BACONIAN_MAP = new HashMap<>();
+
+ static {
+ // Initialize the Baconian cipher mappings
+ String[] baconianAlphabet = {"AAAAA", "AAAAB", "AAABA", "AAABB", "AABAA", "AABAB", "AABBA", "AABBB", "ABAAA", "ABAAB", "ABABA", "ABABB", "ABBAA", "ABBAB", "ABBBA", "ABBBB", "BAAAA", "BAAAB", "BAABA", "BAABB", "BABAA", "BABAB", "BABBA", "BABBB", "BBAAA", "BBAAB"};
+ char letter = 'A';
+ for (String code : baconianAlphabet) {
+ BACONIAN_MAP.put(letter, code);
+ REVERSE_BACONIAN_MAP.put(code, letter);
+ letter++;
+ }
+
+ // Handle I/J as the same letter
+ BACONIAN_MAP.put('I', BACONIAN_MAP.get('J'));
+ REVERSE_BACONIAN_MAP.put(BACONIAN_MAP.get('I'), 'I');
+ }
+
+ /**
+ * Encrypts the given plaintext using the Baconian cipher.
+ *
+ * @param plaintext The plaintext message to encrypt.
+ * @return The ciphertext as a binary (A/B) sequence.
+ */
+ public String encrypt(String plaintext) {
+ StringBuilder ciphertext = new StringBuilder();
+ plaintext = plaintext.toUpperCase().replaceAll("[^A-Z]", ""); // Remove non-letter characters
+
+ for (char letter : plaintext.toCharArray()) {
+ ciphertext.append(BACONIAN_MAP.get(letter));
+ }
+
+ return ciphertext.toString();
+ }
+
+ /**
+ * Decrypts the given ciphertext encoded in binary (A/B) format using the Baconian cipher.
+ *
+ * @param ciphertext The ciphertext to decrypt.
+ * @return The decrypted plaintext message.
+ */
+ public String decrypt(String ciphertext) {
+ StringBuilder plaintext = new StringBuilder();
+
+ for (int i = 0; i < ciphertext.length(); i += 5) {
+ String code = ciphertext.substring(i, i + 5);
+ if (REVERSE_BACONIAN_MAP.containsKey(code)) {
+ plaintext.append(REVERSE_BACONIAN_MAP.get(code));
+ } else {
+ throw new IllegalArgumentException("Invalid Baconian code: " + code);
+ }
+ }
+
+ return plaintext.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/Blowfish.java b/src/main/java/com/thealgorithms/ciphers/Blowfish.java
new file mode 100644
index 000000000000..ea1807e62710
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/Blowfish.java
@@ -0,0 +1,1244 @@
+package com.thealgorithms.ciphers;
+
+/*
+ * Java program for Blowfish Algorithm
+ * Wikipedia: https://en.wikipedia.org/wiki/Blowfish_(cipher)
+ *
+ * Author: Akshay Dubey (https://github.com/itsAkshayDubey)
+ *
+ * */
+
+public class Blowfish {
+
+ // Initializing substitution boxes
+ String[][] sBox = {
+ {
+ "d1310ba6",
+ "98dfb5ac",
+ "2ffd72db",
+ "d01adfb7",
+ "b8e1afed",
+ "6a267e96",
+ "ba7c9045",
+ "f12c7f99",
+ "24a19947",
+ "b3916cf7",
+ "0801f2e2",
+ "858efc16",
+ "636920d8",
+ "71574e69",
+ "a458fea3",
+ "f4933d7e",
+ "0d95748f",
+ "728eb658",
+ "718bcd58",
+ "82154aee",
+ "7b54a41d",
+ "c25a59b5",
+ "9c30d539",
+ "2af26013",
+ "c5d1b023",
+ "286085f0",
+ "ca417918",
+ "b8db38ef",
+ "8e79dcb0",
+ "603a180e",
+ "6c9e0e8b",
+ "b01e8a3e",
+ "d71577c1",
+ "bd314b27",
+ "78af2fda",
+ "55605c60",
+ "e65525f3",
+ "aa55ab94",
+ "57489862",
+ "63e81440",
+ "55ca396a",
+ "2aab10b6",
+ "b4cc5c34",
+ "1141e8ce",
+ "a15486af",
+ "7c72e993",
+ "b3ee1411",
+ "636fbc2a",
+ "2ba9c55d",
+ "741831f6",
+ "ce5c3e16",
+ "9b87931e",
+ "afd6ba33",
+ "6c24cf5c",
+ "7a325381",
+ "28958677",
+ "3b8f4898",
+ "6b4bb9af",
+ "c4bfe81b",
+ "66282193",
+ "61d809cc",
+ "fb21a991",
+ "487cac60",
+ "5dec8032",
+ "ef845d5d",
+ "e98575b1",
+ "dc262302",
+ "eb651b88",
+ "23893e81",
+ "d396acc5",
+ "0f6d6ff3",
+ "83f44239",
+ "2e0b4482",
+ "a4842004",
+ "69c8f04a",
+ "9e1f9b5e",
+ "21c66842",
+ "f6e96c9a",
+ "670c9c61",
+ "abd388f0",
+ "6a51a0d2",
+ "d8542f68",
+ "960fa728",
+ "ab5133a3",
+ "6eef0b6c",
+ "137a3be4",
+ "ba3bf050",
+ "7efb2a98",
+ "a1f1651d",
+ "39af0176",
+ "66ca593e",
+ "82430e88",
+ "8cee8619",
+ "456f9fb4",
+ "7d84a5c3",
+ "3b8b5ebe",
+ "e06f75d8",
+ "85c12073",
+ "401a449f",
+ "56c16aa6",
+ "4ed3aa62",
+ "363f7706",
+ "1bfedf72",
+ "429b023d",
+ "37d0d724",
+ "d00a1248",
+ "db0fead3",
+ "49f1c09b",
+ "075372c9",
+ "80991b7b",
+ "25d479d8",
+ "f6e8def7",
+ "e3fe501a",
+ "b6794c3b",
+ "976ce0bd",
+ "04c006ba",
+ "c1a94fb6",
+ "409f60c4",
+ "5e5c9ec2",
+ "196a2463",
+ "68fb6faf",
+ "3e6c53b5",
+ "1339b2eb",
+ "3b52ec6f",
+ "6dfc511f",
+ "9b30952c",
+ "cc814544",
+ "af5ebd09",
+ "bee3d004",
+ "de334afd",
+ "660f2807",
+ "192e4bb3",
+ "c0cba857",
+ "45c8740f",
+ "d20b5f39",
+ "b9d3fbdb",
+ "5579c0bd",
+ "1a60320a",
+ "d6a100c6",
+ "402c7279",
+ "679f25fe",
+ "fb1fa3cc",
+ "8ea5e9f8",
+ "db3222f8",
+ "3c7516df",
+ "fd616b15",
+ "2f501ec8",
+ "ad0552ab",
+ "323db5fa",
+ "fd238760",
+ "53317b48",
+ "3e00df82",
+ "9e5c57bb",
+ "ca6f8ca0",
+ "1a87562e",
+ "df1769db",
+ "d542a8f6",
+ "287effc3",
+ "ac6732c6",
+ "8c4f5573",
+ "695b27b0",
+ "bbca58c8",
+ "e1ffa35d",
+ "b8f011a0",
+ "10fa3d98",
+ "fd2183b8",
+ "4afcb56c",
+ "2dd1d35b",
+ "9a53e479",
+ "b6f84565",
+ "d28e49bc",
+ "4bfb9790",
+ "e1ddf2da",
+ "a4cb7e33",
+ "62fb1341",
+ "cee4c6e8",
+ "ef20cada",
+ "36774c01",
+ "d07e9efe",
+ "2bf11fb4",
+ "95dbda4d",
+ "ae909198",
+ "eaad8e71",
+ "6b93d5a0",
+ "d08ed1d0",
+ "afc725e0",
+ "8e3c5b2f",
+ "8e7594b7",
+ "8ff6e2fb",
+ "f2122b64",
+ "8888b812",
+ "900df01c",
+ "4fad5ea0",
+ "688fc31c",
+ "d1cff191",
+ "b3a8c1ad",
+ "2f2f2218",
+ "be0e1777",
+ "ea752dfe",
+ "8b021fa1",
+ "e5a0cc0f",
+ "b56f74e8",
+ "18acf3d6",
+ "ce89e299",
+ "b4a84fe0",
+ "fd13e0b7",
+ "7cc43b81",
+ "d2ada8d9",
+ "165fa266",
+ "80957705",
+ "93cc7314",
+ "211a1477",
+ "e6ad2065",
+ "77b5fa86",
+ "c75442f5",
+ "fb9d35cf",
+ "ebcdaf0c",
+ "7b3e89a0",
+ "d6411bd3",
+ "ae1e7e49",
+ "00250e2d",
+ "2071b35e",
+ "226800bb",
+ "57b8e0af",
+ "2464369b",
+ "f009b91e",
+ "5563911d",
+ "59dfa6aa",
+ "78c14389",
+ "d95a537f",
+ "207d5ba2",
+ "02e5b9c5",
+ "83260376",
+ "6295cfa9",
+ "11c81968",
+ "4e734a41",
+ "b3472dca",
+ "7b14a94a",
+ "1b510052",
+ "9a532915",
+ "d60f573f",
+ "bc9bc6e4",
+ "2b60a476",
+ "81e67400",
+ "08ba6fb5",
+ "571be91f",
+ "f296ec6b",
+ "2a0dd915",
+ "b6636521",
+ "e7b9f9b6",
+ "ff34052e",
+ "c5855664",
+ "53b02d5d",
+ "a99f8fa1",
+ "08ba4799",
+ "6e85076a",
+ },
+ {
+ "4b7a70e9",
+ "b5b32944",
+ "db75092e",
+ "c4192623",
+ "ad6ea6b0",
+ "49a7df7d",
+ "9cee60b8",
+ "8fedb266",
+ "ecaa8c71",
+ "699a17ff",
+ "5664526c",
+ "c2b19ee1",
+ "193602a5",
+ "75094c29",
+ "a0591340",
+ "e4183a3e",
+ "3f54989a",
+ "5b429d65",
+ "6b8fe4d6",
+ "99f73fd6",
+ "a1d29c07",
+ "efe830f5",
+ "4d2d38e6",
+ "f0255dc1",
+ "4cdd2086",
+ "8470eb26",
+ "6382e9c6",
+ "021ecc5e",
+ "09686b3f",
+ "3ebaefc9",
+ "3c971814",
+ "6b6a70a1",
+ "687f3584",
+ "52a0e286",
+ "b79c5305",
+ "aa500737",
+ "3e07841c",
+ "7fdeae5c",
+ "8e7d44ec",
+ "5716f2b8",
+ "b03ada37",
+ "f0500c0d",
+ "f01c1f04",
+ "0200b3ff",
+ "ae0cf51a",
+ "3cb574b2",
+ "25837a58",
+ "dc0921bd",
+ "d19113f9",
+ "7ca92ff6",
+ "94324773",
+ "22f54701",
+ "3ae5e581",
+ "37c2dadc",
+ "c8b57634",
+ "9af3dda7",
+ "a9446146",
+ "0fd0030e",
+ "ecc8c73e",
+ "a4751e41",
+ "e238cd99",
+ "3bea0e2f",
+ "3280bba1",
+ "183eb331",
+ "4e548b38",
+ "4f6db908",
+ "6f420d03",
+ "f60a04bf",
+ "2cb81290",
+ "24977c79",
+ "5679b072",
+ "bcaf89af",
+ "de9a771f",
+ "d9930810",
+ "b38bae12",
+ "dccf3f2e",
+ "5512721f",
+ "2e6b7124",
+ "501adde6",
+ "9f84cd87",
+ "7a584718",
+ "7408da17",
+ "bc9f9abc",
+ "e94b7d8c",
+ "ec7aec3a",
+ "db851dfa",
+ "63094366",
+ "c464c3d2",
+ "ef1c1847",
+ "3215d908",
+ "dd433b37",
+ "24c2ba16",
+ "12a14d43",
+ "2a65c451",
+ "50940002",
+ "133ae4dd",
+ "71dff89e",
+ "10314e55",
+ "81ac77d6",
+ "5f11199b",
+ "043556f1",
+ "d7a3c76b",
+ "3c11183b",
+ "5924a509",
+ "f28fe6ed",
+ "97f1fbfa",
+ "9ebabf2c",
+ "1e153c6e",
+ "86e34570",
+ "eae96fb1",
+ "860e5e0a",
+ "5a3e2ab3",
+ "771fe71c",
+ "4e3d06fa",
+ "2965dcb9",
+ "99e71d0f",
+ "803e89d6",
+ "5266c825",
+ "2e4cc978",
+ "9c10b36a",
+ "c6150eba",
+ "94e2ea78",
+ "a5fc3c53",
+ "1e0a2df4",
+ "f2f74ea7",
+ "361d2b3d",
+ "1939260f",
+ "19c27960",
+ "5223a708",
+ "f71312b6",
+ "ebadfe6e",
+ "eac31f66",
+ "e3bc4595",
+ "a67bc883",
+ "b17f37d1",
+ "018cff28",
+ "c332ddef",
+ "be6c5aa5",
+ "65582185",
+ "68ab9802",
+ "eecea50f",
+ "db2f953b",
+ "2aef7dad",
+ "5b6e2f84",
+ "1521b628",
+ "29076170",
+ "ecdd4775",
+ "619f1510",
+ "13cca830",
+ "eb61bd96",
+ "0334fe1e",
+ "aa0363cf",
+ "b5735c90",
+ "4c70a239",
+ "d59e9e0b",
+ "cbaade14",
+ "eecc86bc",
+ "60622ca7",
+ "9cab5cab",
+ "b2f3846e",
+ "648b1eaf",
+ "19bdf0ca",
+ "a02369b9",
+ "655abb50",
+ "40685a32",
+ "3c2ab4b3",
+ "319ee9d5",
+ "c021b8f7",
+ "9b540b19",
+ "875fa099",
+ "95f7997e",
+ "623d7da8",
+ "f837889a",
+ "97e32d77",
+ "11ed935f",
+ "16681281",
+ "0e358829",
+ "c7e61fd6",
+ "96dedfa1",
+ "7858ba99",
+ "57f584a5",
+ "1b227263",
+ "9b83c3ff",
+ "1ac24696",
+ "cdb30aeb",
+ "532e3054",
+ "8fd948e4",
+ "6dbc3128",
+ "58ebf2ef",
+ "34c6ffea",
+ "fe28ed61",
+ "ee7c3c73",
+ "5d4a14d9",
+ "e864b7e3",
+ "42105d14",
+ "203e13e0",
+ "45eee2b6",
+ "a3aaabea",
+ "db6c4f15",
+ "facb4fd0",
+ "c742f442",
+ "ef6abbb5",
+ "654f3b1d",
+ "41cd2105",
+ "d81e799e",
+ "86854dc7",
+ "e44b476a",
+ "3d816250",
+ "cf62a1f2",
+ "5b8d2646",
+ "fc8883a0",
+ "c1c7b6a3",
+ "7f1524c3",
+ "69cb7492",
+ "47848a0b",
+ "5692b285",
+ "095bbf00",
+ "ad19489d",
+ "1462b174",
+ "23820e00",
+ "58428d2a",
+ "0c55f5ea",
+ "1dadf43e",
+ "233f7061",
+ "3372f092",
+ "8d937e41",
+ "d65fecf1",
+ "6c223bdb",
+ "7cde3759",
+ "cbee7460",
+ "4085f2a7",
+ "ce77326e",
+ "a6078084",
+ "19f8509e",
+ "e8efd855",
+ "61d99735",
+ "a969a7aa",
+ "c50c06c2",
+ "5a04abfc",
+ "800bcadc",
+ "9e447a2e",
+ "c3453484",
+ "fdd56705",
+ "0e1e9ec9",
+ "db73dbd3",
+ "105588cd",
+ "675fda79",
+ "e3674340",
+ "c5c43465",
+ "713e38d8",
+ "3d28f89e",
+ "f16dff20",
+ "153e21e7",
+ "8fb03d4a",
+ "e6e39f2b",
+ "db83adf7",
+ },
+ {
+ "e93d5a68",
+ "948140f7",
+ "f64c261c",
+ "94692934",
+ "411520f7",
+ "7602d4f7",
+ "bcf46b2e",
+ "d4a20068",
+ "d4082471",
+ "3320f46a",
+ "43b7d4b7",
+ "500061af",
+ "1e39f62e",
+ "97244546",
+ "14214f74",
+ "bf8b8840",
+ "4d95fc1d",
+ "96b591af",
+ "70f4ddd3",
+ "66a02f45",
+ "bfbc09ec",
+ "03bd9785",
+ "7fac6dd0",
+ "31cb8504",
+ "96eb27b3",
+ "55fd3941",
+ "da2547e6",
+ "abca0a9a",
+ "28507825",
+ "530429f4",
+ "0a2c86da",
+ "e9b66dfb",
+ "68dc1462",
+ "d7486900",
+ "680ec0a4",
+ "27a18dee",
+ "4f3ffea2",
+ "e887ad8c",
+ "b58ce006",
+ "7af4d6b6",
+ "aace1e7c",
+ "d3375fec",
+ "ce78a399",
+ "406b2a42",
+ "20fe9e35",
+ "d9f385b9",
+ "ee39d7ab",
+ "3b124e8b",
+ "1dc9faf7",
+ "4b6d1856",
+ "26a36631",
+ "eae397b2",
+ "3a6efa74",
+ "dd5b4332",
+ "6841e7f7",
+ "ca7820fb",
+ "fb0af54e",
+ "d8feb397",
+ "454056ac",
+ "ba489527",
+ "55533a3a",
+ "20838d87",
+ "fe6ba9b7",
+ "d096954b",
+ "55a867bc",
+ "a1159a58",
+ "cca92963",
+ "99e1db33",
+ "a62a4a56",
+ "3f3125f9",
+ "5ef47e1c",
+ "9029317c",
+ "fdf8e802",
+ "04272f70",
+ "80bb155c",
+ "05282ce3",
+ "95c11548",
+ "e4c66d22",
+ "48c1133f",
+ "c70f86dc",
+ "07f9c9ee",
+ "41041f0f",
+ "404779a4",
+ "5d886e17",
+ "325f51eb",
+ "d59bc0d1",
+ "f2bcc18f",
+ "41113564",
+ "257b7834",
+ "602a9c60",
+ "dff8e8a3",
+ "1f636c1b",
+ "0e12b4c2",
+ "02e1329e",
+ "af664fd1",
+ "cad18115",
+ "6b2395e0",
+ "333e92e1",
+ "3b240b62",
+ "eebeb922",
+ "85b2a20e",
+ "e6ba0d99",
+ "de720c8c",
+ "2da2f728",
+ "d0127845",
+ "95b794fd",
+ "647d0862",
+ "e7ccf5f0",
+ "5449a36f",
+ "877d48fa",
+ "c39dfd27",
+ "f33e8d1e",
+ "0a476341",
+ "992eff74",
+ "3a6f6eab",
+ "f4f8fd37",
+ "a812dc60",
+ "a1ebddf8",
+ "991be14c",
+ "db6e6b0d",
+ "c67b5510",
+ "6d672c37",
+ "2765d43b",
+ "dcd0e804",
+ "f1290dc7",
+ "cc00ffa3",
+ "b5390f92",
+ "690fed0b",
+ "667b9ffb",
+ "cedb7d9c",
+ "a091cf0b",
+ "d9155ea3",
+ "bb132f88",
+ "515bad24",
+ "7b9479bf",
+ "763bd6eb",
+ "37392eb3",
+ "cc115979",
+ "8026e297",
+ "f42e312d",
+ "6842ada7",
+ "c66a2b3b",
+ "12754ccc",
+ "782ef11c",
+ "6a124237",
+ "b79251e7",
+ "06a1bbe6",
+ "4bfb6350",
+ "1a6b1018",
+ "11caedfa",
+ "3d25bdd8",
+ "e2e1c3c9",
+ "44421659",
+ "0a121386",
+ "d90cec6e",
+ "d5abea2a",
+ "64af674e",
+ "da86a85f",
+ "bebfe988",
+ "64e4c3fe",
+ "9dbc8057",
+ "f0f7c086",
+ "60787bf8",
+ "6003604d",
+ "d1fd8346",
+ "f6381fb0",
+ "7745ae04",
+ "d736fccc",
+ "83426b33",
+ "f01eab71",
+ "b0804187",
+ "3c005e5f",
+ "77a057be",
+ "bde8ae24",
+ "55464299",
+ "bf582e61",
+ "4e58f48f",
+ "f2ddfda2",
+ "f474ef38",
+ "8789bdc2",
+ "5366f9c3",
+ "c8b38e74",
+ "b475f255",
+ "46fcd9b9",
+ "7aeb2661",
+ "8b1ddf84",
+ "846a0e79",
+ "915f95e2",
+ "466e598e",
+ "20b45770",
+ "8cd55591",
+ "c902de4c",
+ "b90bace1",
+ "bb8205d0",
+ "11a86248",
+ "7574a99e",
+ "b77f19b6",
+ "e0a9dc09",
+ "662d09a1",
+ "c4324633",
+ "e85a1f02",
+ "09f0be8c",
+ "4a99a025",
+ "1d6efe10",
+ "1ab93d1d",
+ "0ba5a4df",
+ "a186f20f",
+ "2868f169",
+ "dcb7da83",
+ "573906fe",
+ "a1e2ce9b",
+ "4fcd7f52",
+ "50115e01",
+ "a70683fa",
+ "a002b5c4",
+ "0de6d027",
+ "9af88c27",
+ "773f8641",
+ "c3604c06",
+ "61a806b5",
+ "f0177a28",
+ "c0f586e0",
+ "006058aa",
+ "30dc7d62",
+ "11e69ed7",
+ "2338ea63",
+ "53c2dd94",
+ "c2c21634",
+ "bbcbee56",
+ "90bcb6de",
+ "ebfc7da1",
+ "ce591d76",
+ "6f05e409",
+ "4b7c0188",
+ "39720a3d",
+ "7c927c24",
+ "86e3725f",
+ "724d9db9",
+ "1ac15bb4",
+ "d39eb8fc",
+ "ed545578",
+ "08fca5b5",
+ "d83d7cd3",
+ "4dad0fc4",
+ "1e50ef5e",
+ "b161e6f8",
+ "a28514d9",
+ "6c51133c",
+ "6fd5c7e7",
+ "56e14ec4",
+ "362abfce",
+ "ddc6c837",
+ "d79a3234",
+ "92638212",
+ "670efa8e",
+ "406000e0",
+ },
+ {
+ "3a39ce37",
+ "d3faf5cf",
+ "abc27737",
+ "5ac52d1b",
+ "5cb0679e",
+ "4fa33742",
+ "d3822740",
+ "99bc9bbe",
+ "d5118e9d",
+ "bf0f7315",
+ "d62d1c7e",
+ "c700c47b",
+ "b78c1b6b",
+ "21a19045",
+ "b26eb1be",
+ "6a366eb4",
+ "5748ab2f",
+ "bc946e79",
+ "c6a376d2",
+ "6549c2c8",
+ "530ff8ee",
+ "468dde7d",
+ "d5730a1d",
+ "4cd04dc6",
+ "2939bbdb",
+ "a9ba4650",
+ "ac9526e8",
+ "be5ee304",
+ "a1fad5f0",
+ "6a2d519a",
+ "63ef8ce2",
+ "9a86ee22",
+ "c089c2b8",
+ "43242ef6",
+ "a51e03aa",
+ "9cf2d0a4",
+ "83c061ba",
+ "9be96a4d",
+ "8fe51550",
+ "ba645bd6",
+ "2826a2f9",
+ "a73a3ae1",
+ "4ba99586",
+ "ef5562e9",
+ "c72fefd3",
+ "f752f7da",
+ "3f046f69",
+ "77fa0a59",
+ "80e4a915",
+ "87b08601",
+ "9b09e6ad",
+ "3b3ee593",
+ "e990fd5a",
+ "9e34d797",
+ "2cf0b7d9",
+ "022b8b51",
+ "96d5ac3a",
+ "017da67d",
+ "d1cf3ed6",
+ "7c7d2d28",
+ "1f9f25cf",
+ "adf2b89b",
+ "5ad6b472",
+ "5a88f54c",
+ "e029ac71",
+ "e019a5e6",
+ "47b0acfd",
+ "ed93fa9b",
+ "e8d3c48d",
+ "283b57cc",
+ "f8d56629",
+ "79132e28",
+ "785f0191",
+ "ed756055",
+ "f7960e44",
+ "e3d35e8c",
+ "15056dd4",
+ "88f46dba",
+ "03a16125",
+ "0564f0bd",
+ "c3eb9e15",
+ "3c9057a2",
+ "97271aec",
+ "a93a072a",
+ "1b3f6d9b",
+ "1e6321f5",
+ "f59c66fb",
+ "26dcf319",
+ "7533d928",
+ "b155fdf5",
+ "03563482",
+ "8aba3cbb",
+ "28517711",
+ "c20ad9f8",
+ "abcc5167",
+ "ccad925f",
+ "4de81751",
+ "3830dc8e",
+ "379d5862",
+ "9320f991",
+ "ea7a90c2",
+ "fb3e7bce",
+ "5121ce64",
+ "774fbe32",
+ "a8b6e37e",
+ "c3293d46",
+ "48de5369",
+ "6413e680",
+ "a2ae0810",
+ "dd6db224",
+ "69852dfd",
+ "09072166",
+ "b39a460a",
+ "6445c0dd",
+ "586cdecf",
+ "1c20c8ae",
+ "5bbef7dd",
+ "1b588d40",
+ "ccd2017f",
+ "6bb4e3bb",
+ "dda26a7e",
+ "3a59ff45",
+ "3e350a44",
+ "bcb4cdd5",
+ "72eacea8",
+ "fa6484bb",
+ "8d6612ae",
+ "bf3c6f47",
+ "d29be463",
+ "542f5d9e",
+ "aec2771b",
+ "f64e6370",
+ "740e0d8d",
+ "e75b1357",
+ "f8721671",
+ "af537d5d",
+ "4040cb08",
+ "4eb4e2cc",
+ "34d2466a",
+ "0115af84",
+ "e1b00428",
+ "95983a1d",
+ "06b89fb4",
+ "ce6ea048",
+ "6f3f3b82",
+ "3520ab82",
+ "011a1d4b",
+ "277227f8",
+ "611560b1",
+ "e7933fdc",
+ "bb3a792b",
+ "344525bd",
+ "a08839e1",
+ "51ce794b",
+ "2f32c9b7",
+ "a01fbac9",
+ "e01cc87e",
+ "bcc7d1f6",
+ "cf0111c3",
+ "a1e8aac7",
+ "1a908749",
+ "d44fbd9a",
+ "d0dadecb",
+ "d50ada38",
+ "0339c32a",
+ "c6913667",
+ "8df9317c",
+ "e0b12b4f",
+ "f79e59b7",
+ "43f5bb3a",
+ "f2d519ff",
+ "27d9459c",
+ "bf97222c",
+ "15e6fc2a",
+ "0f91fc71",
+ "9b941525",
+ "fae59361",
+ "ceb69ceb",
+ "c2a86459",
+ "12baa8d1",
+ "b6c1075e",
+ "e3056a0c",
+ "10d25065",
+ "cb03a442",
+ "e0ec6e0e",
+ "1698db3b",
+ "4c98a0be",
+ "3278e964",
+ "9f1f9532",
+ "e0d392df",
+ "d3a0342b",
+ "8971f21e",
+ "1b0a7441",
+ "4ba3348c",
+ "c5be7120",
+ "c37632d8",
+ "df359f8d",
+ "9b992f2e",
+ "e60b6f47",
+ "0fe3f11d",
+ "e54cda54",
+ "1edad891",
+ "ce6279cf",
+ "cd3e7e6f",
+ "1618b166",
+ "fd2c1d05",
+ "848fd2c5",
+ "f6fb2299",
+ "f523f357",
+ "a6327623",
+ "93a83531",
+ "56cccd02",
+ "acf08162",
+ "5a75ebb5",
+ "6e163697",
+ "88d273cc",
+ "de966292",
+ "81b949d0",
+ "4c50901b",
+ "71c65614",
+ "e6c6c7bd",
+ "327a140a",
+ "45e1d006",
+ "c3f27b9a",
+ "c9aa53fd",
+ "62a80f00",
+ "bb25bfe2",
+ "35bdd2f6",
+ "71126905",
+ "b2040222",
+ "b6cbcf7c",
+ "cd769c2b",
+ "53113ec0",
+ "1640e3d3",
+ "38abbd60",
+ "2547adf0",
+ "ba38209c",
+ "f746ce76",
+ "77afa1c5",
+ "20756060",
+ "85cbfe4e",
+ "8ae88dd8",
+ "7aaaf9b0",
+ "4cf9aa7e",
+ "1948c25c",
+ "02fb8a8c",
+ "01c36ae4",
+ "d6ebe1f9",
+ "90d4f869",
+ "a65cdea0",
+ "3f09252d",
+ "c208e69f",
+ "b74e6132",
+ "ce77e25b",
+ "578fdfe3",
+ "3ac372e6",
+ },
+ };
+
+ // Initializing subkeys with digits of pi
+ String[] subKeys = {
+ "243f6a88",
+ "85a308d3",
+ "13198a2e",
+ "03707344",
+ "a4093822",
+ "299f31d0",
+ "082efa98",
+ "ec4e6c89",
+ "452821e6",
+ "38d01377",
+ "be5466cf",
+ "34e90c6c",
+ "c0ac29b7",
+ "c97c50dd",
+ "3f84d5b5",
+ "b5470917",
+ "9216d5d9",
+ "8979fb1b",
+ };
+
+ // Initializing modVal to 2^32
+ long modVal = 4294967296L;
+
+ /**
+ * This method returns binary representation of the hexadecimal number passed as parameter
+ *
+ * @param hex Number for which binary representation is required
+ * @return String object which is a binary representation of the hex number passed as parameter
+ */
+ private String hexToBin(String hex) {
+ StringBuilder binary = new StringBuilder();
+ long num;
+ String binary4B;
+ int n = hex.length();
+ for (int i = 0; i < n; i++) {
+ num = Long.parseUnsignedLong(hex.charAt(i) + "", 16);
+ binary4B = Long.toBinaryString(num);
+
+ binary4B = "0000" + binary4B;
+
+ binary4B = binary4B.substring(binary4B.length() - 4);
+ binary.append(binary4B);
+ }
+ return binary.toString();
+ }
+
+ /**
+ * This method returns hexadecimal representation of the binary number passed as parameter
+ *
+ * @param binary Number for which hexadecimal representation is required
+ * @return String object which is a hexadecimal representation of the binary number passed as
+ * parameter
+ */
+ private String binToHex(String binary) {
+ long num = Long.parseUnsignedLong(binary, 2);
+ StringBuilder hex = new StringBuilder(Long.toHexString(num));
+ while (hex.length() < (binary.length() / 4)) {
+ hex.insert(0, "0");
+ }
+
+ return hex.toString();
+ }
+
+ /**
+ * This method returns a string obtained by XOR-ing two strings of same length passed a method
+ * parameters
+ *
+ * @param String a and b are string objects which will be XORed and are to be of same length
+ * @return String object obtained by XOR operation on String a and String b
+ * */
+ private String xor(String a, String b) {
+ a = hexToBin(a);
+ b = hexToBin(b);
+ StringBuilder ans = new StringBuilder();
+ for (int i = 0; i < a.length(); i++) {
+ ans.append((char) (((a.charAt(i) - '0') ^ (b.charAt(i) - '0')) + '0'));
+ }
+ ans = new StringBuilder(binToHex(ans.toString()));
+ return ans.toString();
+ }
+
+ /**
+ * This method returns addition of two hexadecimal numbers passed as parameters and moded with
+ * 2^32
+ *
+ * @param String a and b are hexadecimal numbers
+ * @return String object which is a is addition that is then moded with 2^32 of hex numbers
+ * passed as parameters
+ */
+ private String addBin(String a, String b) {
+ String ans = "";
+ long n1 = Long.parseUnsignedLong(a, 16);
+ long n2 = Long.parseUnsignedLong(b, 16);
+ n1 = (n1 + n2) % modVal;
+ ans = Long.toHexString(n1);
+ ans = "00000000" + ans;
+ return ans.substring(ans.length() - 8);
+ }
+
+ /*F-function splits the 32-bit input into four 8-bit quarters
+ and uses the quarters as input to the S-boxes.
+ The S-boxes accept 8-bit input and produce 32-bit output.
+ The outputs are added modulo 232 and XORed to produce the final 32-bit output
+ */
+ private String f(String plainText) {
+ String[] a = new String[4];
+ String ans = "";
+ for (int i = 0; i < 8; i += 2) {
+ // column number for S-box is a 8-bit value
+ long col = Long.parseUnsignedLong(hexToBin(plainText.substring(i, i + 2)), 2);
+ a[i / 2] = sBox[i / 2][(int) col];
+ }
+ ans = addBin(a[0], a[1]);
+ ans = xor(ans, a[2]);
+ ans = addBin(ans, a[3]);
+ return ans;
+ }
+
+ // generate subkeys
+ private void keyGenerate(String key) {
+ int j = 0;
+ for (int i = 0; i < subKeys.length; i++) {
+ // XOR-ing 32-bit parts of the key with initial subkeys
+ subKeys[i] = xor(subKeys[i], key.substring(j, j + 8));
+
+ j = (j + 8) % key.length();
+ }
+ }
+
+ // round function
+ private String round(int time, String plainText) {
+ String left;
+ String right;
+ left = plainText.substring(0, 8);
+ right = plainText.substring(8, 16);
+ left = xor(left, subKeys[time]);
+
+ // output from F function
+ String fOut = f(left);
+
+ right = xor(fOut, right);
+
+ // swap left and right
+ return right + left;
+ }
+
+ /**
+ * This method returns cipher text for the plaintext passed as the first parameter generated
+ * using the key passed as the second parameter
+ *
+ * @param String plainText is the text which is to be encrypted
+ * @param String key is the key which is to be used for generating cipher text
+ * @return String cipherText is the encrypted value
+ */
+ String encrypt(String plainText, String key) {
+ // generating key
+ keyGenerate(key);
+
+ for (int i = 0; i < 16; i++) {
+ plainText = round(i, plainText);
+ }
+
+ // postprocessing
+ String right = plainText.substring(0, 8);
+ String left = plainText.substring(8, 16);
+ right = xor(right, subKeys[16]);
+ left = xor(left, subKeys[17]);
+ return left + right;
+ }
+
+ /**
+ * This method returns plaintext for the ciphertext passed as the first parameter decoded
+ * using the key passed as the second parameter
+ *
+ * @param String ciphertext is the text which is to be decrypted
+ * @param String key is the key which is to be used for generating cipher text
+ * @return String plainText is the decrypted text
+ */
+ String decrypt(String cipherText, String key) {
+ // generating key
+ keyGenerate(key);
+
+ for (int i = 17; i > 1; i--) {
+ cipherText = round(i, cipherText);
+ }
+
+ // postprocessing
+ String right = cipherText.substring(0, 8);
+ String left = cipherText.substring(8, 16);
+ right = xor(right, subKeys[1]);
+ left = xor(left, subKeys[0]);
+ return left + right;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/Caesar.java b/src/main/java/com/thealgorithms/ciphers/Caesar.java
index bc2fd369d13d..23535bc2b5d2 100644
--- a/src/main/java/com/thealgorithms/ciphers/Caesar.java
+++ b/src/main/java/com/thealgorithms/ciphers/Caesar.java
@@ -1,7 +1,5 @@
package com.thealgorithms.ciphers;
-import java.util.Scanner;
-
/**
* A Java implementation of Caesar Cipher. /It is a type of substitution cipher
* in which each letter in the plaintext is replaced by a letter some fixed
@@ -11,6 +9,9 @@
* @author khalil2535
*/
public class Caesar {
+ private static char normalizeShift(final int shift) {
+ return (char) (shift % 26);
+ }
/**
* Encrypt text by shifting every Latin char by add number shift for ASCII
@@ -18,28 +19,24 @@ public class Caesar {
*
* @return Encrypted message
*/
- public static String encode(String message, int shift) {
+ public String encode(String message, int shift) {
StringBuilder encoded = new StringBuilder();
- shift %= 26;
+ final char shiftChar = normalizeShift(shift);
final int length = message.length();
for (int i = 0; i < length; i++) {
-
- // int current = message.charAt(i); //using char to shift characters because ascii
+ // int current = message.charAt(i); //using char to shift characters because
+ // ascii
// is in-order latin alphabet
char current = message.charAt(i); // Java law : char + int = char
- if (IsCapitalLatinLetter(current)) {
-
- current += shift;
+ if (isCapitalLatinLetter(current)) {
+ current += shiftChar;
encoded.append((char) (current > 'Z' ? current - 26 : current)); // 26 = number of latin letters
-
- } else if (IsSmallLatinLetter(current)) {
-
- current += shift;
+ } else if (isSmallLatinLetter(current)) {
+ current += shiftChar;
encoded.append((char) (current > 'z' ? current - 26 : current)); // 26 = number of latin letters
-
} else {
encoded.append(current);
}
@@ -53,24 +50,20 @@ public static String encode(String message, int shift) {
*
* @return message
*/
- public static String decode(String encryptedMessage, int shift) {
+ public String decode(String encryptedMessage, int shift) {
StringBuilder decoded = new StringBuilder();
- shift %= 26;
+ final char shiftChar = normalizeShift(shift);
final int length = encryptedMessage.length();
for (int i = 0; i < length; i++) {
char current = encryptedMessage.charAt(i);
- if (IsCapitalLatinLetter(current)) {
-
- current -= shift;
+ if (isCapitalLatinLetter(current)) {
+ current -= shiftChar;
decoded.append((char) (current < 'A' ? current + 26 : current)); // 26 = number of latin letters
-
- } else if (IsSmallLatinLetter(current)) {
-
- current -= shift;
+ } else if (isSmallLatinLetter(current)) {
+ current -= shiftChar;
decoded.append((char) (current < 'a' ? current + 26 : current)); // 26 = number of latin letters
-
} else {
decoded.append(current);
}
@@ -81,60 +74,26 @@ public static String decode(String encryptedMessage, int shift) {
/**
* @return true if character is capital Latin letter or false for others
*/
- private static boolean IsCapitalLatinLetter(char c) {
+ private static boolean isCapitalLatinLetter(char c) {
return c >= 'A' && c <= 'Z';
}
/**
* @return true if character is small Latin letter or false for others
*/
- private static boolean IsSmallLatinLetter(char c) {
+ private static boolean isSmallLatinLetter(char c) {
return c >= 'a' && c <= 'z';
}
+
/**
* @return string array which contains all the possible decoded combination.
*/
- public static String[] bruteforce(String encryptedMessage) {
+ public String[] bruteforce(String encryptedMessage) {
String[] listOfAllTheAnswers = new String[27];
- for (int i=0; i<=26; i++) {
+ for (int i = 0; i <= 26; i++) {
listOfAllTheAnswers[i] = decode(encryptedMessage, i);
}
return listOfAllTheAnswers;
}
-
- public static void main(String[] args) {
- Scanner input = new Scanner(System.in);
- int shift = 0;
- System.out.println("Please enter the message (Latin Alphabet)");
- String message = input.nextLine();
- System.out.println(message);
- System.out.println("(E)ncode or (D)ecode or (B)ruteforce?");
- char choice = input.next().charAt(0);
- switch (choice) {
- case 'E':
- case 'e':
- System.out.println("Please enter the shift number");
- shift = input.nextInt() % 26;
- System.out.println(
- "ENCODED MESSAGE IS \n" + encode(message, shift)); // send our function to handle
- break;
- case 'D':
- case 'd':
- System.out.println("Please enter the shift number");
- shift = input.nextInt() % 26;
- System.out.println("DECODED MESSAGE IS \n" + decode(message, shift));
- break;
- case 'B':
- case 'b':
- String[] listOfAllTheAnswers = bruteforce(message);
- for (int i =0; i<=26; i++) {
- System.out.println("FOR SHIFT " + String.valueOf(i) + " decoded message is " + listOfAllTheAnswers[i]);
- }
- default:
- System.out.println("default case");
- }
-
- input.close();
- }
}
diff --git a/src/main/java/com/thealgorithms/ciphers/ColumnarTranspositionCipher.java b/src/main/java/com/thealgorithms/ciphers/ColumnarTranspositionCipher.java
index 4c699a28eba0..b6b889b079ca 100644
--- a/src/main/java/com/thealgorithms/ciphers/ColumnarTranspositionCipher.java
+++ b/src/main/java/com/thealgorithms/ciphers/ColumnarTranspositionCipher.java
@@ -7,13 +7,15 @@
*
* @author freitzzz
*/
-public class ColumnarTranspositionCipher {
+public final class ColumnarTranspositionCipher {
+ private ColumnarTranspositionCipher() {
+ }
private static String keyword;
private static Object[][] table;
private static String abecedarium;
- public static final String ABECEDARIUM
- = "abcdefghijklmnopqrstuvwxyzABCDEFG" + "HIJKLMNOPQRSTUVWXYZ0123456789,.;:-@";
+ public static final String ABECEDARIUM = "abcdefghijklmnopqrstuvwxyzABCDEFG"
+ + "HIJKLMNOPQRSTUVWXYZ0123456789,.;:-@";
private static final String ENCRYPTION_FIELD = "≈";
private static final char ENCRYPTION_FIELD_CHAR = '≈';
@@ -25,13 +27,13 @@ public class ColumnarTranspositionCipher {
* @return a String with the word encrypted by the Columnar Transposition
* Cipher Rule
*/
- public static String encrpyter(String word, String keyword) {
+ public static String encrypt(final String word, final String keyword) {
ColumnarTranspositionCipher.keyword = keyword;
- abecedariumBuilder(500);
+ abecedariumBuilder();
table = tableBuilder(word);
Object[][] sortedTable = sortTable(table);
StringBuilder wordEncrypted = new StringBuilder();
- for (int i = 0; i < sortedTable[i].length; i++) {
+ for (int i = 0; i < sortedTable[0].length; i++) {
for (int j = 1; j < sortedTable.length; j++) {
wordEncrypted.append(sortedTable[j][i]);
}
@@ -49,11 +51,12 @@ public static String encrpyter(String word, String keyword) {
* @return a String with the word encrypted by the Columnar Transposition
* Cipher Rule
*/
- public static String encrpyter(String word, String keyword, String abecedarium) {
+ public static String encrypt(String word, String keyword, String abecedarium) {
ColumnarTranspositionCipher.keyword = keyword;
ColumnarTranspositionCipher.abecedarium = Objects.requireNonNullElse(abecedarium, ABECEDARIUM);
table = tableBuilder(word);
Object[][] sortedTable = sortTable(table);
+
StringBuilder wordEncrypted = new StringBuilder();
for (int i = 0; i < sortedTable[0].length; i++) {
for (int j = 1; j < sortedTable.length; j++) {
@@ -70,7 +73,7 @@ public static String encrpyter(String word, String keyword, String abecedarium)
* @return a String decrypted with the word encrypted by the Columnar
* Transposition Cipher Rule
*/
- public static String decrypter() {
+ public static String decrypt() {
StringBuilder wordDecrypted = new StringBuilder();
for (int i = 1; i < table.length; i++) {
for (Object item : table[i]) {
@@ -89,14 +92,14 @@ public static String decrypter() {
*/
private static Object[][] tableBuilder(String word) {
Object[][] table = new Object[numberOfRows(word) + 1][keyword.length()];
- char[] wordInChards = word.toCharArray();
- // Fils in the respective numbers
+ char[] wordInChars = word.toCharArray();
+ // Fills in the respective numbers for the column
table[0] = findElements();
int charElement = 0;
for (int i = 1; i < table.length; i++) {
for (int j = 0; j < table[i].length; j++) {
- if (charElement < wordInChards.length) {
- table[i][j] = wordInChards[charElement];
+ if (charElement < wordInChars.length) {
+ table[i][j] = wordInChars[charElement];
charElement++;
} else {
table[i][j] = ENCRYPTION_FIELD_CHAR;
@@ -114,7 +117,7 @@ private static Object[][] tableBuilder(String word) {
* order to respect the Columnar Transposition Cipher Rule.
*/
private static int numberOfRows(String word) {
- if (word.length() / keyword.length() > word.length() / keyword.length()) {
+ if (word.length() % keyword.length() != 0) {
return (word.length() / keyword.length()) + 1;
} else {
return word.length() / keyword.length();
@@ -163,8 +166,7 @@ private static Object[] getColumn(Object[][] table, int rows, int column) {
return columnArray;
}
- private static void switchColumns(
- Object[][] table, int firstColumnIndex, int secondColumnIndex, Object[] columnToSwitch) {
+ private static void switchColumns(Object[][] table, int firstColumnIndex, int secondColumnIndex, Object[] columnToSwitch) {
for (int i = 0; i < table.length; i++) {
table[i][secondColumnIndex] = table[i][firstColumnIndex];
table[i][firstColumnIndex] = columnToSwitch[i];
@@ -172,37 +174,13 @@ private static void switchColumns(
}
/**
- * Creates an abecedarium with a specified ascii inded
- *
- * @param value Number of characters being used based on the ASCII Table
+ * Creates an abecedarium with all available ascii values.
*/
- private static void abecedariumBuilder(int value) {
+ private static void abecedariumBuilder() {
StringBuilder t = new StringBuilder();
- for (int i = 0; i < value; i++) {
+ for (int i = 0; i < 256; i++) {
t.append((char) i);
}
abecedarium = t.toString();
}
-
- private static void showTable() {
- for (Object[] table1 : table) {
- for (Object item : table1) {
- System.out.print(item + " ");
- }
- System.out.println();
- }
- }
-
- public static void main(String[] args) {
- String keywordForExample = "asd215";
- String wordBeingEncrypted = "This is a test of the Columnar Transposition Cipher";
- System.out.println("### Example of Columnar Transposition Cipher ###\n");
- System.out.println("Word being encryped ->>> " + wordBeingEncrypted);
- System.out.println(
- "Word encrypted ->>> "
- + ColumnarTranspositionCipher.encrpyter(wordBeingEncrypted, keywordForExample));
- System.out.println("Word decryped ->>> " + ColumnarTranspositionCipher.decrypter());
- System.out.println("\n### Encrypted Table ###");
- showTable();
- }
}
diff --git a/src/main/java/com/thealgorithms/ciphers/DES.java b/src/main/java/com/thealgorithms/ciphers/DES.java
new file mode 100644
index 000000000000..7f3eed70f3c2
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/DES.java
@@ -0,0 +1,250 @@
+package com.thealgorithms.ciphers;
+
+/**
+ * This class is build to demonstrate the application of the DES-algorithm
+ * (https://en.wikipedia.org/wiki/Data_Encryption_Standard) on a plain English message. The supplied
+ * key must be in form of a 64 bit binary String.
+ */
+public class DES {
+
+ private String key;
+ private final String[] subKeys;
+
+ private void sanitize(String key) {
+ int length = key.length();
+ if (length != 64) {
+ throw new IllegalArgumentException("DES key must be supplied as a 64 character binary string");
+ }
+ }
+
+ DES(String key) {
+ sanitize(key);
+ this.key = key;
+ subKeys = getSubkeys(key);
+ }
+
+ public String getKey() {
+ return this.key;
+ }
+
+ public void setKey(String key) {
+ sanitize(key);
+ this.key = key;
+ }
+
+ // Permutation table to convert initial 64-bit key to 56 bit key
+ private static final int[] PC1 = {57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4};
+
+ // Lookup table used to shift the initial key, in order to generate the subkeys
+ private static final int[] KEY_SHIFTS = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
+
+ // Table to convert the 56 bit subkeys to 48 bit subkeys
+ private static final int[] PC2 = {14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32};
+
+ // Initial permutation of each 64 but message block
+ private static final int[] IP = {58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7};
+
+ // Expansion table to convert right half of message blocks from 32 bits to 48 bits
+ private static final int[] EXPANSION = {32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1};
+
+ // The eight substitution boxes are defined below
+ private static final int[][] S1 = {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8}, {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0}, {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}};
+
+ private static final int[][] S2 = {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10}, {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5}, {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15}, {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}};
+
+ private static final int[][] S3 = {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8}, {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1}, {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7}, {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}};
+
+ private static final int[][] S4 = {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15}, {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9}, {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4}, {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}};
+
+ private static final int[][] S5 = {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9}, {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6}, {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14}, {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}};
+
+ private static final int[][] S6 = {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11}, {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8}, {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6}, {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}};
+
+ private static final int[][] S7 = {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1}, {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6}, {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2}, {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}};
+
+ private static final int[][] S8 = {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7}, {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2}, {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8}, {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}};
+
+ private static final int[][][] S = {S1, S2, S3, S4, S5, S6, S7, S8};
+
+ // Permutation table, used in the Feistel function post s-box usage
+ static final int[] PERMUTATION = {16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25};
+
+ // Table used for final inversion of the message box after 16 rounds of Feistel Function
+ static final int[] IP_INVERSE = {40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25};
+
+ private String[] getSubkeys(String originalKey) {
+ StringBuilder permutedKey = new StringBuilder(); // Initial permutation of keys via pc1
+ int i;
+ int j;
+ for (i = 0; i < 56; i++) {
+ permutedKey.append(originalKey.charAt(PC1[i] - 1));
+ }
+ String[] subKeys = new String[16];
+ String initialPermutedKey = permutedKey.toString();
+ String c0 = initialPermutedKey.substring(0, 28);
+ String d0 = initialPermutedKey.substring(28);
+
+ // We will now operate on the left and right halves of the permutedKey
+ for (i = 0; i < 16; i++) {
+ String cN = c0.substring(KEY_SHIFTS[i]) + c0.substring(0, KEY_SHIFTS[i]);
+ String dN = d0.substring(KEY_SHIFTS[i]) + d0.substring(0, KEY_SHIFTS[i]);
+ subKeys[i] = cN + dN;
+ c0 = cN; // Re-assign the values to create running permutation
+ d0 = dN;
+ }
+
+ // Let us shrink the keys to 48 bits (well, characters here) using pc2
+ for (i = 0; i < 16; i++) {
+ String key = subKeys[i];
+ permutedKey.setLength(0);
+ for (j = 0; j < 48; j++) {
+ permutedKey.append(key.charAt(PC2[j] - 1));
+ }
+ subKeys[i] = permutedKey.toString();
+ }
+
+ return subKeys;
+ }
+
+ private String xOR(String a, String b) {
+ int i;
+ int l = a.length();
+ StringBuilder xor = new StringBuilder();
+ for (i = 0; i < l; i++) {
+ int firstBit = a.charAt(i) - 48; // 48 is '0' in ascii
+ int secondBit = b.charAt(i) - 48;
+ xor.append((firstBit ^ secondBit));
+ }
+ return xor.toString();
+ }
+
+ private String createPaddedString(String s, int desiredLength, char pad) {
+ int i;
+ int l = s.length();
+ StringBuilder paddedString = new StringBuilder();
+ int diff = desiredLength - l;
+ for (i = 0; i < diff; i++) {
+ paddedString.append(pad);
+ }
+ return paddedString.toString();
+ }
+
+ private String pad(String s, int desiredLength) {
+ return createPaddedString(s, desiredLength, '0') + s;
+ }
+
+ private String padLast(String s, int desiredLength) {
+ return s + createPaddedString(s, desiredLength, '\u0000');
+ }
+
+ private String feistel(String messageBlock, String key) {
+ int i;
+ StringBuilder expandedKey = new StringBuilder();
+ for (i = 0; i < 48; i++) {
+ expandedKey.append(messageBlock.charAt(EXPANSION[i] - 1));
+ }
+ String mixedKey = xOR(expandedKey.toString(), key);
+ StringBuilder substitutedString = new StringBuilder();
+
+ // Let us now use the s-boxes to transform each 6 bit (length here) block to 4 bits
+ for (i = 0; i < 48; i += 6) {
+ String block = mixedKey.substring(i, i + 6);
+ int row = (block.charAt(0) - 48) * 2 + (block.charAt(5) - 48);
+ int col = (block.charAt(1) - 48) * 8 + (block.charAt(2) - 48) * 4 + (block.charAt(3) - 48) * 2 + (block.charAt(4) - 48);
+ String substitutedBlock = pad(Integer.toBinaryString(S[i / 6][row][col]), 4);
+ substitutedString.append(substitutedBlock);
+ }
+
+ StringBuilder permutedString = new StringBuilder();
+ for (i = 0; i < 32; i++) {
+ permutedString.append(substitutedString.charAt(PERMUTATION[i] - 1));
+ }
+
+ return permutedString.toString();
+ }
+
+ private String encryptBlock(String message, String[] keys) {
+ StringBuilder permutedMessage = new StringBuilder();
+ int i;
+ for (i = 0; i < 64; i++) {
+ permutedMessage.append(message.charAt(IP[i] - 1));
+ }
+ String e0 = permutedMessage.substring(0, 32);
+ String f0 = permutedMessage.substring(32);
+
+ // Iterate 16 times
+ for (i = 0; i < 16; i++) {
+ String eN = f0; // Previous Right block
+ String fN = xOR(e0, feistel(f0, keys[i]));
+ e0 = eN;
+ f0 = fN;
+ }
+
+ String combinedBlock = f0 + e0; // Reverse the 16th block
+ permutedMessage.setLength(0);
+ for (i = 0; i < 64; i++) {
+ permutedMessage.append(combinedBlock.charAt(IP_INVERSE[i] - 1));
+ }
+ return permutedMessage.toString();
+ }
+
+ // To decode, we follow the same process as encoding, but with reversed keys
+ private String decryptBlock(String message, String[] keys) {
+ String[] reversedKeys = new String[keys.length];
+ for (int i = 0; i < keys.length; i++) {
+ reversedKeys[i] = keys[keys.length - i - 1];
+ }
+ return encryptBlock(message, reversedKeys);
+ }
+
+ /**
+ * @param message Message to be encrypted
+ * @return The encrypted message, as a binary string
+ */
+ public String encrypt(String message) {
+ StringBuilder encryptedMessage = new StringBuilder();
+ int l = message.length();
+ int i;
+ int j;
+ if (l % 8 != 0) {
+ int desiredLength = (l / 8 + 1) * 8;
+ l = desiredLength;
+ message = padLast(message, desiredLength);
+ }
+
+ for (i = 0; i < l; i += 8) {
+ String block = message.substring(i, i + 8);
+ StringBuilder bitBlock = new StringBuilder();
+ byte[] bytes = block.getBytes();
+ for (j = 0; j < 8; j++) {
+ bitBlock.append(pad(Integer.toBinaryString(bytes[j]), 8));
+ }
+ encryptedMessage.append(encryptBlock(bitBlock.toString(), subKeys));
+ }
+ return encryptedMessage.toString();
+ }
+
+ /**
+ * @param message The encrypted string. Expects it to be a multiple of 64 bits, in binary format
+ * @return The decrypted String, in plain English
+ */
+ public String decrypt(String message) {
+ StringBuilder decryptedMessage = new StringBuilder();
+ int l = message.length();
+ int i;
+ int j;
+ if (l % 64 != 0) {
+ throw new IllegalArgumentException("Encrypted message should be a multiple of 64 characters in length");
+ }
+ for (i = 0; i < l; i += 64) {
+ String block = message.substring(i, i + 64);
+ String result = decryptBlock(block, subKeys);
+ byte[] res = new byte[8];
+ for (j = 0; j < 64; j += 8) {
+ res[j / 8] = (byte) Integer.parseInt(result.substring(j, j + 8), 2);
+ }
+ decryptedMessage.append(new String(res));
+ }
+ return decryptedMessage.toString().replace("\0", ""); // Get rid of the null bytes used for padding
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/DiffieHellman.java b/src/main/java/com/thealgorithms/ciphers/DiffieHellman.java
new file mode 100644
index 000000000000..7470b40e001a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/DiffieHellman.java
@@ -0,0 +1,36 @@
+package com.thealgorithms.ciphers;
+
+import java.math.BigInteger;
+
+public final class DiffieHellman {
+
+ private final BigInteger base;
+ private final BigInteger secret;
+ private final BigInteger prime;
+
+ // Constructor to initialize base, secret, and prime
+ public DiffieHellman(BigInteger base, BigInteger secret, BigInteger prime) {
+ // Check for non-null and positive values
+ if (base == null || secret == null || prime == null || base.signum() <= 0 || secret.signum() <= 0 || prime.signum() <= 0) {
+ throw new IllegalArgumentException("Base, secret, and prime must be non-null and positive values.");
+ }
+ this.base = base;
+ this.secret = secret;
+ this.prime = prime;
+ }
+
+ // Method to calculate public value (g^x mod p)
+ public BigInteger calculatePublicValue() {
+ // Returns g^x mod p
+ return base.modPow(secret, prime);
+ }
+
+ // Method to calculate the shared secret key (otherPublic^secret mod p)
+ public BigInteger calculateSharedSecret(BigInteger otherPublicValue) {
+ if (otherPublicValue == null || otherPublicValue.signum() <= 0) {
+ throw new IllegalArgumentException("Other public value must be non-null and positive.");
+ }
+ // Returns b^x mod p or a^y mod p
+ return otherPublicValue.modPow(secret, prime);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/ECC.java b/src/main/java/com/thealgorithms/ciphers/ECC.java
new file mode 100644
index 000000000000..7b1e37f0e1e1
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/ECC.java
@@ -0,0 +1,236 @@
+package com.thealgorithms.ciphers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * ECC - Elliptic Curve Cryptography
+ * Elliptic Curve Cryptography is a public-key cryptography method that uses the algebraic structure of
+ * elliptic curves over finite fields. ECC provides a higher level of security with smaller key sizes compared
+ * to other public-key methods like RSA, making it particularly suitable for environments where computational
+ * resources are limited, such as mobile devices and embedded systems.
+ *
+ * This class implements elliptic curve cryptography, providing encryption and decryption
+ * functionalities based on public and private key pairs.
+ *
+ * @author xuyang
+ */
+public class ECC {
+
+ private BigInteger privateKey; // Private key used for decryption
+ private ECPoint publicKey; // Public key used for encryption
+ private EllipticCurve curve; // Elliptic curve used in cryptography
+ private ECPoint basePoint; // Base point G on the elliptic curve
+
+ public ECC(int bits) {
+ generateKeys(bits); // Generates public-private key pair
+ }
+
+ public EllipticCurve getCurve() {
+ return curve; // Returns the elliptic curve
+ }
+
+ public void setCurve(EllipticCurve curve) {
+ this.curve = curve;
+ }
+
+ // Getter and Setter for private key
+ public BigInteger getPrivateKey() {
+ return privateKey;
+ }
+
+ public void setPrivateKey(BigInteger privateKey) {
+ this.privateKey = privateKey;
+ }
+
+ /**
+ * Encrypts the message using the public key.
+ * The message is transformed into an ECPoint and encrypted with elliptic curve operations.
+ *
+ * @param message The plain message to be encrypted
+ * @return The encrypted message as an array of ECPoints (R, S)
+ */
+ public ECPoint[] encrypt(String message) {
+ BigInteger m = new BigInteger(message.getBytes()); // Convert message to BigInteger
+ SecureRandom r = new SecureRandom(); // Generate random value for k
+ BigInteger k = new BigInteger(curve.getFieldSize(), r); // Generate random scalar k
+
+ // Calculate point r = k * G, where G is the base point
+ ECPoint rPoint = basePoint.multiply(k, curve.getP(), curve.getA());
+
+ // Calculate point s = k * publicKey + encodedMessage
+ ECPoint sPoint = publicKey.multiply(k, curve.getP(), curve.getA()).add(curve.encodeMessage(m), curve.getP(), curve.getA());
+
+ return new ECPoint[] {rPoint, sPoint}; // Return encrypted message as two ECPoints
+ }
+
+ /**
+ * Decrypts the encrypted message using the private key.
+ * The decryption process is the reverse of encryption, recovering the original message.
+ *
+ * @param encryptedMessage The encrypted message as an array of ECPoints (R, S)
+ * @return The decrypted plain message as a String
+ */
+ public String decrypt(ECPoint[] encryptedMessage) {
+ ECPoint rPoint = encryptedMessage[0]; // First part of ciphertext
+ ECPoint sPoint = encryptedMessage[1]; // Second part of ciphertext
+
+ // Perform decryption: s - r * privateKey
+ ECPoint decodedMessage = sPoint.subtract(rPoint.multiply(privateKey, curve.getP(), curve.getA()), curve.getP(), curve.getA());
+
+ BigInteger m = curve.decodeMessage(decodedMessage); // Decode the message from ECPoint
+
+ return new String(m.toByteArray()); // Convert BigInteger back to String
+ }
+
+ /**
+ * Generates a new public-private key pair for encryption and decryption.
+ *
+ * @param bits The size (in bits) of the keys to generate
+ */
+ public final void generateKeys(int bits) {
+ SecureRandom r = new SecureRandom();
+ curve = new EllipticCurve(bits); // Initialize a new elliptic curve
+ basePoint = curve.getBasePoint(); // Set the base point G
+
+ // Generate private key as a random BigInteger
+ privateKey = new BigInteger(bits, r);
+
+ // Generate public key as the point publicKey = privateKey * G
+ publicKey = basePoint.multiply(privateKey, curve.getP(), curve.getA());
+ }
+
+ /**
+ * Class representing an elliptic curve with the form y^2 = x^3 + ax + b.
+ */
+ public static class EllipticCurve {
+ private final BigInteger a; // Coefficient a in the curve equation
+ private final BigInteger b; // Coefficient b in the curve equation
+ private final BigInteger p; // Prime number p, defining the finite field
+ private final ECPoint basePoint; // Base point G on the curve
+
+ // Constructor with explicit parameters for a, b, p, and base point
+ public EllipticCurve(BigInteger a, BigInteger b, BigInteger p, ECPoint basePoint) {
+ this.a = a;
+ this.b = b;
+ this.p = p;
+ this.basePoint = basePoint;
+ }
+
+ // Constructor that randomly generates the curve parameters
+ public EllipticCurve(int bits) {
+ SecureRandom r = new SecureRandom();
+ this.p = BigInteger.probablePrime(bits, r); // Random prime p
+ this.a = new BigInteger(bits, r); // Random coefficient a
+ this.b = new BigInteger(bits, r); // Random coefficient b
+ this.basePoint = new ECPoint(BigInteger.valueOf(4), BigInteger.valueOf(8)); // Fixed base point G
+ }
+
+ public ECPoint getBasePoint() {
+ return basePoint;
+ }
+
+ public BigInteger getP() {
+ return p;
+ }
+
+ public BigInteger getA() {
+ return a;
+ }
+
+ public BigInteger getB() {
+ return b;
+ }
+
+ public int getFieldSize() {
+ return p.bitLength();
+ }
+
+ public ECPoint encodeMessage(BigInteger message) {
+ // Simple encoding of a message as an ECPoint (this is a simplified example)
+ return new ECPoint(message, message);
+ }
+
+ public BigInteger decodeMessage(ECPoint point) {
+ return point.getX(); // Decode the message from ECPoint (simplified)
+ }
+ }
+
+ /**
+ * Class representing a point on the elliptic curve.
+ */
+ public static class ECPoint {
+ private final BigInteger x; // X-coordinate of the point
+ private final BigInteger y; // Y-coordinate of the point
+
+ public ECPoint(BigInteger x, BigInteger y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public BigInteger getX() {
+ return x;
+ }
+
+ public BigInteger getY() {
+ return y;
+ }
+
+ @Override
+ public String toString() {
+ return "ECPoint(x=" + x.toString() + ", y=" + y.toString() + ")";
+ }
+
+ /**
+ * Add two points on the elliptic curve.
+ */
+ public ECPoint add(ECPoint other, BigInteger p, BigInteger a) {
+ if (this.x.equals(BigInteger.ZERO) && this.y.equals(BigInteger.ZERO)) {
+ return other; // If this point is the identity, return the other point
+ }
+ if (other.x.equals(BigInteger.ZERO) && other.y.equals(BigInteger.ZERO)) {
+ return this; // If the other point is the identity, return this point
+ }
+
+ BigInteger lambda;
+ if (this.equals(other)) {
+ // Special case: point doubling
+ lambda = this.x.pow(2).multiply(BigInteger.valueOf(3)).add(a).multiply(this.y.multiply(BigInteger.valueOf(2)).modInverse(p)).mod(p);
+ } else {
+ // General case: adding two different points
+ lambda = other.y.subtract(this.y).multiply(other.x.subtract(this.x).modInverse(p)).mod(p);
+ }
+
+ BigInteger xr = lambda.pow(2).subtract(this.x).subtract(other.x).mod(p);
+ BigInteger yr = lambda.multiply(this.x.subtract(xr)).subtract(this.y).mod(p);
+
+ return new ECPoint(xr, yr);
+ }
+
+ /**
+ * Subtract two points on the elliptic curve.
+ */
+ public ECPoint subtract(ECPoint other, BigInteger p, BigInteger a) {
+ ECPoint negOther = new ECPoint(other.x, p.subtract(other.y)); // Negate the Y coordinate
+ return this.add(negOther, p, a); // Add the negated point
+ }
+
+ /**
+ * Multiply a point by a scalar (repeated addition).
+ */
+ public ECPoint multiply(BigInteger k, BigInteger p, BigInteger a) {
+ ECPoint result = new ECPoint(BigInteger.ZERO, BigInteger.ZERO); // Identity point
+ ECPoint addend = this;
+
+ while (k.signum() > 0) {
+ if (k.testBit(0)) {
+ result = result.add(addend, p, a); // Add the current point
+ }
+ addend = addend.add(addend, p, a); // Double the point
+ k = k.shiftRight(1); // Divide k by 2
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/HillCipher.java b/src/main/java/com/thealgorithms/ciphers/HillCipher.java
index c0f6aef12ea8..01b1aeb8bc6c 100644
--- a/src/main/java/com/thealgorithms/ciphers/HillCipher.java
+++ b/src/main/java/com/thealgorithms/ciphers/HillCipher.java
@@ -1,170 +1,103 @@
package com.thealgorithms.ciphers;
-import java.util.Scanner;
-
-/*
- * Java Implementation of Hill Cipher
- * Hill cipher is a polyalphabetic substitution cipher. Each letter is represented by a number belonging to the set Z26 where A=0 , B=1, ..... Z=25.
- * To encrypt a message, each block of n letters (since matrix size is n x n) is multiplied by an invertible n × n matrix, against modulus 26.
- * To decrypt the message, each block is multiplied by the inverse of the matrix used for encryption.
- * The cipher key and plaintext/ciphertext are user inputs.
- * @author Ojasva Jain
- */
public class HillCipher {
- static Scanner in = new Scanner(System.in);
+ // Encrypts the message using the key matrix
+ public String encrypt(String message, int[][] keyMatrix) {
+ message = message.toUpperCase().replaceAll("[^A-Z]", "");
+ int matrixSize = keyMatrix.length;
+ validateDeterminant(keyMatrix, matrixSize);
- /* Following function encrypts the message
- */
- static void encrypt(String message) {
- message = message.toUpperCase();
- // Get key matrix
- System.out.println("Enter key matrix size");
- int n = in.nextInt();
- System.out.println("Enter Key/encryptionKey matrix ");
- int keyMatrix[][] = new int[n][n];
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < n; j++) {
- keyMatrix[i][j] = in.nextInt();
- }
- }
- //check if det = 0
- if (determinant(keyMatrix, n) % 26 == 0) {
- System.out.println("Invalid key, as determinant = 0. Program Terminated");
- return;
- }
+ StringBuilder cipherText = new StringBuilder();
+ int[] messageVector = new int[matrixSize];
+ int[] cipherVector = new int[matrixSize];
+ int index = 0;
- int[][] messageVector = new int[n][1];
- String CipherText = "";
- int cipherMatrix[][] = new int[n][1];
- int j = 0;
- while (j < message.length()) {
- for (int i = 0; i < n; i++) {
- if (j >= message.length()) {
- messageVector[i][0] = 23;
+ while (index < message.length()) {
+ for (int i = 0; i < matrixSize; i++) {
+ if (index < message.length()) {
+ messageVector[i] = message.charAt(index++) - 'A';
} else {
- messageVector[i][0] = (message.charAt(j)) % 65;
+ messageVector[i] = 'X' - 'A'; // Padding with 'X' if needed
}
- System.out.println(messageVector[i][0]);
- j++;
}
- int x, i;
- for (i = 0; i < n; i++) {
- cipherMatrix[i][0] = 0;
- for (x = 0; x < n; x++) {
- cipherMatrix[i][0] += keyMatrix[i][x] * messageVector[x][0];
+ for (int i = 0; i < matrixSize; i++) {
+ cipherVector[i] = 0;
+ for (int j = 0; j < matrixSize; j++) {
+ cipherVector[i] += keyMatrix[i][j] * messageVector[j];
}
- System.out.println(cipherMatrix[i][0]);
- cipherMatrix[i][0] = cipherMatrix[i][0] % 26;
- }
- for (i = 0; i < n; i++) {
- CipherText += (char) (cipherMatrix[i][0] + 65);
+ cipherVector[i] = cipherVector[i] % 26;
+ cipherText.append((char) (cipherVector[i] + 'A'));
}
}
- System.out.println("Ciphertext: " + CipherText);
+
+ return cipherText.toString();
}
- //Following function decrypts a message
- static void decrypt(String message) {
- message = message.toUpperCase();
- // Get key matrix
- System.out.println("Enter key matrix size");
- int n = in.nextInt();
- System.out.println("Enter inverseKey/decryptionKey matrix ");
- int keyMatrix[][] = new int[n][n];
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < n; j++) {
- keyMatrix[i][j] = in.nextInt();
- }
- }
- //check if det = 0
- if (determinant(keyMatrix, n) % 26 == 0) {
- System.out.println("Invalid key, as determinant = 0. Program Terminated");
- return;
- }
- //solving for the required plaintext message
- int[][] messageVector = new int[n][1];
- String PlainText = "";
- int plainMatrix[][] = new int[n][1];
- int j = 0;
- while (j < message.length()) {
- for (int i = 0; i < n; i++) {
- if (j >= message.length()) {
- messageVector[i][0] = 23;
+ // Decrypts the message using the inverse key matrix
+ public String decrypt(String message, int[][] inverseKeyMatrix) {
+ message = message.toUpperCase().replaceAll("[^A-Z]", "");
+ int matrixSize = inverseKeyMatrix.length;
+ validateDeterminant(inverseKeyMatrix, matrixSize);
+
+ StringBuilder plainText = new StringBuilder();
+ int[] messageVector = new int[matrixSize];
+ int[] plainVector = new int[matrixSize];
+ int index = 0;
+
+ while (index < message.length()) {
+ for (int i = 0; i < matrixSize; i++) {
+ if (index < message.length()) {
+ messageVector[i] = message.charAt(index++) - 'A';
} else {
- messageVector[i][0] = (message.charAt(j)) % 65;
+ messageVector[i] = 'X' - 'A'; // Padding with 'X' if needed
}
- System.out.println(messageVector[i][0]);
- j++;
}
- int x, i;
- for (i = 0; i < n; i++) {
- plainMatrix[i][0] = 0;
- for (x = 0; x < n; x++) {
- plainMatrix[i][0] += keyMatrix[i][x] * messageVector[x][0];
+ for (int i = 0; i < matrixSize; i++) {
+ plainVector[i] = 0;
+ for (int j = 0; j < matrixSize; j++) {
+ plainVector[i] += inverseKeyMatrix[i][j] * messageVector[j];
}
-
- plainMatrix[i][0] = plainMatrix[i][0] % 26;
- }
- for (i = 0; i < n; i++) {
- PlainText += (char) (plainMatrix[i][0] + 65);
+ plainVector[i] = plainVector[i] % 26;
+ plainText.append((char) (plainVector[i] + 'A'));
}
}
- System.out.println("Plaintext: " + PlainText);
+
+ return plainText.toString();
}
- // Determinant calculator
- public static int determinant(int a[][], int n) {
- int det = 0, sign = 1, p = 0, q = 0;
+ // Validates that the determinant of the key matrix is not zero modulo 26
+ private void validateDeterminant(int[][] keyMatrix, int n) {
+ int det = determinant(keyMatrix, n) % 26;
+ if (det == 0) {
+ throw new IllegalArgumentException("Invalid key matrix. Determinant is zero modulo 26.");
+ }
+ }
+ // Computes the determinant of a matrix recursively
+ private int determinant(int[][] matrix, int n) {
+ int det = 0;
if (n == 1) {
- det = a[0][0];
- } else {
- int b[][] = new int[n - 1][n - 1];
- for (int x = 0; x < n; x++) {
- p = 0;
- q = 0;
- for (int i = 1; i < n; i++) {
- for (int j = 0; j < n; j++) {
- if (j != x) {
- b[p][q++] = a[i][j];
- if (q % (n - 1) == 0) {
- p++;
- q = 0;
- }
- }
+ return matrix[0][0];
+ }
+ int sign = 1;
+ int[][] subMatrix = new int[n - 1][n - 1];
+ for (int x = 0; x < n; x++) {
+ int subI = 0;
+ for (int i = 1; i < n; i++) {
+ int subJ = 0;
+ for (int j = 0; j < n; j++) {
+ if (j != x) {
+ subMatrix[subI][subJ++] = matrix[i][j];
}
}
- det = det + a[0][x] * determinant(b, n - 1) * sign;
- sign = -sign;
+ subI++;
}
+ det += sign * matrix[0][x] * determinant(subMatrix, n - 1);
+ sign = -sign;
}
return det;
}
-
- // Function to implement Hill Cipher
- static void hillcipher(String message) {
- message.toUpperCase();
- System.out.println("What do you want to process from the message?");
- System.out.println("Press 1: To Encrypt");
- System.out.println("Press 2: To Decrypt");
- short sc = in.nextShort();
- if (sc == 1) {
- encrypt(message);
- } else if (sc == 2) {
- decrypt(message);
- } else {
- System.out.println("Invalid input, program terminated.");
- }
- }
-
- // Driver code
- public static void main(String[] args) {
- // Get the message to be encrypted
- System.out.println("Enter message");
- String message = in.nextLine();
- hillcipher(message);
- }
}
diff --git a/src/main/java/com/thealgorithms/ciphers/MonoAlphabetic.java b/src/main/java/com/thealgorithms/ciphers/MonoAlphabetic.java
new file mode 100644
index 000000000000..1d5b7110a6f3
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/MonoAlphabetic.java
@@ -0,0 +1,48 @@
+package com.thealgorithms.ciphers;
+
+public final class MonoAlphabetic {
+
+ private MonoAlphabetic() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ // Encryption method
+ public static String encrypt(String data, String key) {
+ if (!data.matches("[A-Z]+")) {
+ throw new IllegalArgumentException("Input data contains invalid characters. Only uppercase A-Z are allowed.");
+ }
+ StringBuilder sb = new StringBuilder();
+
+ // Encrypt each character
+ for (char c : data.toCharArray()) {
+ int idx = charToPos(c); // Get the index of the character
+ sb.append(key.charAt(idx)); // Map to the corresponding character in the key
+ }
+ return sb.toString();
+ }
+
+ // Decryption method
+ public static String decrypt(String data, String key) {
+ StringBuilder sb = new StringBuilder();
+
+ // Decrypt each character
+ for (char c : data.toCharArray()) {
+ int idx = key.indexOf(c); // Find the index of the character in the key
+ if (idx == -1) {
+ throw new IllegalArgumentException("Input data contains invalid characters.");
+ }
+ sb.append(posToChar(idx)); // Convert the index back to the original character
+ }
+ return sb.toString();
+ }
+
+ // Helper method: Convert a character to its position in the alphabet
+ private static int charToPos(char c) {
+ return c - 'A'; // Subtract 'A' to get position (0 for A, 1 for B, etc.)
+ }
+
+ // Helper method: Convert a position in the alphabet to a character
+ private static char posToChar(int pos) {
+ return (char) (pos + 'A'); // Add 'A' to convert position back to character
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/PermutationCipher.java b/src/main/java/com/thealgorithms/ciphers/PermutationCipher.java
new file mode 100644
index 000000000000..ce443545db1d
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/PermutationCipher.java
@@ -0,0 +1,194 @@
+package com.thealgorithms.ciphers;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A Java implementation of Permutation Cipher.
+ * It is a type of transposition cipher in which the plaintext is divided into blocks
+ * and the characters within each block are rearranged according to a fixed permutation key.
+ *
+ * For example, with key {3, 1, 2} and plaintext "HELLO", the text is divided into blocks
+ * of 3 characters: "HEL" and "LO" (with padding). The characters are then rearranged
+ * according to the key positions.
+ *
+ * @author GitHub Copilot
+ */
+public class PermutationCipher {
+
+ private static final char PADDING_CHAR = 'X';
+
+ /**
+ * Encrypts the given plaintext using the permutation cipher with the specified key.
+ *
+ * @param plaintext the text to encrypt
+ * @param key the permutation key (array of integers representing positions)
+ * @return the encrypted text
+ * @throws IllegalArgumentException if the key is invalid
+ */
+ public String encrypt(String plaintext, int[] key) {
+ validateKey(key);
+
+ if (plaintext == null || plaintext.isEmpty()) {
+ return plaintext;
+ }
+
+ // Remove spaces and convert to uppercase for consistent processing
+ String cleanText = plaintext.replaceAll("\\s+", "").toUpperCase();
+
+ // Pad the text to make it divisible by key length
+ String paddedText = padText(cleanText, key.length);
+
+ StringBuilder encrypted = new StringBuilder();
+
+ // Process text in blocks of key length
+ for (int i = 0; i < paddedText.length(); i += key.length) {
+ String block = paddedText.substring(i, Math.min(i + key.length, paddedText.length()));
+ encrypted.append(permuteBlock(block, key));
+ }
+
+ return encrypted.toString();
+ }
+
+ /**
+ * Decrypts the given ciphertext using the permutation cipher with the specified key.
+ *
+ * @param ciphertext the text to decrypt
+ * @param key the permutation key (array of integers representing positions)
+ * @return the decrypted text
+ * @throws IllegalArgumentException if the key is invalid
+ */
+ public String decrypt(String ciphertext, int[] key) {
+ validateKey(key);
+
+ if (ciphertext == null || ciphertext.isEmpty()) {
+ return ciphertext;
+ }
+
+ // Create the inverse permutation
+ int[] inverseKey = createInverseKey(key);
+
+ StringBuilder decrypted = new StringBuilder();
+
+ // Process text in blocks of key length
+ for (int i = 0; i < ciphertext.length(); i += key.length) {
+ String block = ciphertext.substring(i, Math.min(i + key.length, ciphertext.length()));
+ decrypted.append(permuteBlock(block, inverseKey));
+ }
+
+ // Remove padding characters from the end
+ return removePadding(decrypted.toString());
+ }
+ /**
+ * Validates that the permutation key is valid.
+ * A valid key must contain all integers from 1 to n exactly once, where n is the key length.
+ *
+ * @param key the permutation key to validate
+ * @throws IllegalArgumentException if the key is invalid
+ */
+ private void validateKey(int[] key) {
+ if (key == null || key.length == 0) {
+ throw new IllegalArgumentException("Key cannot be null or empty");
+ }
+
+ Set keySet = new HashSet<>();
+ for (int position : key) {
+ if (position < 1 || position > key.length) {
+ throw new IllegalArgumentException("Key must contain integers from 1 to " + key.length);
+ }
+ if (!keySet.add(position)) {
+ throw new IllegalArgumentException("Key must contain each position exactly once");
+ }
+ }
+ }
+
+ /**
+ * Pads the text with padding characters to make its length divisible by the block size.
+ *
+ * @param text the text to pad
+ * @param blockSize the size of each block
+ * @return the padded text
+ */
+ private String padText(String text, int blockSize) {
+ int remainder = text.length() % blockSize;
+ if (remainder == 0) {
+ return text;
+ }
+
+ int paddingNeeded = blockSize - remainder;
+ StringBuilder padded = new StringBuilder(text);
+ for (int i = 0; i < paddingNeeded; i++) {
+ padded.append(PADDING_CHAR);
+ }
+
+ return padded.toString();
+ }
+ /**
+ * Applies the permutation to a single block of text.
+ *
+ * @param block the block to permute
+ * @param key the permutation key
+ * @return the permuted block
+ */
+ private String permuteBlock(String block, int[] key) {
+ if (block.length() != key.length) {
+ // Handle case where block is shorter than key (shouldn't happen with proper padding)
+ block = padText(block, key.length);
+ }
+
+ char[] result = new char[key.length];
+ char[] blockChars = block.toCharArray();
+
+ for (int i = 0; i < key.length; i++) {
+ // Key positions are 1-based, so subtract 1 for 0-based array indexing
+ result[i] = blockChars[key[i] - 1];
+ }
+
+ return new String(result);
+ }
+
+ /**
+ * Creates the inverse permutation key for decryption.
+ *
+ * @param key the original permutation key
+ * @return the inverse key
+ */
+ private int[] createInverseKey(int[] key) {
+ int[] inverse = new int[key.length];
+
+ for (int i = 0; i < key.length; i++) {
+ // The inverse key maps each position to where it should go
+ inverse[key[i] - 1] = i + 1;
+ }
+
+ return inverse;
+ }
+
+ /**
+ * Removes padding characters from the end of the decrypted text.
+ *
+ * @param text the text to remove padding from
+ * @return the text without padding
+ */
+ private String removePadding(String text) {
+ if (text.isEmpty()) {
+ return text;
+ }
+
+ int i = text.length() - 1;
+ while (i >= 0 && text.charAt(i) == PADDING_CHAR) {
+ i--;
+ }
+
+ return text.substring(0, i + 1);
+ }
+
+ /**
+ * Gets the padding character used by this cipher.
+ *
+ * @return the padding character
+ */
+ public char getPaddingChar() {
+ return PADDING_CHAR;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/PlayfairCipher.java b/src/main/java/com/thealgorithms/ciphers/PlayfairCipher.java
new file mode 100644
index 000000000000..76ceb6dbce31
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/PlayfairCipher.java
@@ -0,0 +1,128 @@
+package com.thealgorithms.ciphers;
+
+public class PlayfairCipher {
+
+ private char[][] matrix;
+ private String key;
+
+ public PlayfairCipher(String key) {
+ this.key = key;
+ generateMatrix();
+ }
+
+ public String encrypt(String plaintext) {
+ plaintext = prepareText(plaintext.replace("J", "I"));
+ StringBuilder ciphertext = new StringBuilder();
+ for (int i = 0; i < plaintext.length(); i += 2) {
+ char char1 = plaintext.charAt(i);
+ char char2 = plaintext.charAt(i + 1);
+ int[] pos1 = findPosition(char1);
+ int[] pos2 = findPosition(char2);
+ int row1 = pos1[0];
+ int col1 = pos1[1];
+ int row2 = pos2[0];
+ int col2 = pos2[1];
+ if (row1 == row2) {
+ ciphertext.append(matrix[row1][(col1 + 1) % 5]);
+ ciphertext.append(matrix[row2][(col2 + 1) % 5]);
+ } else if (col1 == col2) {
+ ciphertext.append(matrix[(row1 + 1) % 5][col1]);
+ ciphertext.append(matrix[(row2 + 1) % 5][col2]);
+ } else {
+ ciphertext.append(matrix[row1][col2]);
+ ciphertext.append(matrix[row2][col1]);
+ }
+ }
+ return ciphertext.toString();
+ }
+
+ public String decrypt(String ciphertext) {
+ StringBuilder plaintext = new StringBuilder();
+ for (int i = 0; i < ciphertext.length(); i += 2) {
+ char char1 = ciphertext.charAt(i);
+ char char2 = ciphertext.charAt(i + 1);
+ int[] pos1 = findPosition(char1);
+ int[] pos2 = findPosition(char2);
+ int row1 = pos1[0];
+ int col1 = pos1[1];
+ int row2 = pos2[0];
+ int col2 = pos2[1];
+ if (row1 == row2) {
+ plaintext.append(matrix[row1][(col1 + 4) % 5]);
+ plaintext.append(matrix[row2][(col2 + 4) % 5]);
+ } else if (col1 == col2) {
+ plaintext.append(matrix[(row1 + 4) % 5][col1]);
+ plaintext.append(matrix[(row2 + 4) % 5][col2]);
+ } else {
+ plaintext.append(matrix[row1][col2]);
+ plaintext.append(matrix[row2][col1]);
+ }
+ }
+ return plaintext.toString();
+ }
+
+ private void generateMatrix() {
+ String keyWithoutDuplicates = removeDuplicateChars(key + "ABCDEFGHIKLMNOPQRSTUVWXYZ");
+ matrix = new char[5][5];
+ int index = 0;
+ for (int i = 0; i < 5; i++) {
+ for (int j = 0; j < 5; j++) {
+ matrix[i][j] = keyWithoutDuplicates.charAt(index);
+ index++;
+ }
+ }
+ }
+
+ private String removeDuplicateChars(String str) {
+ StringBuilder result = new StringBuilder();
+ for (int i = 0; i < str.length(); i++) {
+ if (result.indexOf(String.valueOf(str.charAt(i))) == -1) {
+ result.append(str.charAt(i));
+ }
+ }
+ return result.toString();
+ }
+
+ private String prepareText(String text) {
+ text = text.toUpperCase().replaceAll("[^A-Z]", "");
+ StringBuilder preparedText = new StringBuilder();
+ char prevChar = '\0';
+ for (char c : text.toCharArray()) {
+ if (c != prevChar) {
+ preparedText.append(c);
+ prevChar = c;
+ } else {
+ preparedText.append('X').append(c);
+ prevChar = '\0';
+ }
+ }
+ if (preparedText.length() % 2 != 0) {
+ preparedText.append('X');
+ }
+ return preparedText.toString();
+ }
+
+ private int[] findPosition(char c) {
+ int[] pos = new int[2];
+ for (int i = 0; i < 5; i++) {
+ for (int j = 0; j < 5; j++) {
+ if (matrix[i][j] == c) {
+ pos[0] = i;
+ pos[1] = j;
+ return pos;
+ }
+ }
+ }
+ return pos;
+ }
+
+ public void printMatrix() {
+ System.out.println("\nPlayfair Cipher Matrix:");
+ for (int i = 0; i < 5; i++) {
+ for (int j = 0; j < 5; j++) {
+ System.out.print(matrix[i][j] + " ");
+ }
+ System.out.println();
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/Polybius.java b/src/main/java/com/thealgorithms/ciphers/Polybius.java
new file mode 100644
index 000000000000..6b3cd6ccae81
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/Polybius.java
@@ -0,0 +1,62 @@
+package com.thealgorithms.ciphers;
+
+/**
+ * A Java implementation of Polybius Cipher
+ * Polybius is a substitution cipher method
+ * It was invented by a greek philosopher that name is Polybius
+ * Letters in alphabet takes place to two dimension table.
+ * Encrypted text is created according to row and column in two dimension table
+ * Decrypted text is generated by looking at the row and column respectively
+ * Additionally, some letters in english alphabet deliberately throws such as U because U is very
+ * similar with V
+ *
+ * @author Hikmet ÇAKIR
+ * @since 08-07-2022+03:00
+ */
+public final class Polybius {
+ private Polybius() {
+ }
+
+ private static final char[][] KEY = {
+ // 0 1 2 3 4
+ /* 0 */ {'A', 'B', 'C', 'D', 'E'},
+ /* 1 */ {'F', 'G', 'H', 'I', 'J'},
+ /* 2 */ {'K', 'L', 'M', 'N', 'O'},
+ /* 3 */ {'P', 'Q', 'R', 'S', 'T'},
+ /* 4 */ {'V', 'W', 'X', 'Y', 'Z'},
+ };
+
+ private static String findLocationByCharacter(final char character) {
+ final StringBuilder location = new StringBuilder();
+ for (int i = 0; i < KEY.length; i++) {
+ for (int j = 0; j < KEY[i].length; j++) {
+ if (character == KEY[i][j]) {
+ location.append(i).append(j);
+ break;
+ }
+ }
+ }
+ return location.toString();
+ }
+
+ public static String encrypt(final String plaintext) {
+ final char[] chars = plaintext.toUpperCase().toCharArray();
+ final StringBuilder ciphertext = new StringBuilder();
+ for (char aChar : chars) {
+ String location = findLocationByCharacter(aChar);
+ ciphertext.append(location);
+ }
+ return ciphertext.toString();
+ }
+
+ public static String decrypt(final String ciphertext) {
+ final char[] chars = ciphertext.toCharArray();
+ final StringBuilder plaintext = new StringBuilder();
+ for (int i = 0; i < chars.length; i += 2) {
+ int pozitionX = Character.getNumericValue(chars[i]);
+ int pozitionY = Character.getNumericValue(chars[i + 1]);
+ plaintext.append(KEY[pozitionX][pozitionY]);
+ }
+ return plaintext.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/ProductCipher.java b/src/main/java/com/thealgorithms/ciphers/ProductCipher.java
index 39683b3e79b3..d7eaea757001 100644
--- a/src/main/java/com/thealgorithms/ciphers/ProductCipher.java
+++ b/src/main/java/com/thealgorithms/ciphers/ProductCipher.java
@@ -2,71 +2,72 @@
import java.util.Scanner;
-class ProductCipher {
+final class ProductCipher {
+ private ProductCipher() {
+ }
- public static void main(String args[]) {
- Scanner sc = new Scanner(System.in);
- System.out.println("Enter the input to be encrypted: ");
- String substitutionInput = sc.nextLine();
- System.out.println(" ");
- System.out.println("Enter a number: ");
- int n = sc.nextInt();
+ public static void main(String[] args) {
+ try (Scanner sc = new Scanner(System.in)) {
+ System.out.println("Enter the input to be encrypted: ");
+ String substitutionInput = sc.nextLine();
+ System.out.println(" ");
+ System.out.println("Enter a number: ");
+ int n = sc.nextInt();
- // Substitution encryption
- StringBuffer substitutionOutput = new StringBuffer();
- for (int i = 0; i < substitutionInput.length(); i++) {
- char c = substitutionInput.charAt(i);
- substitutionOutput.append((char) (c + 5));
- }
- System.out.println(" ");
- System.out.println("Substituted text: ");
- System.out.println(substitutionOutput);
+ // Substitution encryption
+ StringBuffer substitutionOutput = new StringBuffer();
+ for (int i = 0; i < substitutionInput.length(); i++) {
+ char c = substitutionInput.charAt(i);
+ substitutionOutput.append((char) (c + 5));
+ }
+ System.out.println(" ");
+ System.out.println("Substituted text: ");
+ System.out.println(substitutionOutput);
- // Transposition encryption
- String transpositionInput = substitutionOutput.toString();
- int modulus;
- if ((modulus = transpositionInput.length() % n) != 0) {
- modulus = n - modulus;
+ // Transposition encryption
+ String transpositionInput = substitutionOutput.toString();
+ int modulus = transpositionInput.length() % n;
+ if (modulus != 0) {
+ modulus = n - modulus;
- for (; modulus != 0; modulus--) {
- transpositionInput += "/";
+ for (; modulus != 0; modulus--) {
+ transpositionInput += "/";
+ }
}
- }
- StringBuffer transpositionOutput = new StringBuffer();
- System.out.println(" ");
- System.out.println("Transposition Matrix: ");
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < transpositionInput.length() / n; j++) {
- char c = transpositionInput.charAt(i + (j * n));
- System.out.print(c);
- transpositionOutput.append(c);
+ StringBuffer transpositionOutput = new StringBuffer();
+ System.out.println(" ");
+ System.out.println("Transposition Matrix: ");
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < transpositionInput.length() / n; j++) {
+ char c = transpositionInput.charAt(i + (j * n));
+ System.out.print(c);
+ transpositionOutput.append(c);
+ }
+ System.out.println();
}
- System.out.println();
- }
- System.out.println(" ");
- System.out.println("Final encrypted text: ");
- System.out.println(transpositionOutput);
+ System.out.println(" ");
+ System.out.println("Final encrypted text: ");
+ System.out.println(transpositionOutput);
- // Transposition decryption
- n = transpositionOutput.length() / n;
- StringBuffer transpositionPlaintext = new StringBuffer();
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < transpositionOutput.length() / n; j++) {
- char c = transpositionOutput.charAt(i + (j * n));
- transpositionPlaintext.append(c);
+ // Transposition decryption
+ n = transpositionOutput.length() / n;
+ StringBuffer transpositionPlaintext = new StringBuffer();
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < transpositionOutput.length() / n; j++) {
+ char c = transpositionOutput.charAt(i + (j * n));
+ transpositionPlaintext.append(c);
+ }
}
- }
- // Substitution decryption
- StringBuffer plaintext = new StringBuffer();
- for (int i = 0; i < transpositionPlaintext.length(); i++) {
- char c = transpositionPlaintext.charAt(i);
- plaintext.append((char) (c - 5));
- }
+ // Substitution decryption
+ StringBuffer plaintext = new StringBuffer();
+ for (int i = 0; i < transpositionPlaintext.length(); i++) {
+ char c = transpositionPlaintext.charAt(i);
+ plaintext.append((char) (c - 5));
+ }
- System.out.println("Plaintext: ");
- System.out.println(plaintext);
- sc.close();
+ System.out.println("Plaintext: ");
+ System.out.println(plaintext);
+ }
}
-
}
diff --git a/src/main/java/com/thealgorithms/ciphers/RSA.java b/src/main/java/com/thealgorithms/ciphers/RSA.java
index 27b4b457f5bb..28af1a62032a 100644
--- a/src/main/java/com/thealgorithms/ciphers/RSA.java
+++ b/src/main/java/com/thealgorithms/ciphers/RSA.java
@@ -1,76 +1,119 @@
package com.thealgorithms.ciphers;
-import javax.swing.*;
import java.math.BigInteger;
import java.security.SecureRandom;
/**
- * @author Nguyen Duy Tiep on 23-Oct-17.
+ * RSA is an asymmetric cryptographic algorithm used for secure data encryption and decryption.
+ * It relies on a pair of keys: a public key (used for encryption) and a private key
+ * (used for decryption). The algorithm is based on the difficulty of factoring large prime numbers.
+ *
+ * This implementation includes key generation, encryption, and decryption methods that can handle both
+ * text-based messages and BigInteger inputs. For more details on RSA:
+ * RSA Cryptosystem - Wikipedia.
+ *
+ * Example Usage:
+ *
+ * RSA rsa = new RSA(1024);
+ * String encryptedMessage = rsa.encrypt("Hello RSA!");
+ * String decryptedMessage = rsa.decrypt(encryptedMessage);
+ * System.out.println(decryptedMessage); // Output: Hello RSA!
+ *
+ *
+ * Note: The key size directly affects the security and performance of the RSA algorithm.
+ * Larger keys are more secure but slower to compute.
+ *
+ * @author Nguyen Duy Tiep
+ * @version 23-Oct-17
*/
-public final class RSA {
+public class RSA {
- public static void main(String[] args) {
-
- RSA rsa = new RSA(1024);
- String text1 = JOptionPane.showInputDialog("Enter a message to encrypt :");
-
- String ciphertext = rsa.encrypt(text1);
- JOptionPane.showMessageDialog(null, "Your encrypted message : " + ciphertext);
-
- JOptionPane.showMessageDialog(null, "Your message after decrypt : " + rsa.decrypt(ciphertext));
- }
-
- private BigInteger modulus, privateKey, publicKey;
+ private BigInteger modulus;
+ private BigInteger privateKey;
+ private BigInteger publicKey;
+ /**
+ * Constructor that generates RSA keys with the specified number of bits.
+ *
+ * @param bits The bit length of the keys to be generated. Common sizes include 512, 1024, 2048, etc.
+ */
public RSA(int bits) {
generateKeys(bits);
}
/**
- * @return encrypted message
+ * Encrypts a text message using the RSA public key.
+ *
+ * @param message The plaintext message to be encrypted.
+ * @throws IllegalArgumentException If the message is empty.
+ * @return The encrypted message represented as a String.
*/
public synchronized String encrypt(String message) {
+ if (message.isEmpty()) {
+ throw new IllegalArgumentException("Message is empty");
+ }
return (new BigInteger(message.getBytes())).modPow(publicKey, modulus).toString();
}
/**
- * @return encrypted message as big integer
+ * Encrypts a BigInteger message using the RSA public key.
+ *
+ * @param message The plaintext message as a BigInteger.
+ * @return The encrypted message as a BigInteger.
*/
public synchronized BigInteger encrypt(BigInteger message) {
return message.modPow(publicKey, modulus);
}
/**
- * @return plain message
+ * Decrypts an encrypted message (as String) using the RSA private key.
+ *
+ * @param encryptedMessage The encrypted message to be decrypted, represented as a String.
+ * @throws IllegalArgumentException If the message is empty.
+ * @return The decrypted plaintext message as a String.
*/
public synchronized String decrypt(String encryptedMessage) {
+ if (encryptedMessage.isEmpty()) {
+ throw new IllegalArgumentException("Message is empty");
+ }
return new String((new BigInteger(encryptedMessage)).modPow(privateKey, modulus).toByteArray());
}
/**
- * @return plain message as big integer
+ * Decrypts an encrypted BigInteger message using the RSA private key.
+ *
+ * @param encryptedMessage The encrypted message as a BigInteger.
+ * @return The decrypted plaintext message as a BigInteger.
*/
public synchronized BigInteger decrypt(BigInteger encryptedMessage) {
return encryptedMessage.modPow(privateKey, modulus);
}
/**
- * Generate a new public and private key set.
+ * Generates a new RSA key pair (public and private keys) with the specified bit length.
+ * Steps:
+ * 1. Generate two large prime numbers p and q.
+ * 2. Compute the modulus n = p * q.
+ * 3. Compute Euler's totient function: φ(n) = (p-1) * (q-1).
+ * 4. Choose a public key e (starting from 3) that is coprime with φ(n).
+ * 5. Compute the private key d as the modular inverse of e mod φ(n).
+ * The public key is (e, n) and the private key is (d, n).
+ *
+ * @param bits The bit length of the keys to be generated.
*/
- public synchronized void generateKeys(int bits) {
- SecureRandom r = new SecureRandom();
- BigInteger p = new BigInteger(bits / 2, 100, r);
- BigInteger q = new BigInteger(bits / 2, 100, r);
+ public final synchronized void generateKeys(int bits) {
+ SecureRandom random = new SecureRandom();
+ BigInteger p = new BigInteger(bits / 2, 100, random);
+ BigInteger q = new BigInteger(bits / 2, 100, random);
modulus = p.multiply(q);
- BigInteger m = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
-
- publicKey = new BigInteger("3");
+ BigInteger phi = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
- while (m.gcd(publicKey).intValue() > 1) {
- publicKey = publicKey.add(new BigInteger("2"));
+ publicKey = BigInteger.valueOf(3L);
+ while (phi.gcd(publicKey).intValue() > 1) {
+ publicKey = publicKey.add(BigInteger.TWO);
}
- privateKey = publicKey.modInverse(m);
+ privateKey = publicKey.modInverse(phi);
}
}
diff --git a/src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java b/src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java
new file mode 100644
index 000000000000..f81252980468
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java
@@ -0,0 +1,147 @@
+package com.thealgorithms.ciphers;
+
+import java.util.Arrays;
+
+/**
+ * The rail fence cipher (also called a zigzag cipher) is a classical type of transposition cipher.
+ * It derives its name from the manner in which encryption is performed, in analogy to a fence built with horizontal rails.
+ * https://en.wikipedia.org/wiki/Rail_fence_cipher
+ * @author https://github.com/Krounosity
+ */
+
+public class RailFenceCipher {
+
+ // Encrypts the input string using the rail fence cipher method with the given number of rails.
+ public String encrypt(String str, int rails) {
+
+ // Base case of single rail or rails are more than the number of characters in the string
+ if (rails == 1 || rails >= str.length()) {
+ return str;
+ }
+
+ // Boolean flag to determine if the movement is downward or upward in the rail matrix.
+ boolean down = true;
+ // Create a 2D array to represent the rails (rows) and the length of the string (columns).
+ char[][] strRail = new char[rails][str.length()];
+
+ // Initialize all positions in the rail matrix with a placeholder character ('\n').
+ for (int i = 0; i < rails; i++) {
+ Arrays.fill(strRail[i], '\n');
+ }
+
+ int row = 0; // Start at the first row
+ int col = 0; // Start at the first column
+
+ int i = 0;
+
+ // Fill the rail matrix with characters from the string based on the rail pattern.
+ while (col < str.length()) {
+ // Change direction to down when at the first row.
+ if (row == 0) {
+ down = true;
+ }
+ // Change direction to up when at the last row.
+ else if (row == rails - 1) {
+ down = false;
+ }
+
+ // Place the character in the current position of the rail matrix.
+ strRail[row][col] = str.charAt(i);
+ col++; // Move to the next column.
+ // Move to the next row based on the direction.
+ if (down) {
+ row++;
+ } else {
+ row--;
+ }
+
+ i++;
+ }
+
+ // Construct the encrypted string by reading characters row by row.
+ StringBuilder encryptedString = new StringBuilder();
+ for (char[] chRow : strRail) {
+ for (char ch : chRow) {
+ if (ch != '\n') {
+ encryptedString.append(ch);
+ }
+ }
+ }
+ return encryptedString.toString();
+ }
+ // Decrypts the input string using the rail fence cipher method with the given number of rails.
+ public String decrypt(String str, int rails) {
+
+ // Base case of single rail or rails are more than the number of characters in the string
+ if (rails == 1 || rails >= str.length()) {
+ return str;
+ }
+ // Boolean flag to determine if the movement is downward or upward in the rail matrix.
+ boolean down = true;
+
+ // Create a 2D array to represent the rails (rows) and the length of the string (columns).
+ char[][] strRail = new char[rails][str.length()];
+
+ int row = 0; // Start at the first row
+ int col = 0; // Start at the first column
+
+ // Mark the pattern on the rail matrix using '*'.
+ while (col < str.length()) {
+ // Change direction to down when at the first row.
+ if (row == 0) {
+ down = true;
+ }
+ // Change direction to up when at the last row.
+ else if (row == rails - 1) {
+ down = false;
+ }
+
+ // Mark the current position in the rail matrix.
+ strRail[row][col] = '*';
+ col++; // Move to the next column.
+ // Move to the next row based on the direction.
+ if (down) {
+ row++;
+ } else {
+ row--;
+ }
+ }
+
+ int index = 0; // Index to track characters from the input string.
+ // Fill the rail matrix with characters from the input string based on the marked pattern.
+ for (int i = 0; i < rails; i++) {
+ for (int j = 0; j < str.length(); j++) {
+ if (strRail[i][j] == '*') {
+ strRail[i][j] = str.charAt(index++);
+ }
+ }
+ }
+
+ // Construct the decrypted string by following the zigzag pattern.
+ StringBuilder decryptedString = new StringBuilder();
+ row = 0; // Reset to the first row
+ col = 0; // Reset to the first column
+
+ while (col < str.length()) {
+ // Change direction to down when at the first row.
+ if (row == 0) {
+ down = true;
+ }
+ // Change direction to up when at the last row.
+ else if (row == rails - 1) {
+ down = false;
+ }
+ // Append the character from the rail matrix to the decrypted string.
+ decryptedString.append(strRail[row][col]);
+ col++; // Move to the next column.
+ // Move to the next row based on the direction.
+ if (down) {
+ row++;
+ } else {
+ row--;
+ }
+ }
+
+ return decryptedString.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/SimpleSubCipher.java b/src/main/java/com/thealgorithms/ciphers/SimpleSubCipher.java
index 56e5baf38447..f6c88ef730ec 100644
--- a/src/main/java/com/thealgorithms/ciphers/SimpleSubCipher.java
+++ b/src/main/java/com/thealgorithms/ciphers/SimpleSubCipher.java
@@ -19,8 +19,8 @@ public class SimpleSubCipher {
* @param cipherSmall
* @return Encrypted message
*/
- public static String encode(String message, String cipherSmall) {
- String encoded = "";
+ public String encode(String message, String cipherSmall) {
+ StringBuilder encoded = new StringBuilder();
// This map is used to encode
Map cipherMap = new HashMap<>();
@@ -39,13 +39,13 @@ public static String encode(String message, String cipherSmall) {
for (int i = 0; i < message.length(); i++) {
if (Character.isAlphabetic(message.charAt(i))) {
- encoded += cipherMap.get(message.charAt(i));
+ encoded.append(cipherMap.get(message.charAt(i)));
} else {
- encoded += message.charAt(i);
+ encoded.append(message.charAt(i));
}
}
- return encoded;
+ return encoded.toString();
}
/**
@@ -56,10 +56,10 @@ public static String encode(String message, String cipherSmall) {
* @param cipherSmall
* @return message
*/
- public static String decode(String encryptedMessage, String cipherSmall) {
- String decoded = "";
+ public String decode(String encryptedMessage, String cipherSmall) {
+ StringBuilder decoded = new StringBuilder();
- Map cipherMap = new HashMap();
+ Map cipherMap = new HashMap<>();
char beginSmallLetter = 'a';
char beginCapitalLetter = 'A';
@@ -74,19 +74,12 @@ public static String decode(String encryptedMessage, String cipherSmall) {
for (int i = 0; i < encryptedMessage.length(); i++) {
if (Character.isAlphabetic(encryptedMessage.charAt(i))) {
- decoded += cipherMap.get(encryptedMessage.charAt(i));
+ decoded.append(cipherMap.get(encryptedMessage.charAt(i)));
} else {
- decoded += encryptedMessage.charAt(i);
+ decoded.append(encryptedMessage.charAt(i));
}
}
- return decoded;
- }
-
- public static void main(String[] args) {
- String a = encode("defend the east wall of the castle", "phqgiumeaylnofdxjkrcvstzwb");
- String b = decode(a, "phqgiumeaylnofdxjkrcvstzwb");
- System.out.println(b);
+ return decoded.toString();
}
-
}
diff --git a/src/main/java/com/thealgorithms/ciphers/SimpleSubstitutionCipher.java b/src/main/java/com/thealgorithms/ciphers/SimpleSubstitutionCipher.java
deleted file mode 100644
index ac68c7a4a907..000000000000
--- a/src/main/java/com/thealgorithms/ciphers/SimpleSubstitutionCipher.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package com.thealgorithms.ciphers;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * The simple substitution cipher is a cipher that has been in use for many
- * hundreds of years (an excellent history is given in Simon Singhs 'the Code
- * Book'). It basically consists of substituting every plaintext character for a
- * different ciphertext character. It differs from the Caesar cipher in that the
- * cipher alphabet is not simply the alphabet shifted, it is completely jumbled.
- *
- * @author Hassan Elseoudy
- */
-public class SimpleSubstitutionCipher {
-
- /**
- * Encrypt text by replacing each element with its opposite character.
- *
- * @return Encrypted message
- */
- public static String encode(String message, String cipherSmall) {
- StringBuilder encoded = new StringBuilder();
-
- // This map is used to encode
- Map cipherMap = new HashMap<>();
-
- char beginSmallLetter = 'a';
- char beginCapitalLetter = 'A';
-
- cipherSmall = cipherSmall.toLowerCase();
- String cipherCapital = cipherSmall.toUpperCase();
-
- // To handle Small and Capital letters
- for (int i = 0; i < cipherSmall.length(); i++) {
- cipherMap.put(beginSmallLetter++, cipherSmall.charAt(i));
- cipherMap.put(beginCapitalLetter++, cipherCapital.charAt(i));
- }
-
- for (int i = 0; i < message.length(); i++) {
- if (Character.isAlphabetic(message.charAt(i))) {
- encoded.append(cipherMap.get(message.charAt(i)));
- } else {
- encoded.append(message.charAt(i));
- }
- }
-
- return encoded.toString();
- }
-
- /**
- * Decrypt message by replacing each element with its opposite character in
- * cipher.
- *
- * @return message
- */
- public static String decode(String encryptedMessage, String cipherSmall) {
- StringBuilder decoded = new StringBuilder();
-
- Map cipherMap = new HashMap<>();
-
- char beginSmallLetter = 'a';
- char beginCapitalLetter = 'A';
-
- cipherSmall = cipherSmall.toLowerCase();
- String cipherCapital = cipherSmall.toUpperCase();
-
- for (int i = 0; i < cipherSmall.length(); i++) {
- cipherMap.put(cipherSmall.charAt(i), beginSmallLetter++);
- cipherMap.put(cipherCapital.charAt(i), beginCapitalLetter++);
- }
-
- for (int i = 0; i < encryptedMessage.length(); i++) {
- if (Character.isAlphabetic(encryptedMessage.charAt(i))) {
- decoded.append(cipherMap.get(encryptedMessage.charAt(i)));
- } else {
- decoded.append(encryptedMessage.charAt(i));
- }
- }
-
- return decoded.toString();
- }
-
- /**
- * TODO remove main and make JUnit Testing
- */
- public static void main(String[] args) {
- String a = encode("defend the east wall of the castle", "phqgiumeaylnofdxjkrcvstzwb");
- String b = decode(a, "phqgiumeaylnofdxjkrcvstzwb");
- System.out.println(b);
- }
-}
diff --git a/src/main/java/com/thealgorithms/ciphers/Vigenere.java b/src/main/java/com/thealgorithms/ciphers/Vigenere.java
index ced26792cd5b..0f117853bb85 100644
--- a/src/main/java/com/thealgorithms/ciphers/Vigenere.java
+++ b/src/main/java/com/thealgorithms/ciphers/Vigenere.java
@@ -1,62 +1,106 @@
package com.thealgorithms.ciphers;
/**
- * A Java implementation of Vigenere Cipher.
+ * A Java implementation of the Vigenère Cipher.
+ *
+ * The Vigenère Cipher is a polyalphabetic substitution cipher that uses a
+ * keyword to shift letters in the plaintext by different amounts, depending
+ * on the corresponding character in the keyword. It wraps around the alphabet,
+ * ensuring the shifts are within 'A'-'Z' or 'a'-'z'.
+ *
+ * Non-alphabetic characters (like spaces, punctuation) are kept unchanged.
+ *
+ * Encryption Example:
+ * - Plaintext: "Hello World!"
+ * - Key: "suchsecret"
+ * - Encrypted Text: "Zynsg Yfvev!"
+ *
+ * Decryption Example:
+ * - Ciphertext: "Zynsg Yfvev!"
+ * - Key: "suchsecret"
+ * - Decrypted Text: "Hello World!"
+ *
+ * Wikipedia Reference:
+ * Vigenère Cipher - Wikipedia
*
* @author straiffix
* @author beingmartinbmc
*/
public class Vigenere {
- public static String encrypt(final String message, final String key) {
+ /**
+ * Encrypts a given message using the Vigenère Cipher with the specified key.
+ * Steps:
+ * 1. Iterate over each character in the message.
+ * 2. If the character is a letter, shift it by the corresponding character in the key.
+ * 3. Preserve the case of the letter.
+ * 4. Preserve non-alphabetic characters.
+ * 5. Move to the next character in the key (cyclic).
+ * 6. Return the encrypted message.
+ *
+ * @param message The plaintext message to encrypt.
+ * @param key The keyword used for encryption.
+ * @throws IllegalArgumentException if the key is empty.
+ * @return The encrypted message.
+ */
+ public String encrypt(final String message, final String key) {
+ if (key.isEmpty()) {
+ throw new IllegalArgumentException("Key cannot be empty.");
+ }
StringBuilder result = new StringBuilder();
-
- for (int i = 0, j = 0; i < message.length(); i++) {
+ int j = 0;
+ for (int i = 0; i < message.length(); i++) {
char c = message.charAt(i);
if (Character.isLetter(c)) {
if (Character.isUpperCase(c)) {
result.append((char) ((c + key.toUpperCase().charAt(j) - 2 * 'A') % 26 + 'A'));
-
} else {
result.append((char) ((c + key.toLowerCase().charAt(j) - 2 * 'a') % 26 + 'a'));
}
+ j = ++j % key.length();
} else {
result.append(c);
}
- j = ++j % key.length();
}
return result.toString();
}
- public static String decrypt(final String message, final String key) {
- StringBuilder result = new StringBuilder();
-
- for (int i = 0, j = 0; i < message.length(); i++) {
+ /**
+ * Decrypts a given message encrypted with the Vigenère Cipher using the specified key.
+ * Steps:
+ * 1. Iterate over each character in the message.
+ * 2. If the character is a letter, shift it back by the corresponding character in the key.
+ * 3. Preserve the case of the letter.
+ * 4. Preserve non-alphabetic characters.
+ * 5. Move to the next character in the key (cyclic).
+ * 6. Return the decrypted message.
+ *
+ * @param message The encrypted message to decrypt.
+ * @param key The keyword used for decryption.
+ * @throws IllegalArgumentException if the key is empty.
+ * @return The decrypted plaintext message.
+ */
+ public String decrypt(final String message, final String key) {
+ if (key.isEmpty()) {
+ throw new IllegalArgumentException("Key cannot be empty.");
+ }
+ StringBuilder result = new StringBuilder();
+ int j = 0;
+ for (int i = 0; i < message.length(); i++) {
char c = message.charAt(i);
if (Character.isLetter(c)) {
if (Character.isUpperCase(c)) {
result.append((char) ('Z' - (25 - (c - key.toUpperCase().charAt(j))) % 26));
-
} else {
result.append((char) ('z' - (25 - (c - key.toLowerCase().charAt(j))) % 26));
}
+ j = ++j % key.length();
} else {
result.append(c);
}
-
- j = ++j % key.length();
}
return result.toString();
}
-
- public static void main(String[] args) {
- String text = "Hello World!";
- String key = "itsakey";
- System.out.println(text);
- String ciphertext = encrypt(text, key);
- System.out.println(ciphertext);
- System.out.println(decrypt(ciphertext, key));
- }
}
diff --git a/src/main/java/com/thealgorithms/ciphers/XORCipher.java b/src/main/java/com/thealgorithms/ciphers/XORCipher.java
new file mode 100644
index 000000000000..a612ccfbcdef
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/XORCipher.java
@@ -0,0 +1,95 @@
+package com.thealgorithms.ciphers;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.HexFormat;
+
+/**
+ * A simple implementation of the XOR cipher that allows both encryption and decryption
+ * using a given key. This cipher works by applying the XOR bitwise operation between
+ * the bytes of the input text and the corresponding bytes of the key (repeating the key
+ * if necessary).
+ *
+ * Usage:
+ * - Encryption: Converts plaintext into a hexadecimal-encoded ciphertext.
+ * - Decryption: Converts the hexadecimal ciphertext back into plaintext.
+ *
+ * Characteristics:
+ * - Symmetric: The same key is used for both encryption and decryption.
+ * - Simple but vulnerable: XOR encryption is insecure for real-world cryptography,
+ * especially when the same key is reused.
+ *
+ * Example:
+ * Plaintext: "Hello!"
+ * Key: "key"
+ * Encrypted: "27090c03120b"
+ * Decrypted: "Hello!"
+ *
+ * Reference: XOR Cipher - Wikipedia
+ *
+ * @author lcsjunior
+ */
+public final class XORCipher {
+
+ // Default character encoding for string conversion
+ private static final Charset CS_DEFAULT = StandardCharsets.UTF_8;
+
+ private XORCipher() {
+ }
+
+ /**
+ * Applies the XOR operation between the input bytes and the key bytes.
+ * If the key is shorter than the input, it wraps around (cyclically).
+ *
+ * @param inputBytes The input byte array (plaintext or ciphertext).
+ * @param keyBytes The key byte array used for XOR operation.
+ * @return A new byte array containing the XOR result.
+ */
+ public static byte[] xor(final byte[] inputBytes, final byte[] keyBytes) {
+ byte[] outputBytes = new byte[inputBytes.length];
+ for (int i = 0; i < inputBytes.length; ++i) {
+ outputBytes[i] = (byte) (inputBytes[i] ^ keyBytes[i % keyBytes.length]);
+ }
+ return outputBytes;
+ }
+
+ /**
+ * Encrypts the given plaintext using the XOR cipher with the specified key.
+ * The result is a hexadecimal-encoded string representing the ciphertext.
+ *
+ * @param plainText The input plaintext to encrypt.
+ * @param key The encryption key.
+ * @throws IllegalArgumentException if the key is empty.
+ * @return A hexadecimal string representing the encrypted text.
+ */
+ public static String encrypt(final String plainText, final String key) {
+ if (key.isEmpty()) {
+ throw new IllegalArgumentException("Key must not be empty");
+ }
+
+ byte[] plainTextBytes = plainText.getBytes(CS_DEFAULT);
+ byte[] keyBytes = key.getBytes(CS_DEFAULT);
+ byte[] xorResult = xor(plainTextBytes, keyBytes);
+ return HexFormat.of().formatHex(xorResult);
+ }
+
+ /**
+ * Decrypts the given ciphertext (in hexadecimal format) using the XOR cipher
+ * with the specified key. The result is the original plaintext.
+ *
+ * @param cipherText The hexadecimal string representing the encrypted text.
+ * @param key The decryption key (must be the same as the encryption key).
+ * @throws IllegalArgumentException if the key is empty.
+ * @return The decrypted plaintext.
+ */
+ public static String decrypt(final String cipherText, final String key) {
+ if (key.isEmpty()) {
+ throw new IllegalArgumentException("Key must not be empty");
+ }
+
+ byte[] cipherBytes = HexFormat.of().parseHex(cipherText);
+ byte[] keyBytes = key.getBytes(CS_DEFAULT);
+ byte[] xorResult = xor(cipherBytes, keyBytes);
+ return new String(xorResult, CS_DEFAULT);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/a5/A5Cipher.java b/src/main/java/com/thealgorithms/ciphers/a5/A5Cipher.java
new file mode 100644
index 000000000000..cc2e9105229a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/a5/A5Cipher.java
@@ -0,0 +1,63 @@
+package com.thealgorithms.ciphers.a5;
+
+import java.util.BitSet;
+
+/**
+ * The A5Cipher class implements the A5/1 stream cipher, which is a widely used
+ * encryption algorithm, particularly in mobile communications.
+ *
+ * This implementation uses a key stream generator to produce a stream of bits
+ * that are XORed with the plaintext bits to produce the ciphertext.
+ *
+ *
+ * For more details about the A5/1 algorithm, refer to
+ * Wikipedia.
+ *
+ */
+public class A5Cipher {
+
+ private final A5KeyStreamGenerator keyStreamGenerator;
+ private static final int KEY_STREAM_LENGTH = 228; // Length of the key stream in bits (28.5 bytes)
+
+ /**
+ * Constructs an A5Cipher instance with the specified session key and frame counter.
+ *
+ * @param sessionKey a BitSet representing the session key used for encryption.
+ * @param frameCounter a BitSet representing the frame counter that helps in key stream generation.
+ */
+ public A5Cipher(BitSet sessionKey, BitSet frameCounter) {
+ keyStreamGenerator = new A5KeyStreamGenerator();
+ keyStreamGenerator.initialize(sessionKey, frameCounter);
+ }
+
+ /**
+ * Encrypts the given plaintext bits using the A5/1 cipher algorithm.
+ *
+ * This method generates a key stream and XORs it with the provided plaintext
+ * bits to produce the ciphertext.
+ *
+ * @param plainTextBits a BitSet representing the plaintext bits to be encrypted.
+ * @return a BitSet containing the encrypted ciphertext bits.
+ */
+ public BitSet encrypt(BitSet plainTextBits) {
+ // create a copy
+ var result = new BitSet(KEY_STREAM_LENGTH);
+ result.xor(plainTextBits);
+
+ var key = keyStreamGenerator.getNextKeyStream();
+ result.xor(key);
+
+ return result;
+ }
+
+ /**
+ * Resets the internal counter of the key stream generator.
+ *
+ * This method can be called to re-initialize the state of the key stream
+ * generator, allowing for new key streams to be generated for subsequent
+ * encryptions.
+ */
+ public void resetCounter() {
+ keyStreamGenerator.reInitialize();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/a5/A5KeyStreamGenerator.java b/src/main/java/com/thealgorithms/ciphers/a5/A5KeyStreamGenerator.java
new file mode 100644
index 000000000000..ee837ef4241a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/a5/A5KeyStreamGenerator.java
@@ -0,0 +1,121 @@
+package com.thealgorithms.ciphers.a5;
+
+import java.util.BitSet;
+
+/**
+ * The A5KeyStreamGenerator class is responsible for generating key streams
+ * for the A5/1 encryption algorithm using a combination of Linear Feedback Shift Registers (LFSRs).
+ *
+ *
+ * This class extends the CompositeLFSR and initializes a set of LFSRs with
+ * a session key and a frame counter to produce a pseudo-random key stream.
+ *
+ *
+ *
+ * Note: Proper exception handling for invalid usage is to be implemented.
+ *
+ */
+public class A5KeyStreamGenerator extends CompositeLFSR {
+
+ private BitSet initialFrameCounter;
+ private BitSet frameCounter;
+ private BitSet sessionKey;
+ private static final int INITIAL_CLOCKING_CYCLES = 100;
+ private static final int KEY_STREAM_LENGTH = 228;
+
+ /**
+ * Initializes the A5KeyStreamGenerator with the specified session key and frame counter.
+ *
+ *
+ * This method sets up the internal state of the LFSRs using the provided
+ * session key and frame counter. It creates three LFSRs with specific
+ * configurations and initializes them.
+ *
+ *
+ * @param sessionKey a BitSet representing the session key used for key stream generation.
+ * @param frameCounter a BitSet representing the frame counter that influences the key stream.
+ */
+ @Override
+ public void initialize(BitSet sessionKey, BitSet frameCounter) {
+ this.sessionKey = sessionKey;
+ this.frameCounter = (BitSet) frameCounter.clone();
+ this.initialFrameCounter = (BitSet) frameCounter.clone();
+ registers.clear();
+ LFSR lfsr1 = new LFSR(19, 8, new int[] {13, 16, 17, 18});
+ LFSR lfsr2 = new LFSR(22, 10, new int[] {20, 21});
+ LFSR lfsr3 = new LFSR(23, 10, new int[] {7, 20, 21, 22});
+ registers.add(lfsr1);
+ registers.add(lfsr2);
+ registers.add(lfsr3);
+ registers.forEach(lfsr -> lfsr.initialize(sessionKey, frameCounter));
+ }
+
+ /**
+ * Re-initializes the key stream generator with the original session key
+ * and frame counter. This method restores the generator to its initial
+ * state.
+ */
+ public void reInitialize() {
+ this.initialize(sessionKey, initialFrameCounter);
+ }
+
+ /**
+ * Generates the next key stream of bits.
+ *
+ *
+ * This method performs an initial set of clocking cycles and then retrieves
+ * a key stream of the specified length. After generation, it re-initializes
+ * the internal registers.
+ *
+ *
+ * @return a BitSet containing the generated key stream bits.
+ */
+ public BitSet getNextKeyStream() {
+ for (int cycle = 1; cycle <= INITIAL_CLOCKING_CYCLES; ++cycle) {
+ this.clock();
+ }
+
+ BitSet result = new BitSet(KEY_STREAM_LENGTH);
+ for (int cycle = 1; cycle <= KEY_STREAM_LENGTH; ++cycle) {
+ boolean outputBit = this.clock();
+ result.set(cycle - 1, outputBit);
+ }
+
+ reInitializeRegisters();
+ return result;
+ }
+
+ /**
+ * Re-initializes the registers for the LFSRs.
+ *
+ *
+ * This method increments the frame counter and re-initializes each LFSR
+ * with the current session key and frame counter.
+ *
+ */
+ private void reInitializeRegisters() {
+ incrementFrameCounter();
+ registers.forEach(lfsr -> lfsr.initialize(sessionKey, frameCounter));
+ }
+
+ /**
+ * Increments the current frame counter.
+ *
+ *
+ * This method uses a utility function to increment the frame counter,
+ * which influences the key stream generation process.
+ *
+ */
+ private void incrementFrameCounter() {
+ Utils.increment(frameCounter, FRAME_COUNTER_LENGTH);
+ }
+
+ /**
+ * Retrieves the current frame counter.
+ *
+ * @return a BitSet representing the current state of the frame counter.
+ */
+ public BitSet getFrameCounter() {
+ return frameCounter;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/a5/BaseLFSR.java b/src/main/java/com/thealgorithms/ciphers/a5/BaseLFSR.java
new file mode 100644
index 000000000000..18ad913784dc
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/a5/BaseLFSR.java
@@ -0,0 +1,10 @@
+package com.thealgorithms.ciphers.a5;
+
+import java.util.BitSet;
+
+public interface BaseLFSR {
+ void initialize(BitSet sessionKey, BitSet frameCounter);
+ boolean clock();
+ int SESSION_KEY_LENGTH = 64;
+ int FRAME_COUNTER_LENGTH = 22;
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/a5/CompositeLFSR.java b/src/main/java/com/thealgorithms/ciphers/a5/CompositeLFSR.java
new file mode 100644
index 000000000000..029a93848c28
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/a5/CompositeLFSR.java
@@ -0,0 +1,69 @@
+package com.thealgorithms.ciphers.a5;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * The CompositeLFSR class represents a composite implementation of
+ * Linear Feedback Shift Registers (LFSRs) for cryptographic purposes.
+ *
+ *
+ * This abstract class manages a collection of LFSR instances and
+ * provides a mechanism for irregular clocking based on the
+ * majority bit among the registers. It implements the BaseLFSR
+ * interface, requiring subclasses to define specific LFSR behaviors.
+ *
+ */
+public abstract class CompositeLFSR implements BaseLFSR {
+
+ protected final List registers = new ArrayList<>();
+
+ /**
+ * Performs a clocking operation on the composite LFSR.
+ *
+ *
+ * This method determines the majority bit across all registers and
+ * clocks each register based on its clock bit. If a register's
+ * clock bit matches the majority bit, it is clocked (shifted).
+ * The method also computes and returns the XOR of the last bits
+ * of all registers.
+ *
+ *
+ * @return the XOR value of the last bits of all registers.
+ */
+ @Override
+ public boolean clock() {
+ boolean majorityBit = getMajorityBit();
+ boolean result = false;
+ for (var register : registers) {
+ result ^= register.getLastBit();
+ if (register.getClockBit() == majorityBit) {
+ register.clock();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Calculates the majority bit among all registers.
+ *
+ *
+ * This private method counts the number of true and false clock bits
+ * across all LFSR registers. It returns true if the count of true
+ * bits is greater than or equal to the count of false bits; otherwise,
+ * it returns false.
+ *
+ *
+ * @return true if the majority clock bits are true; false otherwise.
+ */
+ private boolean getMajorityBit() {
+ Map bitCount = new TreeMap<>();
+ bitCount.put(Boolean.FALSE, 0);
+ bitCount.put(Boolean.TRUE, 0);
+
+ registers.forEach(lfsr -> bitCount.put(lfsr.getClockBit(), bitCount.get(lfsr.getClockBit()) + 1));
+ return bitCount.get(Boolean.FALSE) <= bitCount.get(Boolean.TRUE);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/a5/LFSR.java b/src/main/java/com/thealgorithms/ciphers/a5/LFSR.java
new file mode 100644
index 000000000000..dc42ae0a7a5e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/a5/LFSR.java
@@ -0,0 +1,79 @@
+package com.thealgorithms.ciphers.a5;
+
+import java.util.BitSet;
+
+public class LFSR implements BaseLFSR {
+
+ private final BitSet register;
+ private final int length;
+ private final int clockBitIndex;
+ private final int[] tappingBitsIndices;
+
+ public LFSR(int length, int clockBitIndex, int[] tappingBitsIndices) {
+ this.length = length;
+ this.clockBitIndex = clockBitIndex;
+ this.tappingBitsIndices = tappingBitsIndices;
+ register = new BitSet(length);
+ }
+
+ @Override
+ public void initialize(BitSet sessionKey, BitSet frameCounter) {
+ register.clear();
+ clock(sessionKey, SESSION_KEY_LENGTH);
+ clock(frameCounter, FRAME_COUNTER_LENGTH);
+ }
+
+ private void clock(BitSet key, int keyLength) {
+ // We start from reverse because LFSR 0 index is the left most bit
+ // while key 0 index is right most bit, so we reverse it
+ for (int i = keyLength - 1; i >= 0; --i) {
+ var newBit = key.get(i) ^ xorTappingBits();
+ pushBit(newBit);
+ }
+ }
+
+ @Override
+ public boolean clock() {
+ return pushBit(xorTappingBits());
+ }
+
+ public boolean getClockBit() {
+ return register.get(clockBitIndex);
+ }
+
+ public boolean get(int bitIndex) {
+ return register.get(bitIndex);
+ }
+
+ public boolean getLastBit() {
+ return register.get(length - 1);
+ }
+
+ private boolean xorTappingBits() {
+ boolean result = false;
+ for (int i : tappingBitsIndices) {
+ result ^= register.get(i);
+ }
+ return result;
+ }
+
+ private boolean pushBit(boolean bit) {
+ boolean discardedBit = rightShift();
+ register.set(0, bit);
+ return discardedBit;
+ }
+
+ private boolean rightShift() {
+ boolean discardedBit = get(length - 1);
+ for (int i = length - 1; i > 0; --i) {
+ register.set(i, get(i - 1));
+ }
+ register.set(0, false);
+ return discardedBit;
+ }
+
+ @Override
+ public String toString() {
+ return register.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/a5/Utils.java b/src/main/java/com/thealgorithms/ciphers/a5/Utils.java
new file mode 100644
index 000000000000..b4addf18dd9d
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/a5/Utils.java
@@ -0,0 +1,25 @@
+package com.thealgorithms.ciphers.a5;
+
+// Source
+// http://www.java2s.com/example/java-utility-method/bitset/increment-bitset-bits-int-size-9fd84.html
+// package com.java2s;
+// License from project: Open Source License
+
+import java.util.BitSet;
+
+public final class Utils {
+ private Utils() {
+ }
+
+ public static boolean increment(BitSet bits, int size) {
+ int i = size - 1;
+ while (i >= 0 && bits.get(i)) {
+ bits.set(i--, false); /*from w w w . j a v a 2s .c o m*/
+ }
+ if (i < 0) {
+ return false;
+ }
+ bits.set(i, true);
+ return true;
+ }
+}
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:
+ *
+ *
+ */
+public final class ArithmeticCoding {
+
+ private ArithmeticCoding() {
+ }
+
+ /**
+ * Compresses a string using the Arithmetic Coding algorithm.
+ *
+ * @param uncompressed The string to be compressed.
+ * @return The compressed representation as a BigDecimal number.
+ * @throws IllegalArgumentException if the input string is null or empty.
+ */
+ public static BigDecimal compress(String uncompressed) {
+ if (uncompressed == null || uncompressed.isEmpty()) {
+ throw new IllegalArgumentException("Input string cannot be null or empty.");
+ }
+
+ Map probabilityTable = calculateProbabilities(uncompressed);
+
+ BigDecimal low = BigDecimal.ZERO;
+ BigDecimal high = BigDecimal.ONE;
+
+ for (char symbol : uncompressed.toCharArray()) {
+ BigDecimal range = high.subtract(low);
+ Symbol sym = probabilityTable.get(symbol);
+
+ high = low.add(range.multiply(sym.high()));
+ low = low.add(range.multiply(sym.low()));
+ }
+
+ return low; // Return the lower bound of the final interval
+ }
+
+ /**
+ * Decompresses a BigDecimal number back into the original string.
+ *
+ * @param compressed The compressed BigDecimal number.
+ * @param length The length of the original uncompressed string.
+ * @param probabilityTable The probability table used during compression.
+ * @return The original, uncompressed string.
+ */
+ public static String decompress(BigDecimal compressed, int length, Map probabilityTable) {
+ StringBuilder decompressed = new StringBuilder();
+
+ // Create a sorted list of symbols for deterministic decompression, matching the
+ // order used in calculateProbabilities
+ List> sortedSymbols = new ArrayList<>(probabilityTable.entrySet());
+ sortedSymbols.sort(Map.Entry.comparingByKey());
+
+ BigDecimal low = BigDecimal.ZERO;
+ BigDecimal high = BigDecimal.ONE;
+
+ for (int i = 0; i < length; i++) {
+ BigDecimal range = high.subtract(low);
+
+ // Find which symbol the compressed value falls into
+ for (Map.Entry entry : sortedSymbols) {
+ Symbol sym = entry.getValue();
+
+ // Calculate the actual range for this symbol in the current interval
+ BigDecimal symLow = low.add(range.multiply(sym.low()));
+ BigDecimal symHigh = low.add(range.multiply(sym.high()));
+
+ // Check if the compressed value falls within this symbol's range
+ if (compressed.compareTo(symLow) >= 0 && compressed.compareTo(symHigh) < 0) {
+ decompressed.append(entry.getKey());
+
+ // Update the interval for the next iteration
+ low = symLow;
+ high = symHigh;
+ break;
+ }
+ }
+ }
+
+ return decompressed.toString();
+ }
+
+ /**
+ * Calculates the frequency and probability range for each character in the
+ * input string in a deterministic order.
+ *
+ * @param text The input string.
+ * @return A map from each character to a Symbol object containing its
+ * probability range.
+ */
+ public static Map calculateProbabilities(String text) {
+ Map frequencies = new HashMap<>();
+ for (char c : text.toCharArray()) {
+ frequencies.put(c, frequencies.getOrDefault(c, 0) + 1);
+ }
+
+ // Sort the characters to ensure a deterministic order for the probability table
+ List sortedKeys = new ArrayList<>(frequencies.keySet());
+ Collections.sort(sortedKeys);
+
+ Map probabilityTable = new HashMap<>();
+ BigDecimal currentLow = BigDecimal.ZERO;
+ int total = text.length();
+
+ for (char symbol : sortedKeys) {
+ BigDecimal probability = BigDecimal.valueOf(frequencies.get(symbol)).divide(BigDecimal.valueOf(total), MathContext.DECIMAL128);
+ BigDecimal high = currentLow.add(probability);
+ probabilityTable.put(symbol, new Symbol(currentLow, high));
+ currentLow = high;
+ }
+
+ return probabilityTable;
+ }
+
+ /**
+ * Helper class to store the probability range [low, high) for a symbol.
+ */
+ public record Symbol(BigDecimal low, BigDecimal high) {
+ }
+}
diff --git a/src/main/java/com/thealgorithms/compression/BurrowsWheelerTransform.java b/src/main/java/com/thealgorithms/compression/BurrowsWheelerTransform.java
new file mode 100644
index 000000000000..a148517e5b55
--- /dev/null
+++ b/src/main/java/com/thealgorithms/compression/BurrowsWheelerTransform.java
@@ -0,0 +1,220 @@
+package com.thealgorithms.compression;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Implementation of the Burrows-Wheeler Transform (BWT) and its inverse.
+ *
+ * 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:
+ *
+ * - Generating all rotations of the input string
+ * - Sorting these rotations lexicographically
+ * - Taking the last column of the sorted matrix as output
+ * - Recording the index of the original string in the sorted matrix
+ *
+ *
+ *
+ * Important: The input string should end with a unique end-of-string marker
+ * (typically '$') that:
+ *
+ * - Does not appear anywhere else in the text
+ * - Is lexicographically smaller than all other characters
+ * - Ensures unique rotations and enables correct inverse transformation
+ *
+ * Without this marker, the inverse transform may not correctly reconstruct the original string.
+ *
+ *
+ * Time Complexity:
+ *
+ * - Forward transform: O(n² log n) where n is the string length
+ * - Inverse transform: O(n) using the LF-mapping technique
+ *
+ *
+ *
+ * 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:
+ *
+ * - Creating the first column by sorting the BWT string
+ * - Building a mapping from first column indices to last column indices
+ * - Following this mapping starting from the original index to reconstruct the string
+ *
+ *
+ *
+ * @param bwtString the transformed string (L-column) from the forward transform; must not be {@code null}
+ * @param originalIndex the index of the original string row from the forward transform;
+ * use -1 for empty strings
+ * @return the original, untransformed string; returns empty string if input is empty or {@code originalIndex} is -1
+ * @throws NullPointerException if {@code bwtString} is {@code null}
+ * @throws IllegalArgumentException if {@code originalIndex} is out of valid range (except -1)
+ */
+ public static String inverseTransform(String bwtString, int originalIndex) {
+ if (bwtString == null || bwtString.isEmpty() || originalIndex == -1) {
+ return "";
+ }
+
+ int n = bwtString.length();
+ if (originalIndex < 0 || originalIndex >= n) {
+ throw new IllegalArgumentException("Original index must be between 0 and " + (n - 1) + ", got: " + originalIndex);
+ }
+
+ char[] lastColumn = bwtString.toCharArray();
+ char[] firstColumn = bwtString.toCharArray();
+ Arrays.sort(firstColumn);
+
+ // Create the "next" array for LF-mapping.
+ // next[i] stores the row index in the last column that corresponds to firstColumn[i]
+ int[] next = new int[n];
+
+ // Track the count of each character seen so far in the last column
+ Map countMap = new HashMap<>();
+
+ // Store the first occurrence index of each character in the first column
+ Map firstOccurrence = new HashMap<>();
+
+ for (int i = 0; i < n; i++) {
+ if (!firstOccurrence.containsKey(firstColumn[i])) {
+ firstOccurrence.put(firstColumn[i], i);
+ }
+ }
+
+ // Build the LF-mapping
+ for (int i = 0; i < n; i++) {
+ char c = lastColumn[i];
+ int count = countMap.getOrDefault(c, 0);
+ int firstIndex = firstOccurrence.get(c);
+ next[firstIndex + count] = i;
+ countMap.put(c, count + 1);
+ }
+
+ // Reconstruct the original string by following the LF-mapping
+ StringBuilder originalString = new StringBuilder(n);
+ int currentRow = originalIndex;
+ for (int i = 0; i < n; i++) {
+ originalString.append(firstColumn[currentRow]);
+ currentRow = next[currentRow];
+ }
+
+ return originalString.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/compression/LZ77.java b/src/main/java/com/thealgorithms/compression/LZ77.java
new file mode 100644
index 000000000000..d02307aa57b5
--- /dev/null
+++ b/src/main/java/com/thealgorithms/compression/LZ77.java
@@ -0,0 +1,168 @@
+package com.thealgorithms.compression;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An implementation of the Lempel-Ziv 77 (LZ77) compression algorithm.
+ *
+ * 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:
+ *
+ *
+ */
+public final class LZ77 {
+
+ private static final int DEFAULT_WINDOW_SIZE = 4096;
+ private static final int DEFAULT_LOOKAHEAD_BUFFER_SIZE = 16;
+ private static final char END_OF_STREAM = '\u0000';
+ private LZ77() {
+ }
+
+ /**
+ * Represents a token in the LZ77 compressed output.
+ * Stores the offset back into the window, the length of the match,
+ * and the next character after the match (or END_OF_STREAM if at end).
+ */
+ public record Token(int offset, int length, char nextChar) {
+ }
+
+ /**
+ * Compresses the input text using the LZ77 algorithm.
+ *
+ * @param text The input string to compress. Must not be null.
+ * @param windowSize The size of the sliding window (search buffer). Must be positive.
+ * @param lookaheadBufferSize The size of the lookahead buffer. Must be positive.
+ * @return A list of {@link Token} objects representing the compressed data.
+ * @throws IllegalArgumentException if windowSize or lookaheadBufferSize are not positive.
+ */
+ public static List compress(String text, int windowSize, int lookaheadBufferSize) {
+ if (text == null) {
+ return new ArrayList<>();
+ }
+ if (windowSize <= 0 || lookaheadBufferSize <= 0) {
+ throw new IllegalArgumentException("Window size and lookahead buffer size must be positive.");
+ }
+
+ List compressedOutput = new ArrayList<>();
+ int currentPosition = 0;
+
+ while (currentPosition < text.length()) {
+ int bestMatchDistance = 0;
+ int bestMatchLength = 0;
+
+ // Define the start of the search window
+ int searchBufferStart = Math.max(0, currentPosition - windowSize);
+ // Define the end of the lookahead buffer (don't go past text length)
+ int lookaheadEnd = Math.min(currentPosition + lookaheadBufferSize, text.length());
+
+ // Search for the longest match in the window
+ for (int i = searchBufferStart; i < currentPosition; i++) {
+ int currentMatchLength = 0;
+
+ // Check how far the match extends into the lookahead buffer
+ // This allows for overlapping matches (e.g., "aaa" can match with offset 1)
+ while (currentPosition + currentMatchLength < lookaheadEnd) {
+ int sourceIndex = i + currentMatchLength;
+
+ // Handle overlapping matches (run-length encoding within LZ77)
+ // When we've matched beyond our starting position, wrap around using modulo
+ if (sourceIndex >= currentPosition) {
+ int offset = currentPosition - i;
+ sourceIndex = i + (currentMatchLength % offset);
+ }
+
+ if (text.charAt(sourceIndex) == text.charAt(currentPosition + currentMatchLength)) {
+ currentMatchLength++;
+ } else {
+ break;
+ }
+ }
+
+ // If this match is longer than the best found so far
+ if (currentMatchLength > bestMatchLength) {
+ bestMatchLength = currentMatchLength;
+ bestMatchDistance = currentPosition - i; // Calculate offset from current position
+ }
+ }
+
+ char nextChar;
+ if (currentPosition + bestMatchLength < text.length()) {
+ nextChar = text.charAt(currentPosition + bestMatchLength);
+ } else {
+ nextChar = END_OF_STREAM;
+ }
+
+ // Add the token to the output
+ compressedOutput.add(new Token(bestMatchDistance, bestMatchLength, nextChar));
+
+ // Move the current position forward
+ // If we're at the end and had a match, just move by the match length
+ if (nextChar == END_OF_STREAM) {
+ currentPosition += bestMatchLength;
+ } else {
+ currentPosition += bestMatchLength + 1;
+ }
+ }
+
+ return compressedOutput;
+ }
+
+ /**
+ * Compresses the input text using the LZ77 algorithm with default buffer sizes.
+ *
+ * @param text The input string to compress. Must not be null.
+ * @return A list of {@link Token} objects representing the compressed data.
+ */
+ public static List compress(String text) {
+ return compress(text, DEFAULT_WINDOW_SIZE, DEFAULT_LOOKAHEAD_BUFFER_SIZE);
+ }
+
+ /**
+ * Decompresses a list of LZ77 tokens back into the original string.
+ *
+ * @param compressedData The list of {@link Token} objects. Must not be null.
+ * @return The original, uncompressed string.
+ */
+ public static String decompress(List compressedData) {
+ if (compressedData == null) {
+ return "";
+ }
+
+ StringBuilder decompressedText = new StringBuilder();
+
+ for (Token token : compressedData) {
+ // Copy matched characters from the sliding window
+ if (token.length > 0) {
+ int startIndex = decompressedText.length() - token.offset;
+
+ // Handle overlapping matches (e.g., when length > offset)
+ for (int i = 0; i < token.length; i++) {
+ decompressedText.append(decompressedText.charAt(startIndex + i));
+ }
+ }
+
+ // Append the next character (if not END_OF_STREAM)
+ if (token.nextChar != END_OF_STREAM) {
+ decompressedText.append(token.nextChar);
+ }
+ }
+
+ return decompressedText.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/compression/LZ78.java b/src/main/java/com/thealgorithms/compression/LZ78.java
new file mode 100644
index 000000000000..904c379cc2a2
--- /dev/null
+++ b/src/main/java/com/thealgorithms/compression/LZ78.java
@@ -0,0 +1,136 @@
+package com.thealgorithms.compression;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An implementation of the Lempel-Ziv 78 (LZ78) compression algorithm.
+ *
+ * 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:
+ *
+ *
+ */
+public final class LZ78 {
+
+ /**
+ * Special character used to mark end of stream when needed.
+ */
+ private static final char END_OF_STREAM = '\u0000';
+
+ /**
+ * Private constructor to prevent instantiation of this utility class.
+ */
+ private LZ78() {
+ }
+
+ /**
+ * Represents a token in the LZ78 compressed output.
+ * Stores the index of the matching prefix in the dictionary and the next character.
+ * Index 0 represents the empty string (no prefix).
+ */
+ public record Token(int index, char nextChar) {
+ }
+
+ /**
+ * A node in the dictionary trie structure.
+ * Each node represents a phrase and can have child nodes for extended phrases.
+ */
+ private static final class TrieNode {
+ Map children = new HashMap<>();
+ int index = -1; // -1 means not assigned yet
+ }
+
+ /**
+ * Compresses the input text using the LZ78 algorithm.
+ *
+ * @param text The input string to compress. Must not be null.
+ * @return A list of {@link Token} objects representing the compressed data.
+ */
+ public static List compress(String text) {
+ if (text == null || text.isEmpty()) {
+ return new ArrayList<>();
+ }
+
+ List compressedOutput = new ArrayList<>();
+ TrieNode root = new TrieNode();
+ int nextDictionaryIndex = 1;
+
+ TrieNode currentNode = root;
+ int lastMatchedIndex = 0;
+
+ for (int i = 0; i < text.length(); i++) {
+ char currentChar = text.charAt(i);
+
+ if (currentNode.children.containsKey(currentChar)) {
+ currentNode = currentNode.children.get(currentChar);
+ lastMatchedIndex = currentNode.index;
+ } else {
+ // Output: (index of longest matching prefix, current character)
+ compressedOutput.add(new Token(lastMatchedIndex, currentChar));
+
+ TrieNode newNode = new TrieNode();
+ newNode.index = nextDictionaryIndex++;
+ currentNode.children.put(currentChar, newNode);
+
+ currentNode = root;
+ lastMatchedIndex = 0;
+ }
+ }
+
+ // Handle remaining phrase at end of input
+ if (currentNode != root) {
+ compressedOutput.add(new Token(lastMatchedIndex, END_OF_STREAM));
+ }
+
+ return compressedOutput;
+ }
+
+ /**
+ * Decompresses a list of LZ78 tokens back into the original string.
+ *
+ * @param compressedData The list of {@link Token} objects. Must not be null.
+ * @return The original, uncompressed string.
+ */
+ public static String decompress(List compressedData) {
+ if (compressedData == null || compressedData.isEmpty()) {
+ return "";
+ }
+
+ StringBuilder decompressedText = new StringBuilder();
+ Map dictionary = new HashMap<>();
+ int nextDictionaryIndex = 1;
+
+ for (Token token : compressedData) {
+ String prefix = (token.index == 0) ? "" : dictionary.get(token.index);
+
+ if (token.nextChar == END_OF_STREAM) {
+ decompressedText.append(prefix);
+ } else {
+ String currentPhrase = prefix + token.nextChar;
+ decompressedText.append(currentPhrase);
+ dictionary.put(nextDictionaryIndex++, currentPhrase);
+ }
+ }
+
+ return decompressedText.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/compression/LZW.java b/src/main/java/com/thealgorithms/compression/LZW.java
new file mode 100644
index 000000000000..c8383815ad4f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/compression/LZW.java
@@ -0,0 +1,136 @@
+package com.thealgorithms.compression;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An implementation of the Lempel-Ziv-Welch (LZW) algorithm.
+ *
+ *
+ * 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.
+ *
+ * - Compressing "TOBEORNOTTOBEORTOBEORNOT" results in a list of integer
+ * codes.
+ * - Decompressing that list of codes results back in the original
+ * string.
+ *
+ *
+ *
+ *
+ * Time Complexity: O(n) for both compression and decompression, where n is the
+ * length of the input string.
+ *
+ *
+ *
+ * References:
+ *
+ *
+ */
+public final class LZW {
+
+ /**
+ * Private constructor to prevent instantiation of this utility class.
+ */
+ private LZW() {
+ }
+
+ /**
+ * Compresses a string using the LZW algorithm.
+ *
+ * @param uncompressed The string to be compressed. Can be null.
+ * @return A list of integers representing the compressed data. Returns an empty
+ * list if the input is null or empty.
+ */
+ public static List compress(String uncompressed) {
+ if (uncompressed == null || uncompressed.isEmpty()) {
+ return new ArrayList<>();
+ }
+
+ // Initialize dictionary with single characters (ASCII 0-255)
+ int dictSize = 256;
+ Map dictionary = new HashMap<>();
+ for (int i = 0; i < dictSize; i++) {
+ dictionary.put("" + (char) i, i);
+ }
+
+ String w = "";
+ List result = new ArrayList<>();
+ for (char c : uncompressed.toCharArray()) {
+ String wc = w + c;
+ if (dictionary.containsKey(wc)) {
+ // If the new string is in the dictionary, extend the current string
+ w = wc;
+ } else {
+ // Otherwise, output the code for the current string
+ result.add(dictionary.get(w));
+ // Add the new string to the dictionary
+ dictionary.put(wc, dictSize++);
+ // Start a new current string
+ w = "" + c;
+ }
+ }
+
+ // Output the code for the last remaining string
+ result.add(dictionary.get(w));
+ return result;
+ }
+
+ /**
+ * Decompresses a list of integers back into a string using the LZW algorithm.
+ *
+ * @param compressed A list of integers representing the compressed data. Can be
+ * null.
+ * @return The original, uncompressed string. Returns an empty string if the
+ * input is null or empty.
+ */
+ public static String decompress(List compressed) {
+ if (compressed == null || compressed.isEmpty()) {
+ return "";
+ }
+
+ // Initialize dictionary with single characters (ASCII 0-255)
+ int dictSize = 256;
+ Map dictionary = new HashMap<>();
+ for (int i = 0; i < dictSize; i++) {
+ dictionary.put(i, "" + (char) i);
+ }
+
+ // Decompress the first code
+ String w = "" + (char) (int) compressed.removeFirst();
+ StringBuilder result = new StringBuilder(w);
+
+ for (int k : compressed) {
+ String entry;
+ if (dictionary.containsKey(k)) {
+ // The code is in the dictionary
+ entry = dictionary.get(k);
+ } else if (k == dictSize) {
+ // Special case for sequences like "ababab"
+ entry = w + w.charAt(0);
+ } else {
+ throw new IllegalArgumentException("Bad compressed k: " + k);
+ }
+
+ result.append(entry);
+
+ // Add new sequence to the dictionary
+ dictionary.put(dictSize++, w + entry.charAt(0));
+
+ w = entry;
+ }
+ return result.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/compression/MoveToFront.java b/src/main/java/com/thealgorithms/compression/MoveToFront.java
new file mode 100644
index 000000000000..fa8976df8262
--- /dev/null
+++ b/src/main/java/com/thealgorithms/compression/MoveToFront.java
@@ -0,0 +1,164 @@
+package com.thealgorithms.compression;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Implementation of the Move-to-Front (MTF) transform and its inverse.
+ *
+ * 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:
+ *
+ * - Maintain a list of symbols (the alphabet), initially in a fixed order
+ * - For each input symbol:
+ *
+ * - Output its current index in the list
+ * - Move that symbol to the front of the list
+ *
+ *
+ *
+ * This means frequently occurring symbols quickly move to the front and are encoded
+ * with small indices (often 0), while rare symbols remain near the back.
+ *
+ *
+ * Time Complexity:
+ *
+ * - Forward transform: O(n × m) where n is input length and m is alphabet size
+ * - Inverse transform: O(n × m)
+ *
+ * Note: Using {@link LinkedList} for O(1) insertions and O(m) search operations.
+ *
+ *
+ * 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 transform(String text, String initialAlphabet) {
+ if (text == null || text.isEmpty()) {
+ return new ArrayList<>();
+ }
+ if (initialAlphabet == null || initialAlphabet.isEmpty()) {
+ throw new IllegalArgumentException("Alphabet cannot be null or empty when text is not empty.");
+ }
+
+ List output = new ArrayList<>(text.length());
+
+ // Use LinkedList for O(1) add-to-front and O(n) remove operations
+ // This is more efficient than ArrayList for the move-to-front pattern
+ List alphabet = initialAlphabet.chars().mapToObj(c -> (char) c).collect(Collectors.toCollection(LinkedList::new));
+
+ for (char c : text.toCharArray()) {
+ int index = alphabet.indexOf(c);
+ if (index == -1) {
+ throw new IllegalArgumentException("Symbol '" + c + "' not found in the initial alphabet.");
+ }
+
+ output.add(index);
+
+ // Move the character to the front
+ Character symbol = alphabet.remove(index);
+ alphabet.addFirst(symbol);
+ }
+ return output;
+ }
+
+ /**
+ * Performs the inverse Move-to-Front transform.
+ *
+ * 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(Collection indices, String initialAlphabet) {
+ if (indices == null || indices.isEmpty() || initialAlphabet == null || initialAlphabet.isEmpty()) {
+ return "";
+ }
+
+ StringBuilder output = new StringBuilder(indices.size());
+
+ // Use LinkedList for O(1) add-to-front and O(n) remove operations
+ List alphabet = initialAlphabet.chars().mapToObj(c -> (char) c).collect(Collectors.toCollection(LinkedList::new));
+
+ for (int index : indices) {
+ if (index < 0 || index >= alphabet.size()) {
+ throw new IllegalArgumentException("Index " + index + " is out of bounds for the current alphabet of size " + alphabet.size() + ".");
+ }
+
+ // Get the symbol at the index
+ char symbol = alphabet.get(index);
+ output.append(symbol);
+
+ // Move the symbol to the front (mirroring the forward transform)
+ alphabet.remove(index);
+ alphabet.addFirst(symbol);
+ }
+ return output.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/compression/RunLengthEncoding.java b/src/main/java/com/thealgorithms/compression/RunLengthEncoding.java
new file mode 100644
index 000000000000..8d065f4648df
--- /dev/null
+++ b/src/main/java/com/thealgorithms/compression/RunLengthEncoding.java
@@ -0,0 +1,87 @@
+package com.thealgorithms.compression;
+
+/**
+ * An implementation of the Run-Length Encoding (RLE) algorithm.
+ *
+ * Run-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:
+ *
+ * - Compressing "AAAABBBCCDAA" results in "4A3B2C1D2A".
+ * - Decompressing "4A3B2C1D2A" results in "AAAABBBCCDAA".
+ *
+ *
+ * Time Complexity: O(n) for both compression and decompression, where n is the
+ * length of the input string.
+ *
+ *
References:
+ *
+ */
+public final class RunLengthEncoding {
+
+ /**
+ * Private constructor to prevent instantiation of this utility class.
+ */
+ private RunLengthEncoding() {
+ }
+
+ /**
+ * Compresses a string using the Run-Length Encoding algorithm.
+ *
+ * @param text The string to be compressed. Must not be null.
+ * @return The compressed string. Returns an empty string if the input is empty.
+ */
+ public static String compress(String text) {
+ if (text == null || text.isEmpty()) {
+ return "";
+ }
+
+ StringBuilder compressed = new StringBuilder();
+ int count = 1;
+
+ for (int i = 0; i < text.length(); i++) {
+ // Check if it's the last character or if the next character is different
+ if (i == text.length() - 1 || text.charAt(i) != text.charAt(i + 1)) {
+ compressed.append(count);
+ compressed.append(text.charAt(i));
+ count = 1; // Reset count for the new character
+ } else {
+ count++;
+ }
+ }
+ return compressed.toString();
+ }
+
+ /**
+ * Decompresses a string that was compressed using the Run-Length Encoding algorithm.
+ *
+ * @param compressedText The compressed string. Must not be null.
+ * @return The original, uncompressed string.
+ */
+ public static String decompress(String compressedText) {
+ if (compressedText == null || compressedText.isEmpty()) {
+ return "";
+ }
+
+ StringBuilder decompressed = new StringBuilder();
+ int count = 0;
+
+ for (char ch : compressedText.toCharArray()) {
+ if (Character.isDigit(ch)) {
+ // Build the number for runs of 10 or more (e.g., "12A")
+ count = count * 10 + ch - '0';
+ } else {
+ // Append the character 'count' times
+ decompressed.append(String.valueOf(ch).repeat(Math.max(0, count)));
+ count = 0; // Reset count for the next sequence
+ }
+ }
+ return decompressed.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/compression/ShannonFano.java b/src/main/java/com/thealgorithms/compression/ShannonFano.java
new file mode 100644
index 000000000000..aa5d7ad91b2f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/compression/ShannonFano.java
@@ -0,0 +1,159 @@
+package com.thealgorithms.compression;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * An implementation of the Shannon-Fano algorithm for generating prefix codes.
+ *
+ * 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:
+ *
+ * - Count the frequency of each symbol in the input data.
+ * - Sort the symbols in descending order of their frequencies.
+ * - Recursively divide the list of symbols into two parts with sums of
+ * frequencies as close as possible to each other.
+ * - Assign a '0' bit to the codes in the first part and a '1' bit to the codes
+ * in the second part.
+ * - Repeat the process for each part until a part contains only one symbol.
+ *
+ *
+ * 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 Comparable {
+ final char character;
+ final int frequency;
+ String code = "";
+
+ Symbol(char character, int frequency) {
+ this.character = character;
+ this.frequency = frequency;
+ }
+
+ @Override
+ public int compareTo(Symbol other) {
+ return Integer.compare(other.frequency, this.frequency); // Sort descending
+ }
+ }
+
+ /**
+ * Generates Shannon-Fano codes for the symbols in a given text.
+ *
+ * @param text The input string for which to generate codes. Must not be null.
+ * @return A map where keys are characters and values are their corresponding Shannon-Fano codes.
+ */
+ public static Map generateCodes(String text) {
+ if (text == null || text.isEmpty()) {
+ return Collections.emptyMap();
+ }
+
+ Map frequencyMap = new HashMap<>();
+ for (char c : text.toCharArray()) {
+ frequencyMap.put(c, frequencyMap.getOrDefault(c, 0) + 1);
+ }
+
+ List symbols = new ArrayList<>();
+ for (Map.Entry entry : frequencyMap.entrySet()) {
+ symbols.add(new Symbol(entry.getKey(), entry.getValue()));
+ }
+
+ Collections.sort(symbols);
+
+ // Special case: only one unique symbol
+ if (symbols.size() == 1) {
+ symbols.getFirst().code = "0";
+ } else {
+ buildCodeTree(symbols, 0, symbols.size() - 1, "");
+ }
+
+ return symbols.stream().collect(Collectors.toMap(s -> s.character, s -> s.code));
+ }
+
+ /**
+ * Recursively builds the Shannon-Fano code tree by partitioning the list of symbols.
+ * Uses index-based approach to avoid sublist creation issues.
+ *
+ * @param symbols The sorted list of symbols to be processed.
+ * @param start The start index of the current partition.
+ * @param end The end index of the current partition (inclusive).
+ * @param prefix The current prefix code being built for the symbols in this partition.
+ */
+ private static void buildCodeTree(List symbols, int start, int end, String prefix) {
+ // The initial check in generateCodes ensures start <= end is always true here.
+ // The base case is when a partition has only one symbol.
+ if (start == end) {
+ symbols.get(start).code = prefix;
+ return;
+ }
+
+ // Find the optimal split point
+ int splitIndex = findSplitIndex(symbols, start, end);
+
+ // Recursively process left and right partitions with updated prefixes
+ buildCodeTree(symbols, start, splitIndex, prefix + "0");
+ buildCodeTree(symbols, splitIndex + 1, end, prefix + "1");
+ }
+
+ /**
+ * Finds the index that splits the range into two parts with the most balanced frequency sums.
+ * This method tries every possible split point and returns the index that minimizes the
+ * absolute difference between the two partition sums.
+ *
+ * @param symbols The sorted list of symbols.
+ * @param start The start index of the range.
+ * @param end The end index of the range (inclusive).
+ * @return The index of the last element in the first partition.
+ */
+ private static int findSplitIndex(List symbols, int start, int end) {
+ // Calculate total frequency for the entire range
+ long totalFrequency = 0;
+ for (int i = start; i <= end; i++) {
+ totalFrequency += symbols.get(i).frequency;
+ }
+
+ long leftSum = 0;
+ long minDifference = Long.MAX_VALUE;
+ int splitIndex = start;
+
+ // Try every possible split point and find the one with minimum difference
+ for (int i = start; i < end; i++) {
+ leftSum += symbols.get(i).frequency;
+ long rightSum = totalFrequency - leftSum;
+ long difference = Math.abs(leftSum - rightSum);
+
+ if (difference < minDifference) {
+ minDifference = difference;
+ splitIndex = i;
+ }
+ }
+ return splitIndex;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/conversions/AffineConverter.java b/src/main/java/com/thealgorithms/conversions/AffineConverter.java
new file mode 100644
index 000000000000..199a6dd517d5
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/AffineConverter.java
@@ -0,0 +1,64 @@
+package com.thealgorithms.conversions;
+
+/**
+ * A utility class to perform affine transformations of the form:
+ * y = slope * x + intercept.
+ *
+ * This class supports inversion and composition of affine transformations.
+ * It is immutable, meaning each instance represents a fixed transformation.
+ */
+public final class AffineConverter {
+ private final double slope;
+ private final double intercept;
+
+ /**
+ * Constructs an AffineConverter with the given slope and intercept.
+ *
+ * @param inSlope The slope of the affine transformation.
+ * @param inIntercept The intercept (constant term) of the affine transformation.
+ * @throws IllegalArgumentException if either parameter is NaN.
+ */
+ public AffineConverter(final double inSlope, final double inIntercept) {
+ if (Double.isNaN(inSlope) || Double.isNaN(inIntercept)) {
+ throw new IllegalArgumentException("Slope and intercept must be valid numbers.");
+ }
+ slope = inSlope;
+ intercept = inIntercept;
+ }
+
+ /**
+ * Converts the given input value using the affine transformation:
+ * result = slope * inValue + intercept.
+ *
+ * @param inValue The input value to convert.
+ * @return The transformed value.
+ */
+ public double convert(final double inValue) {
+ return slope * inValue + intercept;
+ }
+
+ /**
+ * Returns a new AffineConverter representing the inverse of the current transformation.
+ * The inverse of y = slope * x + intercept is x = (y - intercept) / slope.
+ *
+ * @return A new AffineConverter representing the inverse transformation.
+ * @throws AssertionError if the slope is zero, as the inverse would be undefined.
+ */
+ public AffineConverter invert() {
+ assert slope != 0.0 : "Slope cannot be zero for inversion.";
+ return new AffineConverter(1.0 / slope, -intercept / slope);
+ }
+
+ /**
+ * Composes this affine transformation with another, returning a new AffineConverter.
+ * If this transformation is f(x) and the other is g(x), the result is f(g(x)).
+ *
+ * @param other Another AffineConverter to compose with.
+ * @return A new AffineConverter representing the composition of the two transformations.
+ */
+ public AffineConverter compose(final AffineConverter other) {
+ double newSlope = slope * other.slope;
+ double newIntercept = slope * other.intercept + intercept;
+ return new AffineConverter(newSlope, newIntercept);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java b/src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java
index 5c0722e0d4c3..7a9448fd8fe7 100644
--- a/src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java
+++ b/src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java
@@ -13,7 +13,9 @@
* @author Michael Rolland
* @version 2017.10.10
*/
-public class AnyBaseToAnyBase {
+public final class AnyBaseToAnyBase {
+ private AnyBaseToAnyBase() {
+ }
/**
* Smallest and largest base you want to accept as valid input
@@ -25,13 +27,13 @@ public class AnyBaseToAnyBase {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String n;
- int b1, b2;
+ int b1;
+ int b2;
while (true) {
try {
System.out.print("Enter number: ");
n = in.next();
- System.out.print(
- "Enter beginning base (between " + MINIMUM_BASE + " and " + MAXIMUM_BASE + "): ");
+ System.out.print("Enter beginning base (between " + MINIMUM_BASE + " and " + MAXIMUM_BASE + "): ");
b1 = in.nextInt();
if (b1 > MAXIMUM_BASE || b1 < MINIMUM_BASE) {
System.out.println("Invalid base!");
@@ -41,8 +43,7 @@ public static void main(String[] args) {
System.out.println("The number is invalid for this base!");
continue;
}
- System.out.print(
- "Enter end base (between " + MINIMUM_BASE + " and " + MAXIMUM_BASE + "): ");
+ System.out.print("Enter end base (between " + MINIMUM_BASE + " and " + MAXIMUM_BASE + "): ");
b2 = in.nextInt();
if (b2 > MAXIMUM_BASE || b2 < MINIMUM_BASE) {
System.out.println("Invalid base!");
@@ -63,8 +64,42 @@ public static void main(String[] args) {
*/
public static boolean validForBase(String n, int base) {
char[] validDigits = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
- 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
+ '0',
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ 'A',
+ 'B',
+ 'C',
+ 'D',
+ 'E',
+ 'F',
+ 'G',
+ 'H',
+ 'I',
+ 'J',
+ 'K',
+ 'L',
+ 'M',
+ 'N',
+ 'O',
+ 'P',
+ 'Q',
+ 'R',
+ 'S',
+ 'T',
+ 'U',
+ 'V',
+ 'W',
+ 'X',
+ 'Y',
+ 'Z',
};
// digitsForBase contains all the valid digits for the base given
char[] digitsForBase = Arrays.copyOfRange(validDigits, 0, base);
@@ -98,9 +133,10 @@ public static String base2base(String n, int b1, int b2) {
// Declare variables: decimal value of n,
// character of base b1, character of base b2,
// and the string that will be returned.
- int decimalValue = 0, charB2;
+ int decimalValue = 0;
+ int charB2;
char charB1;
- String output = "";
+ StringBuilder output = new StringBuilder();
// Go through every character of n
for (int i = 0; i < n.length(); i++) {
// store the character in charB1
@@ -131,15 +167,15 @@ public static String base2base(String n, int b1, int b2) {
// If the remainder is a digit < 10, simply add it to
// the left side of the new number.
if (decimalValue % b2 < 10) {
- output = Integer.toString(decimalValue % b2) + output;
+ output.insert(0, decimalValue % b2);
} // If the remainder is >= 10, add a character with the
// corresponding value to the new number. (A = 10, B = 11, C = 12, ...)
else {
- output = (char) ((decimalValue % b2) + 55) + output;
+ output.insert(0, (char) ((decimalValue % b2) + 55));
}
// Divide by the new base again
decimalValue /= b2;
}
- return output;
+ return output.toString();
}
}
diff --git a/src/main/java/com/thealgorithms/conversions/AnyBaseToDecimal.java b/src/main/java/com/thealgorithms/conversions/AnyBaseToDecimal.java
index 837b35305c80..cdab98c7c28a 100644
--- a/src/main/java/com/thealgorithms/conversions/AnyBaseToDecimal.java
+++ b/src/main/java/com/thealgorithms/conversions/AnyBaseToDecimal.java
@@ -1,54 +1,52 @@
package com.thealgorithms.conversions;
/**
- * @author Varun Upadhyay (https://github.com/varunu28)
+ * @author Varun Upadhyay (...)
*/
-// Driver program
-public class AnyBaseToDecimal {
+public final class AnyBaseToDecimal {
+ private static final int CHAR_OFFSET_FOR_DIGIT = '0';
+ private static final int CHAR_OFFSET_FOR_UPPERCASE = 'A' - 10;
- public static void main(String[] args) {
- assert convertToDecimal("1010", 2) == Integer.valueOf("1010", 2);
- assert convertToDecimal("777", 8) == Integer.valueOf("777", 8);
- assert convertToDecimal("999", 10) == Integer.valueOf("999", 10);
- assert convertToDecimal("ABCDEF", 16) == Integer.valueOf("ABCDEF", 16);
- assert convertToDecimal("XYZ", 36) == Integer.valueOf("XYZ", 36);
+ private AnyBaseToDecimal() {
}
/**
- * Convert any radix to decimal number
+ * Convert any radix to a decimal number.
*
- * @param s the string to be convert
- * @param radix the radix
- * @return decimal of bits
- * @throws NumberFormatException if {@code bits} or {@code radix} is invalid
+ * @param input the string to be converted
+ * @param radix the radix (base) of the input string
+ * @return the decimal equivalent of the input string
+ * @throws NumberFormatException if the input string or radix is invalid
*/
- public static int convertToDecimal(String s, int radix) {
- int num = 0;
- int pow = 1;
+ public static int convertToDecimal(String input, int radix) {
+ int result = 0;
+ int power = 1;
- for (int i = s.length() - 1; i >= 0; i--) {
- int digit = valOfChar(s.charAt(i));
+ for (int i = input.length() - 1; i >= 0; i--) {
+ int digit = valOfChar(input.charAt(i));
if (digit >= radix) {
- throw new NumberFormatException("For input string " + s);
+ throw new NumberFormatException("For input string: " + input);
}
- num += valOfChar(s.charAt(i)) * pow;
- pow *= radix;
+ result += digit * power;
+ power *= radix;
}
- return num;
+ return result;
}
/**
- * Convert character to integer
+ * Convert a character to its integer value.
*
- * @param c the character
- * @return represented digit of given character
- * @throws NumberFormatException if {@code ch} is not UpperCase or Digit
- * character.
+ * @param character the character to be converted
+ * @return the integer value represented by the character
+ * @throws NumberFormatException if the character is not an uppercase letter or a digit
*/
- public static int valOfChar(char c) {
- if (!(Character.isUpperCase(c) || Character.isDigit(c))) {
- throw new NumberFormatException("invalid character :" + c);
+ private static int valOfChar(char character) {
+ if (Character.isDigit(character)) {
+ return character - CHAR_OFFSET_FOR_DIGIT;
+ } else if (Character.isUpperCase(character)) {
+ return character - CHAR_OFFSET_FOR_UPPERCASE;
+ } else {
+ throw new NumberFormatException("invalid character:" + character);
}
- return Character.isDigit(c) ? c - '0' : c - 'A' + 10;
}
}
diff --git a/src/main/java/com/thealgorithms/conversions/AnytoAny.java b/src/main/java/com/thealgorithms/conversions/AnytoAny.java
index 3eed1fce0fa6..e7bdbc2b79c4 100644
--- a/src/main/java/com/thealgorithms/conversions/AnytoAny.java
+++ b/src/main/java/com/thealgorithms/conversions/AnytoAny.java
@@ -1,30 +1,68 @@
package com.thealgorithms.conversions;
-import java.util.Scanner;
-// given a source number , source base, destination base, this code can give you the destination
-// number.
-// sn ,sb,db ---> ()dn . this is what we have to do .
+/**
+ * A utility class for converting numbers from any base to any other base.
+ *
+ * This class provides a method to convert a source number from a given base
+ * to a destination number in another base. Valid bases range from 2 to 10.
+ */
+public final class AnytoAny {
+ private AnytoAny() {
+ }
+
+ /**
+ * Converts a number from a source base to a destination base.
+ *
+ * @param sourceNumber The number in the source base (as an integer).
+ * @param sourceBase The base of the source number (between 2 and 10).
+ * @param destBase The base to which the number should be converted (between 2 and 10).
+ * @throws IllegalArgumentException if the bases are not between 2 and 10.
+ * @return The converted number in the destination base (as an integer).
+ */
+ public static int convertBase(int sourceNumber, int sourceBase, int destBase) {
+ if (sourceBase < 2 || sourceBase > 10 || destBase < 2 || destBase > 10) {
+ throw new IllegalArgumentException("Bases must be between 2 and 10.");
+ }
+
+ int decimalValue = toDecimal(sourceNumber, sourceBase);
+ return fromDecimal(decimalValue, destBase);
+ }
-public class AnytoAny {
+ /**
+ * Converts a number from a given base to its decimal representation (base 10).
+ *
+ * @param number The number in the original base.
+ * @param base The base of the given number.
+ * @return The decimal representation of the number.
+ */
+ private static int toDecimal(int number, int base) {
+ int decimalValue = 0;
+ int multiplier = 1;
- public static void main(String[] args) {
- Scanner scn = new Scanner(System.in);
- int sn = scn.nextInt();
- int sb = scn.nextInt();
- int db = scn.nextInt();
- int m = 1, dec = 0, dn = 0;
- while (sn != 0) {
- dec = dec + (sn % 10) * m;
- m *= sb;
- sn /= 10;
+ while (number != 0) {
+ decimalValue += (number % 10) * multiplier;
+ multiplier *= base;
+ number /= 10;
}
- m = 1;
- while (dec != 0) {
- dn = dn + (dec % db) * m;
- m *= 10;
- dec /= db;
+ return decimalValue;
+ }
+
+ /**
+ * Converts a decimal (base 10) number to a specified base.
+ *
+ * @param decimal The decimal number to convert.
+ * @param base The destination base for conversion.
+ * @return The number in the specified base.
+ */
+ private static int fromDecimal(int decimal, int base) {
+ int result = 0;
+ int multiplier = 1;
+
+ while (decimal != 0) {
+ result += (decimal % base) * multiplier;
+ multiplier *= 10;
+ decimal /= base;
}
- System.out.println(dn);
- scn.close();
+ return result;
}
}
diff --git a/src/main/java/com/thealgorithms/conversions/Base64.java b/src/main/java/com/thealgorithms/conversions/Base64.java
new file mode 100644
index 000000000000..5219c4ba7f4e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/Base64.java
@@ -0,0 +1,196 @@
+package com.thealgorithms.conversions;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base64 is a group of binary-to-text encoding schemes that represent binary data
+ * in an ASCII string format by translating it into a radix-64 representation.
+ * Each base64 digit represents exactly 6 bits of data.
+ *
+ * Base64 encoding is commonly used when there is a need to encode binary data
+ * that needs to be stored and transferred over media that are designed to deal
+ * with textual data.
+ *
+ * Wikipedia Reference: https://en.wikipedia.org/wiki/Base64
+ * Author: Nithin U.
+ * Github: https://github.com/NithinU2802
+ */
+
+public final class Base64 {
+
+ // Base64 character set
+ private static final String BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ private static final char PADDING_CHAR = '=';
+
+ private Base64() {
+ }
+
+ /**
+ * Encodes the given byte array to a Base64 encoded string.
+ *
+ * @param input the byte array to encode
+ * @return the Base64 encoded string
+ * @throws IllegalArgumentException if input is null
+ */
+ public static String encode(byte[] input) {
+ if (input == null) {
+ throw new IllegalArgumentException("Input cannot be null");
+ }
+
+ if (input.length == 0) {
+ return "";
+ }
+
+ StringBuilder result = new StringBuilder();
+ int padding = 0;
+
+ // Process input in groups of 3 bytes
+ for (int i = 0; i < input.length; i += 3) {
+ // Get up to 3 bytes
+ int byte1 = input[i] & 0xFF;
+ int byte2 = (i + 1 < input.length) ? (input[i + 1] & 0xFF) : 0;
+ int byte3 = (i + 2 < input.length) ? (input[i + 2] & 0xFF) : 0;
+
+ // Calculate padding needed
+ if (i + 1 >= input.length) {
+ padding = 2;
+ } else if (i + 2 >= input.length) {
+ padding = 1;
+ }
+
+ // Combine 3 bytes into a 24-bit number
+ int combined = (byte1 << 16) | (byte2 << 8) | byte3;
+
+ // Extract four 6-bit groups
+ result.append(BASE64_CHARS.charAt((combined >> 18) & 0x3F));
+ result.append(BASE64_CHARS.charAt((combined >> 12) & 0x3F));
+ result.append(BASE64_CHARS.charAt((combined >> 6) & 0x3F));
+ result.append(BASE64_CHARS.charAt(combined & 0x3F));
+ }
+
+ // Replace padding characters
+ if (padding > 0) {
+ result.setLength(result.length() - padding);
+ for (int i = 0; i < padding; i++) {
+ result.append(PADDING_CHAR);
+ }
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * Encodes the given string to a Base64 encoded string using UTF-8 encoding.
+ *
+ * @param input the string to encode
+ * @return the Base64 encoded string
+ * @throws IllegalArgumentException if input is null
+ */
+ public static String encode(String input) {
+ if (input == null) {
+ throw new IllegalArgumentException("Input cannot be null");
+ }
+
+ return encode(input.getBytes(StandardCharsets.UTF_8));
+ }
+
+ /**
+ * Decodes the given Base64 encoded string to a byte array.
+ *
+ * @param input the Base64 encoded string to decode
+ * @return the decoded byte array
+ * @throws IllegalArgumentException if input is null or contains invalid Base64 characters
+ */
+ public static byte[] decode(String input) {
+ if (input == null) {
+ throw new IllegalArgumentException("Input cannot be null");
+ }
+
+ if (input.isEmpty()) {
+ return new byte[0];
+ }
+
+ // Strict RFC 4648 compliance: length must be a multiple of 4
+ if (input.length() % 4 != 0) {
+ throw new IllegalArgumentException("Invalid Base64 input length; must be multiple of 4");
+ }
+
+ // Validate padding: '=' can only appear at the end (last 1 or 2 chars)
+ int firstPadding = input.indexOf('=');
+ if (firstPadding != -1 && firstPadding < input.length() - 2) {
+ throw new IllegalArgumentException("Padding '=' can only appear at the end (last 1 or 2 characters)");
+ }
+
+ List result = new ArrayList<>();
+
+ // Process input in groups of 4 characters
+ for (int i = 0; i < input.length(); i += 4) {
+ // Get up to 4 characters
+ int char1 = getBase64Value(input.charAt(i));
+ int char2 = getBase64Value(input.charAt(i + 1));
+ int char3 = input.charAt(i + 2) == '=' ? 0 : getBase64Value(input.charAt(i + 2));
+ int char4 = input.charAt(i + 3) == '=' ? 0 : getBase64Value(input.charAt(i + 3));
+
+ // Combine four 6-bit groups into a 24-bit number
+ int combined = (char1 << 18) | (char2 << 12) | (char3 << 6) | char4;
+
+ // Extract three 8-bit bytes
+ result.add((byte) ((combined >> 16) & 0xFF));
+ if (input.charAt(i + 2) != '=') {
+ result.add((byte) ((combined >> 8) & 0xFF));
+ }
+ if (input.charAt(i + 3) != '=') {
+ result.add((byte) (combined & 0xFF));
+ }
+ }
+
+ // Convert List to byte[]
+ byte[] resultArray = new byte[result.size()];
+ for (int i = 0; i < result.size(); i++) {
+ resultArray[i] = result.get(i);
+ }
+
+ return resultArray;
+ }
+
+ /**
+ * Decodes the given Base64 encoded string to a string using UTF-8 encoding.
+ *
+ * @param input the Base64 encoded string to decode
+ * @return the decoded string
+ * @throws IllegalArgumentException if input is null or contains invalid Base64 characters
+ */
+ public static String decodeToString(String input) {
+ if (input == null) {
+ throw new IllegalArgumentException("Input cannot be null");
+ }
+
+ byte[] decodedBytes = decode(input);
+ return new String(decodedBytes, StandardCharsets.UTF_8);
+ }
+
+ /**
+ * Gets the numeric value of a Base64 character.
+ *
+ * @param c the Base64 character
+ * @return the numeric value (0-63)
+ * @throws IllegalArgumentException if character is not a valid Base64 character
+ */
+ private static int getBase64Value(char c) {
+ if (c >= 'A' && c <= 'Z') {
+ return c - 'A';
+ } else if (c >= 'a' && c <= 'z') {
+ return c - 'a' + 26;
+ } else if (c >= '0' && c <= '9') {
+ return c - '0' + 52;
+ } else if (c == '+') {
+ return 62;
+ } else if (c == '/') {
+ return 63;
+ } else {
+ throw new IllegalArgumentException("Invalid Base64 character: " + c);
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/conversions/BinaryToDecimal.java b/src/main/java/com/thealgorithms/conversions/BinaryToDecimal.java
index 95de43c54ae8..b3783ab284b2 100644
--- a/src/main/java/com/thealgorithms/conversions/BinaryToDecimal.java
+++ b/src/main/java/com/thealgorithms/conversions/BinaryToDecimal.java
@@ -1,29 +1,59 @@
package com.thealgorithms.conversions;
-import java.util.Scanner;
-
/**
* This class converts a Binary number to a Decimal number
*/
-class BinaryToDecimal {
+final class BinaryToDecimal {
+ private static final int BINARY_BASE = 2;
+
+ private BinaryToDecimal() {
+ }
+
+ /**
+ * Converts a binary number to its decimal equivalent.
+ *
+ * @param binaryNumber The binary number to convert.
+ * @return The decimal equivalent of the binary number.
+ * @throws IllegalArgumentException If the binary number contains digits other than 0 and 1.
+ */
+ public static long binaryToDecimal(long binaryNumber) {
+ long decimalValue = 0;
+ long power = 0;
+
+ while (binaryNumber != 0) {
+ long digit = binaryNumber % 10;
+ if (digit > 1) {
+ throw new IllegalArgumentException("Incorrect binary digit: " + digit);
+ }
+ decimalValue += (long) (digit * Math.pow(BINARY_BASE, power++));
+ binaryNumber /= 10;
+ }
+ return decimalValue;
+ }
/**
- * Main Method
+ * Converts a binary String to its decimal equivalent using bitwise operators.
*
- * @param args Command line arguments
+ * @param binary The binary number to convert.
+ * @return The decimal equivalent of the binary number.
+ * @throws IllegalArgumentException If the binary number contains digits other than 0 and 1.
*/
- public static void main(String args[]) {
- Scanner sc = new Scanner(System.in);
- int binNum, binCopy, d, s = 0, power = 0;
- System.out.print("Binary number: ");
- binNum = sc.nextInt();
- binCopy = binNum;
- while (binCopy != 0) {
- d = binCopy % 10;
- s += d * (int) Math.pow(2, power++);
- binCopy /= 10;
+ public static long binaryStringToDecimal(String binary) {
+ boolean isNegative = binary.charAt(0) == '-';
+ if (isNegative) {
+ binary = binary.substring(1);
}
- System.out.println("Decimal equivalent:" + s);
- sc.close();
+
+ long decimalValue = 0;
+
+ for (char bit : binary.toCharArray()) {
+ if (bit != '0' && bit != '1') {
+ throw new IllegalArgumentException("Incorrect binary digit: " + bit);
+ }
+ // shift left by 1 (multiply by 2) and add bit value
+ decimalValue = (decimalValue << 1) | (bit - '0');
+ }
+
+ return isNegative ? -decimalValue : decimalValue;
}
}
diff --git a/src/main/java/com/thealgorithms/conversions/BinaryToHexadecimal.java b/src/main/java/com/thealgorithms/conversions/BinaryToHexadecimal.java
index c942cbb7d843..9ff2f593fe1f 100644
--- a/src/main/java/com/thealgorithms/conversions/BinaryToHexadecimal.java
+++ b/src/main/java/com/thealgorithms/conversions/BinaryToHexadecimal.java
@@ -1,57 +1,63 @@
package com.thealgorithms.conversions;
-import java.util.*;
+import java.util.HashMap;
+import java.util.Map;
/**
* Converts any Binary Number to a Hexadecimal Number
*
* @author Nishita Aggarwal
*/
-public class BinaryToHexadecimal {
+public final class BinaryToHexadecimal {
+ private static final int BITS_IN_HEX_DIGIT = 4;
+ private static final int BASE_BINARY = 2;
+ private static final int BASE_DECIMAL = 10;
+ private static final int HEX_START_DECIMAL = 10;
+ private static final int HEX_END_DECIMAL = 15;
+
+ private BinaryToHexadecimal() {
+ }
/**
- * This method converts a binary number to a hexadecimal number.
+ * Converts a binary number to a hexadecimal number.
*
- * @param binary The binary number
- * @return The hexadecimal number
+ * @param binary The binary number to convert.
+ * @return The hexadecimal representation of the binary number.
+ * @throws IllegalArgumentException If the binary number contains digits other than 0 and 1.
*/
- static String binToHex(int binary) {
- // hm to store hexadecimal codes for binary numbers within the range: 0000 to 1111 i.e. for
- // decimal numbers 0 to 15
- HashMap hm = new HashMap<>();
- // String to store hexadecimal code
- String hex = "";
- int i;
- for (i = 0; i < 10; i++) {
- hm.put(i, String.valueOf(i));
- }
- for (i = 10; i < 16; i++) {
- hm.put(i, String.valueOf((char) ('A' + i - 10)));
- }
- int currbit;
+ public static String binToHex(int binary) {
+ Map hexMap = initializeHexMap();
+ StringBuilder hex = new StringBuilder();
+
while (binary != 0) {
- int code4 = 0; // to store decimal equivalent of number formed by 4 decimal digits
- for (i = 0; i < 4; i++) {
- currbit = binary % 10;
- binary = binary / 10;
- code4 += currbit * Math.pow(2, i);
+ int decimalValue = 0;
+ for (int i = 0; i < BITS_IN_HEX_DIGIT; i++) {
+ int currentBit = binary % BASE_DECIMAL;
+ if (currentBit > 1) {
+ throw new IllegalArgumentException("Incorrect binary digit: " + currentBit);
+ }
+ binary /= BASE_DECIMAL;
+ decimalValue += (int) (currentBit * Math.pow(BASE_BINARY, i));
}
- hex = hm.get(code4) + hex;
+ hex.insert(0, hexMap.get(decimalValue));
}
- return hex;
+
+ return !hex.isEmpty() ? hex.toString() : "0";
}
/**
- * Main method
+ * Initializes the hexadecimal map with decimal to hexadecimal mappings.
*
- * @param args Command line arguments
+ * @return The initialized map containing mappings from decimal numbers to hexadecimal digits.
*/
- public static void main(String[] args) {
- Scanner sc = new Scanner(System.in);
- System.out.println("Enter binary number:");
- int binary = sc.nextInt();
- String hex = binToHex(binary);
- System.out.println("Hexadecimal Code:" + hex);
- sc.close();
+ private static Map initializeHexMap() {
+ Map hexMap = new HashMap<>();
+ for (int i = 0; i < BASE_DECIMAL; i++) {
+ hexMap.put(i, String.valueOf(i));
+ }
+ for (int i = HEX_START_DECIMAL; i <= HEX_END_DECIMAL; i++) {
+ hexMap.put(i, String.valueOf((char) ('A' + i - HEX_START_DECIMAL)));
+ }
+ return hexMap;
}
}
diff --git a/src/main/java/com/thealgorithms/conversions/BinaryToOctal.java b/src/main/java/com/thealgorithms/conversions/BinaryToOctal.java
index b0d6b32fd63b..5407c8525a23 100644
--- a/src/main/java/com/thealgorithms/conversions/BinaryToOctal.java
+++ b/src/main/java/com/thealgorithms/conversions/BinaryToOctal.java
@@ -1,25 +1,11 @@
package com.thealgorithms.conversions;
-import java.util.Scanner;
+public final class BinaryToOctal {
+ private static final int BITS_PER_OCTAL_DIGIT = 3;
+ private static final int BINARY_BASE = 2;
+ private static final int DECIMAL_BASE = 10;
-/**
- * Converts any Binary number to an Octal Number
- *
- * @author Zachary Jones
- */
-public class BinaryToOctal {
-
- /**
- * Main method
- *
- * @param args Command line arguments
- */
- public static void main(String args[]) {
- Scanner sc = new Scanner(System.in);
- System.out.println("Input the binary number: ");
- int b = sc.nextInt();
- System.out.println("Octal equivalent: " + convertBinaryToOctal(b));
- sc.close();
+ private BinaryToOctal() {
}
/**
@@ -27,21 +13,33 @@ public static void main(String args[]) {
*
* @param binary The binary number
* @return The octal number
+ * @throws IllegalArgumentException if the input is not a valid binary number
*/
public static String convertBinaryToOctal(int binary) {
- String octal = "";
- int currBit = 0, j = 1;
+ if (binary == 0) {
+ return "0";
+ }
+
+ if (!String.valueOf(binary).matches("[01]+")) {
+ throw new IllegalArgumentException("Input is not a valid binary number.");
+ }
+
+ StringBuilder octal = new StringBuilder();
+ int currentBit;
+ int bitValueMultiplier = 1;
+
while (binary != 0) {
- int code3 = 0;
- for (int i = 0; i < 3; i++) {
- currBit = binary % 10;
- binary = binary / 10;
- code3 += currBit * j;
- j *= 2;
+ int octalDigit = 0;
+ for (int i = 0; i < BITS_PER_OCTAL_DIGIT && binary != 0; i++) {
+ currentBit = binary % DECIMAL_BASE;
+ binary /= DECIMAL_BASE;
+ octalDigit += currentBit * bitValueMultiplier;
+ bitValueMultiplier *= BINARY_BASE;
}
- octal = code3 + octal;
- j = 1;
+ octal.insert(0, octalDigit);
+ bitValueMultiplier = 1; // Reset multiplier for the next group
}
- return octal;
+
+ return octal.toString();
}
}
diff --git a/src/main/java/com/thealgorithms/conversions/CoordinateConverter.java b/src/main/java/com/thealgorithms/conversions/CoordinateConverter.java
new file mode 100644
index 000000000000..2766a3a1cf89
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/CoordinateConverter.java
@@ -0,0 +1,57 @@
+package com.thealgorithms.conversions;
+
+/**
+ * A utility class to convert between Cartesian and Polar coordinate systems.
+ *
+ * This class provides methods to perform the following conversions:
+ *
+ * - Cartesian to Polar coordinates
+ * - Polar to Cartesian coordinates
+ *
+ *
+ * The class is final and cannot be instantiated.
+ */
+public final class CoordinateConverter {
+
+ private CoordinateConverter() {
+ // Prevent instantiation
+ }
+
+ /**
+ * Converts Cartesian coordinates to Polar coordinates.
+ *
+ * @param x the x-coordinate in the Cartesian system; must be a finite number
+ * @param y the y-coordinate in the Cartesian system; must be a finite number
+ * @return an array where the first element is the radius (r) and the second element is the angle (theta) in degrees
+ * @throws IllegalArgumentException if x or y is not a finite number
+ */
+ public static double[] cartesianToPolar(double x, double y) {
+ if (!Double.isFinite(x) || !Double.isFinite(y)) {
+ throw new IllegalArgumentException("x and y must be finite numbers.");
+ }
+ double r = Math.sqrt(x * x + y * y);
+ double theta = Math.toDegrees(Math.atan2(y, x));
+ return new double[] {r, theta};
+ }
+
+ /**
+ * Converts Polar coordinates to Cartesian coordinates.
+ *
+ * @param r the radius in the Polar system; must be non-negative
+ * @param thetaDegrees the angle (theta) in degrees in the Polar system; must be a finite number
+ * @return an array where the first element is the x-coordinate and the second element is the y-coordinate in the Cartesian system
+ * @throws IllegalArgumentException if r is negative or thetaDegrees is not a finite number
+ */
+ public static double[] polarToCartesian(double r, double thetaDegrees) {
+ if (r < 0) {
+ throw new IllegalArgumentException("Radius (r) must be non-negative.");
+ }
+ if (!Double.isFinite(thetaDegrees)) {
+ throw new IllegalArgumentException("Theta (angle) must be a finite number.");
+ }
+ double theta = Math.toRadians(thetaDegrees);
+ double x = r * Math.cos(theta);
+ double y = r * Math.sin(theta);
+ return new double[] {x, y};
+ }
+}
diff --git a/src/main/java/com/thealgorithms/conversions/DecimalToAnyBase.java b/src/main/java/com/thealgorithms/conversions/DecimalToAnyBase.java
index 8ef4737b17c3..a5615dc002f5 100644
--- a/src/main/java/com/thealgorithms/conversions/DecimalToAnyBase.java
+++ b/src/main/java/com/thealgorithms/conversions/DecimalToAnyBase.java
@@ -1,67 +1,69 @@
package com.thealgorithms.conversions;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
import java.util.ArrayList;
+import java.util.List;
/**
- * @author Varun Upadhyay (https://github.com/varunu28)
+ * Class that provides methods to convert a decimal number to a string representation
+ * in any specified base between 2 and 36.
+ *
+ * @author Varun Upadhyay (...)
*/
-// Driver Program
-public class DecimalToAnyBase {
+public final class DecimalToAnyBase {
+ private static final int MIN_BASE = 2;
+ private static final int MAX_BASE = 36;
+ private static final char ZERO_CHAR = '0';
+ private static final char A_CHAR = 'A';
+ private static final int DIGIT_OFFSET = 10;
- public static void main(String[] args) throws Exception {
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
- System.out.println("Enter the decimal input below: ");
- int decInput = Integer.parseInt(br.readLine());
- System.out.println();
-
- System.out.println("Enter the base below: ");
- int base = Integer.parseInt(br.readLine());
- System.out.println();
-
- System.out.println("Decimal Input" + " is: " + decInput);
- System.out.println(
- "Value of " + decInput + " in base " + base + " is: " + convertToAnyBase(decInput, base));
-
- br.close();
+ private DecimalToAnyBase() {
}
/**
- * This method produces a String value of any given input decimal in any
- * base
+ * Converts a decimal number to a string representation in the specified base.
+ * For example, converting the decimal number 10 to base 2 would return "1010".
*
- * @param inp Decimal of which we need the value in base in String format
- * @return string format of the converted value in the given base
+ * @param decimal the decimal number to convert
+ * @param base the base to convert to (must be between {@value #MIN_BASE} and {@value #MAX_BASE})
+ * @return the string representation of the number in the specified base
+ * @throws IllegalArgumentException if the base is out of the supported range
*/
- public static String convertToAnyBase(int inp, int base) {
- ArrayList charArr = new ArrayList<>();
+ public static String convertToAnyBase(int decimal, int base) {
+ if (base < MIN_BASE || base > MAX_BASE) {
+ throw new IllegalArgumentException("Base must be between " + MIN_BASE + " and " + MAX_BASE);
+ }
- while (inp > 0) {
- charArr.add(reVal(inp % base));
- inp /= base;
+ if (decimal == 0) {
+ return String.valueOf(ZERO_CHAR);
}
- StringBuilder str = new StringBuilder(charArr.size());
+ List digits = new ArrayList<>();
+ while (decimal > 0) {
+ digits.add(convertToChar(decimal % base));
+ decimal /= base;
+ }
- for (Character ch : charArr) {
- str.append(ch);
+ StringBuilder result = new StringBuilder(digits.size());
+ for (int i = digits.size() - 1; i >= 0; i--) {
+ result.append(digits.get(i));
}
- return str.reverse().toString();
+ return result.toString();
}
/**
- * This method produces character value of the input integer and returns it
+ * Converts an integer value to its corresponding character in the specified base.
+ * This method is used to convert values from 0 to 35 into their appropriate character representation.
+ * For example, 0-9 are represented as '0'-'9', and 10-35 are represented as 'A'-'Z'.
*
- * @param num integer of which we need the character value of
- * @return character value of input integer
+ * @param value the integer value to convert (should be less than the base value)
+ * @return the character representing the value in the specified base
*/
- public static char reVal(int num) {
- if (num >= 0 && num <= 9) {
- return (char) (num + '0');
+ private static char convertToChar(int value) {
+ if (value >= 0 && value <= 9) {
+ return (char) (ZERO_CHAR + value);
} else {
- return (char) (num - 10 + 'A');
+ return (char) (A_CHAR + value - DIGIT_OFFSET);
}
}
}
diff --git a/src/main/java/com/thealgorithms/conversions/DecimalToBinary.java b/src/main/java/com/thealgorithms/conversions/DecimalToBinary.java
index 35cec4079ed6..e8d033e0093c 100644
--- a/src/main/java/com/thealgorithms/conversions/DecimalToBinary.java
+++ b/src/main/java/com/thealgorithms/conversions/DecimalToBinary.java
@@ -1,55 +1,49 @@
package com.thealgorithms.conversions;
-import java.util.Scanner;
-
/**
- * This class converts a Decimal number to a Binary number
+ * This class provides methods to convert a decimal number to a binary number.
*/
-class DecimalToBinary {
+final class DecimalToBinary {
+ private static final int BINARY_BASE = 2;
+ private static final int DECIMAL_MULTIPLIER = 10;
- /**
- * Main Method
- *
- * @param args Command Line Arguments
- */
- public static void main(String args[]) {
- conventionalConversion();
- bitwiseConversion();
+ private DecimalToBinary() {
}
/**
- * This method converts a decimal number to a binary number using a
- * conventional algorithm.
+ * Converts a decimal number to a binary number using a conventional algorithm.
+ * @param decimalNumber the decimal number to convert
+ * @return the binary representation of the decimal number
*/
- public static void conventionalConversion() {
- int n, b = 0, c = 0, d;
- Scanner input = new Scanner(System.in);
- System.out.printf("Conventional conversion.%n Enter the decimal number: ");
- n = input.nextInt();
- while (n != 0) {
- d = n % 2;
- b = b + d * (int) Math.pow(10, c++);
- n /= 2;
- } // converting decimal to binary
- System.out.println("\tBinary number: " + b);
- input.close();
+ public static int convertUsingConventionalAlgorithm(int decimalNumber) {
+ int binaryNumber = 0;
+ int position = 1;
+
+ while (decimalNumber > 0) {
+ int remainder = decimalNumber % BINARY_BASE;
+ binaryNumber += remainder * position;
+ position *= DECIMAL_MULTIPLIER;
+ decimalNumber /= BINARY_BASE;
+ }
+
+ return binaryNumber;
}
/**
- * This method converts a decimal number to a binary number using a bitwise
- * algorithm
+ * Converts a decimal number to a binary number using a bitwise algorithm.
+ * @param decimalNumber the decimal number to convert
+ * @return the binary representation of the decimal number
*/
- public static void bitwiseConversion() {
- int n, b = 0, c = 0, d;
- Scanner input = new Scanner(System.in);
- System.out.printf("Bitwise conversion.%n Enter the decimal number: ");
- n = input.nextInt();
- while (n != 0) {
- d = (n & 1);
- b += d * (int) Math.pow(10, c++);
- n >>= 1;
+ public static int convertUsingBitwiseAlgorithm(int decimalNumber) {
+ int binaryNumber = 0;
+ int position = 1;
+
+ while (decimalNumber > 0) {
+ int leastSignificantBit = decimalNumber & 1;
+ binaryNumber += leastSignificantBit * position;
+ position *= DECIMAL_MULTIPLIER;
+ decimalNumber >>= 1;
}
- System.out.println("\tBinary number: " + b);
- input.close();
+ return binaryNumber;
}
}
diff --git a/src/main/java/com/thealgorithms/conversions/DecimalToHexaDecimal.java b/src/main/java/com/thealgorithms/conversions/DecimalToHexaDecimal.java
deleted file mode 100644
index 83129406cf29..000000000000
--- a/src/main/java/com/thealgorithms/conversions/DecimalToHexaDecimal.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.thealgorithms.conversions;
-
-// hex = [0 - 9] -> [A - F]
-class DecimalToHexaDecimal {
-
- private static final int sizeOfIntInHalfBytes = 8;
- private static final int numberOfBitsInAHalfByte = 4;
- private static final int halfByte = 0x0F;
- private static final char[] hexDigits = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
- };
-
- // Returns the hex value of the dec entered in the parameter.
- public static String decToHex(int dec) {
- StringBuilder hexBuilder = new StringBuilder(sizeOfIntInHalfBytes);
- hexBuilder.setLength(sizeOfIntInHalfBytes);
- for (int i = sizeOfIntInHalfBytes - 1; i >= 0; --i) {
- int j = dec & halfByte;
- hexBuilder.setCharAt(i, hexDigits[j]);
- dec >>= numberOfBitsInAHalfByte;
- }
- return hexBuilder.toString().toLowerCase();
- }
-
- // Test above function.
- public static void main(String[] args) {
- System.out.println("Test...");
- int dec = 305445566;
- String libraryDecToHex = Integer.toHexString(dec);
- String decToHex = decToHex(dec);
- System.out.println("Result from the library : " + libraryDecToHex);
- System.out.println("Result decToHex method : " + decToHex);
- }
-}
diff --git a/src/main/java/com/thealgorithms/conversions/DecimalToHexadecimal.java b/src/main/java/com/thealgorithms/conversions/DecimalToHexadecimal.java
new file mode 100644
index 000000000000..47a1e36b27e3
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/DecimalToHexadecimal.java
@@ -0,0 +1,42 @@
+package com.thealgorithms.conversions;
+
+/**
+ * This class provides a method to convert a decimal number to a hexadecimal string.
+ */
+final class DecimalToHexadecimal {
+ private static final int SIZE_OF_INT_IN_HALF_BYTES = 8;
+ private static final int NUMBER_OF_BITS_IN_HALF_BYTE = 4;
+ private static final int HALF_BYTE_MASK = 0x0F;
+ private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+ private DecimalToHexadecimal() {
+ }
+
+ /**
+ * Converts a decimal number to a hexadecimal string.
+ * @param decimal the decimal number to convert
+ * @return the hexadecimal representation of the decimal number
+ */
+ public static String decToHex(int decimal) {
+ StringBuilder hexBuilder = new StringBuilder(SIZE_OF_INT_IN_HALF_BYTES);
+ for (int i = SIZE_OF_INT_IN_HALF_BYTES - 1; i >= 0; --i) {
+ int currentHalfByte = decimal & HALF_BYTE_MASK;
+ hexBuilder.insert(0, HEX_DIGITS[currentHalfByte]);
+ decimal >>= NUMBER_OF_BITS_IN_HALF_BYTE;
+ }
+ return removeLeadingZeros(hexBuilder.toString().toLowerCase());
+ }
+
+ private static String removeLeadingZeros(String str) {
+ if (str == null || str.isEmpty()) {
+ return str;
+ }
+
+ int i = 0;
+ while (i < str.length() && str.charAt(i) == '0') {
+ i++;
+ }
+
+ return i == str.length() ? "0" : str.substring(i);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/conversions/DecimalToOctal.java b/src/main/java/com/thealgorithms/conversions/DecimalToOctal.java
index 0f72f462c753..75687fc589ae 100644
--- a/src/main/java/com/thealgorithms/conversions/DecimalToOctal.java
+++ b/src/main/java/com/thealgorithms/conversions/DecimalToOctal.java
@@ -1,32 +1,38 @@
package com.thealgorithms.conversions;
-import java.util.Scanner;
-
/**
* This class converts Decimal numbers to Octal Numbers
*/
-public class DecimalToOctal {
+public final class DecimalToOctal {
+ private static final int OCTAL_BASE = 8;
+ private static final int INITIAL_OCTAL_VALUE = 0;
+ private static final int INITIAL_PLACE_VALUE = 1;
+
+ private DecimalToOctal() {
+ }
/**
- * Main Method
+ * Converts a decimal number to its octal equivalent.
*
- * @param args Command line Arguments
+ * @param decimal The decimal number to convert.
+ * @return The octal equivalent as an integer.
+ * @throws IllegalArgumentException if the decimal number is negative.
*/
+ public static int convertToOctal(int decimal) {
+ if (decimal < 0) {
+ throw new IllegalArgumentException("Decimal number cannot be negative.");
+ }
+
+ int octal = INITIAL_OCTAL_VALUE;
+ int placeValue = INITIAL_PLACE_VALUE;
- // enter in a decimal value to get Octal output
- public static void main(String[] args) {
- Scanner sc = new Scanner(System.in);
- int n, k, d, s = 0, c = 0;
- System.out.print("Decimal number: ");
- n = sc.nextInt();
- k = n;
- while (k != 0) {
- d = k % 8;
- s += d * (int) Math.pow(10, c++);
- k /= 8;
+ while (decimal != 0) {
+ int remainder = decimal % OCTAL_BASE;
+ octal += remainder * placeValue;
+ decimal /= OCTAL_BASE;
+ placeValue *= 10;
}
- System.out.println("Octal equivalent:" + s);
- sc.close();
+ return octal;
}
}
diff --git a/src/main/java/com/thealgorithms/conversions/EndianConverter.java b/src/main/java/com/thealgorithms/conversions/EndianConverter.java
new file mode 100644
index 000000000000..0d69098e8255
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/EndianConverter.java
@@ -0,0 +1,47 @@
+package com.thealgorithms.conversions;
+
+/**
+ * Utility class for converting integers between big-endian and little-endian formats.
+ *
+ * Endianness defines how byte sequences represent multi-byte data types:
+ *
+ * - Big-endian: The most significant byte (MSB) comes first.
+ * - Little-endian: The least significant byte (LSB) comes first.
+ *
+ *
+ * Example conversion:
+ *
+ * - Big-endian to little-endian: {@code 0x12345678} → {@code 0x78563412}
+ * - Little-endian to big-endian: {@code 0x78563412} → {@code 0x12345678}
+ *
+ *
+ * Note: Both conversions in this utility are equivalent since reversing the bytes is symmetric.
+ *
+ * This class only supports 32-bit integers.
+ *
+ * @author Hardvan
+ */
+public final class EndianConverter {
+ private EndianConverter() {
+ }
+
+ /**
+ * Converts a 32-bit integer from big-endian to little-endian.
+ *
+ * @param value the integer in big-endian format
+ * @return the integer in little-endian format
+ */
+ public static int bigToLittleEndian(int value) {
+ return Integer.reverseBytes(value);
+ }
+
+ /**
+ * Converts a 32-bit integer from little-endian to big-endian.
+ *
+ * @param value the integer in little-endian format
+ * @return the integer in big-endian format
+ */
+ public static int littleToBigEndian(int value) {
+ return Integer.reverseBytes(value);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/conversions/HexToOct.java b/src/main/java/com/thealgorithms/conversions/HexToOct.java
index 92057c953b60..d3a672d37424 100644
--- a/src/main/java/com/thealgorithms/conversions/HexToOct.java
+++ b/src/main/java/com/thealgorithms/conversions/HexToOct.java
@@ -1,74 +1,62 @@
package com.thealgorithms.conversions;
-import java.util.Scanner;
-
/**
* Converts any Hexadecimal Number to Octal
*
* @author Tanmay Joshi
*/
-public class HexToOct {
+public final class HexToOct {
+ private HexToOct() {
+ }
/**
- * This method converts a Hexadecimal number to a decimal number
+ * Converts a Hexadecimal number to a Decimal number.
*
- * @param s The Hexadecimal Number
- * @return The Decimal number
+ * @param hex The Hexadecimal number as a String.
+ * @return The Decimal equivalent as an integer.
*/
- public static int hex2decimal(String s) {
- String str = "0123456789ABCDEF";
- s = s.toUpperCase();
- int val = 0;
- for (int i = 0; i < s.length(); i++) {
- char a = s.charAt(i);
- int n = str.indexOf(a);
- val = 16 * val + n;
+ public static int hexToDecimal(String hex) {
+ String hexDigits = "0123456789ABCDEF";
+ hex = hex.toUpperCase();
+ int decimalValue = 0;
+
+ for (int i = 0; i < hex.length(); i++) {
+ char hexChar = hex.charAt(i);
+ int digitValue = hexDigits.indexOf(hexChar);
+ decimalValue = 16 * decimalValue + digitValue;
}
- return val;
+
+ return decimalValue;
}
/**
- * This method converts a Decimal number to a octal number
+ * Converts a Decimal number to an Octal number.
*
- * @param q The Decimal Number
- * @return The Octal number
+ * @param decimal The Decimal number as an integer.
+ * @return The Octal equivalent as an integer.
*/
- public static int decimal2octal(int q) {
- int now;
- int i = 1;
- int octnum = 0;
- while (q > 0) {
- now = q % 8;
- octnum = (now * (int) (Math.pow(10, i))) + octnum;
- q /= 8;
- i++;
+ public static int decimalToOctal(int decimal) {
+ int octalValue = 0;
+ int placeValue = 1;
+
+ while (decimal > 0) {
+ int remainder = decimal % 8;
+ octalValue += remainder * placeValue;
+ decimal /= 8;
+ placeValue *= 10;
}
- octnum /= 10;
- return octnum;
+
+ return octalValue;
}
/**
- * Main method that gets the hex input from user and converts it into octal.
+ * Converts a Hexadecimal number to an Octal number.
*
- * @param args arguments
+ * @param hex The Hexadecimal number as a String.
+ * @return The Octal equivalent as an integer.
*/
- public static void main(String args[]) {
- String hexadecnum;
- int decnum, octalnum;
- Scanner scan = new Scanner(System.in);
-
- System.out.print("Enter Hexadecimal Number : ");
- hexadecnum = scan.nextLine();
-
- // first convert hexadecimal to decimal
- decnum
- = hex2decimal(
- hexadecnum); // Pass the string to the hex2decimal function and get the decimal form in
- // variable decnum
-
- // convert decimal to octal
- octalnum = decimal2octal(decnum);
- System.out.println("Number in octal: " + octalnum);
- scan.close();
+ public static int hexToOctal(String hex) {
+ int decimalValue = hexToDecimal(hex);
+ return decimalToOctal(decimalValue);
}
}
diff --git a/src/main/java/com/thealgorithms/conversions/HexaDecimalToBinary.java b/src/main/java/com/thealgorithms/conversions/HexaDecimalToBinary.java
index ef070ae7986a..c0eb9a01ba17 100644
--- a/src/main/java/com/thealgorithms/conversions/HexaDecimalToBinary.java
+++ b/src/main/java/com/thealgorithms/conversions/HexaDecimalToBinary.java
@@ -1,34 +1,62 @@
package com.thealgorithms.conversions;
-// Hex [0-9],[A-F] -> Binary [0,1]
+/**
+ * Utility class for converting hexadecimal numbers to binary representation.
+ *
+ * A hexadecimal number consists of digits from {@code [0-9]} and {@code [A-F]} (case-insensitive),
+ * while binary representation uses only {@code [0, 1]}.
+ *
+ * This class provides methods to:
+ *
+ * - Convert a hexadecimal string to its binary string equivalent.
+ * - Ensure the binary output is padded to 8 bits (1 byte).
+ *
+ *
+ * Example:
+ *
+ * - {@code "A1"} → {@code "10100001"}
+ * - {@code "1"} → {@code "00000001"}
+ *
+ *
+ * This class assumes that the input hexadecimal string is valid.
+ */
public class HexaDecimalToBinary {
- private final int LONG_BITS = 8;
-
- public void convert(String numHex) {
- // String a HexaDecimal:
+ /**
+ * Converts a hexadecimal string to its binary string equivalent.
+ * The binary output is padded to a minimum of 8 bits (1 byte).
+ * Steps:
+ *
+ * - Convert the hexadecimal string to an integer.
+ * - Convert the integer to a binary string.
+ * - Pad the binary string to ensure it is at least 8 bits long.
+ * - Return the padded binary string.
+ *
+ *
+ * @param numHex the hexadecimal string (e.g., "A1", "7F")
+ * @throws NumberFormatException if the input string is not a valid hexadecimal number
+ * @return the binary string representation, padded to 8 bits (e.g., "10100001")
+ */
+ public String convert(String numHex) {
int conHex = Integer.parseInt(numHex, 16);
- // Hex a Binary:
String binary = Integer.toBinaryString(conHex);
- // Output:
- System.out.println(numHex + " = " + completeDigits(binary));
+ return completeDigits(binary);
}
+ /**
+ * Pads the binary string to ensure it is at least 8 bits long.
+ * If the binary string is shorter than 8 bits, it adds leading zeros.
+ *
+ * @param binNum the binary string to pad
+ * @return the padded binary string with a minimum length of 8
+ */
public String completeDigits(String binNum) {
- for (int i = binNum.length(); i < LONG_BITS; i++) {
- binNum = "0" + binNum;
+ final int byteSize = 8;
+ StringBuilder binNumBuilder = new StringBuilder(binNum);
+ while (binNumBuilder.length() < byteSize) {
+ binNumBuilder.insert(0, "0");
}
+ binNum = binNumBuilder.toString();
return binNum;
}
-
- public static void main(String[] args) {
-
- // Testing Numbers:
- String[] hexNums = {"1", "A1", "ef", "BA", "AA", "BB", "19", "01", "02", "03", "04"};
- HexaDecimalToBinary objConvert = new HexaDecimalToBinary();
-
- for (String num : hexNums) {
- objConvert.convert(num);
- }
- }
}
diff --git a/src/main/java/com/thealgorithms/conversions/HexaDecimalToDecimal.java b/src/main/java/com/thealgorithms/conversions/HexaDecimalToDecimal.java
index cb9d7fafde8f..2cf6024d90a3 100644
--- a/src/main/java/com/thealgorithms/conversions/HexaDecimalToDecimal.java
+++ b/src/main/java/com/thealgorithms/conversions/HexaDecimalToDecimal.java
@@ -1,37 +1,45 @@
package com.thealgorithms.conversions;
-import java.util.Scanner;
-
-public class HexaDecimalToDecimal {
+/**
+ * Utility class for converting a hexadecimal string to its decimal representation.
+ *
+ * A hexadecimal number uses the base-16 numeral system, with the following characters:
+ *
+ * - Digits: 0-9
+ * - Letters: A-F (case-insensitive)
+ *
+ * Each character represents a power of 16. For example:
+ *
+ * Hexadecimal "A1" = 10*16^1 + 1*16^0 = 161 (decimal)
+ *
+ *
+ * This class provides a method to perform the conversion without using built-in Java utilities.
+ */
+public final class HexaDecimalToDecimal {
+ private HexaDecimalToDecimal() {
+ }
- // convert hexadecimal to decimal
+ /**
+ * Converts a hexadecimal string to its decimal integer equivalent.
+ * The input string is case-insensitive, and must contain valid hexadecimal characters [0-9, A-F].
+ *
+ * @param hex the hexadecimal string to convert
+ * @return the decimal integer representation of the input hexadecimal string
+ * @throws IllegalArgumentException if the input string contains invalid characters
+ */
public static int getHexaToDec(String hex) {
String digits = "0123456789ABCDEF";
hex = hex.toUpperCase();
int val = 0;
+
for (int i = 0; i < hex.length(); i++) {
int d = digits.indexOf(hex.charAt(i));
+ if (d == -1) {
+ throw new IllegalArgumentException("Invalid hexadecimal character: " + hex.charAt(i));
+ }
val = 16 * val + d;
}
- return val;
- }
-
- // Main method gets the hexadecimal input from user and converts it into Decimal output.
- public static void main(String args[]) {
- String hexa_Input;
- int dec_output;
- Scanner scan = new Scanner(System.in);
- System.out.print("Enter Hexadecimal Number : ");
- hexa_Input = scan.nextLine();
-
- // convert hexadecimal to decimal
- dec_output = getHexaToDec(hexa_Input);
- /*
- Pass the string to the getHexaToDec function
- and it returns the decimal form in the variable dec_output.
- */
- System.out.println("Number in Decimal: " + dec_output);
- scan.close();
+ return val;
}
}
diff --git a/src/main/java/com/thealgorithms/conversions/IPConverter.java b/src/main/java/com/thealgorithms/conversions/IPConverter.java
new file mode 100644
index 000000000000..765cb0201dd5
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/IPConverter.java
@@ -0,0 +1,58 @@
+package com.thealgorithms.conversions;
+
+/**
+ * Converts an IPv4 address to its binary equivalent and vice-versa.
+ * IP to Binary: Converts an IPv4 address to its binary equivalent.
+ * Example: 127.3.4.5 -> 01111111.00000011.00000100.00000101
+ *
+ * Binary to IP: Converts a binary equivalent to an IPv4 address.
+ * Example: 01111111.00000011.00000100.00000101 -> 127.3.4.5
+ *
+ * @author Hardvan
+ */
+public final class IPConverter {
+ private IPConverter() {
+ }
+
+ /**
+ * Converts an IPv4 address to its binary equivalent.
+ * @param ip The IPv4 address to convert.
+ * @return The binary equivalent of the IPv4 address.
+ */
+ public static String ipToBinary(String ip) {
+ StringBuilder binary = new StringBuilder();
+ for (String octet : ip.split("\\.")) {
+ binary.append(octetToBinary(Integer.parseInt(octet))).append(".");
+ }
+ return binary.substring(0, binary.length() - 1);
+ }
+
+ /**
+ * Converts a single octet to its 8-bit binary representation.
+ * @param octet The octet to convert (0-255).
+ * @return The 8-bit binary representation as a String.
+ */
+ private static String octetToBinary(int octet) {
+ char[] binary = {'0', '0', '0', '0', '0', '0', '0', '0'};
+ for (int i = 7; i >= 0; i--) {
+ if ((octet & 1) == 1) {
+ binary[i] = '1';
+ }
+ octet >>>= 1;
+ }
+ return new String(binary);
+ }
+
+ /**
+ * Converts a binary equivalent to an IPv4 address.
+ * @param binary The binary equivalent to convert.
+ * @return The IPv4 address of the binary equivalent.
+ */
+ public static String binaryToIP(String binary) {
+ StringBuilder ip = new StringBuilder();
+ for (String octet : binary.split("\\.")) {
+ ip.append(Integer.parseInt(octet, 2)).append(".");
+ }
+ return ip.substring(0, ip.length() - 1);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/conversions/IPv6Converter.java b/src/main/java/com/thealgorithms/conversions/IPv6Converter.java
new file mode 100644
index 000000000000..d42ffd027514
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/IPv6Converter.java
@@ -0,0 +1,98 @@
+package com.thealgorithms.conversions;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
+/**
+ * A utility class for converting between IPv6 and IPv4 addresses.
+ *
+ * - Converts IPv4 to IPv6-mapped IPv6 address.
+ * - Extracts IPv4 address from IPv6-mapped IPv6.
+ * - Handles exceptions for invalid inputs.
+ *
+ * @author Hardvan
+ */
+public final class IPv6Converter {
+ private IPv6Converter() {
+ }
+
+ /**
+ * Converts an IPv4 address (e.g., "192.0.2.128") to an IPv6-mapped IPv6 address.
+ * Example: IPv4 "192.0.2.128" -> IPv6 "::ffff:192.0.2.128"
+ *
+ * @param ipv4Address The IPv4 address in string format.
+ * @return The corresponding IPv6-mapped IPv6 address.
+ * @throws UnknownHostException If the IPv4 address is invalid.
+ * @throws IllegalArgumentException If the IPv6 address is not a mapped IPv4 address.
+ */
+ public static String ipv4ToIpv6(String ipv4Address) throws UnknownHostException {
+ if (ipv4Address == null || ipv4Address.isEmpty()) {
+ throw new UnknownHostException("IPv4 address is empty.");
+ }
+
+ InetAddress ipv4 = InetAddress.getByName(ipv4Address);
+ byte[] ipv4Bytes = ipv4.getAddress();
+
+ // Create IPv6-mapped IPv6 address (starts with ::ffff:)
+ byte[] ipv6Bytes = new byte[16];
+ ipv6Bytes[10] = (byte) 0xff;
+ ipv6Bytes[11] = (byte) 0xff;
+ System.arraycopy(ipv4Bytes, 0, ipv6Bytes, 12, 4);
+
+ // Manually format to "::ffff:x.x.x.x" format
+ StringBuilder ipv6String = new StringBuilder("::ffff:");
+ for (int i = 12; i < 16; i++) {
+ ipv6String.append(ipv6Bytes[i] & 0xFF);
+ if (i < 15) {
+ ipv6String.append('.');
+ }
+ }
+ return ipv6String.toString();
+ }
+
+ /**
+ * Extracts the IPv4 address from an IPv6-mapped IPv6 address.
+ * Example: IPv6 "::ffff:192.0.2.128" -> IPv4 "192.0.2.128"
+ *
+ * @param ipv6Address The IPv6 address in string format.
+ * @return The extracted IPv4 address.
+ * @throws UnknownHostException If the IPv6 address is invalid or not a mapped IPv4 address.
+ */
+ public static String ipv6ToIpv4(String ipv6Address) throws UnknownHostException {
+ InetAddress ipv6 = InetAddress.getByName(ipv6Address);
+ byte[] ipv6Bytes = ipv6.getAddress();
+
+ // Check if the address is an IPv6-mapped IPv4 address
+ if (isValidIpv6MappedIpv4(ipv6Bytes)) {
+ byte[] ipv4Bytes = Arrays.copyOfRange(ipv6Bytes, 12, 16);
+ InetAddress ipv4 = InetAddress.getByAddress(ipv4Bytes);
+ return ipv4.getHostAddress();
+ } else {
+ throw new IllegalArgumentException("Not a valid IPv6-mapped IPv4 address.");
+ }
+ }
+
+ /**
+ * Helper function to check if the given byte array represents
+ * an IPv6-mapped IPv4 address (prefix 0:0:0:0:0:ffff).
+ *
+ * @param ipv6Bytes Byte array representation of the IPv6 address.
+ * @return True if the address is IPv6-mapped IPv4, otherwise false.
+ */
+ private static boolean isValidIpv6MappedIpv4(byte[] ipv6Bytes) {
+ // IPv6-mapped IPv4 addresses are 16 bytes long, with the first 10 bytes set to 0,
+ // followed by 0xff, 0xff, and the last 4 bytes representing the IPv4 address.
+ if (ipv6Bytes.length != 16) {
+ return false;
+ }
+
+ for (int i = 0; i < 10; i++) {
+ if (ipv6Bytes[i] != 0) {
+ return false;
+ }
+ }
+
+ return ipv6Bytes[10] == (byte) 0xff && ipv6Bytes[11] == (byte) 0xff;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/conversions/IntegerToEnglish.java b/src/main/java/com/thealgorithms/conversions/IntegerToEnglish.java
new file mode 100644
index 000000000000..e85c608af5d0
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/IntegerToEnglish.java
@@ -0,0 +1,108 @@
+package com.thealgorithms.conversions;
+
+import java.util.Map;
+
+/**
+ * A utility class to convert integers to their English word representation.
+ *
+ * The class supports conversion of numbers from 0 to 2,147,483,647
+ * (the maximum value of a 32-bit signed integer). It divides the number
+ * into groups of three digits (thousands, millions, billions, etc.) and
+ * translates each group into words.
+ *
+ * Example Usage
+ *
+ * IntegerToEnglish.integerToEnglishWords(12345);
+ * // Output: "Twelve Thousand Three Hundred Forty Five"
+ *
+ *
+ * This class uses two maps:
+ *
+ * - BASE_NUMBERS_MAP: Holds English words for numbers 0-20, multiples of 10 up to 90, and 100.
+ * - THOUSAND_POWER_MAP: Maps powers of 1000 (e.g., Thousand, Million, Billion).
+ *
+ */
+public final class IntegerToEnglish {
+
+ private static final Map BASE_NUMBERS_MAP = Map.ofEntries(Map.entry(0, ""), Map.entry(1, "One"), Map.entry(2, "Two"), Map.entry(3, "Three"), Map.entry(4, "Four"), Map.entry(5, "Five"), Map.entry(6, "Six"), Map.entry(7, "Seven"), Map.entry(8, "Eight"), Map.entry(9, "Nine"),
+ Map.entry(10, "Ten"), Map.entry(11, "Eleven"), Map.entry(12, "Twelve"), Map.entry(13, "Thirteen"), Map.entry(14, "Fourteen"), Map.entry(15, "Fifteen"), Map.entry(16, "Sixteen"), Map.entry(17, "Seventeen"), Map.entry(18, "Eighteen"), Map.entry(19, "Nineteen"), Map.entry(20, "Twenty"),
+ Map.entry(30, "Thirty"), Map.entry(40, "Forty"), Map.entry(50, "Fifty"), Map.entry(60, "Sixty"), Map.entry(70, "Seventy"), Map.entry(80, "Eighty"), Map.entry(90, "Ninety"), Map.entry(100, "Hundred"));
+
+ private static final Map THOUSAND_POWER_MAP = Map.ofEntries(Map.entry(1, "Thousand"), Map.entry(2, "Million"), Map.entry(3, "Billion"));
+
+ private IntegerToEnglish() {
+ }
+
+ /**
+ * Converts numbers less than 1000 into English words.
+ *
+ * @param number the integer value (0-999) to convert
+ * @return the English word representation of the input number
+ */
+ private static String convertToWords(int number) {
+ int remainder = number % 100;
+ StringBuilder result = new StringBuilder();
+
+ if (remainder <= 20) {
+ result.append(BASE_NUMBERS_MAP.get(remainder));
+ } else if (BASE_NUMBERS_MAP.containsKey(remainder)) {
+ result.append(BASE_NUMBERS_MAP.get(remainder));
+ } else {
+ int tensDigit = remainder / 10;
+ int onesDigit = remainder % 10;
+ String tens = BASE_NUMBERS_MAP.getOrDefault(tensDigit * 10, "");
+ String ones = BASE_NUMBERS_MAP.getOrDefault(onesDigit, "");
+ result.append(tens);
+ if (ones != null && !ones.isEmpty()) {
+ result.append(" ").append(ones);
+ }
+ }
+
+ int hundredsDigit = number / 100;
+ if (hundredsDigit > 0) {
+ if (result.length() > 0) {
+ result.insert(0, " ");
+ }
+ result.insert(0, String.format("%s Hundred", BASE_NUMBERS_MAP.get(hundredsDigit)));
+ }
+
+ return result.toString().trim();
+ }
+
+ /**
+ * Converts a non-negative integer to its English word representation.
+ *
+ * @param number the integer to convert (0-2,147,483,647)
+ * @return the English word representation of the input number
+ */
+ public static String integerToEnglishWords(int number) {
+ if (number == 0) {
+ return "Zero";
+ }
+
+ StringBuilder result = new StringBuilder();
+ int index = 0;
+
+ while (number > 0) {
+ int remainder = number % 1000;
+ number /= 1000;
+
+ if (remainder > 0) {
+ String subResult = convertToWords(remainder);
+ if (!subResult.isEmpty()) {
+ if (index > 0) {
+ subResult += " " + THOUSAND_POWER_MAP.get(index);
+ }
+ if (result.length() > 0) {
+ result.insert(0, " ");
+ }
+ result.insert(0, subResult);
+ }
+ }
+
+ index++;
+ }
+
+ return result.toString().trim();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/conversions/IntegerToRoman.java b/src/main/java/com/thealgorithms/conversions/IntegerToRoman.java
index 53c07d58c4fd..fec437668fe6 100644
--- a/src/main/java/com/thealgorithms/conversions/IntegerToRoman.java
+++ b/src/main/java/com/thealgorithms/conversions/IntegerToRoman.java
@@ -1,40 +1,68 @@
package com.thealgorithms.conversions;
/**
- * Converting Integers into Roman Numerals
+ * A utility class to convert integers into Roman numerals.
*
- *
- * ('I', 1); ('IV',4); ('V', 5); ('IX',9); ('X', 10); ('XL',40); ('L', 50);
- * ('XC',90); ('C', 100); ('D', 500); ('M', 1000);
+ *
Roman numerals follow these rules:
+ *
+ * - I = 1
+ * - IV = 4
+ * - V = 5
+ * - IX = 9
+ * - X = 10
+ * - XL = 40
+ * - L = 50
+ * - XC = 90
+ * - C = 100
+ * - D = 500
+ * - M = 1000
+ *
+ *
+ * Conversion is based on repeatedly subtracting the largest possible Roman numeral value
+ * from the input number until it reaches zero. For example, 1994 is converted as:
+ *
+ * 1994 -> MCMXCIV (1000 + 900 + 90 + 4)
+ *
*/
-public class IntegerToRoman {
+public final class IntegerToRoman {
+
+ // Array of Roman numeral values in descending order
+ private static final int[] ALL_ROMAN_NUMBERS_IN_ARABIC = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
- private static int[] allArabianRomanNumbers
- = new int[]{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
- private static String[] allRomanNumbers
- = new String[]{"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
+ // Corresponding Roman numeral symbols
+ private static final String[] ALL_ROMAN_NUMBERS = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
+
+ private IntegerToRoman() {
+ }
- // Value must be > 0
+ /**
+ * Converts an integer to its Roman numeral representation.
+ * Steps:
+ *
+ * - Iterate over the Roman numeral values in descending order
+ * - Calculate how many times a numeral fits
+ * - Append the corresponding symbol
+ * - Subtract the value from the number
+ * - Repeat until the number is zero
+ * - Return the Roman numeral representation
+ *
+ *
+ * @param num the integer value to convert (must be greater than 0)
+ * @return the Roman numeral representation of the input integer
+ * or an empty string if the input is non-positive
+ */
public static String integerToRoman(int num) {
if (num <= 0) {
return "";
}
StringBuilder builder = new StringBuilder();
-
- for (int a = 0; a < allArabianRomanNumbers.length; a++) {
- int times = num / allArabianRomanNumbers[a];
- for (int b = 0; b < times; b++) {
- builder.append(allRomanNumbers[a]);
- }
-
- num -= times * allArabianRomanNumbers[a];
+ for (int i = 0; i < ALL_ROMAN_NUMBERS_IN_ARABIC.length; i++) {
+ int times = num / ALL_ROMAN_NUMBERS_IN_ARABIC[i];
+ builder.append(ALL_ROMAN_NUMBERS[i].repeat(Math.max(0, times)));
+ num -= times * ALL_ROMAN_NUMBERS_IN_ARABIC[i];
}
return builder.toString();
}
-
- public static void main(String[] args) {
- System.out.println(IntegerToRoman.integerToRoman(2131));
- }
}
diff --git a/src/main/java/com/thealgorithms/conversions/MorseCodeConverter.java b/src/main/java/com/thealgorithms/conversions/MorseCodeConverter.java
new file mode 100644
index 000000000000..a3973da0c586
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/MorseCodeConverter.java
@@ -0,0 +1,98 @@
+package com.thealgorithms.conversions;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Converts text to Morse code and vice-versa.
+ * Text to Morse code: Each letter is separated by a space and each word is separated by a pipe (|).
+ * Example: "HELLO WORLD" -> ".... . .-.. .-.. --- | .-- --- .-. .-.. -.."
+ *
+ * Morse code to text: Each letter is separated by a space and each word is separated by a pipe (|).
+ * Example: ".... . .-.. .-.. --- | .-- --- .-. .-.. -.." -> "HELLO WORLD"
+ *
+ * Applications: Used in radio communications and algorithmic challenges.
+ *
+ * @author Hardvan
+ */
+public final class MorseCodeConverter {
+ private MorseCodeConverter() {
+ }
+
+ private static final Map MORSE_MAP = new HashMap<>();
+ private static final Map REVERSE_MAP = new HashMap<>();
+
+ static {
+ MORSE_MAP.put('A', ".-");
+ MORSE_MAP.put('B', "-...");
+ MORSE_MAP.put('C', "-.-.");
+ MORSE_MAP.put('D', "-..");
+ MORSE_MAP.put('E', ".");
+ MORSE_MAP.put('F', "..-.");
+ MORSE_MAP.put('G', "--.");
+ MORSE_MAP.put('H', "....");
+ MORSE_MAP.put('I', "..");
+ MORSE_MAP.put('J', ".---");
+ MORSE_MAP.put('K', "-.-");
+ MORSE_MAP.put('L', ".-..");
+ MORSE_MAP.put('M', "--");
+ MORSE_MAP.put('N', "-.");
+ MORSE_MAP.put('O', "---");
+ MORSE_MAP.put('P', ".--.");
+ MORSE_MAP.put('Q', "--.-");
+ MORSE_MAP.put('R', ".-.");
+ MORSE_MAP.put('S', "...");
+ MORSE_MAP.put('T', "-");
+ MORSE_MAP.put('U', "..-");
+ MORSE_MAP.put('V', "...-");
+ MORSE_MAP.put('W', ".--");
+ MORSE_MAP.put('X', "-..-");
+ MORSE_MAP.put('Y', "-.--");
+ MORSE_MAP.put('Z', "--..");
+
+ // Build reverse map for decoding
+ MORSE_MAP.forEach((k, v) -> REVERSE_MAP.put(v, k));
+ }
+
+ /**
+ * Converts text to Morse code.
+ * Each letter is separated by a space and each word is separated by a pipe (|).
+ *
+ * @param text The text to convert to Morse code.
+ * @return The Morse code representation of the text.
+ */
+ public static String textToMorse(String text) {
+ StringBuilder morse = new StringBuilder();
+ String[] words = text.toUpperCase().split(" ");
+ for (int i = 0; i < words.length; i++) {
+ for (char c : words[i].toCharArray()) {
+ morse.append(MORSE_MAP.getOrDefault(c, "")).append(" ");
+ }
+ if (i < words.length - 1) {
+ morse.append("| ");
+ }
+ }
+ return morse.toString().trim();
+ }
+
+ /**
+ * Converts Morse code to text.
+ * Each letter is separated by a space and each word is separated by a pipe (|).
+ *
+ * @param morse The Morse code to convert to text.
+ * @return The text representation of the Morse code.
+ */
+ public static String morseToText(String morse) {
+ StringBuilder text = new StringBuilder();
+ String[] words = morse.split(" \\| ");
+ for (int i = 0; i < words.length; i++) {
+ for (String code : words[i].split(" ")) {
+ text.append(REVERSE_MAP.getOrDefault(code, '?'));
+ }
+ if (i < words.length - 1) {
+ text.append(" ");
+ }
+ }
+ return text.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/conversions/NumberToWords.java b/src/main/java/com/thealgorithms/conversions/NumberToWords.java
new file mode 100644
index 000000000000..e39c5b2dea86
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/NumberToWords.java
@@ -0,0 +1,100 @@
+package com.thealgorithms.conversions;
+
+import java.math.BigDecimal;
+
+/**
+ A Java-based utility for converting numeric values into their English word
+ representations. Whether you need to convert a small number, a large number
+ with millions and billions, or even a number with decimal places, this utility
+ has you covered.
+ *
+ */
+public final class NumberToWords {
+
+ private NumberToWords() {
+ }
+
+ private static final String[] UNITS = {"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"};
+
+ private static final String[] TENS = {"", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"};
+
+ private static final String[] POWERS = {"", "Thousand", "Million", "Billion", "Trillion"};
+
+ private static final String ZERO = "Zero";
+ private static final String POINT = " Point";
+ private static final String NEGATIVE = "Negative ";
+
+ public static String convert(BigDecimal number) {
+ if (number == null) {
+ return "Invalid Input";
+ }
+
+ // Check for negative sign
+ boolean isNegative = number.signum() < 0;
+
+ // Split the number into whole and fractional parts
+ BigDecimal[] parts = number.abs().divideAndRemainder(BigDecimal.ONE);
+ BigDecimal wholePart = parts[0]; // Keep whole part as BigDecimal
+ String fractionalPartStr = parts[1].compareTo(BigDecimal.ZERO) > 0 ? parts[1].toPlainString().substring(2) : ""; // Get fractional part only if it exists
+
+ // Convert whole part to words
+ StringBuilder result = new StringBuilder();
+ if (isNegative) {
+ result.append(NEGATIVE);
+ }
+ result.append(convertWholeNumberToWords(wholePart));
+
+ // Convert fractional part to words
+ if (!fractionalPartStr.isEmpty()) {
+ result.append(POINT);
+ for (char digit : fractionalPartStr.toCharArray()) {
+ int digitValue = Character.getNumericValue(digit);
+ result.append(" ").append(digitValue == 0 ? ZERO : UNITS[digitValue]);
+ }
+ }
+
+ return result.toString().trim();
+ }
+
+ private static String convertWholeNumberToWords(BigDecimal number) {
+ if (number.compareTo(BigDecimal.ZERO) == 0) {
+ return ZERO;
+ }
+
+ StringBuilder words = new StringBuilder();
+ int power = 0;
+
+ while (number.compareTo(BigDecimal.ZERO) > 0) {
+ // Get the last three digits
+ BigDecimal[] divisionResult = number.divideAndRemainder(BigDecimal.valueOf(1000));
+ int chunk = divisionResult[1].intValue();
+
+ if (chunk > 0) {
+ String chunkWords = convertChunk(chunk);
+ if (power > 0) {
+ words.insert(0, POWERS[power] + " ");
+ }
+ words.insert(0, chunkWords + " ");
+ }
+
+ number = divisionResult[0]; // Continue with the remaining part
+ power++;
+ }
+
+ return words.toString().trim();
+ }
+
+ private static String convertChunk(int number) {
+ String chunkWords;
+
+ if (number < 20) {
+ chunkWords = UNITS[number];
+ } else if (number < 100) {
+ chunkWords = TENS[number / 10] + (number % 10 > 0 ? " " + UNITS[number % 10] : "");
+ } else {
+ chunkWords = UNITS[number / 100] + " Hundred" + (number % 100 > 0 ? " " + convertChunk(number % 100) : "");
+ }
+
+ return chunkWords;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/conversions/OctalToBinary.java b/src/main/java/com/thealgorithms/conversions/OctalToBinary.java
new file mode 100644
index 000000000000..a66db97633b4
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/OctalToBinary.java
@@ -0,0 +1,82 @@
+package com.thealgorithms.conversions;
+
+/**
+ * A utility class to convert an octal (base-8) number into its binary (base-2) representation.
+ *
+ * This class provides methods to:
+ *
+ * - Convert an octal number to its binary equivalent
+ * - Convert individual octal digits to binary
+ *
+ *
+ * Octal to Binary Conversion:
+ * An octal number is converted to binary by converting each octal digit to its 3-bit binary equivalent.
+ * The result is a long representing the full binary equivalent of the octal number.
+ *
+ * Example Usage
+ *
+ * long binary = OctalToBinary.convertOctalToBinary(52); // Output: 101010 (52 in octal is 101010 in binary)
+ *
+ *
+ * @author Bama Charan Chhandogi
+ * @see Octal Number System
+ * @see Binary Number System
+ */
+public final class OctalToBinary {
+ private OctalToBinary() {
+ }
+
+ /**
+ * Converts an octal number to its binary representation.
+ *
+ * Each octal digit is individually converted to its 3-bit binary equivalent, and the binary
+ * digits are concatenated to form the final binary number.
+ *
+ * @param octalNumber the octal number to convert (non-negative integer)
+ * @return the binary equivalent as a long
+ */
+ public static long convertOctalToBinary(int octalNumber) {
+ long binaryNumber = 0;
+ int digitPosition = 1;
+
+ while (octalNumber != 0) {
+ int octalDigit = octalNumber % 10;
+ long binaryDigit = convertOctalDigitToBinary(octalDigit);
+
+ binaryNumber += binaryDigit * digitPosition;
+
+ octalNumber /= 10;
+ digitPosition *= 1000;
+ }
+
+ return binaryNumber;
+ }
+
+ /**
+ * Converts a single octal digit (0-7) to its binary equivalent.
+ *
+ * For example:
+ *
+ * - Octal digit 7 is converted to binary 111
+ * - Octal digit 3 is converted to binary 011
+ *
+ *
+ *
+ * @param octalDigit a single octal digit (0-7)
+ * @return the binary equivalent as a long
+ */
+ public static long convertOctalDigitToBinary(int octalDigit) {
+ long binaryDigit = 0;
+ int binaryMultiplier = 1;
+
+ while (octalDigit != 0) {
+ int octalDigitRemainder = octalDigit % 2;
+ binaryDigit += octalDigitRemainder * binaryMultiplier;
+
+ octalDigit /= 2;
+ binaryMultiplier *= 10;
+ }
+
+ return binaryDigit;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/conversions/OctalToDecimal.java b/src/main/java/com/thealgorithms/conversions/OctalToDecimal.java
index 978adee4b7db..d91ce6eb3634 100644
--- a/src/main/java/com/thealgorithms/conversions/OctalToDecimal.java
+++ b/src/main/java/com/thealgorithms/conversions/OctalToDecimal.java
@@ -1,47 +1,42 @@
package com.thealgorithms.conversions;
-import java.util.Scanner;
-
/**
- * Converts any Octal Number to a Decimal Number
+ * Class for converting an octal number to a decimal number. Octal numbers are based on 8, using digits from 0 to 7.
*
- * @author Zachary Jones
*/
-public class OctalToDecimal {
+public final class OctalToDecimal {
+ private static final int OCTAL_BASE = 8;
- /**
- * Main method
- *
- * @param args Command line arguments
- */
- public static void main(String args[]) {
- Scanner sc = new Scanner(System.in);
- System.out.print("Octal Input: ");
- String inputOctal = sc.nextLine();
- int result = convertOctalToDecimal(inputOctal);
- if (result != -1) {
- System.out.println("Result convertOctalToDecimal : " + result);
- }
- sc.close();
+ private OctalToDecimal() {
}
/**
- * This method converts an octal number to a decimal number.
+ * Converts a given octal number (as a string) to its decimal representation.
+ * If the input is not a valid octal number (i.e., contains characters other than 0-7),
+ * the method throws an IllegalArgumentException.
*
- * @param inputOctal The octal number
- * @return The decimal number
+ * @param inputOctal The octal number as a string
+ * @return The decimal equivalent of the octal number
+ * @throws IllegalArgumentException if the input is not a valid octal number
*/
public static int convertOctalToDecimal(String inputOctal) {
+ if (inputOctal == null || inputOctal.isEmpty()) {
+ throw new IllegalArgumentException("Input cannot be null or empty");
+ }
+
+ int decimalValue = 0;
+
+ for (int i = 0; i < inputOctal.length(); i++) {
+ char currentChar = inputOctal.charAt(i);
- try {
- // Actual conversion of Octal to Decimal:
- Integer outputDecimal = Integer.parseInt(inputOctal, 8);
- return outputDecimal;
- } catch (NumberFormatException ne) {
- // Printing a warning message if the input is not a valid octal
- // number:
- System.out.println("Invalid Input, Expecting octal number 0-7");
- return -1;
+ if (currentChar < '0' || currentChar > '7') {
+ throw new IllegalArgumentException("Incorrect input: Expecting an octal number (digits 0-7)");
+ }
+
+ int currentDigit = currentChar - '0';
+ decimalValue = decimalValue * OCTAL_BASE + currentDigit;
}
+
+ return decimalValue;
}
}
diff --git a/src/main/java/com/thealgorithms/conversions/OctalToHexadecimal.java b/src/main/java/com/thealgorithms/conversions/OctalToHexadecimal.java
index f757ef4e9aca..bac56dc2e221 100644
--- a/src/main/java/com/thealgorithms/conversions/OctalToHexadecimal.java
+++ b/src/main/java/com/thealgorithms/conversions/OctalToHexadecimal.java
@@ -1,64 +1,61 @@
package com.thealgorithms.conversions;
-import java.util.Scanner;
-
/**
- * Converts any Octal Number to HexaDecimal
+ * Class for converting an Octal number to its Hexadecimal equivalent.
*
* @author Tanmay Joshi
*/
-public class OctalToHexadecimal {
+public final class OctalToHexadecimal {
+ private static final int OCTAL_BASE = 8;
+ private static final int HEX_BASE = 16;
+ private static final String HEX_DIGITS = "0123456789ABCDEF";
+
+ private OctalToHexadecimal() {
+ }
/**
- * This method converts a Octal number to a decimal number
+ * Converts an Octal number (as a string) to its Decimal equivalent.
*
- * @param s The Octal Number
- * @return The Decimal number
+ * @param octalNumber The Octal number as a string
+ * @return The Decimal equivalent of the Octal number
+ * @throws IllegalArgumentException if the input contains invalid octal digits
*/
- public static int octToDec(String s) {
- int i = 0;
- for (int j = 0; j < s.length(); j++) {
- char num = s.charAt(j);
- num -= '0';
- i *= 8;
- i += num;
+ public static int octalToDecimal(String octalNumber) {
+ if (octalNumber == null || octalNumber.isEmpty()) {
+ throw new IllegalArgumentException("Input cannot be null or empty");
}
- return i;
+
+ int decimalValue = 0;
+ for (int i = 0; i < octalNumber.length(); i++) {
+ char currentChar = octalNumber.charAt(i);
+ if (currentChar < '0' || currentChar > '7') {
+ throw new IllegalArgumentException("Incorrect octal digit: " + currentChar);
+ }
+ int currentDigit = currentChar - '0';
+ decimalValue = decimalValue * OCTAL_BASE + currentDigit;
+ }
+
+ return decimalValue;
}
/**
- * This method converts a Decimal number to a Hexadecimal number
+ * Converts a Decimal number to its Hexadecimal equivalent.
*
- * @param d The Decimal Number
- * @return The Hexadecimal number
+ * @param decimalNumber The Decimal number
+ * @return The Hexadecimal equivalent of the Decimal number
*/
- public static String decimalToHex(int d) {
- String digits = "0123456789ABCDEF";
- if (d <= 0) {
+ public static String decimalToHexadecimal(int decimalNumber) {
+ if (decimalNumber == 0) {
return "0";
}
- String hex = "";
- while (d > 0) {
- int digit = d % 16;
- hex = digits.charAt(digit) + hex;
- d = d / 16;
- }
- return hex;
- }
-
- public static void main(String args[]) {
- Scanner input = new Scanner(System.in);
- System.out.print("Enter the Octal number: ");
- // Take octal number as input from user in a string
- String oct = input.next();
-
- // Pass the octal number to function and get converted decimal form
- int decimal = octToDec(oct);
+ StringBuilder hexValue = new StringBuilder();
+ while (decimalNumber > 0) {
+ int digit = decimalNumber % HEX_BASE;
+ hexValue.insert(0, HEX_DIGITS.charAt(digit));
+ decimalNumber /= HEX_BASE;
+ }
- // Pass the decimal number to function and get converted Hex form of the number
- String hex = decimalToHex(decimal);
- System.out.println("The Hexadecimal equivalant is: " + hex);
- input.close();
+ return hexValue.toString();
}
}
diff --git a/src/main/java/com/thealgorithms/conversions/PhoneticAlphabetConverter.java b/src/main/java/com/thealgorithms/conversions/PhoneticAlphabetConverter.java
new file mode 100644
index 000000000000..730ce2214e2d
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/PhoneticAlphabetConverter.java
@@ -0,0 +1,84 @@
+package com.thealgorithms.conversions;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Converts text to the NATO phonetic alphabet.
+ * Examples:
+ * "ABC" -> "Alpha Bravo Charlie"
+ * "Hello" -> "Hotel Echo Lima Lima Oscar"
+ * "123" -> "One Two Three"
+ * "A1B2C3" -> "Alpha One Bravo Two Charlie Three"
+ *
+ * @author Hardvan
+ */
+public final class PhoneticAlphabetConverter {
+ private PhoneticAlphabetConverter() {
+ }
+
+ private static final Map PHONETIC_MAP = new HashMap<>();
+
+ static {
+ PHONETIC_MAP.put('A', "Alpha");
+ PHONETIC_MAP.put('B', "Bravo");
+ PHONETIC_MAP.put('C', "Charlie");
+ PHONETIC_MAP.put('D', "Delta");
+ PHONETIC_MAP.put('E', "Echo");
+ PHONETIC_MAP.put('F', "Foxtrot");
+ PHONETIC_MAP.put('G', "Golf");
+ PHONETIC_MAP.put('H', "Hotel");
+ PHONETIC_MAP.put('I', "India");
+ PHONETIC_MAP.put('J', "Juliett");
+ PHONETIC_MAP.put('K', "Kilo");
+ PHONETIC_MAP.put('L', "Lima");
+ PHONETIC_MAP.put('M', "Mike");
+ PHONETIC_MAP.put('N', "November");
+ PHONETIC_MAP.put('O', "Oscar");
+ PHONETIC_MAP.put('P', "Papa");
+ PHONETIC_MAP.put('Q', "Quebec");
+ PHONETIC_MAP.put('R', "Romeo");
+ PHONETIC_MAP.put('S', "Sierra");
+ PHONETIC_MAP.put('T', "Tango");
+ PHONETIC_MAP.put('U', "Uniform");
+ PHONETIC_MAP.put('V', "Victor");
+ PHONETIC_MAP.put('W', "Whiskey");
+ PHONETIC_MAP.put('X', "X-ray");
+ PHONETIC_MAP.put('Y', "Yankee");
+ PHONETIC_MAP.put('Z', "Zulu");
+ PHONETIC_MAP.put('0', "Zero");
+ PHONETIC_MAP.put('1', "One");
+ PHONETIC_MAP.put('2', "Two");
+ PHONETIC_MAP.put('3', "Three");
+ PHONETIC_MAP.put('4', "Four");
+ PHONETIC_MAP.put('5', "Five");
+ PHONETIC_MAP.put('6', "Six");
+ PHONETIC_MAP.put('7', "Seven");
+ PHONETIC_MAP.put('8', "Eight");
+ PHONETIC_MAP.put('9', "Nine");
+ }
+
+ /**
+ * Converts text to the NATO phonetic alphabet.
+ * Steps:
+ * 1. Convert the text to uppercase.
+ * 2. Iterate over each character in the text.
+ * 3. Get the phonetic equivalent of the character from the map.
+ * 4. Append the phonetic equivalent to the result.
+ * 5. Append a space to separate the phonetic equivalents.
+ * 6. Return the result.
+ *
+ * @param text the text to convert
+ * @return the NATO phonetic alphabet
+ */
+ public static String textToPhonetic(String text) {
+ StringBuilder phonetic = new StringBuilder();
+ for (char c : text.toUpperCase().toCharArray()) {
+ if (Character.isWhitespace(c)) {
+ continue;
+ }
+ phonetic.append(PHONETIC_MAP.getOrDefault(c, String.valueOf(c))).append(" ");
+ }
+ return phonetic.toString().trim();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/conversions/RgbHsvConversion.java b/src/main/java/com/thealgorithms/conversions/RgbHsvConversion.java
index 81e28919d368..84cbff09db6b 100644
--- a/src/main/java/com/thealgorithms/conversions/RgbHsvConversion.java
+++ b/src/main/java/com/thealgorithms/conversions/RgbHsvConversion.java
@@ -10,39 +10,41 @@
* models how colors appear under light. In it, colors are represented using
* three components: hue, saturation and (brightness-)value. This class provides
* methods for converting colors from one representation to the other.
- * (description adapted from https://en.wikipedia.org/wiki/RGB_color_model and
- * https://en.wikipedia.org/wiki/HSL_and_HSV).
+ * (description adapted from [1] and
+ * [2]).
*/
-public class RgbHsvConversion {
+public final class RgbHsvConversion {
+ private RgbHsvConversion() {
+ }
public static void main(String[] args) {
// Expected RGB-values taken from https://www.rapidtables.com/convert/color/hsv-to-rgb.html
// Test hsvToRgb-method
- assert Arrays.equals(hsvToRgb(0, 0, 0), new int[]{0, 0, 0});
- assert Arrays.equals(hsvToRgb(0, 0, 1), new int[]{255, 255, 255});
- assert Arrays.equals(hsvToRgb(0, 1, 1), new int[]{255, 0, 0});
- assert Arrays.equals(hsvToRgb(60, 1, 1), new int[]{255, 255, 0});
- assert Arrays.equals(hsvToRgb(120, 1, 1), new int[]{0, 255, 0});
- assert Arrays.equals(hsvToRgb(240, 1, 1), new int[]{0, 0, 255});
- assert Arrays.equals(hsvToRgb(300, 1, 1), new int[]{255, 0, 255});
- assert Arrays.equals(hsvToRgb(180, 0.5, 0.5), new int[]{64, 128, 128});
- assert Arrays.equals(hsvToRgb(234, 0.14, 0.88), new int[]{193, 196, 224});
- assert Arrays.equals(hsvToRgb(330, 0.75, 0.5), new int[]{128, 32, 80});
+ assert Arrays.equals(hsvToRgb(0, 0, 0), new int[] {0, 0, 0});
+ assert Arrays.equals(hsvToRgb(0, 0, 1), new int[] {255, 255, 255});
+ assert Arrays.equals(hsvToRgb(0, 1, 1), new int[] {255, 0, 0});
+ assert Arrays.equals(hsvToRgb(60, 1, 1), new int[] {255, 255, 0});
+ assert Arrays.equals(hsvToRgb(120, 1, 1), new int[] {0, 255, 0});
+ assert Arrays.equals(hsvToRgb(240, 1, 1), new int[] {0, 0, 255});
+ assert Arrays.equals(hsvToRgb(300, 1, 1), new int[] {255, 0, 255});
+ assert Arrays.equals(hsvToRgb(180, 0.5, 0.5), new int[] {64, 128, 128});
+ assert Arrays.equals(hsvToRgb(234, 0.14, 0.88), new int[] {193, 196, 224});
+ assert Arrays.equals(hsvToRgb(330, 0.75, 0.5), new int[] {128, 32, 80});
// Test rgbToHsv-method
// approximate-assertions needed because of small deviations due to converting between
// int-values and double-values.
- assert approximatelyEqualHsv(rgbToHsv(0, 0, 0), new double[]{0, 0, 0});
- assert approximatelyEqualHsv(rgbToHsv(255, 255, 255), new double[]{0, 0, 1});
- assert approximatelyEqualHsv(rgbToHsv(255, 0, 0), new double[]{0, 1, 1});
- assert approximatelyEqualHsv(rgbToHsv(255, 255, 0), new double[]{60, 1, 1});
- assert approximatelyEqualHsv(rgbToHsv(0, 255, 0), new double[]{120, 1, 1});
- assert approximatelyEqualHsv(rgbToHsv(0, 0, 255), new double[]{240, 1, 1});
- assert approximatelyEqualHsv(rgbToHsv(255, 0, 255), new double[]{300, 1, 1});
- assert approximatelyEqualHsv(rgbToHsv(64, 128, 128), new double[]{180, 0.5, 0.5});
- assert approximatelyEqualHsv(rgbToHsv(193, 196, 224), new double[]{234, 0.14, 0.88});
- assert approximatelyEqualHsv(rgbToHsv(128, 32, 80), new double[]{330, 0.75, 0.5});
+ assert approximatelyEqualHsv(rgbToHsv(0, 0, 0), new double[] {0, 0, 0});
+ assert approximatelyEqualHsv(rgbToHsv(255, 255, 255), new double[] {0, 0, 1});
+ assert approximatelyEqualHsv(rgbToHsv(255, 0, 0), new double[] {0, 1, 1});
+ assert approximatelyEqualHsv(rgbToHsv(255, 255, 0), new double[] {60, 1, 1});
+ assert approximatelyEqualHsv(rgbToHsv(0, 255, 0), new double[] {120, 1, 1});
+ assert approximatelyEqualHsv(rgbToHsv(0, 0, 255), new double[] {240, 1, 1});
+ assert approximatelyEqualHsv(rgbToHsv(255, 0, 255), new double[] {300, 1, 1});
+ assert approximatelyEqualHsv(rgbToHsv(64, 128, 128), new double[] {180, 0.5, 0.5});
+ assert approximatelyEqualHsv(rgbToHsv(193, 196, 224), new double[] {234, 0.14, 0.88});
+ assert approximatelyEqualHsv(rgbToHsv(128, 32, 80), new double[] {330, 0.75, 0.5});
}
/**
@@ -115,7 +117,7 @@ public static double[] rgbToHsv(int red, int green, int blue) {
hue = (hue + 360) % 360;
- return new double[]{hue, saturation, value};
+ return new double[] {hue, saturation, value};
}
private static boolean approximatelyEqualHsv(double[] hsv1, double[] hsv2) {
@@ -126,8 +128,7 @@ private static boolean approximatelyEqualHsv(double[] hsv1, double[] hsv2) {
return bHue && bSaturation && bValue;
}
- private static int[] getRgbBySection(
- double hueSection, double chroma, double matchValue, double secondLargestComponent) {
+ private static int[] getRgbBySection(double hueSection, double chroma, double matchValue, double secondLargestComponent) {
int red;
int green;
int blue;
@@ -158,7 +159,7 @@ private static int[] getRgbBySection(
blue = convertToInt(secondLargestComponent + matchValue);
}
- return new int[]{red, green, blue};
+ return new int[] {red, green, blue};
}
private static int convertToInt(double input) {
diff --git a/src/main/java/com/thealgorithms/conversions/RomanToInteger.java b/src/main/java/com/thealgorithms/conversions/RomanToInteger.java
index 77b35b257891..a634c720326f 100644
--- a/src/main/java/com/thealgorithms/conversions/RomanToInteger.java
+++ b/src/main/java/com/thealgorithms/conversions/RomanToInteger.java
@@ -1,15 +1,31 @@
package com.thealgorithms.conversions;
-import java.util.*;
+import java.util.HashMap;
+import java.util.Map;
-public class RomanToInteger {
-
- private static Map map
- = new HashMap() {
- /**
- * */
- private static final long serialVersionUID = 87605733047260530L;
+/**
+ * A utility class to convert Roman numerals into integers.
+ *
+ * Roman numerals are based on seven symbols given below:
+ *
+ * - I = 1
+ * - V = 5
+ * - X = 10
+ * - L = 50
+ * - C = 100
+ * - D = 500
+ * - M = 1000
+ *
+ *
+ * If a smaller numeral appears before a larger numeral, it is subtracted.
+ * Otherwise, it is added. For example:
+ *
+ * MCMXCIV = 1000 + (1000 - 100) + (100 - 10) + (5 - 1) = 1994
+ *
+ */
+public final class RomanToInteger {
+ private static final Map ROMAN_TO_INT = new HashMap<>() {
{
put('I', 1);
put('V', 5);
@@ -20,48 +36,56 @@ public class RomanToInteger {
put('M', 1000);
}
};
- // Roman Number = Roman Numerals
+
+ private RomanToInteger() {
+ }
/**
- * This function convert Roman number into Integer
+ * Converts a single Roman numeral character to its integer value.
*
- * @param A Roman number string
- * @return integer
+ * @param symbol the Roman numeral character
+ * @return the corresponding integer value
+ * @throws IllegalArgumentException if the symbol is not a valid Roman numeral
*/
- public static int romanToInt(String A) {
+ private static int romanSymbolToInt(final char symbol) {
+ return ROMAN_TO_INT.computeIfAbsent(symbol, c -> { throw new IllegalArgumentException("Unknown Roman symbol: " + c); });
+ }
- A = A.toUpperCase();
- char prev = ' ';
+ /**
+ * Converts a Roman numeral string to its integer equivalent.
+ * Steps:
+ *
+ * - Iterate over the string from right to left.
+ * - For each character, convert it to an integer value.
+ * - If the current value is greater than or equal to the max previous value, add it.
+ * - Otherwise, subtract it from the sum.
+ * - Update the max previous value.
+ * - Return the sum.
+ *
+ *
+ * @param roman the Roman numeral string
+ * @return the integer value of the Roman numeral
+ * @throws IllegalArgumentException if the input contains invalid Roman characters
+ * @throws NullPointerException if the input is {@code null}
+ */
+ public static int romanToInt(String roman) {
+ if (roman == null) {
+ throw new NullPointerException("Input cannot be null");
+ }
+ roman = roman.toUpperCase();
int sum = 0;
-
- int newPrev = 0;
- for (int i = A.length() - 1; i >= 0; i--) {
- char c = A.charAt(i);
-
- if (prev != ' ') {
- // checking current Number greater then previous or not
- newPrev = map.get(prev) > newPrev ? map.get(prev) : newPrev;
- }
-
- int currentNum = map.get(c);
-
- // if current number greater then prev max previous then add
- if (currentNum >= newPrev) {
- sum += currentNum;
+ int maxPrevValue = 0;
+ for (int i = roman.length() - 1; i >= 0; i--) {
+ int currentValue = romanSymbolToInt(roman.charAt(i));
+ if (currentValue >= maxPrevValue) {
+ sum += currentValue;
+ maxPrevValue = currentValue;
} else {
- // subtract upcoming number until upcoming number not greater then prev max
- sum -= currentNum;
+ sum -= currentValue;
}
-
- prev = c;
}
return sum;
}
-
- public static void main(String[] args) {
- int sum = romanToInt("MDCCCIV");
- System.out.println(sum);
- }
}
diff --git a/src/main/java/com/thealgorithms/conversions/TimeConverter.java b/src/main/java/com/thealgorithms/conversions/TimeConverter.java
new file mode 100644
index 000000000000..41cae37d7ad1
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/TimeConverter.java
@@ -0,0 +1,97 @@
+package com.thealgorithms.conversions;
+
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * A utility class to convert between different units of time.
+ *
+ * This class supports conversions between the following units:
+ *
+ * - seconds
+ * - minutes
+ * - hours
+ * - days
+ * - weeks
+ * - months (approximated as 30.44 days)
+ * - years (approximated as 365.25 days)
+ *
+ *
+ * The conversion is based on predefined constants in seconds.
+ * Results are rounded to three decimal places for consistency.
+ *
+ *
This class is final and cannot be instantiated.
+ *
+ * @see Wikipedia: Unit of time
+ */
+public final class TimeConverter {
+
+ private TimeConverter() {
+ // Prevent instantiation
+ }
+
+ /**
+ * Supported time units with their equivalent in seconds.
+ */
+ private enum TimeUnit {
+ SECONDS(1.0),
+ MINUTES(60.0),
+ HOURS(3600.0),
+ DAYS(86400.0),
+ WEEKS(604800.0),
+ MONTHS(2629800.0), // 30.44 days
+ YEARS(31557600.0); // 365.25 days
+
+ private final double seconds;
+
+ TimeUnit(double seconds) {
+ this.seconds = seconds;
+ }
+
+ public double toSeconds(double value) {
+ return value * seconds;
+ }
+
+ public double fromSeconds(double secondsValue) {
+ return secondsValue / seconds;
+ }
+ }
+
+ private static final Map UNIT_LOOKUP
+ = Map.ofEntries(Map.entry("seconds", TimeUnit.SECONDS), Map.entry("minutes", TimeUnit.MINUTES), Map.entry("hours", TimeUnit.HOURS), Map.entry("days", TimeUnit.DAYS), Map.entry("weeks", TimeUnit.WEEKS), Map.entry("months", TimeUnit.MONTHS), Map.entry("years", TimeUnit.YEARS));
+
+ /**
+ * Converts a time value from one unit to another.
+ *
+ * @param timeValue the numeric value of time to convert; must be non-negative
+ * @param unitFrom the unit of the input value (e.g., "minutes", "hours")
+ * @param unitTo the unit to convert into (e.g., "seconds", "days")
+ * @return the converted value in the target unit, rounded to three decimals
+ * @throws IllegalArgumentException if {@code timeValue} is negative
+ * @throws IllegalArgumentException if either {@code unitFrom} or {@code unitTo} is not supported
+ */
+ public static double convertTime(double timeValue, String unitFrom, String unitTo) {
+ if (timeValue < 0) {
+ throw new IllegalArgumentException("timeValue must be a non-negative number.");
+ }
+
+ TimeUnit from = resolveUnit(unitFrom);
+ TimeUnit to = resolveUnit(unitTo);
+
+ double secondsValue = from.toSeconds(timeValue);
+ double converted = to.fromSeconds(secondsValue);
+
+ return Math.round(converted * 1000.0) / 1000.0;
+ }
+
+ private static TimeUnit resolveUnit(String unit) {
+ if (unit == null) {
+ throw new IllegalArgumentException("Unit cannot be null.");
+ }
+ TimeUnit resolved = UNIT_LOOKUP.get(unit.toLowerCase(Locale.ROOT));
+ if (resolved == null) {
+ throw new IllegalArgumentException("Invalid unit '" + unit + "'. Supported units are: " + UNIT_LOOKUP.keySet());
+ }
+ return resolved;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java b/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java
index 0929496a1fe6..30030de6c1bd 100644
--- a/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java
+++ b/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java
@@ -1,41 +1,55 @@
package com.thealgorithms.conversions;
-import java.util.Scanner;
-
/**
* Converts turkish character to latin character
*
* @author Özgün Gökşenli
*/
-public class TurkishToLatinConversion {
-
- /**
- * Main method
- *
- * @param args Command line arguments
- */
- public static void main(String args[]) {
- Scanner sc = new Scanner(System.in);
- System.out.println("Input the string: ");
- String b = sc.next();
- System.out.println("Converted: " + convertTurkishToLatin(b));
- sc.close();
+public final class TurkishToLatinConversion {
+ private TurkishToLatinConversion() {
}
/**
* This method converts a turkish character to latin character.
+ * Steps:
+ * 1. Define turkish characters and their corresponding latin characters
+ * 2. Replace all turkish characters with their corresponding latin characters
+ * 3. Return the converted string
*
* @param param String paramter
* @return String
*/
public static String convertTurkishToLatin(String param) {
- char[] turkishChars
- = new char[]{0x131, 0x130, 0xFC, 0xDC, 0xF6, 0xD6, 0x15F, 0x15E, 0xE7, 0xC7, 0x11F, 0x11E};
- char[] latinChars = new char[]{'i', 'I', 'u', 'U', 'o', 'O', 's', 'S', 'c', 'C', 'g', 'G'};
+ char[] turkishChars = new char[] {
+ 0x131,
+ 0x130,
+ 0xFC,
+ 0xDC,
+ 0xF6,
+ 0xD6,
+ 0x15F,
+ 0x15E,
+ 0xE7,
+ 0xC7,
+ 0x11F,
+ 0x11E,
+ };
+ char[] latinChars = new char[] {
+ 'i',
+ 'I',
+ 'u',
+ 'U',
+ 'o',
+ 'O',
+ 's',
+ 'S',
+ 'c',
+ 'C',
+ 'g',
+ 'G',
+ };
for (int i = 0; i < turkishChars.length; i++) {
- param
- = param.replaceAll(
- new String(new char[]{turkishChars[i]}), new String(new char[]{latinChars[i]}));
+ param = param.replaceAll(String.valueOf(turkishChars[i]), String.valueOf(latinChars[i]));
}
return param;
}
diff --git a/src/main/java/com/thealgorithms/conversions/UnitConversions.java b/src/main/java/com/thealgorithms/conversions/UnitConversions.java
new file mode 100644
index 000000000000..15f74a21a17e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/UnitConversions.java
@@ -0,0 +1,51 @@
+package com.thealgorithms.conversions;
+
+import static java.util.Map.entry;
+
+import java.util.Map;
+import org.apache.commons.lang3.tuple.Pair;
+
+/**
+ * A utility class to perform unit conversions between different measurement systems.
+ *
+ * Currently, the class supports temperature conversions between several scales:
+ * Celsius, Fahrenheit, Kelvin, Réaumur, Delisle, and Rankine.
+ *
+ *
Example Usage
+ *
+ * double result = UnitConversions.TEMPERATURE.convert("Celsius", "Fahrenheit", 100.0);
+ * // Output: 212.0 (Celsius to Fahrenheit conversion of 100°C)
+ *
+ *
+ * This class makes use of an {@link UnitsConverter} that handles the conversion logic
+ * based on predefined affine transformations. These transformations include scaling factors
+ * and offsets for temperature conversions.
+ *
+ *
Temperature Scales Supported
+ *
+ * - Celsius
+ * - Fahrenheit
+ * - Kelvin
+ * - Réaumur
+ * - Delisle
+ * - Rankine
+ *
+ */
+public final class UnitConversions {
+ private UnitConversions() {
+ }
+
+ /**
+ * A preconfigured instance of {@link UnitsConverter} for temperature conversions.
+ * The converter handles conversions between the following temperature units:
+ *
+ * - Kelvin to Celsius
+ * - Celsius to Fahrenheit
+ * - Réaumur to Celsius
+ * - Delisle to Celsius
+ * - Rankine to Kelvin
+ *
+ */
+ public static final UnitsConverter TEMPERATURE = new UnitsConverter(Map.ofEntries(entry(Pair.of("Kelvin", "Celsius"), new AffineConverter(1.0, -273.15)), entry(Pair.of("Celsius", "Fahrenheit"), new AffineConverter(9.0 / 5.0, 32.0)),
+ entry(Pair.of("Réaumur", "Celsius"), new AffineConverter(5.0 / 4.0, 0.0)), entry(Pair.of("Delisle", "Celsius"), new AffineConverter(-2.0 / 3.0, 100.0)), entry(Pair.of("Rankine", "Kelvin"), new AffineConverter(5.0 / 9.0, 0.0))));
+}
diff --git a/src/main/java/com/thealgorithms/conversions/UnitsConverter.java b/src/main/java/com/thealgorithms/conversions/UnitsConverter.java
new file mode 100644
index 000000000000..00690b2c0f9b
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/UnitsConverter.java
@@ -0,0 +1,147 @@
+package com.thealgorithms.conversions;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import org.apache.commons.lang3.tuple.Pair;
+
+/**
+ * A class that handles unit conversions using affine transformations.
+ *
+ * The {@code UnitsConverter} allows converting values between different units using
+ * pre-defined affine conversion formulas. Each conversion is represented by an
+ * {@link AffineConverter} that defines the scaling and offset for the conversion.
+ *
+ *
For each unit, both direct conversions (e.g., Celsius to Fahrenheit) and inverse
+ * conversions (e.g., Fahrenheit to Celsius) are generated automatically. It also computes
+ * transitive conversions (e.g., Celsius to Kelvin via Fahrenheit if both conversions exist).
+ *
+ *
Key features include:
+ *
+ * - Automatic handling of inverse conversions (e.g., Fahrenheit to Celsius).
+ * - Compositional conversions, meaning if conversions between A -> B and B -> C exist,
+ * it can automatically generate A -> C conversion.
+ * - Supports multiple unit systems as long as conversions are provided in pairs.
+ *
+ *
+ * Example Usage
+ *
+ * Map<Pair<String, String>, AffineConverter> basicConversions = Map.ofEntries(
+ * entry(Pair.of("Celsius", "Fahrenheit"), new AffineConverter(9.0 / 5.0, 32.0)),
+ * entry(Pair.of("Kelvin", "Celsius"), new AffineConverter(1.0, -273.15))
+ * );
+ *
+ * UnitsConverter converter = new UnitsConverter(basicConversions);
+ * double result = converter.convert("Celsius", "Fahrenheit", 100.0);
+ * // Output: 212.0 (Celsius to Fahrenheit conversion of 100°C)
+ *
+ *
+ * Exception Handling
+ *
+ * - If the input unit and output unit are the same, an {@link IllegalArgumentException} is thrown.
+ * - If a conversion between the requested units does not exist, a {@link NoSuchElementException} is thrown.
+ *
+ */
+public final class UnitsConverter {
+ private final Map, AffineConverter> conversions;
+ private final Set units;
+
+ private static void putIfNeeded(Map, AffineConverter> conversions, final String inputUnit, final String outputUnit, final AffineConverter converter) {
+ if (!inputUnit.equals(outputUnit)) {
+ final var key = Pair.of(inputUnit, outputUnit);
+ conversions.putIfAbsent(key, converter);
+ }
+ }
+
+ private static Map, AffineConverter> addInversions(final Map, AffineConverter> knownConversions) {
+ Map, AffineConverter> res = new HashMap, AffineConverter>();
+ for (final var curConversion : knownConversions.entrySet()) {
+ final var inputUnit = curConversion.getKey().getKey();
+ final var outputUnit = curConversion.getKey().getValue();
+ putIfNeeded(res, inputUnit, outputUnit, curConversion.getValue());
+ putIfNeeded(res, outputUnit, inputUnit, curConversion.getValue().invert());
+ }
+ return res;
+ }
+
+ private static Map, AffineConverter> addCompositions(final Map, AffineConverter> knownConversions) {
+ Map, AffineConverter> res = new HashMap, AffineConverter>();
+ for (final var first : knownConversions.entrySet()) {
+ final var firstKey = first.getKey();
+ putIfNeeded(res, firstKey.getKey(), firstKey.getValue(), first.getValue());
+ for (final var second : knownConversions.entrySet()) {
+ final var secondKey = second.getKey();
+ if (firstKey.getValue().equals(secondKey.getKey())) {
+ final var newConversion = second.getValue().compose(first.getValue());
+ putIfNeeded(res, firstKey.getKey(), secondKey.getValue(), newConversion);
+ }
+ }
+ }
+ return res;
+ }
+
+ private static Map, AffineConverter> addAll(final Map, AffineConverter> knownConversions) {
+ final var res = addInversions(knownConversions);
+ return addCompositions(res);
+ }
+
+ private static Map, AffineConverter> computeAllConversions(final Map, AffineConverter> basicConversions) {
+ var tmp = basicConversions;
+ var res = addAll(tmp);
+ while (res.size() != tmp.size()) {
+ tmp = res;
+ res = addAll(tmp);
+ }
+ return res;
+ }
+
+ private static Set extractUnits(final Map, AffineConverter> conversions) {
+ Set res = new HashSet<>();
+ for (final var conversion : conversions.entrySet()) {
+ res.add(conversion.getKey().getKey());
+ }
+ return res;
+ }
+
+ /**
+ * Constructor for {@code UnitsConverter}.
+ *
+ * Accepts a map of basic conversions and automatically generates inverse and
+ * transitive conversions.
+ *
+ * @param basicConversions the initial set of unit conversions to add.
+ */
+ public UnitsConverter(final Map, AffineConverter> basicConversions) {
+ conversions = computeAllConversions(basicConversions);
+ units = extractUnits(conversions);
+ }
+
+ /**
+ * Converts a value from one unit to another.
+ *
+ * @param inputUnit the unit of the input value.
+ * @param outputUnit the unit to convert the value into.
+ * @param value the value to convert.
+ * @return the converted value in the target unit.
+ * @throws IllegalArgumentException if inputUnit equals outputUnit.
+ * @throws NoSuchElementException if no conversion exists between the units.
+ */
+ public double convert(final String inputUnit, final String outputUnit, final double value) {
+ if (inputUnit.equals(outputUnit)) {
+ throw new IllegalArgumentException("inputUnit must be different from outputUnit.");
+ }
+ final var conversionKey = Pair.of(inputUnit, outputUnit);
+ return conversions.computeIfAbsent(conversionKey, k -> { throw new NoSuchElementException("No converter for: " + k); }).convert(value);
+ }
+
+ /**
+ * Retrieves the set of all units supported by this converter.
+ *
+ * @return a set of available units.
+ */
+ public Set availableUnits() {
+ return units;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java
new file mode 100644
index 000000000000..e2b81a0f4b47
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java
@@ -0,0 +1,343 @@
+package com.thealgorithms.conversions;
+
+import java.io.Serial;
+import java.math.BigDecimal;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ A Java-based utility for converting English word representations of numbers
+ into their numeric form. This utility supports whole numbers, decimals,
+ large values up to trillions, and even scientific notation where applicable.
+ It ensures accurate parsing while handling edge cases like negative numbers,
+ improper word placements, and ambiguous inputs.
+ *
+ */
+
+public final class WordsToNumber {
+
+ private WordsToNumber() {
+ }
+
+ private enum NumberWord {
+ ZERO("zero", 0),
+ ONE("one", 1),
+ TWO("two", 2),
+ THREE("three", 3),
+ FOUR("four", 4),
+ FIVE("five", 5),
+ SIX("six", 6),
+ SEVEN("seven", 7),
+ EIGHT("eight", 8),
+ NINE("nine", 9),
+ TEN("ten", 10),
+ ELEVEN("eleven", 11),
+ TWELVE("twelve", 12),
+ THIRTEEN("thirteen", 13),
+ FOURTEEN("fourteen", 14),
+ FIFTEEN("fifteen", 15),
+ SIXTEEN("sixteen", 16),
+ SEVENTEEN("seventeen", 17),
+ EIGHTEEN("eighteen", 18),
+ NINETEEN("nineteen", 19),
+ TWENTY("twenty", 20),
+ THIRTY("thirty", 30),
+ FORTY("forty", 40),
+ FIFTY("fifty", 50),
+ SIXTY("sixty", 60),
+ SEVENTY("seventy", 70),
+ EIGHTY("eighty", 80),
+ NINETY("ninety", 90);
+
+ private final String word;
+ private final int value;
+
+ NumberWord(String word, int value) {
+ this.word = word;
+ this.value = value;
+ }
+
+ public static Integer getValue(String word) {
+ for (NumberWord num : values()) {
+ if (word.equals(num.word)) {
+ return num.value;
+ }
+ }
+ return null;
+ }
+ }
+
+ private enum PowerOfTen {
+ THOUSAND("thousand", new BigDecimal("1000")),
+ MILLION("million", new BigDecimal("1000000")),
+ BILLION("billion", new BigDecimal("1000000000")),
+ TRILLION("trillion", new BigDecimal("1000000000000"));
+
+ private final String word;
+ private final BigDecimal value;
+
+ PowerOfTen(String word, BigDecimal value) {
+ this.word = word;
+ this.value = value;
+ }
+
+ public static BigDecimal getValue(String word) {
+ for (PowerOfTen power : values()) {
+ if (word.equals(power.word)) {
+ return power.value;
+ }
+ }
+ return null;
+ }
+ }
+
+ public static String convert(String numberInWords) {
+ if (numberInWords == null) {
+ throw new WordsToNumberException(WordsToNumberException.ErrorType.NULL_INPUT, "");
+ }
+
+ ArrayDeque wordDeque = preprocessWords(numberInWords);
+ BigDecimal completeNumber = convertWordQueueToBigDecimal(wordDeque);
+
+ return completeNumber.toString();
+ }
+
+ public static BigDecimal convertToBigDecimal(String numberInWords) {
+ String conversionResult = convert(numberInWords);
+ return new BigDecimal(conversionResult);
+ }
+
+ private static ArrayDeque preprocessWords(String numberInWords) {
+ String[] wordSplitArray = numberInWords.trim().split("[ ,-]");
+ ArrayDeque wordDeque = new ArrayDeque<>();
+ for (String word : wordSplitArray) {
+ if (word.isEmpty()) {
+ continue;
+ }
+ wordDeque.add(word.toLowerCase());
+ }
+ if (wordDeque.isEmpty()) {
+ throw new WordsToNumberException(WordsToNumberException.ErrorType.NULL_INPUT, "");
+ }
+ return wordDeque;
+ }
+
+ private static void handleConjunction(boolean prevNumWasHundred, boolean prevNumWasPowerOfTen, ArrayDeque wordDeque) {
+ if (wordDeque.isEmpty()) {
+ throw new WordsToNumberException(WordsToNumberException.ErrorType.INVALID_CONJUNCTION, "");
+ }
+
+ String nextWord = wordDeque.pollFirst();
+ String afterNextWord = wordDeque.peekFirst();
+
+ wordDeque.addFirst(nextWord);
+
+ Integer number = NumberWord.getValue(nextWord);
+
+ boolean isPrevWordValid = prevNumWasHundred || prevNumWasPowerOfTen;
+ boolean isNextWordValid = number != null && (number >= 10 || afterNextWord == null || "point".equals(afterNextWord));
+
+ if (!isPrevWordValid || !isNextWordValid) {
+ throw new WordsToNumberException(WordsToNumberException.ErrorType.INVALID_CONJUNCTION, "");
+ }
+ }
+
+ private static BigDecimal handleHundred(BigDecimal currentChunk, String word, boolean prevNumWasPowerOfTen) {
+ boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0;
+ if (currentChunk.compareTo(BigDecimal.TEN) >= 0 || prevNumWasPowerOfTen) {
+ throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word);
+ }
+ if (currentChunkIsZero) {
+ currentChunk = currentChunk.add(BigDecimal.ONE);
+ }
+ return currentChunk.multiply(BigDecimal.valueOf(100));
+ }
+
+ private static void handlePowerOfTen(List chunks, BigDecimal currentChunk, BigDecimal powerOfTen, String word, boolean prevNumWasPowerOfTen) {
+ boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0;
+ if (currentChunkIsZero || prevNumWasPowerOfTen) {
+ throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word);
+ }
+ BigDecimal nextChunk = currentChunk.multiply(powerOfTen);
+
+ if (!(chunks.isEmpty() || isAdditionSafe(chunks.getLast(), nextChunk))) {
+ throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word);
+ }
+ chunks.add(nextChunk);
+ }
+
+ private static BigDecimal handleNumber(Collection chunks, BigDecimal currentChunk, String word, Integer number) {
+ boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0;
+ if (number == 0 && !(currentChunkIsZero && chunks.isEmpty())) {
+ throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word);
+ }
+ BigDecimal bigDecimalNumber = BigDecimal.valueOf(number);
+
+ if (!currentChunkIsZero && !isAdditionSafe(currentChunk, bigDecimalNumber)) {
+ throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word);
+ }
+ return currentChunk.add(bigDecimalNumber);
+ }
+
+ private static void handlePoint(Collection chunks, BigDecimal currentChunk, ArrayDeque wordDeque) {
+ boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0;
+ if (!currentChunkIsZero) {
+ chunks.add(currentChunk);
+ }
+
+ String decimalPart = convertDecimalPart(wordDeque);
+ chunks.add(new BigDecimal(decimalPart));
+ }
+
+ private static void handleNegative(boolean isNegative) {
+ if (isNegative) {
+ throw new WordsToNumberException(WordsToNumberException.ErrorType.MULTIPLE_NEGATIVES, "");
+ }
+ throw new WordsToNumberException(WordsToNumberException.ErrorType.INVALID_NEGATIVE, "");
+ }
+
+ private static BigDecimal convertWordQueueToBigDecimal(ArrayDeque wordDeque) {
+ BigDecimal currentChunk = BigDecimal.ZERO;
+ List chunks = new ArrayList<>();
+
+ boolean isNegative = "negative".equals(wordDeque.peek());
+ if (isNegative) {
+ wordDeque.poll();
+ }
+
+ boolean prevNumWasHundred = false;
+ boolean prevNumWasPowerOfTen = false;
+
+ while (!wordDeque.isEmpty()) {
+ String word = wordDeque.poll();
+
+ switch (word) {
+ case "and" -> {
+ handleConjunction(prevNumWasHundred, prevNumWasPowerOfTen, wordDeque);
+ continue;
+ }
+ case "hundred" -> {
+ currentChunk = handleHundred(currentChunk, word, prevNumWasPowerOfTen);
+ prevNumWasHundred = true;
+ continue;
+ }
+ default -> {
+
+ }
+ }
+ prevNumWasHundred = false;
+
+ BigDecimal powerOfTen = PowerOfTen.getValue(word);
+ if (powerOfTen != null) {
+ handlePowerOfTen(chunks, currentChunk, powerOfTen, word, prevNumWasPowerOfTen);
+ currentChunk = BigDecimal.ZERO;
+ prevNumWasPowerOfTen = true;
+ continue;
+ }
+ prevNumWasPowerOfTen = false;
+
+ Integer number = NumberWord.getValue(word);
+ if (number != null) {
+ currentChunk = handleNumber(chunks, currentChunk, word, number);
+ continue;
+ }
+
+ switch (word) {
+ case "point" -> {
+ handlePoint(chunks, currentChunk, wordDeque);
+ currentChunk = BigDecimal.ZERO;
+ continue;
+ }
+ case "negative" -> {
+ handleNegative(isNegative);
+ }
+ default -> {
+
+ }
+ }
+
+ throw new WordsToNumberException(WordsToNumberException.ErrorType.UNKNOWN_WORD, word);
+ }
+
+ if (currentChunk.compareTo(BigDecimal.ZERO) != 0) {
+ chunks.add(currentChunk);
+ }
+
+ BigDecimal completeNumber = combineChunks(chunks);
+ return isNegative ? completeNumber.multiply(BigDecimal.valueOf(-1))
+ :
+ completeNumber;
+ }
+
+ private static boolean isAdditionSafe(BigDecimal currentChunk, BigDecimal number) {
+ int chunkDigitCount = currentChunk.toString().length();
+ int numberDigitCount = number.toString().length();
+ return chunkDigitCount > numberDigitCount;
+ }
+
+ private static String convertDecimalPart(ArrayDeque wordDeque) {
+ StringBuilder decimalPart = new StringBuilder(".");
+
+ while (!wordDeque.isEmpty()) {
+ String word = wordDeque.poll();
+ Integer number = NumberWord.getValue(word);
+ if (number == null) {
+ throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD_AFTER_POINT, word);
+ }
+ decimalPart.append(number);
+ }
+
+ boolean missingNumbers = decimalPart.length() == 1;
+ if (missingNumbers) {
+ throw new WordsToNumberException(WordsToNumberException.ErrorType.MISSING_DECIMAL_NUMBERS, "");
+ }
+ return decimalPart.toString();
+ }
+
+ private static BigDecimal combineChunks(List chunks) {
+ BigDecimal completeNumber = BigDecimal.ZERO;
+ for (BigDecimal chunk : chunks) {
+ completeNumber = completeNumber.add(chunk);
+ }
+ return completeNumber;
+ }
+ }
+
+ class WordsToNumberException extends RuntimeException {
+
+ @Serial private static final long serialVersionUID = 1L;
+
+ enum ErrorType {
+ NULL_INPUT("'null' or empty input provided"),
+ UNKNOWN_WORD("Unknown Word: "),
+ UNEXPECTED_WORD("Unexpected Word: "),
+ UNEXPECTED_WORD_AFTER_POINT("Unexpected Word (after Point): "),
+ MISSING_DECIMAL_NUMBERS("Decimal part is missing numbers."),
+ MULTIPLE_NEGATIVES("Multiple 'Negative's detected."),
+ INVALID_NEGATIVE("Incorrect 'negative' placement"),
+ INVALID_CONJUNCTION("Incorrect 'and' placement");
+
+ private final String message;
+
+ ErrorType(String message) {
+ this.message = message;
+ }
+
+ public String formatMessage(String details) {
+ return "Invalid Input. " + message + (details.isEmpty() ? "" : details);
+ }
+ }
+
+ public final ErrorType errorType;
+
+ WordsToNumberException(ErrorType errorType, String details) {
+ super(errorType.formatMessage(details));
+ this.errorType = errorType;
+ }
+
+ public ErrorType getErrorType() {
+ return errorType;
+ }
+ }
diff --git a/src/main/java/com/thealgorithms/datastructures/Node.java b/src/main/java/com/thealgorithms/datastructures/Node.java
new file mode 100644
index 000000000000..c8d0e6cb4f7d
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/Node.java
@@ -0,0 +1,32 @@
+package com.thealgorithms.datastructures;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Node {
+
+ private final T value;
+ private final List> children;
+
+ public Node(final T value) {
+ this.value = value;
+ this.children = new ArrayList<>();
+ }
+
+ public Node(final T value, final List> children) {
+ this.value = value;
+ this.children = children;
+ }
+
+ public T getValue() {
+ return value;
+ }
+
+ public void addChild(Node child) {
+ children.add(child);
+ }
+
+ public List> getChildren() {
+ return children;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/datastructures/bags/Bag.java b/src/main/java/com/thealgorithms/datastructures/bags/Bag.java
index 1d03e5cf46a3..afc3bbe40cce 100644
--- a/src/main/java/com/thealgorithms/datastructures/bags/Bag.java
+++ b/src/main/java/com/thealgorithms/datastructures/bags/Bag.java
@@ -4,23 +4,28 @@
import java.util.NoSuchElementException;
/**
- * Collection which does not allow removing elements (only collect and iterate)
+ * A generic collection that allows adding and iterating over elements but does not support
+ * element removal. This class implements a simple bag data structure, which can hold duplicate
+ * elements and provides operations to check for membership and the size of the collection.
*
- * @param - the generic type of an element in this bag
+ * Bag is not thread-safe and should not be accessed by multiple threads concurrently.
+ *
+ * @param the type of elements in this bag
*/
-public class Bag implements Iterable {
-
- private Node firstElement; // first element of the bag
- private int size; // size of bag
+public class Bag implements Iterable {
- private static class Node {
+ private Node firstElement; // Reference to the first element in the bag
+ private int size; // Count of elements in the bag
- private Element content;
- private Node nextElement;
+ // Node class representing each element in the bag
+ private static final class Node {
+ private E content;
+ private Node nextElement;
}
/**
- * Create an empty bag
+ * Constructs an empty bag.
+ * This initializes the bag with zero elements.
*/
public Bag() {
firstElement = null;
@@ -28,40 +33,50 @@ public Bag() {
}
/**
- * @return true if this bag is empty, false otherwise
+ * Checks if the bag is empty.
+ *
+ * @return {@code true} if the bag contains no elements; {@code false} otherwise
*/
public boolean isEmpty() {
- return firstElement == null;
+ return size == 0;
}
/**
- * @return the number of elements
+ * Returns the number of elements in the bag.
+ *
+ * @return the number of elements currently in the bag
*/
public int size() {
return size;
}
/**
- * @param element - the element to add
+ * Adds an element to the bag.
+ *
+ *
This method adds the specified element to the bag. Duplicates are allowed, and the
+ * bag will maintain the order in which elements are added.
+ *
+ * @param element the element to add; must not be {@code null}
*/
- public void add(Element element) {
- Node oldfirst = firstElement;
- firstElement = new Node<>();
- firstElement.content = element;
- firstElement.nextElement = oldfirst;
+ public void add(E element) {
+ Node newNode = new Node<>();
+ newNode.content = element;
+ newNode.nextElement = firstElement;
+ firstElement = newNode;
size++;
}
/**
- * Checks if the bag contains a specific element
+ * Checks if the bag contains a specific element.
*
- * @param element which you want to look for
- * @return true if bag contains element, otherwise false
+ * This method uses the {@code equals} method of the element to determine membership.
+ *
+ * @param element the element to check for; must not be {@code null}
+ * @return {@code true} if the bag contains the specified element; {@code false} otherwise
*/
- public boolean contains(Element element) {
- Iterator iterator = this.iterator();
- while (iterator.hasNext()) {
- if (iterator.next().equals(element)) {
+ public boolean contains(E element) {
+ for (E value : this) {
+ if (value.equals(element)) {
return true;
}
}
@@ -69,61 +84,55 @@ public boolean contains(Element element) {
}
/**
- * @return an iterator that iterates over the elements in this bag in
- * arbitrary order
+ * Returns an iterator over the elements in this bag.
+ *
+ * The iterator provides a way to traverse the elements in the order they were added.
+ *
+ * @return an iterator that iterates over the elements in the bag
*/
- public Iterator iterator() {
+ @Override
+ public Iterator iterator() {
return new ListIterator<>(firstElement);
}
- @SuppressWarnings("hiding")
- private class ListIterator implements Iterator {
+ // Private class for iterating over elements
+ private static class ListIterator implements Iterator {
- private Node currentElement;
+ private Node currentElement;
- public ListIterator(Node firstElement) {
- currentElement = firstElement;
+ /**
+ * Constructs a ListIterator starting from the given first element.
+ *
+ * @param firstElement the first element of the bag to iterate over
+ */
+ ListIterator(Node firstElement) {
+ this.currentElement = firstElement;
}
+ /**
+ * Checks if there are more elements to iterate over.
+ *
+ * @return {@code true} if there are more elements; {@code false} otherwise
+ */
+ @Override
public boolean hasNext() {
return currentElement != null;
}
/**
- * remove is not allowed in a bag
+ * Returns the next element in the iteration.
+ *
+ * @return the next element in the bag
+ * @throws NoSuchElementException if there are no more elements to return
*/
@Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- public Element next() {
+ public E next() {
if (!hasNext()) {
- throw new NoSuchElementException();
+ throw new NoSuchElementException("No more elements in the bag.");
}
- Element element = currentElement.content;
+ E element = currentElement.content;
currentElement = currentElement.nextElement;
return element;
}
}
-
- /**
- * main-method for testing
- */
- public static void main(String[] args) {
- Bag bag = new Bag<>();
-
- bag.add("1");
- bag.add("1");
- bag.add("2");
-
- System.out.println("size of bag = " + bag.size());
- for (String s : bag) {
- System.out.println(s);
- }
-
- System.out.println(bag.contains(null));
- System.out.println(bag.contains("1"));
- System.out.println(bag.contains("3"));
- }
}
diff --git a/src/main/java/com/thealgorithms/datastructures/bloomfilter/BloomFilter.java b/src/main/java/com/thealgorithms/datastructures/bloomfilter/BloomFilter.java
new file mode 100644
index 000000000000..90625ad1c902
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/bloomfilter/BloomFilter.java
@@ -0,0 +1,177 @@
+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
+ * in the set when it is not, but they will never produce false negatives.
+ *
+ *
+ * @param The type of elements to be stored in the Bloom filter.
+ */
+@SuppressWarnings("rawtypes")
+public class BloomFilter {
+
+ private final int numberOfHashFunctions;
+ private final BitSet bitArray;
+ private final Hash[] hashFunctions;
+
+ /**
+ * Constructs a BloomFilter with a specified number of hash functions and bit
+ * array size.
+ *
+ * @param numberOfHashFunctions the number of hash functions to use
+ * @param bitArraySize the size of the bit array, which determines the
+ * capacity of the filter
+ * @throws IllegalArgumentException if numberOfHashFunctions or bitArraySize is
+ * less than 1
+ */
+ @SuppressWarnings("unchecked")
+ public BloomFilter(int numberOfHashFunctions, int bitArraySize) {
+ if (numberOfHashFunctions < 1 || bitArraySize < 1) {
+ throw new IllegalArgumentException("Number of hash functions and bit array size must be greater than 0");
+ }
+ this.numberOfHashFunctions = numberOfHashFunctions;
+ this.bitArray = new BitSet(bitArraySize);
+ this.hashFunctions = new Hash[numberOfHashFunctions];
+ initializeHashFunctions();
+ }
+
+ /**
+ * Initializes the hash functions with unique indices to ensure different
+ * hashing.
+ */
+ private void initializeHashFunctions() {
+ for (int i = 0; i < numberOfHashFunctions; i++) {
+ hashFunctions[i] = new Hash<>(i);
+ }
+ }
+
+ /**
+ * Inserts an element into the Bloom filter.
+ *
+ * This method hashes the element using all defined hash functions and sets the
+ * corresponding
+ * bits in the bit array.
+ *
+ *
+ * @param key the element to insert into the Bloom filter
+ */
+ public void insert(T key) {
+ for (Hash hash : hashFunctions) {
+ int position = Math.abs(hash.compute(key) % bitArray.size());
+ bitArray.set(position);
+ }
+ }
+
+ /**
+ * 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
+ * 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
+ */
+ public boolean contains(T key) {
+ for (Hash hash : hashFunctions) {
+ int position = Math.abs(hash.compute(key) % bitArray.size());
+ if (!bitArray.get(position)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Inner class representing a hash function used by the Bloom filter.
+ *
+ * Each instance of this class represents a different hash function based on its
+ * index.
+ *
+ *
+ * @param The type of elements to be hashed.
+ */
+ private static class Hash {
+
+ private final int index;
+
+ /**
+ * Constructs a Hash function with a specified index.
+ *
+ * @param index the index of this hash function, used to create a unique hash
+ */
+ Hash(int index) {
+ this.index = index;
+ }
+
+ /**
+ * Computes the hash of the given key.
+ *
+ * The hash value is calculated by multiplying the index of the hash function
+ * with the ASCII sum of the string representation of the key.
+ *
+ *
+ * @param key the element to hash
+ * @return the computed hash value
+ */
+ public int compute(T key) {
+ return index * contentHash(key);
+ }
+
+ /**
+ * Computes the ASCII value sum of the characters in a string.
+ *
+ * This method iterates through each character of the string and accumulates
+ * their ASCII values to produce a single integer value.
+ *
+ *
+ * @param word the string to compute
+ * @return the sum of ASCII values of the characters in the string
+ */
+ private int asciiString(String word) {
+ int sum = 0;
+ for (char c : word.toCharArray()) {
+ sum += c;
+ }
+ return sum;
+ }
+
+ /**
+ * Computes a content-based hash for arrays; falls back to ASCII-sum of String value otherwise.
+ */
+ private int contentHash(Object key) {
+ if (key instanceof int[]) {
+ return Arrays.hashCode((int[]) key);
+ } else if (key instanceof long[]) {
+ return Arrays.hashCode((long[]) key);
+ } else if (key instanceof byte[]) {
+ return Arrays.hashCode((byte[]) key);
+ } else if (key instanceof short[]) {
+ return Arrays.hashCode((short[]) key);
+ } else if (key instanceof char[]) {
+ return Arrays.hashCode((char[]) key);
+ } else if (key instanceof boolean[]) {
+ return Arrays.hashCode((boolean[]) key);
+ } else if (key instanceof float[]) {
+ return Arrays.hashCode((float[]) key);
+ } else if (key instanceof double[]) {
+ return Arrays.hashCode((double[]) key);
+ } else if (key instanceof Object[]) {
+ return Arrays.deepHashCode((Object[]) key);
+ }
+ return asciiString(String.valueOf(key));
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/datastructures/buffers/CircularBuffer.java b/src/main/java/com/thealgorithms/datastructures/buffers/CircularBuffer.java
index 200322478a8e..3b89c2119ae0 100644
--- a/src/main/java/com/thealgorithms/datastructures/buffers/CircularBuffer.java
+++ b/src/main/java/com/thealgorithms/datastructures/buffers/CircularBuffer.java
@@ -1,133 +1,133 @@
package com.thealgorithms.datastructures.buffers;
-import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
-public class CircularBuffer {
-
- private char[] _buffer;
- public final int _buffer_size;
- private int _write_index = 0;
- private int _read_index = 0;
- private AtomicInteger _readable_data = new AtomicInteger(0);
-
- public CircularBuffer(int buffer_size) {
- if (!IsPowerOfTwo(buffer_size)) {
- throw new IllegalArgumentException();
+/**
+ * The {@code CircularBuffer} class implements a generic circular (or ring) buffer.
+ * A circular buffer is a fixed-size data structure that operates in a FIFO (First In, First Out) manner.
+ * The buffer allows you to overwrite old data when the buffer is full and efficiently use limited memory.
+ * When the buffer is full, adding a new item will overwrite the oldest data.
+ *
+ * @param - The type of elements stored in the circular buffer.
+ */
+@SuppressWarnings("unchecked")
+public class CircularBuffer
- {
+ private final Item[] buffer;
+ private final CircularPointer putPointer;
+ private final CircularPointer getPointer;
+ private final AtomicInteger size = new AtomicInteger(0);
+
+ /**
+ * Constructor to initialize the circular buffer with a specified size.
+ *
+ * @param size The size of the circular buffer.
+ * @throws IllegalArgumentException if the size is zero or negative.
+ */
+ public CircularBuffer(int size) {
+ if (size <= 0) {
+ throw new IllegalArgumentException("Buffer size must be positive");
}
- this._buffer_size = buffer_size;
- _buffer = new char[buffer_size];
+ // noinspection unchecked
+ this.buffer = (Item[]) new Object[size];
+ this.putPointer = new CircularPointer(0, size);
+ this.getPointer = new CircularPointer(0, size);
}
- private boolean IsPowerOfTwo(int i) {
- return (i & (i - 1)) == 0;
+ /**
+ * Checks if the circular buffer is empty.
+ * This method is based on the current size of the buffer.
+ *
+ * @return {@code true} if the buffer is empty, {@code false} otherwise.
+ */
+ public boolean isEmpty() {
+ return size.get() == 0;
}
- private int getTrueIndex(int i) {
- return i % _buffer_size;
+ /**
+ * Checks if the circular buffer is full.
+ * The buffer is considered full when its size equals its capacity.
+ *
+ * @return {@code true} if the buffer is full, {@code false} otherwise.
+ */
+ public boolean isFull() {
+ return size.get() == buffer.length;
}
- public Character readOutChar() {
- Character result = null;
-
- // if we have data to read
- if (_readable_data.get() > 0) {
-
- result = Character.valueOf(_buffer[getTrueIndex(_read_index)]);
- _readable_data.decrementAndGet();
- _read_index++;
+ /**
+ * Retrieves and removes the item at the front of the buffer (FIFO).
+ * This operation will move the {@code getPointer} forward.
+ *
+ * @return The item at the front of the buffer, or {@code null} if the buffer is empty.
+ */
+ public Item get() {
+ if (isEmpty()) {
+ return null;
}
- return result;
+ Item item = buffer[getPointer.getAndIncrement()];
+ size.decrementAndGet();
+ return item;
}
- public boolean writeToCharBuffer(char c) {
- boolean result = false;
-
- // if we can write to the buffer
- if (_readable_data.get() < _buffer_size) {
- // write to buffer
- _buffer[getTrueIndex(_write_index)] = c;
- _readable_data.incrementAndGet();
- _write_index++;
- result = true;
+ /**
+ * Adds an item to the end of the buffer (FIFO).
+ * If the buffer is full, this operation will overwrite the oldest data.
+ *
+ * @param item The item to be added.
+ * @throws IllegalArgumentException if the item is null.
+ * @return {@code true} if the item was successfully added, {@code false} if the buffer was full and the item overwrote existing data.
+ */
+ public boolean put(Item item) {
+ if (item == null) {
+ throw new IllegalArgumentException("Null items are not allowed");
}
- return result;
- }
-
- private static class TestWriteWorker implements Runnable {
-
- String _alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
- Random _random = new Random();
- CircularBuffer _buffer;
-
- public TestWriteWorker(CircularBuffer cb) {
- this._buffer = cb;
+ boolean wasEmpty = isEmpty();
+ if (isFull()) {
+ getPointer.getAndIncrement(); // Move get pointer to discard oldest item
+ } else {
+ size.incrementAndGet();
}
- private char getRandomChar() {
- return _alphabet.charAt(_random.nextInt(_alphabet.length()));
- }
-
- public void run() {
- while (!Thread.interrupted()) {
- if (!_buffer.writeToCharBuffer(getRandomChar())) {
- Thread.yield();
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
- return;
- }
- }
- }
- }
+ buffer[putPointer.getAndIncrement()] = item;
+ return wasEmpty;
}
- private static class TestReadWorker implements Runnable {
-
- CircularBuffer _buffer;
-
- public TestReadWorker(CircularBuffer cb) {
- this._buffer = cb;
+ /**
+ * The {@code CircularPointer} class is a helper class used to track the current index (pointer)
+ * in the circular buffer.
+ * The max value represents the capacity of the buffer.
+ * The `CircularPointer` class ensures that the pointer automatically wraps around to 0
+ * when it reaches the maximum index.
+ * This is achieved in the `getAndIncrement` method, where the pointer
+ * is incremented and then taken modulo the maximum value (`max`).
+ * This operation ensures that the pointer always stays within the bounds of the buffer.
+ */
+ private static class CircularPointer {
+ private int pointer;
+ private final int max;
+
+ /**
+ * Constructor to initialize the circular pointer.
+ *
+ * @param pointer The initial position of the pointer.
+ * @param max The maximum size (capacity) of the circular buffer.
+ */
+ CircularPointer(int pointer, int max) {
+ this.pointer = pointer;
+ this.max = max;
}
- @Override
- public void run() {
- System.out.println("Printing Buffer:");
- while (!Thread.interrupted()) {
- Character c = _buffer.readOutChar();
- if (c != null) {
- System.out.print(c.charValue());
- } else {
- Thread.yield();
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
- System.out.println();
- return;
- }
- }
- }
+ /**
+ * Increments the pointer by 1 and wraps it around to 0 if it reaches the maximum value.
+ * This ensures the pointer always stays within the buffer's bounds.
+ *
+ * @return The current pointer value before incrementing.
+ */
+ public int getAndIncrement() {
+ int tmp = pointer;
+ pointer = (pointer + 1) % max;
+ return tmp;
}
}
-
- public static void main(String[] args) throws InterruptedException {
- int buffer_size = 1024;
- // create circular buffer
- CircularBuffer cb = new CircularBuffer(buffer_size);
-
- // create threads that read and write the buffer.
- Thread write_thread = new Thread(new TestWriteWorker(cb));
- Thread read_thread = new Thread(new TestReadWorker(cb));
- read_thread.start();
- write_thread.start();
-
- // wait some amount of time
- Thread.sleep(10000);
-
- // interrupt threads and exit
- write_thread.interrupt();
- read_thread.interrupt();
- }
}
diff --git a/src/main/java/com/thealgorithms/datastructures/caches/FIFOCache.java b/src/main/java/com/thealgorithms/datastructures/caches/FIFOCache.java
new file mode 100644
index 000000000000..fa048434a187
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/caches/FIFOCache.java
@@ -0,0 +1,549 @@
+package com.thealgorithms.datastructures.caches;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.BiConsumer;
+
+/**
+ * A thread-safe generic cache implementation using the First-In-First-Out eviction policy.
+ *
+ * The cache holds a fixed number of entries, defined by its capacity. When the cache is full and a
+ * new entry is added, the oldest entry in the cache is selected and evicted to make space.
+ *
+ * Optionally, entries can have a time-to-live (TTL) in milliseconds. If a TTL is set, entries will
+ * automatically expire and be removed upon access or insertion attempts.
+ *
+ * Features:
+ *
+ * - Removes oldest entry when capacity is exceeded
+ * - Optional TTL (time-to-live in milliseconds) per entry or default TTL for all entries
+ * - Thread-safe access using locking
+ * - Hit and miss counters for cache statistics
+ * - Eviction listener callback support
+ *
+ *
+ * @param the type of keys maintained by this cache
+ * @param the type of mapped values
+ * See FIFO
+ * @author Kevin Babu (GitHub)
+ */
+public final class FIFOCache {
+
+ private final int capacity;
+ private final long defaultTTL;
+ private final Map> cache;
+ private final Lock lock;
+
+ private long hits = 0;
+ private long misses = 0;
+ private final BiConsumer evictionListener;
+ private final EvictionStrategy evictionStrategy;
+
+ /**
+ * Internal structure to store value + expiry timestamp.
+ *
+ * @param the type of the value being cached
+ */
+ private static class CacheEntry {
+ V value;
+ long expiryTime;
+
+ /**
+ * Constructs a new {@code CacheEntry} with the specified value and time-to-live (TTL).
+ * If TTL is 0, the entry is kept indefinitely, that is, unless it is the first value,
+ * then it will be removed according to the FIFO principle
+ *
+ * @param value the value to cache
+ * @param ttlMillis the time-to-live in milliseconds
+ */
+ CacheEntry(V value, long ttlMillis) {
+ this.value = value;
+ if (ttlMillis == 0) {
+ this.expiryTime = Long.MAX_VALUE;
+ } else {
+ this.expiryTime = System.currentTimeMillis() + ttlMillis;
+ }
+ }
+
+ /**
+ * Checks if the cache entry has expired.
+ *
+ * @return {@code true} if the current time is past the expiration time; {@code false} otherwise
+ */
+ boolean isExpired() {
+ return System.currentTimeMillis() > expiryTime;
+ }
+ }
+
+ /**
+ * Constructs a new {@code FIFOCache} instance using the provided {@link Builder}.
+ *
+ * This constructor initializes the cache with the specified capacity and default TTL,
+ * sets up internal data structures (a {@code LinkedHashMap} for cache entries and configures eviction.
+ *
+ * @param builder the {@code Builder} object containing configuration parameters
+ */
+ private FIFOCache(Builder builder) {
+ this.capacity = builder.capacity;
+ this.defaultTTL = builder.defaultTTL;
+ this.cache = new LinkedHashMap<>();
+ this.lock = new ReentrantLock();
+ this.evictionListener = builder.evictionListener;
+ this.evictionStrategy = builder.evictionStrategy;
+ }
+
+ /**
+ * Retrieves the value associated with the specified key from the cache.
+ *
+ * If the key is not present or the corresponding entry has expired, this method
+ * returns {@code null}. If an expired entry is found, it will be removed and the
+ * eviction listener (if any) will be notified. Cache hit-and-miss statistics are
+ * also updated accordingly.
+ *
+ * @param key the key whose associated value is to be returned; must not be {@code null}
+ * @return the cached value associated with the key, or {@code null} if not present or expired
+ * @throws IllegalArgumentException if {@code key} is {@code null}
+ */
+ public V get(K key) {
+ if (key == null) {
+ throw new IllegalArgumentException("Key must not be null");
+ }
+
+ lock.lock();
+ try {
+ evictionStrategy.onAccess(this);
+
+ CacheEntry entry = cache.get(key);
+ if (entry == null || entry.isExpired()) {
+ if (entry != null) {
+ cache.remove(key);
+ notifyEviction(key, entry.value);
+ }
+ misses++;
+ return null;
+ }
+ hits++;
+ return entry.value;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Adds a key-value pair to the cache using the default time-to-live (TTL).
+ *
+ * The key may overwrite an existing entry. The actual insertion is delegated
+ * to the overloaded {@link #put(K, V, long)} method.
+ *
+ * @param key the key to cache the value under
+ * @param value the value to be cached
+ */
+ public void put(K key, V value) {
+ put(key, value, defaultTTL);
+ }
+
+ /**
+ * Adds a key-value pair to the cache with a specified time-to-live (TTL).
+ *
+ *
If the key already exists, its value is removed, re-inserted at tail and its TTL is reset.
+ * If the key does not exist and the cache is full, the oldest entry is evicted to make space.
+ * Expired entries are also cleaned up prior to any eviction. The eviction listener
+ * is notified when an entry gets evicted.
+ *
+ * @param key the key to associate with the cached value; must not be {@code null}
+ * @param value the value to be cached; must not be {@code null}
+ * @param ttlMillis the time-to-live for this entry in milliseconds; must be >= 0
+ * @throws IllegalArgumentException if {@code key} or {@code value} is {@code null}, or if {@code ttlMillis} is negative
+ */
+ public void put(K key, V value, long ttlMillis) {
+ if (key == null || value == null) {
+ throw new IllegalArgumentException("Key and value must not be null");
+ }
+ if (ttlMillis < 0) {
+ throw new IllegalArgumentException("TTL must be >= 0");
+ }
+
+ lock.lock();
+ try {
+ // If key already exists, remove it
+ CacheEntry oldEntry = cache.remove(key);
+ if (oldEntry != null && !oldEntry.isExpired()) {
+ notifyEviction(key, oldEntry.value);
+ }
+
+ // Evict expired entries to make space for new entry
+ evictExpired();
+
+ // If no expired entry was removed, remove the oldest
+ if (cache.size() >= capacity) {
+ Iterator>> it = cache.entrySet().iterator();
+ if (it.hasNext()) {
+ Map.Entry> eldest = it.next();
+ it.remove();
+ notifyEviction(eldest.getKey(), eldest.getValue().value);
+ }
+ }
+
+ // Insert new entry at tail
+ cache.put(key, new CacheEntry<>(value, ttlMillis));
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Removes all expired entries from the cache.
+ *
+ * This method iterates through the list of cached keys and checks each associated
+ * entry for expiration. Expired entries are removed the cache map. For each eviction,
+ * the eviction listener is notified.
+ */
+ private int evictExpired() {
+ int count = 0;
+ Iterator>> it = cache.entrySet().iterator();
+
+ while (it.hasNext()) {
+ Map.Entry> entry = it.next();
+ if (entry != null && entry.getValue().isExpired()) {
+ it.remove();
+ notifyEviction(entry.getKey(), entry.getValue().value);
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ /**
+ * Removes the specified key and its associated entry from the cache.
+ *
+ * @param key the key to remove from the cache;
+ * @return the value associated with the key; or {@code null} if no such key exists
+ */
+ public V removeKey(K key) {
+ if (key == null) {
+ throw new IllegalArgumentException("Key cannot be null");
+ }
+ CacheEntry entry = cache.remove(key);
+
+ // No such key in cache
+ if (entry == null) {
+ return null;
+ }
+
+ notifyEviction(key, entry.value);
+ return entry.value;
+ }
+
+ /**
+ * Notifies the eviction listener, if one is registered, that a key-value pair has been evicted.
+ *
+ * If the {@code evictionListener} is not {@code null}, it is invoked with the provided key
+ * and value. Any exceptions thrown by the listener are caught and logged to standard error,
+ * preventing them from disrupting cache operations.
+ *
+ * @param key the key that was evicted
+ * @param value the value that was associated with the evicted key
+ */
+ private void notifyEviction(K key, V value) {
+ if (evictionListener != null) {
+ try {
+ evictionListener.accept(key, value);
+ } catch (Exception e) {
+ System.err.println("Eviction listener failed: " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Returns the number of successful cache lookups (hits).
+ *
+ * @return the number of cache hits
+ */
+ public long getHits() {
+ lock.lock();
+ try {
+ return hits;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns the number of failed cache lookups (misses), including expired entries.
+ *
+ * @return the number of cache misses
+ */
+ public long getMisses() {
+ lock.lock();
+ try {
+ return misses;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns the current number of entries in the cache, excluding expired ones.
+ *
+ * @return the current cache size
+ */
+ public int size() {
+ lock.lock();
+ try {
+ evictionStrategy.onAccess(this);
+
+ int count = 0;
+ for (CacheEntry entry : cache.values()) {
+ if (!entry.isExpired()) {
+ ++count;
+ }
+ }
+ return count;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Removes all entries from the cache, regardless of their expiration status.
+ *
+ * This method clears the internal cache map entirely, resets the hit-and-miss counters,
+ * and notifies the eviction listener (if any) for each removed entry.
+ * Note that expired entries are treated the same as active ones for the purpose of clearing.
+ *
+ *
This operation acquires the internal lock to ensure thread safety.
+ */
+ public void clear() {
+ lock.lock();
+ try {
+ for (Map.Entry> entry : cache.entrySet()) {
+ notifyEviction(entry.getKey(), entry.getValue().value);
+ }
+ cache.clear();
+ hits = 0;
+ misses = 0;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns a set of all keys currently stored in the cache that have not expired.
+ *
+ * This method iterates through the cache and collects the keys of all non-expired entries.
+ * Expired entries are ignored but not removed. If you want to ensure expired entries are cleaned up,
+ * consider invoking {@link EvictionStrategy#onAccess(FIFOCache)} or calling {@link #evictExpired()} manually.
+ *
+ *
This operation acquires the internal lock to ensure thread safety.
+ *
+ * @return a set containing all non-expired keys currently in the cache
+ */
+ public Set getAllKeys() {
+ lock.lock();
+ try {
+ Set keys = new LinkedHashSet<>();
+
+ for (Map.Entry> entry : cache.entrySet()) {
+ if (!entry.getValue().isExpired()) {
+ keys.add(entry.getKey());
+ }
+ }
+
+ return keys;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns the current {@link EvictionStrategy} used by this cache instance.
+
+ * @return the eviction strategy currently assigned to this cache
+ */
+ public EvictionStrategy getEvictionStrategy() {
+ return evictionStrategy;
+ }
+
+ /**
+ * Returns a string representation of the cache, including metadata and current non-expired entries.
+ *
+ * The returned string includes the cache's capacity, current size (excluding expired entries),
+ * hit-and-miss counts, and a map of all non-expired key-value pairs. This method acquires a lock
+ * to ensure thread-safe access.
+ *
+ * @return a string summarizing the state of the cache
+ */
+ @Override
+ public String toString() {
+ lock.lock();
+ try {
+ Map visible = new LinkedHashMap<>();
+ for (Map.Entry> entry : cache.entrySet()) {
+ if (!entry.getValue().isExpired()) {
+ visible.put(entry.getKey(), entry.getValue().value);
+ }
+ }
+ return String.format("Cache(capacity=%d, size=%d, hits=%d, misses=%d, entries=%s)", capacity, visible.size(), hits, misses, visible);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * A strategy interface for controlling when expired entries are evicted from the cache.
+ *
+ * Implementations decide whether and when to trigger {@link FIFOCache#evictExpired()} based
+ * on cache usage patterns. This allows for flexible eviction behaviour such as periodic cleanup,
+ * or no automatic cleanup.
+ *
+ * @param the type of keys maintained by the cache
+ * @param the type of cached values
+ */
+ public interface EvictionStrategy {
+ /**
+ * Called on each cache access (e.g., {@link FIFOCache#get(Object)}) to optionally trigger eviction.
+ *
+ * @param cache the cache instance on which this strategy is applied
+ * @return the number of expired entries evicted during this access
+ */
+ int onAccess(FIFOCache cache);
+ }
+
+ /**
+ * An eviction strategy that performs eviction of expired entries on each call.
+ *
+ * @param the type of keys
+ * @param the type of values
+ */
+ public static class ImmediateEvictionStrategy implements EvictionStrategy {
+ @Override
+ public int onAccess(FIFOCache cache) {
+ return cache.evictExpired();
+ }
+ }
+
+ /**
+ * An eviction strategy that triggers eviction on every fixed number of accesses.
+ *
+ * This deterministic strategy ensures cleanup occurs at predictable intervals,
+ * ideal for moderately active caches where memory usage is a concern.
+ *
+ * @param the type of keys
+ * @param the type of values
+ */
+ public static class PeriodicEvictionStrategy implements EvictionStrategy {
+ private final int interval;
+ private final AtomicInteger counter = new AtomicInteger();
+
+ /**
+ * Constructs a periodic eviction strategy.
+ *
+ * @param interval the number of accesses between evictions; must be > 0
+ * @throws IllegalArgumentException if {@code interval} is less than or equal to 0
+ */
+ public PeriodicEvictionStrategy(int interval) {
+ if (interval <= 0) {
+ throw new IllegalArgumentException("Interval must be > 0");
+ }
+ this.interval = interval;
+ }
+
+ @Override
+ public int onAccess(FIFOCache cache) {
+ if (counter.incrementAndGet() % interval == 0) {
+ return cache.evictExpired();
+ }
+
+ return 0;
+ }
+ }
+
+ /**
+ * A builder for constructing a {@link FIFOCache} instance with customizable settings.
+ *
+ * Allows configuring capacity, default TTL, eviction listener, and a pluggable eviction
+ * strategy. Call {@link #build()} to create the configured cache instance.
+ *
+ * @param the type of keys maintained by the cache
+ * @param the type of values stored in the cache
+ */
+ public static class Builder {
+ private final int capacity;
+ private long defaultTTL = 0;
+ private BiConsumer evictionListener;
+ private EvictionStrategy evictionStrategy = new FIFOCache.ImmediateEvictionStrategy<>();
+ /**
+ * Creates a new {@code Builder} with the specified cache capacity.
+ *
+ * @param capacity the maximum number of entries the cache can hold; must be > 0
+ * @throws IllegalArgumentException if {@code capacity} is less than or equal to 0
+ */
+ public Builder(int capacity) {
+ if (capacity <= 0) {
+ throw new IllegalArgumentException("Capacity must be > 0");
+ }
+ this.capacity = capacity;
+ }
+
+ /**
+ * Sets the default time-to-live (TTL) in milliseconds for cache entries.
+ *
+ * @param ttlMillis the TTL duration in milliseconds; must be >= 0
+ * @return this builder instance for chaining
+ * @throws IllegalArgumentException if {@code ttlMillis} is negative
+ */
+ public Builder defaultTTL(long ttlMillis) {
+ if (ttlMillis < 0) {
+ throw new IllegalArgumentException("Default TTL must be >= 0");
+ }
+ this.defaultTTL = ttlMillis;
+ return this;
+ }
+
+ /**
+ * Sets an eviction listener to be notified when entries are evicted from the cache.
+ *
+ * @param listener a {@link BiConsumer} that accepts evicted keys and values; must not be {@code null}
+ * @return this builder instance for chaining
+ * @throws IllegalArgumentException if {@code listener} is {@code null}
+ */
+ public Builder evictionListener(BiConsumer listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("Listener must not be null");
+ }
+ this.evictionListener = listener;
+ return this;
+ }
+
+ /**
+ * Builds and returns a new {@link FIFOCache} instance with the configured parameters.
+ *
+ * @return a fully configured {@code FIFOCache} instance
+ */
+ public FIFOCache build() {
+ return new FIFOCache<>(this);
+ }
+
+ /**
+ * Sets the eviction strategy used to determine when to clean up expired entries.
+ *
+ * @param strategy an {@link EvictionStrategy} implementation; must not be {@code null}
+ * @return this builder instance
+ * @throws IllegalArgumentException if {@code strategy} is {@code null}
+ */
+ public Builder evictionStrategy(EvictionStrategy strategy) {
+ if (strategy == null) {
+ throw new IllegalArgumentException("Eviction strategy must not be null");
+ }
+ this.evictionStrategy = strategy;
+ return this;
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/datastructures/caches/LFUCache.java b/src/main/java/com/thealgorithms/datastructures/caches/LFUCache.java
new file mode 100644
index 000000000000..bf2b928ec33c
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/caches/LFUCache.java
@@ -0,0 +1,185 @@
+package com.thealgorithms.datastructures.caches;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The {@code LFUCache} class implements a Least Frequently Used (LFU) cache.
+ * An LFU cache evicts the least frequently used item when the cache reaches its capacity.
+ * It maintains a mapping of keys to nodes, where each node contains the key, its associated value,
+ * and a frequency count that tracks how many times the item has been accessed. A doubly linked list
+ * is used to efficiently manage the ordering of items based on their usage frequency.
+ *
+ * This implementation is designed to provide O(1) time complexity for both the {@code get} and
+ * {@code put} operations, which is achieved through the use of a hashmap for quick access and a
+ * doubly linked list for maintaining the order of item frequencies.
+ *
+ *
+ * Reference: LFU Cache - Wikipedia
+ *
+ *
+ * @param The type of keys maintained by this cache.
+ * @param The type of mapped values.
+ *
+ * @author Akshay Dubey (https://github.com/itsAkshayDubey)
+ */
+public class LFUCache {
+
+ /**
+ * The {@code Node} class represents an element in the LFU cache.
+ * Each node contains a key, a value, and a frequency count.
+ * It also has pointers to the previous and next nodes in the doubly linked list.
+ */
+ private class Node {
+ private final K key;
+ private V value;
+ private int frequency;
+ private Node previous;
+ private Node next;
+
+ /**
+ * Constructs a new {@code Node} with the specified key, value, and frequency.
+ *
+ * @param key The key associated with this node.
+ * @param value The value stored in this node.
+ * @param frequency The frequency of usage of this node.
+ */
+ Node(K key, V value, int frequency) {
+ this.key = key;
+ this.value = value;
+ this.frequency = frequency;
+ }
+ }
+
+ private Node head;
+ private Node tail;
+ private final Map cache;
+ private final int capacity;
+ private static final int DEFAULT_CAPACITY = 100;
+
+ /**
+ * Constructs an LFU cache with the default capacity.
+ */
+ public LFUCache() {
+ this(DEFAULT_CAPACITY);
+ }
+
+ /**
+ * Constructs an LFU cache with the specified capacity.
+ *
+ * @param capacity The maximum number of items that the cache can hold.
+ * @throws IllegalArgumentException if the specified capacity is less than or equal to zero.
+ */
+ public LFUCache(int capacity) {
+ if (capacity <= 0) {
+ throw new IllegalArgumentException("Capacity must be greater than zero.");
+ }
+ this.capacity = capacity;
+ this.cache = new HashMap<>();
+ }
+
+ /**
+ * Retrieves the value associated with the given key from the cache.
+ * If the key exists, the node's frequency is incremented, and the node is repositioned
+ * in the linked list based on its updated frequency.
+ *
+ * @param key The key whose associated value is to be returned.
+ * @return The value associated with the key, or {@code null} if the key is not present in the cache.
+ */
+ public V get(K key) {
+ Node node = cache.get(key);
+ if (node == null) {
+ return null;
+ }
+ removeNode(node);
+ node.frequency += 1;
+ addNodeWithUpdatedFrequency(node);
+ return node.value;
+ }
+
+ /**
+ * Inserts or updates a key-value pair in the cache.
+ * If the key already exists, the value is updated and its frequency is incremented.
+ * If the cache is full, the least frequently used item is removed before inserting the new item.
+ *
+ * @param key The key associated with the value to be inserted or updated.
+ * @param value The value to be inserted or updated.
+ */
+ public void put(K key, V value) {
+ if (cache.containsKey(key)) {
+ Node node = cache.get(key);
+ node.value = value;
+ node.frequency += 1;
+ removeNode(node);
+ addNodeWithUpdatedFrequency(node);
+ } else {
+ if (cache.size() >= capacity) {
+ cache.remove(this.head.key); // Evict least frequently used item
+ removeNode(head);
+ }
+ Node node = new Node(key, value, 1);
+ addNodeWithUpdatedFrequency(node);
+ cache.put(key, node);
+ }
+ }
+
+ /**
+ * Adds a node to the linked list in the correct position based on its frequency.
+ * The linked list is ordered by frequency, with the least frequently used node at the head.
+ *
+ * @param node The node to be inserted into the list.
+ */
+ private void addNodeWithUpdatedFrequency(Node node) {
+ if (tail != null && head != null) {
+ Node temp = this.head;
+ while (true) {
+ if (temp.frequency > node.frequency) {
+ if (temp == head) {
+ node.next = temp;
+ temp.previous = node;
+ this.head = node;
+ break;
+ } else {
+ node.next = temp;
+ node.previous = temp.previous;
+ temp.previous.next = node;
+ temp.previous = node;
+ break;
+ }
+ } else {
+ temp = temp.next;
+ if (temp == null) {
+ tail.next = node;
+ node.previous = tail;
+ node.next = null;
+ tail = node;
+ break;
+ }
+ }
+ }
+ } else {
+ tail = node;
+ head = tail;
+ }
+ }
+
+ /**
+ * Removes a node from the doubly linked list.
+ * This method ensures that the pointers of neighboring nodes are properly updated.
+ *
+ * @param node The node to be removed from the list.
+ */
+ private void removeNode(Node node) {
+ if (node.previous != null) {
+ node.previous.next = node.next;
+ } else {
+ this.head = node.next;
+ }
+
+ if (node.next != null) {
+ node.next.previous = node.previous;
+ } else {
+ this.tail = node.previous;
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/datastructures/caches/LIFOCache.java b/src/main/java/com/thealgorithms/datastructures/caches/LIFOCache.java
new file mode 100644
index 000000000000..df3d4da912fe
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/caches/LIFOCache.java
@@ -0,0 +1,563 @@
+package com.thealgorithms.datastructures.caches;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.BiConsumer;
+
+/**
+ * A thread-safe generic cache implementation using the Last-In-First-Out eviction policy.
+ *
+ * The cache holds a fixed number of entries, defined by its capacity. When the cache is full and a
+ * new entry is added, the youngest entry in the cache is selected and evicted to make space.
+ *
+ * Optionally, entries can have a time-to-live (TTL) in milliseconds. If a TTL is set, entries will
+ * automatically expire and be removed upon access or insertion attempts.
+ *
+ * Features:
+ *
+ * - Removes youngest entry when capacity is exceeded
+ * - Optional TTL (time-to-live in milliseconds) per entry or default TTL for all entries
+ * - Thread-safe access using locking
+ * - Hit and miss counters for cache statistics
+ * - Eviction listener callback support
+ *
+ *
+ * @param the type of keys maintained by this cache
+ * @param the type of mapped values
+ * See LIFO
+ * @author Kevin Babu (GitHub)
+ */
+public final class LIFOCache {
+
+ private final int capacity;
+ private final long defaultTTL;
+ private final Map> cache;
+ private final Lock lock;
+ private final Deque keys;
+ private long hits = 0;
+ private long misses = 0;
+ private final BiConsumer evictionListener;
+ private final EvictionStrategy evictionStrategy;
+
+ /**
+ * Internal structure to store value + expiry timestamp.
+ *
+ * @param the type of the value being cached
+ */
+ private static class CacheEntry {
+ V value;
+ long expiryTime;
+
+ /**
+ * Constructs a new {@code CacheEntry} with the specified value and time-to-live (TTL).
+ * If TTL is 0, the entry is kept indefinitely, that is, unless it is the first value,
+ * then it will be removed according to the LIFO principle
+ *
+ * @param value the value to cache
+ * @param ttlMillis the time-to-live in milliseconds
+ */
+ CacheEntry(V value, long ttlMillis) {
+ this.value = value;
+ if (ttlMillis == 0) {
+ this.expiryTime = Long.MAX_VALUE;
+ } else {
+ this.expiryTime = System.currentTimeMillis() + ttlMillis;
+ }
+ }
+
+ /**
+ * Checks if the cache entry has expired.
+ *
+ * @return {@code true} if the current time is past the expiration time; {@code false} otherwise
+ */
+ boolean isExpired() {
+ return System.currentTimeMillis() > expiryTime;
+ }
+ }
+
+ /**
+ * Constructs a new {@code LIFOCache} instance using the provided {@link Builder}.
+ *
+ * This constructor initializes the cache with the specified capacity and default TTL,
+ * sets up internal data structures (a {@code HashMap} for cache entries,
+ * {an @code ArrayDeque}, for key storage, and configures eviction.
+ *
+ * @param builder the {@code Builder} object containing configuration parameters
+ */
+ private LIFOCache(Builder builder) {
+ this.capacity = builder.capacity;
+ this.defaultTTL = builder.defaultTTL;
+ this.cache = new HashMap<>(builder.capacity);
+ this.keys = new ArrayDeque<>(builder.capacity);
+ this.lock = new ReentrantLock();
+ this.evictionListener = builder.evictionListener;
+ this.evictionStrategy = builder.evictionStrategy;
+ }
+
+ /**
+ * Retrieves the value associated with the specified key from the cache.
+ *
+ * If the key is not present or the corresponding entry has expired, this method
+ * returns {@code null}. If an expired entry is found, it will be removed and the
+ * eviction listener (if any) will be notified. Cache hit-and-miss statistics are
+ * also updated accordingly.
+ *
+ * @param key the key whose associated value is to be returned; must not be {@code null}
+ * @return the cached value associated with the key, or {@code null} if not present or expired
+ * @throws IllegalArgumentException if {@code key} is {@code null}
+ */
+ public V get(K key) {
+ if (key == null) {
+ throw new IllegalArgumentException("Key must not be null");
+ }
+
+ lock.lock();
+ try {
+ evictionStrategy.onAccess(this);
+
+ final CacheEntry entry = cache.get(key);
+ if (entry == null || entry.isExpired()) {
+ if (entry != null) {
+ cache.remove(key);
+ keys.remove(key);
+ notifyEviction(key, entry.value);
+ }
+ misses++;
+ return null;
+ }
+ hits++;
+ return entry.value;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Adds a key-value pair to the cache using the default time-to-live (TTL).
+ *
+ * The key may overwrite an existing entry. The actual insertion is delegated
+ * to the overloaded {@link #put(K, V, long)} method.
+ *
+ * @param key the key to cache the value under
+ * @param value the value to be cached
+ */
+ public void put(K key, V value) {
+ put(key, value, defaultTTL);
+ }
+
+ /**
+ * Adds a key-value pair to the cache with a specified time-to-live (TTL).
+ *
+ *
If the key already exists, its value is removed, re-inserted at tail and its TTL is reset.
+ * If the key does not exist and the cache is full, the youngest entry is evicted to make space.
+ * Expired entries are also cleaned up prior to any eviction. The eviction listener
+ * is notified when an entry gets evicted.
+ *
+ * @param key the key to associate with the cached value; must not be {@code null}
+ * @param value the value to be cached; must not be {@code null}
+ * @param ttlMillis the time-to-live for this entry in milliseconds; must be >= 0
+ * @throws IllegalArgumentException if {@code key} or {@code value} is {@code null}, or if {@code ttlMillis} is negative
+ */
+ public void put(K key, V value, long ttlMillis) {
+ if (key == null || value == null) {
+ throw new IllegalArgumentException("Key and value must not be null");
+ }
+ if (ttlMillis < 0) {
+ throw new IllegalArgumentException("TTL must be >= 0");
+ }
+
+ lock.lock();
+ try {
+ // If key already exists, remove it. It will later be re-inserted at top of stack
+ keys.remove(key);
+ final CacheEntry oldEntry = cache.remove(key);
+ if (oldEntry != null && !oldEntry.isExpired()) {
+ notifyEviction(key, oldEntry.value);
+ }
+
+ // Evict expired entries to make space for new entry
+ evictExpired();
+
+ // If no expired entry was removed, remove the youngest
+ if (cache.size() >= capacity) {
+ final K youngestKey = keys.pollLast();
+ final CacheEntry youngestEntry = cache.remove(youngestKey);
+ notifyEviction(youngestKey, youngestEntry.value);
+ }
+
+ // Insert new entry at tail
+ keys.add(key);
+ cache.put(key, new CacheEntry<>(value, ttlMillis));
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Removes all expired entries from the cache.
+ *
+ * This method iterates through the list of cached keys and checks each associated
+ * entry for expiration. Expired entries are removed the cache map. For each eviction,
+ * the eviction listener is notified.
+ */
+ private int evictExpired() {
+ int count = 0;
+ final Iterator it = keys.iterator();
+
+ while (it.hasNext()) {
+ final K k = it.next();
+ final CacheEntry entry = cache.get(k);
+ if (entry != null && entry.isExpired()) {
+ it.remove();
+ cache.remove(k);
+ notifyEviction(k, entry.value);
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ /**
+ * Removes the specified key and its associated entry from the cache.
+ *
+ * @param key the key to remove from the cache;
+ * @return the value associated with the key; or {@code null} if no such key exists
+ */
+ public V removeKey(K key) {
+ if (key == null) {
+ throw new IllegalArgumentException("Key cannot be null");
+ }
+ lock.lock();
+ try {
+ final CacheEntry entry = cache.remove(key);
+ keys.remove(key);
+
+ // No such key in cache
+ if (entry == null) {
+ return null;
+ }
+
+ notifyEviction(key, entry.value);
+ return entry.value;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Notifies the eviction listener, if one is registered, that a key-value pair has been evicted.
+ *
+ * If the {@code evictionListener} is not {@code null}, it is invoked with the provided key
+ * and value. Any exceptions thrown by the listener are caught and logged to standard error,
+ * preventing them from disrupting cache operations.
+ *
+ * @param key the key that was evicted
+ * @param value the value that was associated with the evicted key
+ */
+ private void notifyEviction(K key, V value) {
+ if (evictionListener != null) {
+ try {
+ evictionListener.accept(key, value);
+ } catch (Exception e) {
+ System.err.println("Eviction listener failed: " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Returns the number of successful cache lookups (hits).
+ *
+ * @return the number of cache hits
+ */
+ public long getHits() {
+ lock.lock();
+ try {
+ return hits;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns the number of failed cache lookups (misses), including expired entries.
+ *
+ * @return the number of cache misses
+ */
+ public long getMisses() {
+ lock.lock();
+ try {
+ return misses;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns the current number of entries in the cache, excluding expired ones.
+ *
+ * @return the current cache size
+ */
+ public int size() {
+ lock.lock();
+ try {
+ evictionStrategy.onAccess(this);
+
+ int count = 0;
+ for (CacheEntry entry : cache.values()) {
+ if (!entry.isExpired()) {
+ ++count;
+ }
+ }
+ return count;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Removes all entries from the cache, regardless of their expiration status.
+ *
+ * This method clears the internal cache map entirely, resets the hit-and-miss counters,
+ * and notifies the eviction listener (if any) for each removed entry.
+ * Note that expired entries are treated the same as active ones for the purpose of clearing.
+ *
+ *
This operation acquires the internal lock to ensure thread safety.
+ */
+ public void clear() {
+ lock.lock();
+ try {
+ for (Map.Entry> entry : cache.entrySet()) {
+ notifyEviction(entry.getKey(), entry.getValue().value);
+ }
+ keys.clear();
+ cache.clear();
+ hits = 0;
+ misses = 0;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns a set of all keys currently stored in the cache that have not expired.
+ *
+ * This method iterates through the cache and collects the keys of all non-expired entries.
+ * Expired entries are ignored but not removed. If you want to ensure expired entries are cleaned up,
+ * consider invoking {@link EvictionStrategy#onAccess(LIFOCache)} or calling {@link #evictExpired()} manually.
+ *
+ *
This operation acquires the internal lock to ensure thread safety.
+ *
+ * @return a set containing all non-expired keys currently in the cache
+ */
+ public Set getAllKeys() {
+ lock.lock();
+ try {
+ final Set result = new HashSet<>();
+
+ for (Map.Entry> entry : cache.entrySet()) {
+ if (!entry.getValue().isExpired()) {
+ result.add(entry.getKey());
+ }
+ }
+
+ return result;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns the current {@link EvictionStrategy} used by this cache instance.
+
+ * @return the eviction strategy currently assigned to this cache
+ */
+ public EvictionStrategy getEvictionStrategy() {
+ return evictionStrategy;
+ }
+
+ /**
+ * Returns a string representation of the cache, including metadata and current non-expired entries.
+ *
+ * The returned string includes the cache's capacity, current size (excluding expired entries),
+ * hit-and-miss counts, and a map of all non-expired key-value pairs. This method acquires a lock
+ * to ensure thread-safe access.
+ *
+ * @return a string summarizing the state of the cache
+ */
+ @Override
+ public String toString() {
+ lock.lock();
+ try {
+ final Map visible = new LinkedHashMap<>();
+ for (Map.Entry> entry : cache.entrySet()) {
+ if (!entry.getValue().isExpired()) {
+ visible.put(entry.getKey(), entry.getValue().value);
+ }
+ }
+ return String.format("Cache(capacity=%d, size=%d, hits=%d, misses=%d, entries=%s)", capacity, visible.size(), hits, misses, visible);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * A strategy interface for controlling when expired entries are evicted from the cache.
+ *
+ * Implementations decide whether and when to trigger {@link LIFOCache#evictExpired()} based
+ * on cache usage patterns. This allows for flexible eviction behaviour such as periodic cleanup,
+ * or no automatic cleanup.
+ *
+ * @param the type of keys maintained by the cache
+ * @param the type of cached values
+ */
+ public interface EvictionStrategy {
+ /**
+ * Called on each cache access (e.g., {@link LIFOCache#get(Object)}) to optionally trigger eviction.
+ *
+ * @param cache the cache instance on which this strategy is applied
+ * @return the number of expired entries evicted during this access
+ */
+ int onAccess(LIFOCache cache);
+ }
+
+ /**
+ * An eviction strategy that performs eviction of expired entries on each call.
+ *
+ * @param the type of keys
+ * @param the type of values
+ */
+ public static class ImmediateEvictionStrategy implements EvictionStrategy {
+ @Override
+ public int onAccess(LIFOCache cache) {
+ return cache.evictExpired();
+ }
+ }
+
+ /**
+ * An eviction strategy that triggers eviction on every fixed number of accesses.
+ *
+ * This deterministic strategy ensures cleanup occurs at predictable intervals,
+ * ideal for moderately active caches where memory usage is a concern.
+ *
+ * @param the type of keys
+ * @param the type of values
+ */
+ public static class PeriodicEvictionStrategy implements EvictionStrategy {
+ private final int interval;
+ private final AtomicInteger counter = new AtomicInteger();
+
+ /**
+ * Constructs a periodic eviction strategy.
+ *
+ * @param interval the number of accesses between evictions; must be > 0
+ * @throws IllegalArgumentException if {@code interval} is less than or equal to 0
+ */
+ public PeriodicEvictionStrategy(int interval) {
+ if (interval <= 0) {
+ throw new IllegalArgumentException("Interval must be > 0");
+ }
+ this.interval = interval;
+ }
+
+ @Override
+ public int onAccess(LIFOCache cache) {
+ if (counter.incrementAndGet() % interval == 0) {
+ return cache.evictExpired();
+ }
+
+ return 0;
+ }
+ }
+
+ /**
+ * A builder for constructing a {@link LIFOCache} instance with customizable settings.
+ *
+ * Allows configuring capacity, default TTL, eviction listener, and a pluggable eviction
+ * strategy. Call {@link #build()} to create the configured cache instance.
+ *
+ * @param the type of keys maintained by the cache
+ * @param the type of values stored in the cache
+ */
+ public static class Builder {
+ private final int capacity;
+ private long defaultTTL = 0;
+ private BiConsumer evictionListener;
+ private EvictionStrategy evictionStrategy = new LIFOCache.ImmediateEvictionStrategy<>();
+ /**
+ * Creates a new {@code Builder} with the specified cache capacity.
+ *
+ * @param capacity the maximum number of entries the cache can hold; must be > 0
+ * @throws IllegalArgumentException if {@code capacity} is less than or equal to 0
+ */
+ public Builder(int capacity) {
+ if (capacity <= 0) {
+ throw new IllegalArgumentException("Capacity must be > 0");
+ }
+ this.capacity = capacity;
+ }
+
+ /**
+ * Sets the default time-to-live (TTL) in milliseconds for cache entries.
+ *
+ * @param ttlMillis the TTL duration in milliseconds; must be >= 0
+ * @return this builder instance for chaining
+ * @throws IllegalArgumentException if {@code ttlMillis} is negative
+ */
+ public Builder defaultTTL(long ttlMillis) {
+ if (ttlMillis < 0) {
+ throw new IllegalArgumentException("Default TTL must be >= 0");
+ }
+ this.defaultTTL = ttlMillis;
+ return this;
+ }
+
+ /**
+ * Sets an eviction listener to be notified when entries are evicted from the cache.
+ *
+ * @param listener a {@link BiConsumer} that accepts evicted keys and values; must not be {@code null}
+ * @return this builder instance for chaining
+ * @throws IllegalArgumentException if {@code listener} is {@code null}
+ */
+ public Builder evictionListener(BiConsumer listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("Listener must not be null");
+ }
+ this.evictionListener = listener;
+ return this;
+ }
+
+ /**
+ * Builds and returns a new {@link LIFOCache} instance with the configured parameters.
+ *
+ * @return a fully configured {@code LIFOCache} instance
+ */
+ public LIFOCache build() {
+ return new LIFOCache<>(this);
+ }
+
+ /**
+ * Sets the eviction strategy used to determine when to clean up expired entries.
+ *
+ * @param strategy an {@link EvictionStrategy} implementation; must not be {@code null}
+ * @return this builder instance
+ * @throws IllegalArgumentException if {@code strategy} is {@code null}
+ */
+ public Builder evictionStrategy(EvictionStrategy strategy) {
+ if (strategy == null) {
+ throw new IllegalArgumentException("Eviction strategy must not be null");
+ }
+ this.evictionStrategy = strategy;
+ return this;
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/datastructures/caches/LRUCache.java b/src/main/java/com/thealgorithms/datastructures/caches/LRUCache.java
index b905499bf814..ec39d2a6ed28 100644
--- a/src/main/java/com/thealgorithms/datastructures/caches/LRUCache.java
+++ b/src/main/java/com/thealgorithms/datastructures/caches/LRUCache.java
@@ -4,15 +4,40 @@
import java.util.Map;
/**
- * Least recently used (LRU)
- *
- * Discards the least recently used items first. This algorithm requires keeping
- * track of what was used when, which is expensive if one wants to make sure the
- * algorithm always discards the least recently used item.
- * https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)
+ * A Least Recently Used (LRU) Cache implementation.
*
- * @param key type
- * @param value type
+ * An LRU cache is a fixed-size cache that maintains items in order of use. When the cache reaches
+ * its capacity and a new item needs to be added, it removes the least recently used item first.
+ * This implementation provides O(1) time complexity for both get and put operations.
+ *
+ * Features:
+ *
+ * - Fixed-size cache with configurable capacity
+ * - Constant time O(1) operations for get and put
+ * - Thread-unsafe - should be externally synchronized if used in concurrent environments
+ * - Supports null values but not null keys
+ *
+ *
+ * Implementation Details:
+ *
+ * - Uses a HashMap for O(1) key-value lookups
+ * - Maintains a doubly-linked list for tracking access order
+ * - The head of the list contains the least recently used item
+ * - The tail of the list contains the most recently used item
+ *
+ *
+ * Example usage:
+ *
+ * LRUCache cache = new LRUCache<>(3); // Create cache with capacity 3
+ * cache.put("A", 1); // Cache: A=1
+ * cache.put("B", 2); // Cache: A=1, B=2
+ * cache.put("C", 3); // Cache: A=1, B=2, C=3
+ * cache.get("A"); // Cache: B=2, C=3, A=1 (A moved to end)
+ * cache.put("D", 4); // Cache: C=3, A=1, D=4 (B evicted)
+ *
+ *
+ * @param the type of keys maintained by this cache
+ * @param the type of mapped values
*/
public class LRUCache {
@@ -30,6 +55,11 @@ public LRUCache(int cap) {
setCapacity(cap);
}
+ /**
+ * Returns the current capacity of the cache.
+ *
+ * @param newCapacity the new capacity of the cache
+ */
private void setCapacity(int newCapacity) {
checkCapacity(newCapacity);
for (int i = data.size(); i > newCapacity; i--) {
@@ -39,6 +69,11 @@ private void setCapacity(int newCapacity) {
this.cap = newCapacity;
}
+ /**
+ * Evicts the least recently used item from the cache.
+ *
+ * @return the evicted entry
+ */
private Entry evict() {
if (head == null) {
throw new RuntimeException("cache cannot be empty!");
@@ -50,12 +85,25 @@ private Entry evict() {
return evicted;
}
+ /**
+ * Checks if the capacity is valid.
+ *
+ * @param capacity the capacity to check
+ */
private void checkCapacity(int capacity) {
if (capacity <= 0) {
throw new RuntimeException("capacity must greater than 0!");
}
}
+ /**
+ * Returns the value to which the specified key is mapped, or null if this cache contains no
+ * mapping for the key.
+ *
+ * @param key the key whose associated value is to be returned
+ * @return the value to which the specified key is mapped, or null if this cache contains no
+ * mapping for the key
+ */
public V get(K key) {
if (!data.containsKey(key)) {
return null;
@@ -65,6 +113,11 @@ public V get(K key) {
return entry.getValue();
}
+ /**
+ * Moves the specified entry to the end of the list.
+ *
+ * @param entry the entry to move
+ */
private void moveNodeToLast(Entry entry) {
if (tail == entry) {
return;
@@ -86,6 +139,12 @@ private void moveNodeToLast(Entry entry) {
tail = entry;
}
+ /**
+ * Associates the specified value with the specified key in this cache.
+ *
+ * @param key the key with which the specified value is to be associated
+ * @param value the value to be associated with the specified key
+ */
public void put(K key, V value) {
if (data.containsKey(key)) {
final Entry existingEntry = data.get(key);
@@ -107,6 +166,11 @@ public void put(K key, V value) {
data.put(key, newEntry);
}
+ /**
+ * Adds a new entry to the end of the list.
+ *
+ * @param newEntry the entry to add
+ */
private void addNewEntry(Entry newEntry) {
if (data.isEmpty()) {
head = newEntry;
@@ -126,10 +190,10 @@ static final class Entry