diff --git a/DIRECTORY.md b/DIRECTORY.md index ee09790ed64d..1bad5d3b98a3 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -22,6 +22,7 @@ * [WordSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/WordSearch.java) * bitmanipulation * [BitSwap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java) + * [CountSetBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java) * [HighestSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java) * [IndexOfRightMostSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java) * [IsEven](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/IsEven.java) @@ -52,6 +53,7 @@ * [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) * [Vigenere](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Vigenere.java) + * [XORCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/XORCipher.java) * conversions * [AffineConverter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/AffineConverter.java) * [AnyBaseToAnyBase](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java) @@ -67,6 +69,7 @@ * [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) + * [IntegerToEnglish](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/IntegerToEnglish.java) * [IntegerToRoman](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/IntegerToRoman.java) * [OctalToBinary](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/OctalToBinary.java) * [OctalToDecimal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/OctalToDecimal.java) @@ -107,6 +110,7 @@ * [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) * [DijkstraAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithm.java) + * [EdmondsBlossomAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java) * [FloydWarshall](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/FloydWarshall.java) * [FordFulkerson](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/FordFulkerson.java) * [Graphs](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/Graphs.java) @@ -155,6 +159,7 @@ * [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) * [SkipList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SkipList.java) + * [SortedLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SortedLinkedList.java) * [Node](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/Node.java) * queues * [CircularQueue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/CircularQueue.java) @@ -236,6 +241,7 @@ * [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) + * [LongestArithmeticSubsequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequence.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) @@ -264,9 +270,11 @@ * greedyalgorithms * [ActivitySelection](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/ActivitySelection.java) * [CoinChange](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/CoinChange.java) + * [DigitSeparation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/DigitSeparation.java) * [FractionalKnapsack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/FractionalKnapsack.java) * [GaleShapley](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/GaleShapley.java) * [JobSequencing](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/JobSequencing.java) + * [MergeIntervals](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/MergeIntervals.java) * [MinimizingLateness](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/MinimizingLateness.java) * io * [BufferedReader](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/io/BufferedReader.java) @@ -396,13 +404,13 @@ * [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) * [Sparsity](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/Sparsity.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) + * [ArrayRightRotation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/ArrayRightRotation.java) * [BankersAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/BankersAlgorithm.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) @@ -410,9 +418,6 @@ * cn * [HammingDistance](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/cn/HammingDistance.java) * [Conway](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Conway.java) - * [CountChar](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/CountChar.java) - * [CountSetBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/CountSetBits.java) - * [CountWords](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/CountWords.java) * [CRC16](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/CRC16.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) @@ -441,15 +446,15 @@ * [PrintAMatrixInSpiralOrder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/PrintAMatrixInSpiralOrder.java) * [QueueUsingTwoStacks](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/QueueUsingTwoStacks.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) * [RotateMatrixBy90Degrees](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/RotateMatrixBy90Degrees.java) * [SkylineProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/SkylineProblem.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) * [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) + * Recursion + * [GenerateSubsets](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/Recursion/GenerateSubsets.java) * scheduling * [FCFSScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/FCFSScheduling.java) * [PreemptivePriorityScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/PreemptivePriorityScheduling.java) @@ -499,7 +504,6 @@ * [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) * [DualPivotQuickSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/DualPivotQuickSort.java) * [DutchNationalFlagSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/DutchNationalFlagSort.java) * [ExchangeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/ExchangeSort.java) @@ -540,11 +544,13 @@ * [DecimalToAnyUsingStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/DecimalToAnyUsingStack.java) * [DuplicateBrackets](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/DuplicateBrackets.java) * [InfixToPostfix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/InfixToPostfix.java) + * [InfixToPrefix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/InfixToPrefix.java) * [LargestRectangle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/LargestRectangle.java) * [MaximumMinimumWindow](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/MaximumMinimumWindow.java) * [NextGreaterElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/NextGreaterElement.java) * [NextSmallerElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/NextSmallerElement.java) * [PostfixToInfix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/PostfixToInfix.java) + * [PrefixToInfix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/PrefixToInfix.java) * [StackPostfixNotation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/StackPostfixNotation.java) * strings * [AhoCorasick](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/AhoCorasick.java) @@ -553,6 +559,8 @@ * [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) + * [CountChar](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/CountChar.java) + * [CountWords](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/CountWords.java) * [HammingDistance](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/HammingDistance.java) * [HorspoolSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/HorspoolSearch.java) * [Isomorphic](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Isomorphic.java) @@ -567,11 +575,13 @@ * [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) * [RabinKarp](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/RabinKarp.java) + * [ReturnSubsequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/ReturnSubsequence.java) * [ReverseString](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/ReverseString.java) * [ReverseStringRecursive](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/ReverseStringRecursive.java) * [ReverseWordsInString](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/ReverseWordsInString.java) * [Rotation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Rotation.java) * [StringCompression](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/StringCompression.java) + * [StringMatchFiniteAutomata](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/StringMatchFiniteAutomata.java) * [Upper](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Upper.java) * [ValidParentheses](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/ValidParentheses.java) * [WordLadder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/WordLadder.java) @@ -596,6 +606,7 @@ * [WordSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/WordSearchTest.java) * bitmanipulation * [BitSwapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/BitSwapTest.java) + * [CountSetBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java) * [HighestSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/HighestSetBitTest.java) * [IndexOfRightMostSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBitTest.java) * [IsEvenTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/IsEvenTest.java) @@ -610,11 +621,13 @@ * [BlowfishTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/BlowfishTest.java) * [CaesarTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/CaesarTest.java) * [DESTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/DESTest.java) + * [HillCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/HillCipherTest.java) * [PlayfairTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/PlayfairTest.java) * [PolybiusTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/PolybiusTest.java) * [RSATest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/RSATest.java) * [SimpleSubCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/SimpleSubCipherTest.java) * [VigenereTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/VigenereTest.java) + * [XORCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/XORCipherTest.java) * conversions * [AnyBaseToDecimalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/AnyBaseToDecimalTest.java) * [BinaryToDecimalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/BinaryToDecimalTest.java) @@ -627,6 +640,7 @@ * [HexaDecimalToBinaryTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/HexaDecimalToBinaryTest.java) * [HexaDecimalToDecimalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/HexaDecimalToDecimalTest.java) * [HexToOctTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/HexToOctTest.java) + * [IntegerToEnglishTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/IntegerToEnglishTest.java) * [IntegerToRomanTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/IntegerToRomanTest.java) * [OctalToBinaryTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/OctalToBinaryTest.java) * [OctalToDecimalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/OctalToDecimalTest.java) @@ -659,6 +673,7 @@ * graphs * [BoruvkaAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/BoruvkaAlgorithmTest.java) * [DijkstraAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java) + * [EdmondsBlossomAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java) * [FordFulkersonTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/FordFulkersonTest.java) * [HamiltonianCycleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/HamiltonianCycleTest.java) * [KosarajuTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/KosarajuTest.java) @@ -683,6 +698,7 @@ * [RotateSinglyLinkedListsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedListsTest.java) * [SinglyLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java) * [SkipListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/SkipListTest.java) + * [SortedLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/SortedLinkedListTest.java) * queues * [CircularQueueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/CircularQueueTest.java) * [DequeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/DequeTest.java) @@ -713,10 +729,12 @@ * [SameTreesCheckTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/SameTreesCheckTest.java) * [SplayTreeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/SplayTreeTest.java) * [TreeTestUtils](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/TreeTestUtils.java) + * [TrieImpTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/TrieImpTest.java) * [VerticalOrderTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/VerticalOrderTraversalTest.java) * [ZigzagTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/ZigzagTraversalTest.java) * divideandconquer * [BinaryExponentiationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/BinaryExponentiationTest.java) + * [SkylineAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/SkylineAlgorithmTest.java) * [StrassenMatrixMultiplicationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplicationTest.java) * dynamicprogramming * [BoardPathTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/BoardPathTest.java) @@ -728,6 +746,8 @@ * [KnapsackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackTest.java) * [LevenshteinDistanceTests](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LevenshteinDistanceTests.java) * [LongestAlternatingSubsequenceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestAlternatingSubsequenceTest.java) + * [LongestArithmeticSubsequenceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequenceTest.java) + * [LongestCommonSubsequenceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java) * [LongestIncreasingSubsequenceTests](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceTests.java) * [LongestPalindromicSubstringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstringTest.java) * [LongestValidParenthesesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestValidParenthesesTest.java) @@ -749,9 +769,11 @@ * greedyalgorithms * [ActivitySelectionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/ActivitySelectionTest.java) * [CoinChangeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/CoinChangeTest.java) + * [DigitSeparationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/DigitSeparationTest.java) * [FractionalKnapsackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/FractionalKnapsackTest.java) * [GaleShapleyTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/GaleShapleyTest.java) * [JobSequencingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/JobSequencingTest.java) + * [MergeIntervalsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/MergeIntervalsTest.java) * [MinimizingLatenessTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/MinimizingLatenessTest.java) * io * [BufferedReaderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/io/BufferedReaderTest.java) @@ -859,7 +881,6 @@ * [TwoSumProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/TwoSumProblemTest.java) * others * [ArrayLeftRotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ArrayLeftRotationTest.java) - * [ArrayRightRotation](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ArrayRightRotation.java) * [ArrayRightRotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ArrayRightRotationTest.java) * [BestFitCPUTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/BestFitCPUTest.java) * [BFPRTTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/BFPRTTest.java) @@ -867,10 +888,7 @@ * cn * [HammingDistanceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java) * [ConwayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ConwayTest.java) - * [CountCharTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/CountCharTest.java) * [CountFriendsPairingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/CountFriendsPairingTest.java) - * [CountSetBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/CountSetBitsTest.java) - * [CountWordsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/CountWordsTest.java) * [CRC16Test](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/CRC16Test.java) * [CRCAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/CRCAlgorithmTest.java) * [FirstFitCPUTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/FirstFitCPUTest.java) @@ -885,12 +903,12 @@ * [PasswordGenTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/PasswordGenTest.java) * [QueueUsingTwoStacksTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/QueueUsingTwoStacksTest.java) * [RemoveDuplicateFromStringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/RemoveDuplicateFromStringTest.java) - * [ReturnSubsequenceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ReturnSubsequenceTest.java) * [ReverseStackUsingRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ReverseStackUsingRecursionTest.java) - * [StringMatchFiniteAutomataTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/StringMatchFiniteAutomataTest.java) * [TestPrintMatrixInSpiralOrder](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TestPrintMatrixInSpiralOrder.java) * [TwoPointersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TwoPointersTest.java) * [WorstFitCPUTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/WorstFitCPUTest.java) + * Recursion + * [GenerateSubsetsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/Recursion/GenerateSubsetsTest.java) * scheduling * [FCFSSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/FCFSSchedulingTest.java) * [PreemptivePrioritySchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/PreemptivePrioritySchedulingTest.java) @@ -963,10 +981,12 @@ * [DecimalToAnyUsingStackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/DecimalToAnyUsingStackTest.java) * [DuplicateBracketsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/DuplicateBracketsTest.java) * [InfixToPostfixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/InfixToPostfixTest.java) + * [InfixToPrefixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java) * [LargestRectangleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/LargestRectangleTest.java) * [NextGreaterElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/NextGreaterElementTest.java) * [NextSmallerElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/NextSmallerElementTest.java) * [PostfixToInfixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/PostfixToInfixTest.java) + * [PrefixToInfixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/PrefixToInfixTest.java) * [StackPostfixNotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/StackPostfixNotationTest.java) * strings * [AhoCorasickTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/AhoCorasickTest.java) @@ -975,6 +995,8 @@ * [CharacterSameTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/CharacterSameTest.java) * [CheckAnagramsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/CheckAnagramsTest.java) * [CheckVowelsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/CheckVowelsTest.java) + * [CountCharTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/CountCharTest.java) + * [CountWordsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/CountWordsTest.java) * [HammingDistanceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/HammingDistanceTest.java) * [HorspoolSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/HorspoolSearchTest.java) * [IsomorphicTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/IsomorphicTest.java) @@ -987,11 +1009,13 @@ * [PalindromeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/PalindromeTest.java) * [PangramTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/PangramTest.java) * [PermuteStringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/PermuteStringTest.java) + * [ReturnSubsequenceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/ReturnSubsequenceTest.java) * [ReverseStringRecursiveTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/ReverseStringRecursiveTest.java) * [ReverseStringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/ReverseStringTest.java) * [ReverseWordsInStringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/ReverseWordsInStringTest.java) * [RotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/RotationTest.java) * [StringCompressionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/StringCompressionTest.java) + * [StringMatchFiniteAutomataTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/StringMatchFiniteAutomataTest.java) * [UpperTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/UpperTest.java) * [ValidParenthesesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java) * [WordLadderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/WordLadderTest.java) diff --git a/pom.xml b/pom.xml index 882575fc654e..ab12e8ec4082 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ org.junit junit-bom - 5.11.1 + 5.11.2 pom import @@ -31,7 +31,7 @@ org.junit.jupiter junit-jupiter - 5.11.1 + 5.11.2 test @@ -44,7 +44,7 @@ org.junit.jupiter junit-jupiter-api - 5.11.1 + 5.11.2 test diff --git a/src/main/java/com/thealgorithms/Recursion/GenerateSubsets.java b/src/main/java/com/thealgorithms/Recursion/GenerateSubsets.java new file mode 100644 index 000000000000..417bf1307790 --- /dev/null +++ b/src/main/java/com/thealgorithms/Recursion/GenerateSubsets.java @@ -0,0 +1,36 @@ +package com.thealgorithms.Recursion; + +// program to find power set of a string + +import java.util.ArrayList; +import java.util.List; + +public final class GenerateSubsets { + + private GenerateSubsets() { + throw new UnsupportedOperationException("Utility class"); + } + + public static List subsetRecursion(String str) { + return doRecursion("", str); + } + + private static List doRecursion(String p, String up) { + if (up.isEmpty()) { + List list = new ArrayList<>(); + list.add(p); + return list; + } + + // Taking the character + char ch = up.charAt(0); + // Adding the character in the recursion + List left = doRecursion(p + ch, up.substring(1)); + // Not adding the character in the recursion + List right = doRecursion(p, up.substring(1)); + + left.addAll(right); + + return left; + } +} diff --git a/src/main/java/com/thealgorithms/others/CountSetBits.java b/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java similarity index 97% rename from src/main/java/com/thealgorithms/others/CountSetBits.java rename to src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java index b26f745d4cd7..eb0886e30292 100644 --- a/src/main/java/com/thealgorithms/others/CountSetBits.java +++ b/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java @@ -1,4 +1,4 @@ -package com.thealgorithms.others; +package com.thealgorithms.bitmanipulation; public class CountSetBits { diff --git a/src/main/java/com/thealgorithms/ciphers/HillCipher.java b/src/main/java/com/thealgorithms/ciphers/HillCipher.java index 780009c2f1d6..01b1aeb8bc6c 100644 --- a/src/main/java/com/thealgorithms/ciphers/HillCipher.java +++ b/src/main/java/com/thealgorithms/ciphers/HillCipher.java @@ -1,178 +1,103 @@ package com.thealgorithms.ciphers; -import java.util.Scanner; +public class HillCipher { -/* - * 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 final class HillCipher { - private HillCipher() { - } - - static Scanner userInput = new Scanner(System.in); - - /* Following function encrypts the message - */ - static void encrypt(String message) { - message = message.toUpperCase(); - // Get key matrix - System.out.println("Enter key matrix size"); - int matrixSize = userInput.nextInt(); - System.out.println("Enter Key/encryptionKey matrix "); - int[][] keyMatrix = new int[matrixSize][matrixSize]; - for (int i = 0; i < matrixSize; i++) { - for (int j = 0; j < matrixSize; j++) { - keyMatrix[i][j] = userInput.nextInt(); - } - } - // check if det = 0 + // 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); - int[][] messageVector = new int[matrixSize][1]; - String cipherText = ""; - int[][] cipherMatrix = new int[matrixSize][1]; - int j = 0; - while (j < message.length()) { + StringBuilder cipherText = new StringBuilder(); + int[] messageVector = new int[matrixSize]; + int[] cipherVector = new int[matrixSize]; + int index = 0; + + while (index < message.length()) { for (int i = 0; i < matrixSize; i++) { - if (j >= message.length()) { - messageVector[i][0] = 23; + 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; - int i; - for (i = 0; i < matrixSize; i++) { - cipherMatrix[i][0] = 0; - for (x = 0; x < matrixSize; 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 < matrixSize; 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 = userInput.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] = userInput.nextInt(); - } - } - // check if det = 0 - validateDeterminant(keyMatrix, n); + // 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; - // 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; + 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; - int 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; - int sign = 1; - int p = 0; - int 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) { - 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 = userInput.nextShort(); - if (sc == 1) { - encrypt(message); - } else if (sc == 2) { - decrypt(message); - } else { - System.out.println("Invalid input, program terminated."); - } - } - - static void validateDeterminant(int[][] keyMatrix, int n) { - if (determinant(keyMatrix, n) % 26 == 0) { - System.out.println("Invalid key, as determinant = 0. Program Terminated"); - } - } - - // Driver code - public static void main(String[] args) { - // Get the message to be encrypted - System.out.println("Enter message"); - String message = userInput.nextLine(); - hillCipher(message); - } } 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..c4410d8c77ba --- /dev/null +++ b/src/main/java/com/thealgorithms/ciphers/XORCipher.java @@ -0,0 +1,41 @@ +package com.thealgorithms.ciphers; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.HexFormat; + +/** + * A simple implementation of XOR cipher that, given a key, allows to encrypt and decrypt a plaintext. + * + * @author lcsjunior + * + */ +public final class XORCipher { + + private static final Charset CS_DEFAULT = StandardCharsets.UTF_8; + + private XORCipher() { + } + + 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; + } + + public static String encrypt(final String plainText, final String key) { + byte[] plainTextBytes = plainText.getBytes(CS_DEFAULT); + byte[] keyBytes = key.getBytes(CS_DEFAULT); + byte[] xorResult = xor(plainTextBytes, keyBytes); + return HexFormat.of().formatHex(xorResult); + } + + public static String decrypt(final String cipherText, final String key) { + 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/conversions/IntegerToEnglish.java b/src/main/java/com/thealgorithms/conversions/IntegerToEnglish.java new file mode 100644 index 000000000000..d3b938bf492d --- /dev/null +++ b/src/main/java/com/thealgorithms/conversions/IntegerToEnglish.java @@ -0,0 +1,80 @@ +package com.thealgorithms.conversions; + +import java.util.Map; + +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 < 1000 to english words + */ + private static String convertToWords(int number) { + int remainder = number % 100; + + String result; + + if (remainder <= 20) { + result = BASE_NUMBERS_MAP.get(remainder); + } else if (BASE_NUMBERS_MAP.containsKey(remainder)) { + result = BASE_NUMBERS_MAP.get(remainder); + } else { + int tensDigit = remainder / 10; + int onesDigit = remainder % 10; + + result = String.format("%s %s", BASE_NUMBERS_MAP.get(tensDigit * 10), BASE_NUMBERS_MAP.get(onesDigit)); + } + + int hundredsDigit = number / 100; + + if (hundredsDigit > 0) { + result = String.format("%s %s%s", BASE_NUMBERS_MAP.get(hundredsDigit), BASE_NUMBERS_MAP.get(100), result.isEmpty() ? "" : " " + result); + } + + return result; + } + + /** + Only convert groups of three digit if they are non-zero + */ + 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 (!result.isEmpty()) { + result.insert(0, subResult + " " + THOUSAND_POWER_MAP.get(index) + " "); + } else { + if (index > 0) { + result = new StringBuilder(subResult + " " + THOUSAND_POWER_MAP.get(index)); + } else { + result = new StringBuilder(subResult); + } + } + } + } + + index++; + } + + return result.toString(); + } +} diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java new file mode 100644 index 000000000000..27ad96d71876 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -0,0 +1,251 @@ +package com.thealgorithms.datastructures.graphs; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * The EdmondsBlossomAlgorithm class implements Edmonds' Blossom Algorithm + * to find the maximum matching in a general graph. The algorithm efficiently + * handles cases where the graph contains odd-length cycles by contracting + * "blossoms" and finding augmenting paths. + *

+ * Documentation of Algorithm (Stanford University) + *

+ * Wikipedia Documentation + */ +public final class EdmondsBlossomAlgorithm { + + private EdmondsBlossomAlgorithm() { + } + + private static final int UNMATCHED = -1; // Constant to represent unmatched vertices + + /** + * Finds the maximum matching in a general graph (Edmonds Blossom Algorithm). + * + * @param edges A list of edges in the graph. + * @param vertexCount The number of vertices in the graph. + * @return A list of matched pairs of vertices. + */ + public static List maximumMatching(List edges, int vertexCount) { + List> graph = new ArrayList<>(vertexCount); + + // Initialize each vertex's adjacency list. + for (int i = 0; i < vertexCount; i++) { + graph.add(new ArrayList<>()); + } + + // Populate the graph with the edges + for (int[] edge : edges) { + int u = edge[0]; + int v = edge[1]; + graph.get(u).add(v); + graph.get(v).add(u); + } + + // Initial matching array and auxiliary data structures + int[] match = new int[vertexCount]; + Arrays.fill(match, UNMATCHED); // All vertices are initially unmatched + int[] parent = new int[vertexCount]; + int[] base = new int[vertexCount]; + boolean[] inBlossom = new boolean[vertexCount]; // Indicates if a vertex is part of a blossom + boolean[] inQueue = new boolean[vertexCount]; // Tracks vertices in the BFS queue + + // Main logic for finding maximum matching + for (int u = 0; u < vertexCount; u++) { + if (match[u] == UNMATCHED) { + // BFS initialization + Arrays.fill(parent, UNMATCHED); + for (int i = 0; i < vertexCount; i++) { + base[i] = i; // Each vertex is its own base initially + } + Arrays.fill(inBlossom, false); + Arrays.fill(inQueue, false); + + Queue queue = new LinkedList<>(); + queue.add(u); + inQueue[u] = true; + + boolean augmentingPathFound = false; + + // BFS to find augmenting paths + while (!queue.isEmpty() && !augmentingPathFound) { + int current = queue.poll(); // Use a different name for clarity + for (int y : graph.get(current)) { + // Skip if we are looking at the same edge as the current match + if (match[current] == y) { + continue; + } + + if (base[current] == base[y]) { + continue; // Avoid self-loops + } + + if (parent[y] == UNMATCHED) { + // Case 1: y is unmatched, we've found an augmenting path + if (match[y] == UNMATCHED) { + parent[y] = current; + augmentingPathFound = true; + updateMatching(match, parent, y); // Augment along this path + break; + } + + // Case 2: y is matched, add y's match to the queue + int z = match[y]; + parent[y] = current; + parent[z] = y; + if (!inQueue[z]) { + queue.add(z); + inQueue[z] = true; + } + } else { + // Case 3: Both x and y have a parent; check for a cycle/blossom + int baseU = findBase(base, parent, current, y); + if (baseU != UNMATCHED) { + contractBlossom(new BlossomData(new BlossomAuxData(queue, parent, base, inBlossom, match, inQueue), current, y, baseU)); + } + } + } + } + } + } + + // Create result list of matched pairs + List matchingResult = new ArrayList<>(); + for (int v = 0; v < vertexCount; v++) { + if (match[v] != UNMATCHED && v < match[v]) { + matchingResult.add(new int[] {v, match[v]}); + } + } + + return matchingResult; + } + + /** + * Updates the matching along the augmenting path found. + * + * @param match The matching array. + * @param parent The parent array used during the BFS. + * @param u The starting node of the augmenting path. + */ + private static void updateMatching(int[] match, int[] parent, int u) { + while (u != UNMATCHED) { + int v = parent[u]; + int next = match[v]; + match[v] = u; + match[u] = v; + u = next; + } + } + + /** + * Finds the base of a node in the blossom. + * + * @param base The base array. + * @param parent The parent array. + * @param u One end of the edge. + * @param v The other end of the edge. + * @return The base of the node or UNMATCHED. + */ + private static int findBase(int[] base, int[] parent, int u, int v) { + boolean[] visited = new boolean[base.length]; + + // Mark ancestors of u + int currentU = u; + while (true) { + currentU = base[currentU]; // Move assignment out of the condition + visited[currentU] = true; + if (parent[currentU] == UNMATCHED) { + break; + } + currentU = parent[currentU]; // Move assignment out of the condition + } + + // Find the common ancestor of v + int currentV = v; + while (true) { + currentV = base[currentV]; // Move assignment out of the condition + if (visited[currentV]) { + return currentV; + } + currentV = parent[currentV]; // Move assignment out of the condition + } + } + + /** + * Contracts a blossom and updates the base array. + * + * @param blossomData The data containing the parameters related to the blossom contraction. + */ + private static void contractBlossom(BlossomData blossomData) { + for (int x = blossomData.u; blossomData.auxData.base[x] != blossomData.lca; x = blossomData.auxData.parent[blossomData.auxData.match[x]]) { + int baseX = blossomData.auxData.base[x]; + int matchBaseX = blossomData.auxData.base[blossomData.auxData.match[x]]; + + // Split the inner assignment into two separate assignments + blossomData.auxData.inBlossom[baseX] = true; + blossomData.auxData.inBlossom[matchBaseX] = true; + } + + for (int x = blossomData.v; blossomData.auxData.base[x] != blossomData.lca; x = blossomData.auxData.parent[blossomData.auxData.match[x]]) { + int baseX = blossomData.auxData.base[x]; + int matchBaseX = blossomData.auxData.base[blossomData.auxData.match[x]]; + + // Split the inner assignment into two separate assignments + blossomData.auxData.inBlossom[baseX] = true; + blossomData.auxData.inBlossom[matchBaseX] = true; + } + + // Update the base for all marked vertices + for (int i = 0; i < blossomData.auxData.base.length; i++) { + if (blossomData.auxData.inBlossom[blossomData.auxData.base[i]]) { + blossomData.auxData.base[i] = blossomData.lca; // Contract to the lowest common ancestor + if (!blossomData.auxData.inQueue[i]) { + blossomData.auxData.queue.add(i); // Add to queue if not already present + blossomData.auxData.inQueue[i] = true; + } + } + } + } + + /** + * Auxiliary data class to encapsulate common parameters for the blossom operations. + */ + static class BlossomAuxData { + Queue queue; // Queue for BFS traversal + int[] parent; // Parent array to store the paths + int[] base; // Base array to track the base of each vertex + boolean[] inBlossom; // Flags to indicate if a vertex is in a blossom + int[] match; // Array to store matches for each vertex + boolean[] inQueue; // Flags to track vertices in the BFS queue + + BlossomAuxData(Queue queue, int[] parent, int[] base, boolean[] inBlossom, int[] match, boolean[] inQueue) { + this.queue = queue; + this.parent = parent; + this.base = base; + this.inBlossom = inBlossom; + this.match = match; + this.inQueue = inQueue; + } + } + + /** + * BlossomData class with reduced parameters. + */ + static class BlossomData { + BlossomAuxData auxData; // Use the auxiliary data class + int u; // One vertex in the edge + int v; // Another vertex in the edge + int lca; // Lowest Common Ancestor + + BlossomData(BlossomAuxData auxData, int u, int v, int lca) { + this.auxData = auxData; + this.u = u; + this.v = v; + this.lca = lca; + } + } +} diff --git a/src/main/java/com/thealgorithms/datastructures/lists/SortedLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/SortedLinkedList.java new file mode 100644 index 000000000000..4cf782679b7c --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/lists/SortedLinkedList.java @@ -0,0 +1,141 @@ +package com.thealgorithms.datastructures.lists; + +import java.util.ArrayList; +import java.util.List; + +/** + * A SortedLinkedList is a data structure that maintains a sorted list of elements. + * Elements are ordered based on their natural ordering or by a Comparator provided at the time of creation. + * This implementation uses a singly linked list to store the elements. + * Further details can be found on this link + * https://runestone.academy/ns/books/published/cppds/LinearLinked/ImplementinganOrderedList.html + */ +public class SortedLinkedList { + private Node head; + private Node tail; + + public SortedLinkedList() { + this.head = null; + this.tail = null; + } + + /** + * Inserts a new element into the sorted linked list. + * @param value the value to be inserted + */ + public void insert(int value) { + Node newNode = new Node(value); + if (head == null) { + this.head = newNode; + this.tail = newNode; + } else if (value < head.value) { + newNode.next = this.head; + this.head = newNode; + } else if (value > tail.value) { + this.tail.next = newNode; + this.tail = newNode; + } else { + Node temp = head; + while (temp.next != null && temp.next.value < value) { + temp = temp.next; + } + newNode.next = temp.next; + temp.next = newNode; + if (newNode.next == null) { + this.tail = newNode; + } + } + } + + /** + * Displays the elements of the sorted linked list. + */ + public void display() { + System.out.println(this.toString()); + } + + /** + * Deletes the first occurrence of the specified element in the sorted linked list. + * @param value the value to be deleted + * @return true if the element is found and deleted, false otherwise + */ + public boolean delete(int value) { + if (this.head == null) { + return false; + } else if (this.head.value == value) { + if (this.head.next == null) { + this.head = null; + this.tail = null; + } else { + this.head = this.head.next; + } + return true; + } else { + Node temp = this.head; + while (temp.next != null) { + if (temp.next.value == value) { + if (temp.next == this.tail) { + this.tail = temp; + } + temp.next = temp.next.next; + return true; + } + temp = temp.next; + } + return false; + } + } + + /** + * Searches for the specified element in the sorted linked list. + * @param value the value to be searched + * @return true if the element is found, false otherwise + */ + public boolean search(int value) { + Node temp = this.head; + while (temp != null) { + if (temp.value == value) { + return true; + } + temp = temp.next; + } + return false; + } + + /** + * Checks if the sorted linked list is empty. + * @return true if the list is empty, false otherwise + */ + public boolean isEmpty() { + return head == null; + } + /** + * Returns a string representation of the sorted linked list. + * @return a string representation of the sorted linked list + */ + @Override + public String toString() { + if (this.head != null) { + List elements = new ArrayList<>(); + Node temp = this.head; + while (temp != null) { + elements.add(String.valueOf(temp.value)); + temp = temp.next; + } + return "[" + String.join(", ", elements) + "]"; + + } else { + return "[]"; + } + } + + public final class Node { + public final int value; + public Node next; + + public Node(int value) { + this.value = value; + this.next = null; + } + } +} diff --git a/src/main/java/com/thealgorithms/datastructures/lists/SwapNodes.java b/src/main/java/com/thealgorithms/datastructures/lists/SwapNodes.java new file mode 100644 index 000000000000..d6204455a047 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/lists/SwapNodes.java @@ -0,0 +1,96 @@ +// Java program to swap the nodes of a linked list rather +// than swapping the data from the nodes. +class Node { + int data; + Node next; + + Node(int data) { + this.data = data; + this.next = null; + } +} + +public class SwapNodes { + + // Function to swap nodes x and y in linked list by changing links + static Node swapNodes(Node head, int x, int y) { + + // Nothing to do if x and y are the same + if (x == y) { + return head; + } + + Node prevX = null, currX = null; + Node prevY = null, currY = null; + Node curr = head; + + // First loop to find x + while (curr != null) { + if (curr.data == x) { + currX = curr; + break; + } + prevX = curr; + curr = curr.next; + } + + curr = head; + + // Second loop to find y + while (curr != null) { + if (curr.data == y) { + currY = curr; + break; + } + prevY = curr; + curr = curr.next; + } + + // If either x or y is not present, nothing to do + if (currX == null || currY == null) { + return head; + } + + // If x is not head of the linked list + if (prevX != null) { + prevX.next = currY; + } else { + head = currY; + } + + // If y is not head of the linked list + if (prevY != null) { + prevY.next = currX; + } else { + head = currX; + } + + // Swap next pointers + Node temp = currY.next; + currY.next = currX.next; + currX.next = temp; + + return head; + } + + static void printList(Node curr) { + while (curr != null) { + System.out.print(curr.data + " "); + curr = curr.next; + } + System.out.println(); + } + + public static void main(String[] args) { + + // Constructed linked list: 1->2->3->4->5 + Node head = new Node(1); + head.next = new Node(2); + head.next.next = new Node(3); + head.next.next.next = new Node(4); + head.next.next.next.next = new Node(5); + + head = swapNodes(head, 4, 3); + printList(head); + } +} diff --git a/src/main/java/com/thealgorithms/datastructures/trees/TrieImp.java b/src/main/java/com/thealgorithms/datastructures/trees/TrieImp.java index d166653ff1b4..a43a454146cb 100644 --- a/src/main/java/com/thealgorithms/datastructures/trees/TrieImp.java +++ b/src/main/java/com/thealgorithms/datastructures/trees/TrieImp.java @@ -1,19 +1,35 @@ package com.thealgorithms.datastructures.trees; -import java.util.Scanner; - /** - * Trie Data structure implementation without any libraries + * Trie Data structure implementation without any libraries. + *

+ * The Trie (also known as a prefix tree) is a special tree-like data structure + * that is used to store a dynamic set or associative array where the keys are + * usually strings. It is highly efficient for prefix-based searches. + *

+ * This implementation supports basic Trie operations like insertion, search, + * and deletion. + *

+ * Each node of the Trie represents a character and has child nodes for each + * possible character. * * @author Dheeraj Kumar Barnwal */ public class TrieImp { + /** + * Represents a Trie Node that stores a character and pointers to its children. + * Each node has an array of 26 children (one for each letter from 'a' to 'z'). + */ public class TrieNode { TrieNode[] child; boolean end; + /** + * Constructor to initialize a TrieNode with an empty child array + * and set end to false. + */ public TrieNode() { child = new TrieNode[26]; end = false; @@ -22,10 +38,22 @@ public TrieNode() { private final TrieNode root; + /** + * Constructor to initialize the Trie. + * The root node is created but doesn't represent any character. + */ public TrieImp() { root = new TrieNode(); } + /** + * Inserts a word into the Trie. + *

+ * The method traverses the Trie from the root, character by character, and adds + * nodes if necessary. It marks the last node of the word as an end node. + * + * @param word The word to be inserted into the Trie. + */ public void insert(String word) { TrieNode currentNode = root; for (int i = 0; i < word.length(); i++) { @@ -39,6 +67,16 @@ public void insert(String word) { currentNode.end = true; } + /** + * Searches for a word in the Trie. + *

+ * This method traverses the Trie based on the input word and checks whether + * the word exists. It returns true if the word is found and its end flag is + * true. + * + * @param word The word to search in the Trie. + * @return true if the word exists in the Trie, false otherwise. + */ public boolean search(String word) { TrieNode currentNode = root; for (int i = 0; i < word.length(); i++) { @@ -52,6 +90,17 @@ public boolean search(String word) { return currentNode.end; } + /** + * Deletes a word from the Trie. + *

+ * The method traverses the Trie to find the word and marks its end flag as + * false. + * It returns true if the word was successfully deleted, false if the word + * wasn't found. + * + * @param word The word to be deleted from the Trie. + * @return true if the word was found and deleted, false if it was not found. + */ public boolean delete(String word) { TrieNode currentNode = root; for (int i = 0; i < word.length(); i++) { @@ -69,75 +118,26 @@ public boolean delete(String word) { return false; } + /** + * Helper method to print a string to the console. + * + * @param print The string to be printed. + */ public static void sop(String print) { System.out.println(print); } /** - * Regex to check if word contains only a-z character + * Validates if a given word contains only lowercase alphabetic characters + * (a-z). + *

+ * The method uses a regular expression to check if the word matches the pattern + * of only lowercase letters. + * + * @param word The word to be validated. + * @return true if the word is valid (only a-z), false otherwise. */ public static boolean isValid(String word) { return word.matches("^[a-z]+$"); } - - public static void main(String[] args) { - TrieImp obj = new TrieImp(); - String word; - @SuppressWarnings("resource") Scanner scan = new Scanner(System.in); - sop("string should contain only a-z character for all operation"); - while (true) { - sop("1. Insert\n2. Search\n3. Delete\n4. Quit"); - try { - int t = scan.nextInt(); - switch (t) { - case 1: - word = scan.next(); - if (isValid(word)) { - obj.insert(word); - } else { - sop("Invalid string: allowed only a-z"); - } - break; - case 2: - word = scan.next(); - boolean resS = false; - if (isValid(word)) { - resS = obj.search(word); - } else { - sop("Invalid string: allowed only a-z"); - } - if (resS) { - sop("word found"); - } else { - sop("word not found"); - } - break; - case 3: - word = scan.next(); - boolean resD = false; - if (isValid(word)) { - resD = obj.delete(word); - } else { - sop("Invalid string: allowed only a-z"); - } - if (resD) { - sop("word got deleted successfully"); - } else { - sop("word not found"); - } - break; - case 4: - sop("Quit successfully"); - System.exit(1); - break; - default: - sop("Input int from 1-4"); - break; - } - } catch (Exception e) { - String badInput = scan.next(); - sop("This is bad input: " + badInput); - } - } - } } diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequence.java b/src/main/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequence.java new file mode 100644 index 000000000000..b5ac62b4674b --- /dev/null +++ b/src/main/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequence.java @@ -0,0 +1,42 @@ +package com.thealgorithms.dynamicprogramming; + +import java.util.HashMap; + +final class LongestArithmeticSubsequence { + private LongestArithmeticSubsequence() { + } + + /** + * Returns the length of the longest arithmetic subsequence in the given array. + * + * A sequence seq is arithmetic if seq[i + 1] - seq[i] are all the same value + * (for 0 <= i < seq.length - 1). + * + * @param nums the input array of integers + * @return the length of the longest arithmetic subsequence + */ + public static int getLongestArithmeticSubsequenceLength(int[] nums) { + if (nums == null) { + throw new IllegalArgumentException("Input array cannot be null"); + } + + if (nums.length <= 1) { + return nums.length; + } + + HashMap[] dp = new HashMap[nums.length]; + int maxLength = 2; + + // fill the dp array + for (int i = 0; i < nums.length; i++) { + dp[i] = new HashMap<>(); + for (int j = 0; j < i; j++) { + final int diff = nums[i] - nums[j]; + dp[i].put(diff, dp[j].getOrDefault(diff, 1) + 1); + maxLength = Math.max(maxLength, dp[i].get(diff)); + } + } + + return maxLength; + } +} diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequence.java b/src/main/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequence.java index 2d1fa1d1153f..54837b5f4e71 100644 --- a/src/main/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequence.java +++ b/src/main/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequence.java @@ -1,73 +1,98 @@ package com.thealgorithms.dynamicprogramming; +/** + * This class implements the Longest Common Subsequence (LCS) problem. + * The LCS of two sequences is the longest sequence that appears in both + * sequences + * in the same order, but not necessarily consecutively. + * + * This implementation uses dynamic programming to find the LCS of two strings. + */ final class LongestCommonSubsequence { + private LongestCommonSubsequence() { } + /** + * Returns the Longest Common Subsequence (LCS) of two given strings. + * + * @param str1 The first string. + * @param str2 The second string. + * @return The LCS of the two strings, or null if one of the strings is null. + */ public static String getLCS(String str1, String str2) { - // At least one string is null + // If either string is null, return null as LCS can't be computed. if (str1 == null || str2 == null) { return null; } - - // At least one string is empty + // If either string is empty, return an empty string as LCS. if (str1.length() == 0 || str2.length() == 0) { return ""; } + // Convert the strings into arrays of characters String[] arr1 = str1.split(""); String[] arr2 = str2.split(""); - // lcsMatrix[i][j] = LCS of first i elements of arr1 and first j characters of arr2 + // lcsMatrix[i][j] = LCS(first i characters of str1, first j characters of str2) int[][] lcsMatrix = new int[arr1.length + 1][arr2.length + 1]; + // Base Case: Fill the LCS matrix 0th row & 0th column with 0s + // as LCS of any string with an empty string is 0. for (int i = 0; i < arr1.length + 1; i++) { lcsMatrix[i][0] = 0; } for (int j = 1; j < arr2.length + 1; j++) { lcsMatrix[0][j] = 0; } + + // Build the LCS matrix by comparing characters of str1 & str2 for (int i = 1; i < arr1.length + 1; i++) { for (int j = 1; j < arr2.length + 1; j++) { + // If characters match, the LCS increases by 1 if (arr1[i - 1].equals(arr2[j - 1])) { lcsMatrix[i][j] = lcsMatrix[i - 1][j - 1] + 1; } else { + // Otherwise, take the maximum of the left or above values lcsMatrix[i][j] = Math.max(lcsMatrix[i - 1][j], lcsMatrix[i][j - 1]); } } } + + // Call helper function to reconstruct the LCS from the matrix return lcsString(str1, str2, lcsMatrix); } + /** + * Reconstructs the LCS string from the LCS matrix. + * + * @param str1 The first string. + * @param str2 The second string. + * @param lcsMatrix The matrix storing the lengths of LCSs + * of substrings of str1 and str2. + * @return The LCS string. + */ public static String lcsString(String str1, String str2, int[][] lcsMatrix) { - StringBuilder lcs = new StringBuilder(); - int i = str1.length(); - int j = str2.length(); + StringBuilder lcs = new StringBuilder(); // Hold the LCS characters. + int i = str1.length(); // Start from the end of str1. + int j = str2.length(); // Start from the end of str2. + + // Trace back through the LCS matrix to reconstruct the LCS while (i > 0 && j > 0) { + // If characters match, add to the LCS and move diagonally in the matrix if (str1.charAt(i - 1) == str2.charAt(j - 1)) { lcs.append(str1.charAt(i - 1)); i--; j--; } else if (lcsMatrix[i - 1][j] > lcsMatrix[i][j - 1]) { + // If the value above is larger, move up i--; } else { + // If the value to the left is larger, move left j--; } } - return lcs.reverse().toString(); - } - public static void main(String[] args) { - String str1 = "DSGSHSRGSRHTRD"; - String str2 = "DATRGAGTSHS"; - String lcs = getLCS(str1, str2); - - // Print LCS - if (lcs != null) { - System.out.println("String 1: " + str1); - System.out.println("String 2: " + str2); - System.out.println("LCS: " + lcs); - System.out.println("LCS length: " + lcs.length()); - } + return lcs.reverse().toString(); // LCS built in reverse, so reverse it back } } diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/SumOfSubset.java b/src/main/java/com/thealgorithms/dynamicprogramming/SumOfSubset.java index dd48008bd21e..e9c15c1b4f24 100644 --- a/src/main/java/com/thealgorithms/dynamicprogramming/SumOfSubset.java +++ b/src/main/java/com/thealgorithms/dynamicprogramming/SumOfSubset.java @@ -1,9 +1,35 @@ package com.thealgorithms.dynamicprogramming; +/** + * A utility class that contains the Sum of Subset problem solution using + * recursion. + * + * The Sum of Subset problem determines whether a subset of elements from a + * given array sums up to a specific target value. + * + * Wikipedia: https://en.wikipedia.org/wiki/Subset_sum_problem + */ public final class SumOfSubset { + private SumOfSubset() { } + /** + * Determines if there exists a subset of elements in the array `arr` that + * adds up to the given `key` value using recursion. + * + * @param arr The array of integers. + * @param num The index of the current element being considered. + * @param key The target sum we are trying to achieve. + * @return true if a subset of `arr` adds up to `key`, false otherwise. + * + * This is a recursive solution that checks for two possibilities at + * each step: + * 1. Include the current element in the subset and check if the + * remaining elements can sum up to the remaining target. + * 2. Exclude the current element and check if the remaining elements + * can sum up to the target without this element. + */ public static boolean subsetSum(int[] arr, int num, int key) { if (key == 0) { return true; @@ -14,7 +40,6 @@ public static boolean subsetSum(int[] arr, int num, int key) { boolean include = subsetSum(arr, num - 1, key - arr[num]); boolean exclude = subsetSum(arr, num - 1, key); - return include || exclude; } } diff --git a/src/main/java/com/thealgorithms/greedyalgorithms/DigitSeparation.java b/src/main/java/com/thealgorithms/greedyalgorithms/DigitSeparation.java new file mode 100644 index 000000000000..bee5f98cd2ee --- /dev/null +++ b/src/main/java/com/thealgorithms/greedyalgorithms/DigitSeparation.java @@ -0,0 +1,40 @@ +package com.thealgorithms.greedyalgorithms; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * This class provides methods to separate the digits of a large positive number into a list. + */ +public class DigitSeparation { + public DigitSeparation() { + } + /** + * Separates the digits of a large positive number into a list in reverse order. + * @param largeNumber The large number to separate digits from. + * @return A list of digits in reverse order. + */ + public List digitSeparationReverseOrder(long largeNumber) { + List result = new ArrayList<>(); + if (largeNumber != 0) { + while (largeNumber != 0) { + result.add(Math.abs(largeNumber % 10)); + largeNumber = largeNumber / 10; + } + } else { + result.add(0L); + } + return result; + } + /** + * Separates the digits of a large positive number into a list in forward order. + * @param largeNumber The large number to separate digits from. + * @return A list of digits in forward order. + */ + public List digitSeparationForwardOrder(long largeNumber) { + List result = this.digitSeparationReverseOrder(largeNumber); + Collections.reverse(result); + return result; + } +} diff --git a/src/main/java/com/thealgorithms/greedyalgorithms/MergeIntervals.java b/src/main/java/com/thealgorithms/greedyalgorithms/MergeIntervals.java new file mode 100644 index 000000000000..07bd0b73326f --- /dev/null +++ b/src/main/java/com/thealgorithms/greedyalgorithms/MergeIntervals.java @@ -0,0 +1,64 @@ +package com.thealgorithms.greedyalgorithms; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Problem Statement: + * Given an array of intervals where intervals[i] = [starti, endi]. + * + * Merge all overlapping intervals and return an array of the non-overlapping + * intervals + * that cover all the intervals in the input. + */ +public final class MergeIntervals { + + /** + * Private constructor to prevent instantiation of this utility class. + */ + private MergeIntervals() { + } + + /** + * Merges overlapping intervals from the given array of intervals. + * + * The method sorts the intervals by their start time, then iterates through the + * sorted intervals + * and merges overlapping intervals. If an interval overlaps with the last + * merged interval, + * it updates the end time of the last merged interval. Otherwise, it adds the + * interval as a new entry. + * + * @param intervals A 2D array representing intervals where each element is an + * interval [starti, endi]. + * @return A 2D array of merged intervals where no intervals overlap. + * + * Example: + * Input: {{1, 3}, {2, 6}, {8, 10}, {15, 18}} + * Output: {{1, 6}, {8, 10}, {15, 18}} + */ + public static int[][] merge(int[][] intervals) { + // Sort the intervals by their start time (ascending order) + Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0])); + + // List to store merged intervals + List merged = new ArrayList<>(); + + for (int[] interval : intervals) { // Each interval + // If the merged list is empty or the current interval does not overlap with + // the last merged interval, add it to the merged list. + if (merged.isEmpty() || interval[0] > merged.get(merged.size() - 1)[1]) { + merged.add(interval); + } else { + // If there is an overlap, merge the intervals by updating the end time + // of the last merged interval to the maximum end time between the two + // intervals. + merged.get(merged.size() - 1)[1] = Math.max(merged.get(merged.size() - 1)[1], interval[1]); + } + } + + // Convert the list of merged intervals back to a 2D array and return it + return merged.toArray(new int[merged.size()][]); + } +} diff --git a/src/main/java/com/thealgorithms/misc/Sort012D.java b/src/main/java/com/thealgorithms/misc/Sort012D.java deleted file mode 100644 index 706e877e40c1..000000000000 --- a/src/main/java/com/thealgorithms/misc/Sort012D.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.thealgorithms.misc; - -import java.util.Scanner; - -/** - * The array is divided into four sections: a[1..Lo-1] zeroes a[Lo..Mid-1] ones - * a[Mid..Hi] unknown a[Hi+1..N] twos If array [mid] =0, then swap array [mid] - * with array [low] and increment both pointers once. If array [mid] = 1, then - * no swapping is required. Increment mid pointer once. If array [mid] = 2, then - * we swap array [mid] with array [high] and decrement the high pointer once. - * For more information on the Dutch national flag algorithm refer - * https://en.wikipedia.org/wiki/Dutch_national_flag_problem - */ -public final class Sort012D { - private Sort012D() { - } - - public static void main(String[] args) { - Scanner np = new Scanner(System.in); - int n = np.nextInt(); - int[] a = new int[n]; - for (int i = 0; i < n; i++) { - a[i] = np.nextInt(); - } - sort012(a); - np.close(); - } - - public static void sort012(int[] a) { - int l = 0; - int h = a.length - 1; - int mid = 0; - int temp; - while (mid <= h) { - switch (a[mid]) { - case 0: - temp = a[l]; - a[l] = a[mid]; - a[mid] = temp; - l++; - mid++; - break; - - case 1: - mid++; - break; - case 2: - temp = a[mid]; - a[mid] = a[h]; - a[h] = temp; - h--; - break; - - default: - throw new IllegalArgumentException("Unexpected value: " + a[mid]); - } - } - System.out.println("the Sorted array is "); - for (int i = 0; i < a.length; i++) { - System.out.print(+a[i] + " "); - } - } -} diff --git a/src/test/java/com/thealgorithms/others/ArrayRightRotation.java b/src/main/java/com/thealgorithms/others/ArrayRightRotation.java similarity index 52% rename from src/test/java/com/thealgorithms/others/ArrayRightRotation.java rename to src/main/java/com/thealgorithms/others/ArrayRightRotation.java index 11e4f44500b1..125edadb6e73 100644 --- a/src/test/java/com/thealgorithms/others/ArrayRightRotation.java +++ b/src/main/java/com/thealgorithms/others/ArrayRightRotation.java @@ -1,8 +1,23 @@ package com.thealgorithms.others; +/** + * Provides a method to perform a right rotation on an array. + * A left rotation operation shifts each element of the array + * by a specified number of positions to the right. + * + * https://en.wikipedia.org/wiki/Right_rotation * + */ public final class ArrayRightRotation { private ArrayRightRotation() { } + + /** + * Performs a right rotation on the given array by the specified number of positions. + * + * @param arr the array to be rotated + * @param k the number of positions to rotate the array to the left + * @return a new array containing the elements of the input array rotated to the left + */ public static int[] rotateRight(int[] arr, int k) { if (arr == null || arr.length == 0 || k < 0) { throw new IllegalArgumentException("Invalid input"); @@ -18,6 +33,12 @@ public static int[] rotateRight(int[] arr, int k) { return arr; } + /** + * Performs reversing of a array + * @param arr the array to be reversed + * @param start starting position + * @param end ending position + */ private static void reverseArray(int[] arr, int start, int end) { while (start < end) { int temp = arr[start]; diff --git a/src/main/java/com/thealgorithms/others/Sudoku.java b/src/main/java/com/thealgorithms/others/Sudoku.java index 0839a376c5de..0e88aee46f4d 100644 --- a/src/main/java/com/thealgorithms/others/Sudoku.java +++ b/src/main/java/com/thealgorithms/others/Sudoku.java @@ -1,33 +1,47 @@ package com.thealgorithms.others; +/** + * A class that provides methods to solve Sudoku puzzles of any n x n size + * using a backtracking approach, where n must be a perfect square. + * The algorithm checks for safe number placements in rows, columns, + * and subgrids (which are sqrt(n) x sqrt(n) in size) and recursively solves the puzzle. + * Though commonly used for 9x9 grids, it is adaptable to other valid Sudoku dimensions. + */ final class Sudoku { + private Sudoku() { } + /** + * Checks if placing a number in a specific position on the Sudoku board is safe. + * The number is considered safe if it does not violate any of the Sudoku rules: + * - It should not be present in the same row. + * - It should not be present in the same column. + * - It should not be present in the corresponding 3x3 subgrid. + * - It should not be present in the corresponding subgrid, which is sqrt(n) x sqrt(n) in size (e.g., for a 9x9 grid, the subgrid will be 3x3). + * + * @param board The current state of the Sudoku board. + * @param row The row index where the number is to be placed. + * @param col The column index where the number is to be placed. + * @param num The number to be placed on the board. + * @return True if the placement is safe, otherwise false. + */ public static boolean isSafe(int[][] board, int row, int col, int num) { - // Row has the unique (row-clash) + // Check the row for duplicates for (int d = 0; d < board.length; d++) { - // Check if the number we are trying to - // place is already present in - // that row, return false; if (board[row][d] == num) { return false; } } - // Column has the unique numbers (column-clash) + // Check the column for duplicates for (int r = 0; r < board.length; r++) { - // Check if the number - // we are trying to - // place is already present in - // that column, return false; if (board[r][col] == num) { return false; } } - // Corresponding square has - // unique number (box-clash) + // Check the corresponding 3x3 subgrid for duplicates int sqrt = (int) Math.sqrt(board.length); int boxRowStart = row - row % sqrt; int boxColStart = col - col % sqrt; @@ -40,22 +54,37 @@ public static boolean isSafe(int[][] board, int row, int col, int num) { } } - // if there is no clash, it's safe return true; } + /** + * Solves the Sudoku puzzle using backtracking. + * The algorithm finds an empty cell and tries placing numbers + * from 1 to n, where n is the size of the board + * (for example, from 1 to 9 in a standard 9x9 Sudoku). + * The algorithm finds an empty cell and tries placing numbers from 1 to 9. + * The standard version of Sudoku uses numbers from 1 to 9, so the algorithm can be + * easily modified for other variations of the game. + * If a number placement is valid (checked via `isSafe`), the number is + * placed and the function recursively attempts to solve the rest of the puzzle. + * If no solution is possible, the number is removed (backtracked), + * and the process is repeated. + * + * @param board The current state of the Sudoku board. + * @param n The size of the Sudoku board (typically 9 for a standard puzzle). + * @return True if the Sudoku puzzle is solvable, false otherwise. + */ public static boolean solveSudoku(int[][] board, int n) { int row = -1; int col = -1; boolean isEmpty = true; + + // Find the next empty cell for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (board[i][j] == 0) { row = i; col = j; - - // We still have some remaining - // missing values in Sudoku isEmpty = false; break; } @@ -70,12 +99,12 @@ public static boolean solveSudoku(int[][] board, int n) { return true; } - // Else for each-row backtrack + // Try placing numbers 1 to n in the empty cell (n should be a perfect square) + // Eg: n=9 for a standard 9x9 Sudoku puzzle, n=16 for a 16x16 puzzle, etc. for (int num = 1; num <= n; num++) { if (isSafe(board, row, col, num)) { board[row][col] = num; if (solveSudoku(board, n)) { - // print(board, n); return true; } else { // replace it @@ -86,8 +115,17 @@ public static boolean solveSudoku(int[][] board, int n) { return false; } + /** + * Prints the current state of the Sudoku board in a readable format. + * Each row is printed on a new line, with numbers separated by spaces. + * + * @param board The current state of the Sudoku board. + * @param n The size of the Sudoku board (typically 9 for a standard puzzle). + */ public static void print(int[][] board, int n) { - // We got the answer, just print it + // Print the board in a nxn grid format + // if n=9, print the board in a 9x9 grid format + // if n=16, print the board in a 16x16 grid format for (int r = 0; r < n; r++) { for (int d = 0; d < n; d++) { System.out.print(board[r][d]); @@ -101,7 +139,13 @@ public static void print(int[][] board, int n) { } } - // Driver Code + /** + * The driver method to demonstrate solving a Sudoku puzzle. + * A sample 9x9 Sudoku puzzle is provided, and the program attempts to solve it + * using the `solveSudoku` method. If a solution is found, it is printed to the console. + * + * @param args Command-line arguments (not used in this program). + */ public static void main(String[] args) { int[][] board = new int[][] { {3, 0, 6, 5, 0, 8, 4, 0, 0}, @@ -117,7 +161,6 @@ public static void main(String[] args) { int n = board.length; if (solveSudoku(board, n)) { - // print solution print(board, n); } else { System.out.println("No solution"); diff --git a/src/main/java/com/thealgorithms/searches/BinarySearch2dArray.java b/src/main/java/com/thealgorithms/searches/BinarySearch2dArray.java index 53f5d7c8434e..aa938447b864 100644 --- a/src/main/java/com/thealgorithms/searches/BinarySearch2dArray.java +++ b/src/main/java/com/thealgorithms/searches/BinarySearch2dArray.java @@ -1,87 +1,127 @@ package com.thealgorithms.searches; -/* -To apply this method, the provided array must be strictly sorted. In this method, two pointers, one -at 0th row & the other at the last row are taken & the searching is done on the basis of the middle -element of the middle column. If that element is equal to target, its coordinates are returned, else -if it is smaller than the target, the rows above that element are ignored (because the elements -above it will also be smaller than the target), else that element is greater than the target, then -the rows below it are ignored. +/** + * This class provides a method to search for a target value in a 2D sorted + * array. + * The search is performed using a combination of binary search on rows and + * columns. + * The 2D array must be strictly sorted in both rows and columns. + * + * The algorithm works by: + * 1. Performing a binary search on the middle column of the 2D array. + * 2. Depending on the value found, it eliminates rows above or below the middle + * element. + * 3. After finding or eliminating rows, it further applies binary search in the + * relevant columns. */ public final class BinarySearch2dArray { + private BinarySearch2dArray() { } + /** + * Performs a binary search on a 2D sorted array to find the target value. + * The array must be sorted in ascending order in both rows and columns. + * + * @param arr The 2D array to search in. + * @param target The value to search for. + * @return An array containing the row and column indices of the target, or [-1, + * -1] if the target is not found. + */ static int[] binarySearch(int[][] arr, int target) { int rowCount = arr.length; int colCount = arr[0].length; + // Edge case: If there's only one row, search that row directly. if (rowCount == 1) { return binarySearch(arr, target, 0, 0, colCount); } + // Set initial boundaries for binary search on rows. int startRow = 0; int endRow = rowCount - 1; - int midCol = colCount / 2; + int midCol = colCount / 2; // Middle column index for comparison. + // Perform binary search on rows based on the middle column. while (startRow < endRow - 1) { - int midRow = startRow + (endRow - startRow) / 2; // getting the index of middle row + int midRow = startRow + (endRow - startRow) / 2; + // If the middle element matches the target, return its position. if (arr[midRow][midCol] == target) { return new int[] {midRow, midCol}; - } else if (arr[midRow][midCol] < target) { + } + // If the middle element is smaller than the target, discard the upper half. + else if (arr[midRow][midCol] < target) { startRow = midRow; - } else { + } + // If the middle element is larger than the target, discard the lower half. + else { endRow = midRow; } } - /* - if the above search fails to find the target element, these conditions will be used to - find the target element, which further uses the binary search algorithm in the places - which were left unexplored. - */ + + // If the target wasn't found during the row search, check the middle column of + // startRow and endRow. if (arr[startRow][midCol] == target) { - return new int[] { - startRow, - midCol, - }; + return new int[] {startRow, midCol}; } if (arr[endRow][midCol] == target) { return new int[] {endRow, midCol}; } + // If target is smaller than the element in the left of startRow, perform a + // binary search on the left of startRow. if (target <= arr[startRow][midCol - 1]) { return binarySearch(arr, target, startRow, 0, midCol - 1); } + // If target is between midCol and the last column of startRow, perform a binary + // search on that part of the row. if (target >= arr[startRow][midCol + 1] && target <= arr[startRow][colCount - 1]) { return binarySearch(arr, target, startRow, midCol + 1, colCount - 1); } + // If target is smaller than the element in the left of endRow, perform a binary + // search on the left of endRow. if (target <= arr[endRow][midCol - 1]) { return binarySearch(arr, target, endRow, 0, midCol - 1); } else { + // Otherwise, search on the right of endRow. return binarySearch(arr, target, endRow, midCol + 1, colCount - 1); } } + /** + * Performs a binary search on a specific row of the 2D array. + * + * @param arr The 2D array to search in. + * @param target The value to search for. + * @param row The row index where the target will be searched. + * @param colStart The starting column index for the search. + * @param colEnd The ending column index for the search. + * @return An array containing the row and column indices of the target, or [-1, + * -1] if the target is not found. + */ static int[] binarySearch(int[][] arr, int target, int row, int colStart, int colEnd) { + // Perform binary search within the specified column range. while (colStart <= colEnd) { int midIndex = colStart + (colEnd - colStart) / 2; + // If the middle element matches the target, return its position. if (arr[row][midIndex] == target) { - return new int[] { - row, - midIndex, - }; - } else if (arr[row][midIndex] < target) { + return new int[] {row, midIndex}; + } + // If the middle element is smaller than the target, move to the right half. + else if (arr[row][midIndex] < target) { colStart = midIndex + 1; - } else { + } + // If the middle element is larger than the target, move to the left half. + else { colEnd = midIndex - 1; } } - return new int[] {-1, -1}; + return new int[] {-1, -1}; // Target not found } } diff --git a/src/main/java/com/thealgorithms/sorts/DNFSort.java b/src/main/java/com/thealgorithms/sorts/DNFSort.java deleted file mode 100644 index 4b1e913cf3e0..000000000000 --- a/src/main/java/com/thealgorithms/sorts/DNFSort.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.thealgorithms.sorts; - -public final class DNFSort { - private DNFSort() { - } - - // Sort the input array, the array is assumed to - // have values in {0, 1, 2} - static void sort012(int[] a, int arrSize) { - int low = 0; - int high = arrSize - 1; - int mid = 0; - int temp; - while (mid <= high) { - switch (a[mid]) { - case 0: - temp = a[low]; - a[low] = a[mid]; - a[mid] = temp; - low++; - mid++; - break; - - case 1: - mid++; - break; - case 2: - temp = a[mid]; - a[mid] = a[high]; - a[high] = temp; - high--; - break; - - default: - throw new IllegalArgumentException("Unexpected value: " + a[mid]); - } - } - } - - /* Utility function to print array arr[] */ - static void printArray(int[] arr, int arrSize) { - for (int i = 0; i < arrSize; i++) { - System.out.print(arr[i] + " "); - } - System.out.println(); - } - - /*Driver function to check for above functions*/ - public static void main(String[] args) { - int[] arr = {0, 1, 1, 0, 1, 2, 1, 2, 0, 0, 0, 1}; - int arrSize = arr.length; - sort012(arr, arrSize); - System.out.println("Array after seggregation "); - printArray(arr, arrSize); - } -} diff --git a/src/main/java/com/thealgorithms/stacks/InfixToPrefix.java b/src/main/java/com/thealgorithms/stacks/InfixToPrefix.java new file mode 100644 index 000000000000..3d90d14e0d1e --- /dev/null +++ b/src/main/java/com/thealgorithms/stacks/InfixToPrefix.java @@ -0,0 +1,92 @@ +package com.thealgorithms.stacks; + +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class InfixToPrefix { + private InfixToPrefix() { + } + + /** + * Convert an infix expression to a prefix expression using stack. + * + * @param infixExpression the infix expression to convert + * @return the prefix expression + * @throws IllegalArgumentException if the infix expression has unbalanced brackets + * @throws NullPointerException if the infix expression is null + */ + public static String infix2Prefix(String infixExpression) throws IllegalArgumentException { + if (infixExpression == null) { + throw new NullPointerException("Input expression cannot be null."); + } + infixExpression = infixExpression.trim(); + if (infixExpression.isEmpty()) { + return ""; + } + if (!BalancedBrackets.isBalanced(filterBrackets(infixExpression))) { + throw new IllegalArgumentException("Invalid expression: unbalanced brackets."); + } + + StringBuilder output = new StringBuilder(); + Stack stack = new Stack<>(); + // Reverse the infix expression for prefix conversion + String reversedInfix = new StringBuilder(infixExpression).reverse().toString(); + for (char element : reversedInfix.toCharArray()) { + if (Character.isLetterOrDigit(element)) { + output.append(element); + } else if (element == ')') { + stack.push(element); + } else if (element == '(') { + while (!stack.isEmpty() && stack.peek() != ')') { + output.append(stack.pop()); + } + stack.pop(); + } else { + while (!stack.isEmpty() && precedence(element) < precedence(stack.peek())) { + output.append(stack.pop()); + } + stack.push(element); + } + } + while (!stack.isEmpty()) { + output.append(stack.pop()); + } + + // Reverse the result to get the prefix expression + return output.reverse().toString(); + } + + /** + * Determines the precedence of an operator. + * + * @param operator the operator whose precedence is to be determined + * @return the precedence of the operator + */ + private static int precedence(char operator) { + switch (operator) { + case '+': + case '-': + return 0; + case '*': + case '/': + return 1; + case '^': + return 2; + default: + return -1; + } + } + + /** + * Filters out all characters from the input string except brackets. + * + * @param input the input string to filter + * @return a string containing only brackets from the input string + */ + private static String filterBrackets(String input) { + Pattern pattern = Pattern.compile("[^(){}\\[\\]<>]"); + Matcher matcher = pattern.matcher(input); + return matcher.replaceAll(""); + } +} diff --git a/src/main/java/com/thealgorithms/stacks/PrefixToInfix.java b/src/main/java/com/thealgorithms/stacks/PrefixToInfix.java new file mode 100644 index 000000000000..41eb974b0e5b --- /dev/null +++ b/src/main/java/com/thealgorithms/stacks/PrefixToInfix.java @@ -0,0 +1,69 @@ +package com.thealgorithms.stacks; + +import java.util.Stack; + +/** + * Converts a prefix expression to an infix expression using a stack. + * + * The input prefix expression should consist of + * valid operands (letters or digits) and operators (+, -, *, /, ^). + * Parentheses are not required in the prefix string. + */ +public final class PrefixToInfix { + private PrefixToInfix() { + } + + /** + * Determines if a given character is a valid arithmetic operator. + * + * @param token the character to check + * @return true if the character is an operator, false otherwise + */ + public static boolean isOperator(char token) { + return token == '+' || token == '-' || token == '/' || token == '*' || token == '^'; + } + + /** + * Converts a valid prefix expression to an infix expression. + * + * @param prefix the prefix expression to convert + * @return the equivalent infix expression + * @throws NullPointerException if the prefix expression is null + */ + public static String getPrefixToInfix(String prefix) { + if (prefix == null) { + throw new NullPointerException("Null prefix expression"); + } + if (prefix.isEmpty()) { + return ""; + } + + Stack stack = new Stack<>(); + + // Iterate over the prefix expression from right to left + for (int i = prefix.length() - 1; i >= 0; i--) { + char token = prefix.charAt(i); + + if (isOperator(token)) { + // Pop two operands from stack + String operandA = stack.pop(); + String operandB = stack.pop(); + + // Form the infix expression with parentheses + String infix = "(" + operandA + token + operandB + ")"; + + // Push the resulting infix expression back onto the stack + stack.push(infix); + } else { + // Push operand onto stack + stack.push(Character.toString(token)); + } + } + + if (stack.size() != 1) { + throw new ArithmeticException("Malformed prefix expression"); + } + + return stack.pop(); // final element on the stack is the full infix expression + } +} diff --git a/src/main/java/com/thealgorithms/others/CountChar.java b/src/main/java/com/thealgorithms/strings/CountChar.java similarity index 93% rename from src/main/java/com/thealgorithms/others/CountChar.java rename to src/main/java/com/thealgorithms/strings/CountChar.java index 00cff6860216..348905445347 100644 --- a/src/main/java/com/thealgorithms/others/CountChar.java +++ b/src/main/java/com/thealgorithms/strings/CountChar.java @@ -1,4 +1,4 @@ -package com.thealgorithms.others; +package com.thealgorithms.strings; public final class CountChar { private CountChar() { diff --git a/src/main/java/com/thealgorithms/others/CountWords.java b/src/main/java/com/thealgorithms/strings/CountWords.java similarity index 97% rename from src/main/java/com/thealgorithms/others/CountWords.java rename to src/main/java/com/thealgorithms/strings/CountWords.java index 515c5d33fbf3..8ab0700f5586 100644 --- a/src/main/java/com/thealgorithms/others/CountWords.java +++ b/src/main/java/com/thealgorithms/strings/CountWords.java @@ -1,4 +1,4 @@ -package com.thealgorithms.others; +package com.thealgorithms.strings; /** * @author Marcus diff --git a/src/main/java/com/thealgorithms/others/ReturnSubsequence.java b/src/main/java/com/thealgorithms/strings/ReturnSubsequence.java similarity index 97% rename from src/main/java/com/thealgorithms/others/ReturnSubsequence.java rename to src/main/java/com/thealgorithms/strings/ReturnSubsequence.java index 7ef660ce6579..afa8c5f98678 100644 --- a/src/main/java/com/thealgorithms/others/ReturnSubsequence.java +++ b/src/main/java/com/thealgorithms/strings/ReturnSubsequence.java @@ -1,4 +1,4 @@ -package com.thealgorithms.others; +package com.thealgorithms.strings; /** * Class for generating all subsequences of a given string. diff --git a/src/main/java/com/thealgorithms/others/StringMatchFiniteAutomata.java b/src/main/java/com/thealgorithms/strings/StringMatchFiniteAutomata.java similarity index 99% rename from src/main/java/com/thealgorithms/others/StringMatchFiniteAutomata.java rename to src/main/java/com/thealgorithms/strings/StringMatchFiniteAutomata.java index 561845f41a07..719898a1fd74 100644 --- a/src/main/java/com/thealgorithms/others/StringMatchFiniteAutomata.java +++ b/src/main/java/com/thealgorithms/strings/StringMatchFiniteAutomata.java @@ -1,4 +1,4 @@ -package com.thealgorithms.others; +package com.thealgorithms.strings; import java.util.Set; import java.util.TreeSet; diff --git a/src/test/java/com/thealgorithms/Recursion/GenerateSubsetsTest.java b/src/test/java/com/thealgorithms/Recursion/GenerateSubsetsTest.java new file mode 100644 index 000000000000..d4bc7e488f80 --- /dev/null +++ b/src/test/java/com/thealgorithms/Recursion/GenerateSubsetsTest.java @@ -0,0 +1,36 @@ +package com.thealgorithms.Recursion; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import java.util.List; +import org.junit.jupiter.api.Test; + +public final class GenerateSubsetsTest { + + @Test + void subsetRecursionTestOne() { + String str = "abc"; + String[] expected = new String[] {"abc", "ab", "ac", "a", "bc", "b", "c", ""}; + + List ans = GenerateSubsets.subsetRecursion(str); + assertArrayEquals(ans.toArray(), expected); + } + + @Test + void subsetRecursionTestTwo() { + String str = "cbf"; + String[] expected = new String[] {"cbf", "cb", "cf", "c", "bf", "b", "f", ""}; + + List ans = GenerateSubsets.subsetRecursion(str); + assertArrayEquals(ans.toArray(), expected); + } + + @Test + void subsetRecursionTestThree() { + String str = "aba"; + String[] expected = new String[] {"aba", "ab", "aa", "a", "ba", "b", "a", ""}; + + List ans = GenerateSubsets.subsetRecursion(str); + assertArrayEquals(ans.toArray(), expected); + } +} diff --git a/src/test/java/com/thealgorithms/others/CountSetBitsTest.java b/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java similarity index 90% rename from src/test/java/com/thealgorithms/others/CountSetBitsTest.java rename to src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java index ab34c6ba7876..412312109bec 100644 --- a/src/test/java/com/thealgorithms/others/CountSetBitsTest.java +++ b/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java @@ -1,4 +1,4 @@ -package com.thealgorithms.others; +package com.thealgorithms.bitmanipulation; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/com/thealgorithms/ciphers/HillCipherTest.java b/src/test/java/com/thealgorithms/ciphers/HillCipherTest.java new file mode 100644 index 000000000000..8121b6177aa9 --- /dev/null +++ b/src/test/java/com/thealgorithms/ciphers/HillCipherTest.java @@ -0,0 +1,36 @@ +package com.thealgorithms.ciphers; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class HillCipherTest { + + HillCipher hillCipher = new HillCipher(); + + @Test + void hillCipherEncryptTest() { + // given + String message = "ACT"; // Plaintext message + int[][] keyMatrix = {{6, 24, 1}, {13, 16, 10}, {20, 17, 15}}; // Encryption key matrix + + // when + String cipherText = hillCipher.encrypt(message, keyMatrix); + + // then + assertEquals("POH", cipherText); + } + + @Test + void hillCipherDecryptTest() { + // given + String cipherText = "POH"; // Ciphertext message + int[][] inverseKeyMatrix = {{8, 5, 10}, {21, 8, 21}, {21, 12, 8}}; // Decryption (inverse key) matrix + + // when + String plainText = hillCipher.decrypt(cipherText, inverseKeyMatrix); + + // then + assertEquals("ACT", plainText); + } +} diff --git a/src/test/java/com/thealgorithms/ciphers/XORCipherTest.java b/src/test/java/com/thealgorithms/ciphers/XORCipherTest.java new file mode 100644 index 000000000000..15e27d5d6778 --- /dev/null +++ b/src/test/java/com/thealgorithms/ciphers/XORCipherTest.java @@ -0,0 +1,34 @@ +package com.thealgorithms.ciphers; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class XORCipherTest { + + @Test + void xorEncryptTest() { + // given + String plaintext = "My t&xt th@t will be ençrypted..."; + String key = "My ç&cret key!"; + + // when + String cipherText = XORCipher.encrypt(plaintext, key); + + // then + assertEquals("000000b7815e1752111c601f450e48211500a1c206061ca6d35212150d4429570eed", cipherText); + } + + @Test + void xorDecryptTest() { + // given + String cipherText = "000000b7815e1752111c601f450e48211500a1c206061ca6d35212150d4429570eed"; + String key = "My ç&cret key!"; + + // when + String plainText = XORCipher.decrypt(cipherText, key); + + // then + assertEquals("My t&xt th@t will be ençrypted...", plainText); + } +} diff --git a/src/test/java/com/thealgorithms/conversions/IntegerToEnglishTest.java b/src/test/java/com/thealgorithms/conversions/IntegerToEnglishTest.java new file mode 100644 index 000000000000..49c43402aeca --- /dev/null +++ b/src/test/java/com/thealgorithms/conversions/IntegerToEnglishTest.java @@ -0,0 +1,15 @@ +package com.thealgorithms.conversions; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class IntegerToEnglishTest { + + @Test + public void testIntegerToEnglish() { + assertEquals("Two Billion One Hundred Forty Seven Million Four Hundred Eighty Three Thousand Six Hundred Forty Seven", IntegerToEnglish.integerToEnglishWords(2147483647)); + assertEquals("One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven", IntegerToEnglish.integerToEnglishWords(1234567)); + assertEquals("Twelve Thousand Three Hundred Forty Five", IntegerToEnglish.integerToEnglishWords(12345)); + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java new file mode 100644 index 000000000000..4a7232447e50 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java @@ -0,0 +1,119 @@ +package com.thealgorithms.datastructures.graphs; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for the EdmondsBlossomAlgorithm class. + * + * These tests ensure that the Edmonds' Blossom Algorithm implementation + * works as expected for various graph structures, returning the correct + * maximum matching. + */ +public class EdmondsBlossomAlgorithmTest { + + /** + * Helper method to convert a list of matching pairs into a sorted 2D array. + * Sorting ensures consistent ordering of pairs and vertices for easier comparison in tests. + * + * @param matching List of matched pairs returned by the algorithm. + * @return A sorted 2D array of matching pairs. + */ + private int[][] convertMatchingToArray(List matching) { + // Convert the list of pairs into an array + int[][] result = matching.toArray(new int[0][]); + + // Sort each individual pair for consistency + for (int[] pair : result) { + Arrays.sort(pair); + } + + // Sort the array of pairs to ensure consistent order + Arrays.sort(result, (a, b) -> Integer.compare(a[0], b[0])); + return result; + } + + /** + * Test Case 1: A triangle graph where vertices 0, 1, and 2 form a cycle. + * The expected maximum matching is a single pair (0, 1) or any equivalent pair from the cycle. + */ + @Test + public void testCase1() { + List edges = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 0}); + List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 3); + + int[][] expected = new int[][] {{0, 1}}; + assertArrayEquals(expected, convertMatchingToArray(matching)); + } + + /** + * Test Case 2: A disconnected graph where vertices 0, 1, 2 form one component, + * and vertices 3, 4 form another. The expected maximum matching is two pairs: + * (0, 1) and (3, 4). + */ + @Test + public void testCase2() { + List edges = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {3, 4}); + List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 5); + + int[][] expected = new int[][] {{0, 1}, {3, 4}}; + assertArrayEquals(expected, convertMatchingToArray(matching)); + } + + /** + * Test Case 3: A cycle graph involving vertices 0, 1, 2, 3 forming a cycle, + * with an additional edge (4, 5) outside the cycle. + * The expected maximum matching is (0, 1) and (4, 5). + */ + @Test + public void testCase3() { + List edges = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 0}, new int[] {4, 5}); + List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 6); + + // Updated expected output to include the maximum matching pairs + int[][] expected = new int[][] {{0, 1}, {2, 3}, {4, 5}}; + assertArrayEquals(expected, convertMatchingToArray(matching)); + } + + /** + * Test Case 4: A graph with no edges. + * Since there are no edges, the expected matching is an empty set. + */ + @Test + public void testCaseNoMatching() { + List edges = Collections.emptyList(); // No edges + List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 3); + + int[][] expected = new int[][] {}; // No pairs expected + assertArrayEquals(expected, convertMatchingToArray(matching)); + } + + /** + * Test Case 5: A more complex graph with multiple cycles and extra edges. + * This tests the algorithm's ability to handle larger, more intricate graphs. + * The expected matching is {{0, 1}, {2, 5}, {3, 4}}. + */ + @Test + public void testCaseLargeGraph() { + List edges = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 4}, new int[] {4, 5}, new int[] {5, 0}, new int[] {1, 4}, new int[] {2, 5}); + List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 6); + + // Check if the size of the matching is correct (i.e., 3 pairs) + assertEquals(3, matching.size()); + + // Check that the result contains valid pairs (any order is fine) + // Valid maximum matchings could be {{0, 1}, {2, 5}, {3, 4}} or {{0, 1}, {2, 3}, {4, 5}}, etc. + int[][] possibleMatching1 = new int[][] {{0, 1}, {2, 5}, {3, 4}}; + int[][] possibleMatching2 = new int[][] {{0, 1}, {2, 3}, {4, 5}}; + int[][] result = convertMatchingToArray(matching); + + // Assert that the result is one of the valid maximum matchings + assertTrue(Arrays.deepEquals(result, possibleMatching1) || Arrays.deepEquals(result, possibleMatching2)); + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/lists/SortedLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/SortedLinkedListTest.java new file mode 100644 index 000000000000..4877e6db4ec4 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/lists/SortedLinkedListTest.java @@ -0,0 +1,67 @@ +package com.thealgorithms.datastructures.lists; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +public class SortedLinkedListTest { + + @Test + public void testInsert() { + SortedLinkedList list = new SortedLinkedList(); + list.insert(5); + list.insert(3); + list.insert(7); + assertEquals("[3, 5, 7]", list.toString()); + } + + @Test + public void testDelete() { + SortedLinkedList list = new SortedLinkedList(); + list.insert(5); + list.insert(3); + list.insert(7); + assertTrue(list.delete(5)); + assertEquals("[3, 7]", list.toString()); + assertFalse(list.delete(10)); + } + + @Test + public void testSearch() { + SortedLinkedList list = new SortedLinkedList(); + list.insert(5); + list.insert(3); + list.insert(7); + assertTrue(list.search(5)); + assertFalse(list.search(10)); + } + @Test + public void testEmptyList() { + SortedLinkedList list = new SortedLinkedList(); + assertEquals("[]", list.toString()); + assertFalse(list.delete(5)); + assertFalse(list.search(5)); + } + @Test + public void testIsEmptyOnEmptyList() { + SortedLinkedList list = new SortedLinkedList(); + assertTrue(list.isEmpty()); + } + + @Test + public void testIsEmptyOnNonEmptyList() { + SortedLinkedList list = new SortedLinkedList(); + list.insert(10); + assertFalse(list.isEmpty()); + } + + @Test + public void testIsEmptyAfterDeletion() { + SortedLinkedList list = new SortedLinkedList(); + list.insert(10); + list.delete(10); + assertTrue(list.isEmpty()); + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/trees/TrieImpTest.java b/src/test/java/com/thealgorithms/datastructures/trees/TrieImpTest.java new file mode 100644 index 000000000000..600fdef0a718 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/trees/TrieImpTest.java @@ -0,0 +1,76 @@ +package com.thealgorithms.datastructures.trees; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class TrieImpTest { + private TrieImp trie; + + @BeforeEach + public void setUp() { + trie = new TrieImp(); + } + + @Test + public void testInsertAndSearchBasic() { + String word = "hello"; + trie.insert(word); + assertTrue(trie.search(word), "Search should return true for an inserted word."); + } + + @Test + public void testSearchNonExistentWord() { + String word = "world"; + assertFalse(trie.search(word), "Search should return false for a non-existent word."); + } + + @Test + public void testInsertAndSearchMultipleWords() { + String word1 = "cat"; + String word2 = "car"; + trie.insert(word1); + trie.insert(word2); + + assertTrue(trie.search(word1), "Search should return true for an inserted word."); + assertTrue(trie.search(word2), "Search should return true for another inserted word."); + assertFalse(trie.search("dog"), "Search should return false for a word not in the Trie."); + } + + @Test + public void testDeleteExistingWord() { + String word = "remove"; + trie.insert(word); + assertTrue(trie.delete(word), "Delete should return true for an existing word."); + assertFalse(trie.search(word), "Search should return false after deletion."); + } + + @Test + public void testDeleteNonExistentWord() { + String word = "nonexistent"; + assertFalse(trie.delete(word), "Delete should return false for a non-existent word."); + } + + @Test + public void testInsertAndSearchPrefix() { + String prefix = "pre"; + String word = "prefix"; + trie.insert(prefix); + trie.insert(word); + + assertTrue(trie.search(prefix), "Search should return true for an inserted prefix."); + assertTrue(trie.search(word), "Search should return true for a word with the prefix."); + assertFalse(trie.search("pref"), "Search should return false for a prefix that is not a full word."); + } + + @Test + public void testIsValidWord() { + assertTrue(TrieImp.isValid("validword"), "Word should be valid (only lowercase letters)."); + assertFalse(TrieImp.isValid("InvalidWord"), "Word should be invalid (contains uppercase letters)."); + assertFalse(TrieImp.isValid("123abc"), "Word should be invalid (contains numbers)."); + assertFalse(TrieImp.isValid("hello!"), "Word should be invalid (contains special characters)."); + assertFalse(TrieImp.isValid(""), "Empty string should be invalid."); + } +} diff --git a/src/test/java/com/thealgorithms/divideandconquer/SkylineAlgorithmTest.java b/src/test/java/com/thealgorithms/divideandconquer/SkylineAlgorithmTest.java new file mode 100644 index 000000000000..f85515110b70 --- /dev/null +++ b/src/test/java/com/thealgorithms/divideandconquer/SkylineAlgorithmTest.java @@ -0,0 +1,102 @@ +package com.thealgorithms.divideandconquer; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class SkylineAlgorithmTest { + + private SkylineAlgorithm skylineAlgorithm; + + @BeforeEach + public void setUp() { + skylineAlgorithm = new SkylineAlgorithm(); + } + + @Test + public void testProduceSubSkyLinesSinglePoint() { + // Test with a single point + ArrayList points = new ArrayList<>(); + points.add(new SkylineAlgorithm.Point(1, 10)); + + ArrayList result = skylineAlgorithm.produceSubSkyLines(points); + + assertEquals(1, result.size()); + assertEquals(1, result.get(0).getX()); + assertEquals(10, result.get(0).getY()); + } + + @Test + public void testProduceSubSkyLinesTwoPoints() { + // Test with two points, one dominated by the other + ArrayList points = new ArrayList<>(); + points.add(new SkylineAlgorithm.Point(1, 10)); + points.add(new SkylineAlgorithm.Point(1, 5)); + + ArrayList result = skylineAlgorithm.produceSubSkyLines(points); + + assertEquals(1, result.size()); + assertEquals(1, result.get(0).getX()); + assertEquals(5, result.get(0).getY()); + } + + @Test + public void testProduceSubSkyLinesMultiplePoints() { + // Test with more than two points + ArrayList points = new ArrayList<>(); + points.add(new SkylineAlgorithm.Point(1, 10)); + points.add(new SkylineAlgorithm.Point(2, 15)); + points.add(new SkylineAlgorithm.Point(3, 5)); + points.add(new SkylineAlgorithm.Point(4, 20)); + + ArrayList result = skylineAlgorithm.produceSubSkyLines(points); + + assertEquals(2, result.size()); + + // Assert the correct points in skyline + assertEquals(1, result.get(0).getX()); + assertEquals(10, result.get(0).getY()); + assertEquals(3, result.get(1).getX()); + assertEquals(5, result.get(1).getY()); + } + + @Test + public void testProduceFinalSkyLine() { + // Test merging two skylines + ArrayList left = new ArrayList<>(); + left.add(new SkylineAlgorithm.Point(1, 10)); + left.add(new SkylineAlgorithm.Point(2, 5)); + + ArrayList right = new ArrayList<>(); + right.add(new SkylineAlgorithm.Point(3, 8)); + right.add(new SkylineAlgorithm.Point(4, 3)); + + ArrayList result = skylineAlgorithm.produceFinalSkyLine(left, right); + + assertEquals(3, result.size()); + + // Assert the correct points in the final skyline + assertEquals(1, result.get(0).getX()); + assertEquals(10, result.get(0).getY()); + assertEquals(2, result.get(1).getX()); + assertEquals(5, result.get(1).getY()); + assertEquals(4, result.get(2).getX()); + assertEquals(3, result.get(2).getY()); + } + + @Test + public void testXComparator() { + // Test the XComparator used for sorting the points + SkylineAlgorithm.XComparator comparator = new SkylineAlgorithm().new XComparator(); + + SkylineAlgorithm.Point p1 = new SkylineAlgorithm.Point(1, 10); + SkylineAlgorithm.Point p2 = new SkylineAlgorithm.Point(2, 5); + + // Check if the XComparator sorts points by their x-value + assertEquals(-1, comparator.compare(p1, p2)); // p1.x < p2.x + assertEquals(1, comparator.compare(p2, p1)); // p2.x > p1.x + assertEquals(0, comparator.compare(p1, new SkylineAlgorithm.Point(1, 15))); // p1.x == p2.x + } +} diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequenceTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequenceTest.java new file mode 100644 index 000000000000..6384fe2afebe --- /dev/null +++ b/src/test/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequenceTest.java @@ -0,0 +1,35 @@ +package com.thealgorithms.dynamicprogramming; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.stream.Stream; +import org.apache.commons.lang3.ArrayUtils; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class LongestArithmeticSubsequenceTest { + @ParameterizedTest + @MethodSource("provideTestCases") + void testGetLongestArithmeticSubsequenceLength(int[] nums, int expected) { + assertEquals(expected, LongestArithmeticSubsequence.getLongestArithmeticSubsequenceLength(nums)); + } + @ParameterizedTest + @MethodSource("provideTestCases") + void testGetLongestArithmeticSubsequenceLengthReversedInput(int[] nums, int expected) { + ArrayUtils.reverse(nums); + assertEquals(expected, LongestArithmeticSubsequence.getLongestArithmeticSubsequenceLength(nums)); + } + + @Test + void testGetLongestArithmeticSubsequenceLengthThrowsForNullInput() { + assertThrows(IllegalArgumentException.class, () -> LongestArithmeticSubsequence.getLongestArithmeticSubsequenceLength(null)); + } + + private static Stream provideTestCases() { + return Stream.of(Arguments.of(new int[] {3, 6, 9, 12, 15}, 5), Arguments.of(new int[] {1, 7, 10, 13, 14, 19}, 4), Arguments.of(new int[] {1, 2, 3, 4}, 4), Arguments.of(new int[] {}, 0), Arguments.of(new int[] {10}, 1), Arguments.of(new int[] {9, 4, 7, 2, 10}, 3), + Arguments.of(new int[] {1, 2, 2, 2, 2, 5}, 4)); + } +} diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java new file mode 100644 index 000000000000..40bbdff15ca6 --- /dev/null +++ b/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java @@ -0,0 +1,89 @@ +package com.thealgorithms.dynamicprogramming; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class LongestCommonSubsequenceTest { + + @Test + public void testLCSBasic() { + String str1 = "ABCBDAB"; + String str2 = "BDCAB"; + String expected = "BDAB"; // The longest common subsequence + String result = LongestCommonSubsequence.getLCS(str1, str2); + assertEquals(expected, result); + } + + @Test + public void testLCSIdenticalStrings() { + String str1 = "AGGTAB"; + String str2 = "AGGTAB"; + String expected = "AGGTAB"; // LCS is the same as the strings + String result = LongestCommonSubsequence.getLCS(str1, str2); + assertEquals(expected, result); + } + + @Test + public void testLCSNoCommonCharacters() { + String str1 = "ABC"; + String str2 = "XYZ"; + String expected = ""; // No common subsequence + String result = LongestCommonSubsequence.getLCS(str1, str2); + assertEquals(expected, result); + } + + @Test + public void testLCSWithEmptyString() { + String str1 = ""; + String str2 = "XYZ"; + String expected = ""; // LCS with an empty string should be empty + String result = LongestCommonSubsequence.getLCS(str1, str2); + assertEquals(expected, result); + } + + @Test + public void testLCSWithBothEmptyStrings() { + String str1 = ""; + String str2 = ""; + String expected = ""; // LCS with both strings empty should be empty + String result = LongestCommonSubsequence.getLCS(str1, str2); + assertEquals(expected, result); + } + + @Test + public void testLCSWithNullFirstString() { + String str1 = null; + String str2 = "XYZ"; + String expected = null; // Should return null if first string is null + String result = LongestCommonSubsequence.getLCS(str1, str2); + assertEquals(expected, result); + } + + @Test + public void testLCSWithNullSecondString() { + String str1 = "ABC"; + String str2 = null; + String expected = null; // Should return null if second string is null + String result = LongestCommonSubsequence.getLCS(str1, str2); + assertEquals(expected, result); + } + + @Test + public void testLCSWithNullBothStrings() { + String str1 = null; + String str2 = null; + String expected = null; // Should return null if both strings are null + String result = LongestCommonSubsequence.getLCS(str1, str2); + assertEquals(expected, result); + } + + @Test + public void testLCSWithLongerStringContainingCommonSubsequence() { + String str1 = "ABCDEF"; + String str2 = "AEBDF"; + String expected = "ABDF"; // Common subsequence is "ABDF" + String result = LongestCommonSubsequence.getLCS(str1, str2); + assertEquals(expected, result); + } +} diff --git a/src/test/java/com/thealgorithms/greedyalgorithms/DigitSeparationTest.java b/src/test/java/com/thealgorithms/greedyalgorithms/DigitSeparationTest.java new file mode 100644 index 000000000000..1fe018ecce18 --- /dev/null +++ b/src/test/java/com/thealgorithms/greedyalgorithms/DigitSeparationTest.java @@ -0,0 +1,78 @@ +package com.thealgorithms.greedyalgorithms; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import org.junit.jupiter.api.Test; +public class DigitSeparationTest { + + @Test + public void testDigitSeparationReverseOrderSingleDigit() { + DigitSeparation digitSeparation = new DigitSeparation(); + List result = digitSeparation.digitSeparationReverseOrder(5); + assertEquals(List.of(5L), result); + } + + @Test + public void testDigitSeparationReverseOrderMultipleDigits() { + DigitSeparation digitSeparation = new DigitSeparation(); + List result = digitSeparation.digitSeparationReverseOrder(123); + assertEquals(List.of(3L, 2L, 1L), result); + } + + @Test + public void testDigitSeparationReverseOrderLargeNumber() { + DigitSeparation digitSeparation = new DigitSeparation(); + List result = digitSeparation.digitSeparationReverseOrder(123456789); + assertEquals(List.of(9L, 8L, 7L, 6L, 5L, 4L, 3L, 2L, 1L), result); + } + + @Test + public void testDigitSeparationReverseOrderZero() { + DigitSeparation digitSeparation = new DigitSeparation(); + List result = digitSeparation.digitSeparationReverseOrder(0); + assertEquals(List.of(0L), result); + } + + @Test + public void testDigitSeparationReverseOrderNegativeNumbers() { + DigitSeparation digitSeparation = new DigitSeparation(); + List result = digitSeparation.digitSeparationReverseOrder(-123); + assertEquals(List.of(3L, 2L, 1L), result); + } + + @Test + public void testDigitSeparationForwardOrderSingleDigit() { + DigitSeparation digitSeparation = new DigitSeparation(); + List result = digitSeparation.digitSeparationForwardOrder(5); + assertEquals(List.of(5L), result); + } + + @Test + public void testDigitSeparationForwardOrderMultipleDigits() { + DigitSeparation digitSeparation = new DigitSeparation(); + List result = digitSeparation.digitSeparationForwardOrder(123); + assertEquals(List.of(1L, 2L, 3L), result); + } + + @Test + public void testDigitSeparationForwardOrderLargeNumber() { + DigitSeparation digitSeparation = new DigitSeparation(); + List result = digitSeparation.digitSeparationForwardOrder(123456789); + assertEquals(List.of(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L), result); + } + + @Test + public void testDigitSeparationForwardOrderZero() { + DigitSeparation digitSeparation = new DigitSeparation(); + List result = digitSeparation.digitSeparationForwardOrder(0); + assertEquals(List.of(0L), result); + } + + @Test + public void testDigitSeparationForwardOrderNegativeNumber() { + DigitSeparation digitSeparation = new DigitSeparation(); + List result = digitSeparation.digitSeparationForwardOrder(-123); + assertEquals(List.of(1L, 2L, 3L), result); + } +} diff --git a/src/test/java/com/thealgorithms/greedyalgorithms/MergeIntervalsTest.java b/src/test/java/com/thealgorithms/greedyalgorithms/MergeIntervalsTest.java new file mode 100644 index 000000000000..0135f9d73260 --- /dev/null +++ b/src/test/java/com/thealgorithms/greedyalgorithms/MergeIntervalsTest.java @@ -0,0 +1,71 @@ +package com.thealgorithms.greedyalgorithms; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import org.junit.jupiter.api.Test; + +public class MergeIntervalsTest { + + @Test + public void testMergeIntervalsWithOverlappingIntervals() { + // Test case where some intervals overlap and should be merged + int[][] intervals = {{1, 3}, {2, 6}, {8, 10}, {15, 18}}; + int[][] expected = {{1, 6}, {8, 10}, {15, 18}}; + int[][] result = MergeIntervals.merge(intervals); + assertArrayEquals(expected, result); + } + + @Test + public void testMergeIntervalsWithNoOverlap() { + // Test case where intervals do not overlap + int[][] intervals = {{1, 2}, {3, 4}, {5, 6}}; + int[][] expected = {{1, 2}, {3, 4}, {5, 6}}; + int[][] result = MergeIntervals.merge(intervals); + assertArrayEquals(expected, result); + } + + @Test + public void testMergeIntervalsWithCompleteOverlap() { + // Test case where intervals completely overlap + int[][] intervals = {{1, 5}, {2, 4}, {3, 6}}; + int[][] expected = {{1, 6}}; + int[][] result = MergeIntervals.merge(intervals); + assertArrayEquals(expected, result); + } + + @Test + public void testMergeIntervalsWithSingleInterval() { + // Test case where only one interval is given + int[][] intervals = {{1, 2}}; + int[][] expected = {{1, 2}}; + int[][] result = MergeIntervals.merge(intervals); + assertArrayEquals(expected, result); + } + + @Test + public void testMergeIntervalsWithEmptyArray() { + // Test case where the input array is empty + int[][] intervals = {}; + int[][] expected = {}; + int[][] result = MergeIntervals.merge(intervals); + assertArrayEquals(expected, result); + } + + @Test + public void testMergeIntervalsWithIdenticalIntervals() { + // Test case where multiple identical intervals are given + int[][] intervals = {{1, 3}, {1, 3}, {1, 3}}; + int[][] expected = {{1, 3}}; + int[][] result = MergeIntervals.merge(intervals); + assertArrayEquals(expected, result); + } + + @Test + public void testMergeIntervalsWithRandomIntervals() { + // Test case with a mix of overlapping and non-overlapping intervals + int[][] intervals = {{1, 4}, {5, 7}, {2, 6}, {8, 10}}; + int[][] expected = {{1, 7}, {8, 10}}; + int[][] result = MergeIntervals.merge(intervals); + assertArrayEquals(expected, result); + } +} diff --git a/src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java b/src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java new file mode 100644 index 000000000000..91be8a63da62 --- /dev/null +++ b/src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java @@ -0,0 +1,44 @@ +package com.thealgorithms.stacks; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class InfixToPrefixTest { + + @ParameterizedTest + @MethodSource("provideValidExpressions") + void testValidExpressions(String infix, String expectedPrefix) throws Exception { + assertEquals(expectedPrefix, InfixToPrefix.infix2Prefix(infix)); + } + + @Test + void testEmptyString() { + // Assuming that an empty string returns an empty prefix or throws an exception + assertEquals("", InfixToPrefix.infix2Prefix("")); + } + + @Test + void testNullValue() { + // Assuming that a null input throws a NullPointerException + assertThrows(NullPointerException.class, () -> InfixToPrefix.infix2Prefix(null)); + } + + private static Stream provideValidExpressions() { + return Stream.of(Arguments.of("3+2", "+32"), // Simple addition + Arguments.of("1+(2+3)", "+1+23"), // Parentheses + Arguments.of("(3+4)*5-6", "-*+3456"), // Nested operations + Arguments.of("a+b*c", "+a*bc"), // Multiplication precedence + Arguments.of("a+b*c/d", "+a/*bcd"), // Division precedence + Arguments.of("a+b*c-d", "-+a*bcd"), // Subtraction precedence + Arguments.of("a+b*c/d-e", "-+a/*bcde"), // Mixed precedence + Arguments.of("a+b*(c-d)", "+a*b-cd"), // Parentheses precedence + Arguments.of("a+b*(c-d)/e", "+a/*b-cde") // Mixed precedence with parentheses + ); + } +} diff --git a/src/test/java/com/thealgorithms/stacks/PrefixToInfixTest.java b/src/test/java/com/thealgorithms/stacks/PrefixToInfixTest.java new file mode 100644 index 000000000000..83fd09e1bbf6 --- /dev/null +++ b/src/test/java/com/thealgorithms/stacks/PrefixToInfixTest.java @@ -0,0 +1,44 @@ +package com.thealgorithms.stacks; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class PrefixToInfixTest { + + @ParameterizedTest + @MethodSource("provideValidPrefixToInfixTestCases") + void testValidPrefixToInfixConversion(String prefix, String expectedInfix) { + assertEquals(expectedInfix, PrefixToInfix.getPrefixToInfix(prefix)); + } + + static Stream provideValidPrefixToInfixTestCases() { + return Stream.of(Arguments.of("A", "A"), // Single operand + Arguments.of("+AB", "(A+B)"), // Addition + Arguments.of("*+ABC", "((A+B)*C)"), // Addition and multiplication + Arguments.of("-+A*BCD", "((A+(B*C))-D)"), // Mixed operators + Arguments.of("/-A*BC+DE", "((A-(B*C))/(D+E))"), // Mixed operators + Arguments.of("^+AB*CD", "((A+B)^(C*D))") // Mixed operators + ); + } + + @Test + void testEmptyPrefixExpression() { + assertEquals("", PrefixToInfix.getPrefixToInfix("")); + } + + @Test + void testNullPrefixExpression() { + assertThrows(NullPointerException.class, () -> PrefixToInfix.getPrefixToInfix(null)); + } + + @Test + void testMalformedPrefixExpression() { + assertThrows(ArithmeticException.class, () -> PrefixToInfix.getPrefixToInfix("+ABC")); + } +} diff --git a/src/test/java/com/thealgorithms/others/CountCharTest.java b/src/test/java/com/thealgorithms/strings/CountCharTest.java similarity index 96% rename from src/test/java/com/thealgorithms/others/CountCharTest.java rename to src/test/java/com/thealgorithms/strings/CountCharTest.java index 2b87d3806002..c84f2d01c2c5 100644 --- a/src/test/java/com/thealgorithms/others/CountCharTest.java +++ b/src/test/java/com/thealgorithms/strings/CountCharTest.java @@ -1,4 +1,4 @@ -package com.thealgorithms.others; +package com.thealgorithms.strings; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/com/thealgorithms/others/CountWordsTest.java b/src/test/java/com/thealgorithms/strings/CountWordsTest.java similarity index 97% rename from src/test/java/com/thealgorithms/others/CountWordsTest.java rename to src/test/java/com/thealgorithms/strings/CountWordsTest.java index 17bb3aa692e7..a8aca1ae6092 100644 --- a/src/test/java/com/thealgorithms/others/CountWordsTest.java +++ b/src/test/java/com/thealgorithms/strings/CountWordsTest.java @@ -1,4 +1,4 @@ -package com.thealgorithms.others; +package com.thealgorithms.strings; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/com/thealgorithms/others/ReturnSubsequenceTest.java b/src/test/java/com/thealgorithms/strings/ReturnSubsequenceTest.java similarity index 96% rename from src/test/java/com/thealgorithms/others/ReturnSubsequenceTest.java rename to src/test/java/com/thealgorithms/strings/ReturnSubsequenceTest.java index 0ae30c48c2a6..d4e1248d05ad 100644 --- a/src/test/java/com/thealgorithms/others/ReturnSubsequenceTest.java +++ b/src/test/java/com/thealgorithms/strings/ReturnSubsequenceTest.java @@ -1,4 +1,4 @@ -package com.thealgorithms.others; +package com.thealgorithms.strings; import static org.junit.jupiter.api.Assertions.assertArrayEquals; diff --git a/src/test/java/com/thealgorithms/others/StringMatchFiniteAutomataTest.java b/src/test/java/com/thealgorithms/strings/StringMatchFiniteAutomataTest.java similarity index 97% rename from src/test/java/com/thealgorithms/others/StringMatchFiniteAutomataTest.java rename to src/test/java/com/thealgorithms/strings/StringMatchFiniteAutomataTest.java index 6e1947b76a38..be460c7c4d91 100644 --- a/src/test/java/com/thealgorithms/others/StringMatchFiniteAutomataTest.java +++ b/src/test/java/com/thealgorithms/strings/StringMatchFiniteAutomataTest.java @@ -1,4 +1,4 @@ -package com.thealgorithms.others; +package com.thealgorithms.strings; import static org.junit.jupiter.api.Assertions.assertEquals;