diff --git a/.github/workflows/update-directorymd.yml b/.github/workflows/update-directorymd.yml index 101d82427e38..1cfee6e36e4e 100644 --- a/.github/workflows/update-directorymd.yml +++ b/.github/workflows/update-directorymd.yml @@ -33,7 +33,7 @@ jobs: git diff --cached --quiet || git commit -m "Update DIRECTORY.md" - name: Create Pull Request - uses: peter-evans/create-pull-request@v7 + uses: peter-evans/create-pull-request@v8 with: token: ${{ secrets.REPO_SCOPED_TOKEN }} branch: update-directory diff --git a/DIRECTORY.md b/DIRECTORY.md index deaf59636fa4..585c634c3429 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -626,8 +626,6 @@ - πŸ“„ [SkylineProblem](src/main/java/com/thealgorithms/others/SkylineProblem.java) - πŸ“„ [TwoPointers](src/main/java/com/thealgorithms/others/TwoPointers.java) - πŸ“„ [Verhoeff](src/main/java/com/thealgorithms/others/Verhoeff.java) - - πŸ“ **cn** - - πŸ“„ [HammingDistance](src/main/java/com/thealgorithms/others/cn/HammingDistance.java) - πŸ“ **physics** - πŸ“„ [CoulombsLaw](src/main/java/com/thealgorithms/physics/CoulombsLaw.java) - πŸ“„ [DampedOscillator](src/main/java/com/thealgorithms/physics/DampedOscillator.java) @@ -701,7 +699,6 @@ - πŸ“„ [LowerBound](src/main/java/com/thealgorithms/searches/LowerBound.java) - πŸ“„ [MonteCarloTreeSearch](src/main/java/com/thealgorithms/searches/MonteCarloTreeSearch.java) - πŸ“„ [OrderAgnosticBinarySearch](src/main/java/com/thealgorithms/searches/OrderAgnosticBinarySearch.java) - - πŸ“„ [PerfectBinarySearch](src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java) - πŸ“„ [QuickSelect](src/main/java/com/thealgorithms/searches/QuickSelect.java) - πŸ“„ [RabinKarpAlgorithm](src/main/java/com/thealgorithms/searches/RabinKarpAlgorithm.java) - πŸ“„ [RandomSearch](src/main/java/com/thealgorithms/searches/RandomSearch.java) @@ -710,7 +707,6 @@ - πŸ“„ [SaddlebackSearch](src/main/java/com/thealgorithms/searches/SaddlebackSearch.java) - πŸ“„ [SearchInARowAndColWiseSortedMatrix](src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java) - πŸ“„ [SentinelLinearSearch](src/main/java/com/thealgorithms/searches/SentinelLinearSearch.java) - - πŸ“„ [SortOrderAgnosticBinarySearch](src/main/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearch.java) - πŸ“„ [SquareRootBinarySearch](src/main/java/com/thealgorithms/searches/SquareRootBinarySearch.java) - πŸ“„ [TernarySearch](src/main/java/com/thealgorithms/searches/TernarySearch.java) - πŸ“„ [UnionFind](src/main/java/com/thealgorithms/searches/UnionFind.java) @@ -817,7 +813,6 @@ - πŸ“„ [LetterCombinationsOfPhoneNumber](src/main/java/com/thealgorithms/strings/LetterCombinationsOfPhoneNumber.java) - πŸ“„ [LongestCommonPrefix](src/main/java/com/thealgorithms/strings/LongestCommonPrefix.java) - πŸ“„ [LongestNonRepetitiveSubstring](src/main/java/com/thealgorithms/strings/LongestNonRepetitiveSubstring.java) - - πŸ“„ [LongestPalindromicSubstring](src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java) - πŸ“„ [Lower](src/main/java/com/thealgorithms/strings/Lower.java) - πŸ“„ [Manacher](src/main/java/com/thealgorithms/strings/Manacher.java) - πŸ“„ [MyAtoi](src/main/java/com/thealgorithms/strings/MyAtoi.java) @@ -834,7 +829,6 @@ - πŸ“„ [StringMatchFiniteAutomata](src/main/java/com/thealgorithms/strings/StringMatchFiniteAutomata.java) - πŸ“„ [SuffixArray](src/main/java/com/thealgorithms/strings/SuffixArray.java) - πŸ“„ [Upper](src/main/java/com/thealgorithms/strings/Upper.java) - - πŸ“„ [ValidParentheses](src/main/java/com/thealgorithms/strings/ValidParentheses.java) - πŸ“„ [WordLadder](src/main/java/com/thealgorithms/strings/WordLadder.java) - πŸ“„ [ZAlgorithm](src/main/java/com/thealgorithms/strings/ZAlgorithm.java) - πŸ“ **zigZagPattern** @@ -1395,7 +1389,6 @@ - πŸ“„ [MaximumSumOfDistinctSubarraysWithLengthKTest](src/test/java/com/thealgorithms/others/MaximumSumOfDistinctSubarraysWithLengthKTest.java) - πŸ“„ [MiniMaxAlgorithmTest](src/test/java/com/thealgorithms/others/MiniMaxAlgorithmTest.java) - πŸ“„ [MosAlgorithmTest](src/test/java/com/thealgorithms/others/MosAlgorithmTest.java) - - πŸ“„ [NewManShanksPrimeTest](src/test/java/com/thealgorithms/others/NewManShanksPrimeTest.java) - πŸ“„ [NextFitTest](src/test/java/com/thealgorithms/others/NextFitTest.java) - πŸ“„ [PageRankTest](src/test/java/com/thealgorithms/others/PageRankTest.java) - πŸ“„ [PasswordGenTest](src/test/java/com/thealgorithms/others/PasswordGenTest.java) @@ -1404,8 +1397,6 @@ - πŸ“„ [SkylineProblemTest](src/test/java/com/thealgorithms/others/SkylineProblemTest.java) - πŸ“„ [TwoPointersTest](src/test/java/com/thealgorithms/others/TwoPointersTest.java) - πŸ“„ [WorstFitCPUTest](src/test/java/com/thealgorithms/others/WorstFitCPUTest.java) - - πŸ“ **cn** - - πŸ“„ [HammingDistanceTest](src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java) - πŸ“ **physics** - πŸ“„ [CoulombsLawTest](src/test/java/com/thealgorithms/physics/CoulombsLawTest.java) - πŸ“„ [DampedOscillatorTest](src/test/java/com/thealgorithms/physics/DampedOscillatorTest.java) @@ -1479,7 +1470,6 @@ - πŸ“„ [LowerBoundTest](src/test/java/com/thealgorithms/searches/LowerBoundTest.java) - πŸ“„ [MonteCarloTreeSearchTest](src/test/java/com/thealgorithms/searches/MonteCarloTreeSearchTest.java) - πŸ“„ [OrderAgnosticBinarySearchTest](src/test/java/com/thealgorithms/searches/OrderAgnosticBinarySearchTest.java) - - πŸ“„ [PerfectBinarySearchTest](src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java) - πŸ“„ [QuickSelectTest](src/test/java/com/thealgorithms/searches/QuickSelectTest.java) - πŸ“„ [RabinKarpAlgorithmTest](src/test/java/com/thealgorithms/searches/RabinKarpAlgorithmTest.java) - πŸ“„ [RandomSearchTest](src/test/java/com/thealgorithms/searches/RandomSearchTest.java) @@ -1488,7 +1478,6 @@ - πŸ“„ [SaddlebackSearchTest](src/test/java/com/thealgorithms/searches/SaddlebackSearchTest.java) - πŸ“„ [SearchInARowAndColWiseSortedMatrixTest](src/test/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrixTest.java) - πŸ“„ [SentinelLinearSearchTest](src/test/java/com/thealgorithms/searches/SentinelLinearSearchTest.java) - - πŸ“„ [SortOrderAgnosticBinarySearchTest](src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java) - πŸ“„ [SquareRootBinarySearchTest](src/test/java/com/thealgorithms/searches/SquareRootBinarySearchTest.java) - πŸ“„ [TernarySearchTest](src/test/java/com/thealgorithms/searches/TernarySearchTest.java) - πŸ“„ [TestSearchInARowAndColWiseSortedMatrix](src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java) @@ -1593,7 +1582,6 @@ - πŸ“„ [LetterCombinationsOfPhoneNumberTest](src/test/java/com/thealgorithms/strings/LetterCombinationsOfPhoneNumberTest.java) - πŸ“„ [LongestCommonPrefixTest](src/test/java/com/thealgorithms/strings/LongestCommonPrefixTest.java) - πŸ“„ [LongestNonRepetitiveSubstringTest](src/test/java/com/thealgorithms/strings/LongestNonRepetitiveSubstringTest.java) - - πŸ“„ [LongestPalindromicSubstringTest](src/test/java/com/thealgorithms/strings/LongestPalindromicSubstringTest.java) - πŸ“„ [LowerTest](src/test/java/com/thealgorithms/strings/LowerTest.java) - πŸ“„ [ManacherTest](src/test/java/com/thealgorithms/strings/ManacherTest.java) - πŸ“„ [MyAtoiTest](src/test/java/com/thealgorithms/strings/MyAtoiTest.java) @@ -1609,7 +1597,6 @@ - πŸ“„ [StringMatchFiniteAutomataTest](src/test/java/com/thealgorithms/strings/StringMatchFiniteAutomataTest.java) - πŸ“„ [SuffixArrayTest](src/test/java/com/thealgorithms/strings/SuffixArrayTest.java) - πŸ“„ [UpperTest](src/test/java/com/thealgorithms/strings/UpperTest.java) - - πŸ“„ [ValidParenthesesTest](src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java) - πŸ“„ [WordLadderTest](src/test/java/com/thealgorithms/strings/WordLadderTest.java) - πŸ“„ [ZAlgorithmTest](src/test/java/com/thealgorithms/strings/ZAlgorithmTest.java) - πŸ“ **zigZagPattern** diff --git a/README-ko.md b/README-ko.md deleted file mode 100644 index 4f8cab92fc42..000000000000 --- a/README-ko.md +++ /dev/null @@ -1,191 +0,0 @@ -# μ•Œκ³ λ¦¬μ¦˜ - μžλ°” - -## 이 [개발브런치](https://github.com/TheAlgorithms/Java/tree/Development)λŠ” κΈ°μ‘΄ ν”„λ‘œμ νŠΈλ₯Ό Java ν”„λ‘œμ νŠΈ ꡬ쑰둜 μž¬κ°œλ°œν•˜κΈ° μœ„ν•΄ μž‘μ„±λ˜μ—ˆλ‹€. 기여도λ₯Ό μœ„ν•΄ 개발 μ§€μ‚¬λ‘œ μ „ν™˜ν•  수 μžˆλ‹€. μžμ„Έν•œ λ‚΄μš©μ€ 이 문제λ₯Ό μ°Έμ‘°ν•˜μ‹­μ‹œμ˜€. μ»¨νŠΈλ¦¬λ·°μ…˜μ„ μœ„ν•΄ [개발브런치](https://github.com/TheAlgorithms/Java/tree/Development)둜 μ „ν™˜ν•  수 μžˆλ‹€. μžμ„Έν•œ λ‚΄μš©μ€ [이 이슈](https://github.com/TheAlgorithms/Java/issues/474)λ₯Ό μ°Έκ³ ν•˜μ‹­μ‹œμ˜€. - -### μžλ°”λ‘œ κ΅¬ν˜„λœ λͺ¨λ“  μ•Œκ³ λ¦¬μ¦˜λ“€ (ꡐ윑용) - -이것듀은 단지 μ‹œλ²”μ„ μœ„ν•œ 것이닀. ν‘œμ€€ μžλ°” λΌμ΄λΈŒλŸ¬λ¦¬μ—λŠ” μ„±λŠ₯μƒμ˜ 이유둜 더 λ‚˜μ€ 것듀이 κ΅¬ν˜„λ˜μ–΄μžˆλ‹€ - -## μ •λ ¬ μ•Œκ³ λ¦¬μ¦˜ - -### Bubble(버블 μ •λ ¬) - -![alt text][bubble-image] - -From [Wikipedia][bubble-wiki]: 버블 μ†ŒνŠΈ(sinking sor라고도 λΆˆλ¦¬μ›€)λŠ” 리슀트λ₯Ό 반볡적인 λ‹¨κ³„λ‘œ μ ‘κ·Όν•˜μ—¬ μ •λ ¬ν•œλ‹€. 각각의 짝을 λΉ„κ΅ν•˜λ©°, μˆœμ„œκ°€ 잘λͺ»λœ 경우 κ·Έμ ‘ν•œ μ•„μ΄ν…œλ“€μ„ μŠ€μ™‘ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜μ΄λ‹€. 더 이상 μŠ€μ™‘ν•  것이 없을 λ•ŒκΉŒμ§€ λ°˜λ³΅ν•˜λ©°, 반볡이 λλ‚¨μŒ λ¦¬μŠ€νŠΈκ°€ μ •λ ¬λ˜μ—ˆμŒμ„ μ˜λ―Έν•œλ‹€. - -**속성** - -- μ΅œμ•…μ˜ μ„±λŠ₯ O(n^2) -- 졜고의 μ„±λŠ₯ O(n) -- 평균 μ„±λŠ₯ O(n^2) - -###### View the algorithm in [action][bubble-toptal] - -### Insertion(μ‚½μž… μ •λ ¬) - -![alt text][insertion-image] - -From [Wikipedia][insertion-wiki]: μ‚½μž… 정렬은 μ΅œμ’… μ •λ ¬λœ λ°°μ—΄(λ˜λŠ” 리슀트)을 ν•œλ²ˆμ— ν•˜λ‚˜μ”© κ΅¬μΆ•ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜μ΄λ‹€. 이것은 큰 λ¦¬μŠ€νŠΈμ—μ„œ 더 λ‚˜μ€ μ•Œκ³ λ¦¬μ¦˜μΈ 퀡 μ†ŒνŠΈ, νž™ μ†ŒνŠΈ, λ˜λŠ” λ¨Έμ§€ μ†ŒνŠΈλ³΄λ‹€ 훨씬 μ•ˆμ’‹μ€ νš¨μœ¨μ„ κ°€μ§„λ‹€. κ·Έλ¦Όμ—μ„œ 각 λ§‰λŒ€λŠ” μ •λ ¬ν•΄μ•Ό ν•˜λŠ” λ°°μ—΄μ˜ μš”μ†Œλ₯Ό λ‚˜νƒ€λ‚Έλ‹€. 상단과 두 번째 상단 λ§‰λŒ€μ˜ 첫 번째 κ΅μ°¨μ μ—μ„œ λ°œμƒν•˜λŠ” 것은 두 번째 μš”μ†Œκ°€ 첫 번째 μš”μ†Œλ³΄λ‹€ 더 높은 μš°μ„  μˆœμœ„λ₯Ό κ°€μ§€κΈ° λ•Œλ¬Έμ— λ§‰λŒ€λ‘œ ν‘œμ‹œλ˜λŠ” μ΄λŸ¬ν•œ μš”μ†Œλ₯Ό κ΅ν™˜ν•œ 것이닀. 이 방법을 λ°˜λ³΅ν•˜λ©΄ μ‚½μž… 정렬이 μ™„λ£Œλœλ‹€. - -**속성** - -- μ΅œμ•…μ˜ μ„±λŠ₯ O(n^2) -- 졜고의 μ„±λŠ₯ O(n) -- 평균 O(n^2) - -###### View the algorithm in [action][insertion-toptal] - -### Merge(합병 μ •λ ¬) - -![alt text][merge-image] - -From [Wikipedia][merge-wiki]: 컴퓨터 κ³Όν•™μ—μ„œ, 합병 정렬은 효율적인, λ²”μš©μ μΈ, 비ꡐ 기반 μ •λ ¬ μ•Œκ³ λ¦¬μ¦˜μ΄λ‹€. λŒ€λΆ€λΆ„μ˜ κ΅¬ν˜„μ€ μ•ˆμ •μ μΈ λΆ„λ₯˜λ₯Ό μ΄λ£¨λŠ”λ°, 이것은 κ΅¬ν˜„μ΄ μ •λ ¬λœ 좜λ ₯에 λ™μΌν•œ μš”μ†Œμ˜ μž…λ ₯ μˆœμ„œλ₯Ό μœ μ§€ν•œλ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€. 합병 정렬은 1945년에 John von Neumann이 발λͺ…ν•œ λΆ„ν•  정볡 μ•Œκ³ λ¦¬μ¦˜μ΄λ‹€. - -**속성** - -- μ΅œμ•…μ˜ μ„±λŠ₯ O(n log n) (일반적) -- 졜고의 μ„±λŠ₯ O(n log n) -- 평균 O(n log n) - -###### View the algorithm in [action][merge-toptal] - -### Quick(퀡 μ •λ ¬) - -![alt text][quick-image] - -From [Wikipedia][quick-wiki]: 퀡 μ •λ ¬sometimes called partition-exchange sort)은 효율적인 μ •λ ¬ μ•Œκ³ λ¦¬μ¦˜μœΌλ‘œ, λ°°μ—΄μ˜ μš”μ†Œλ₯Ό μˆœμ„œλŒ€λ‘œ μ •λ ¬ν•˜λŠ” 체계적인 방법 μ—­ν™œμ„ ν•œλ‹€. - -**속성** - -- μ΅œμ•…μ˜ μ„±λŠ₯ O(n^2) -- 졜고의 μ„±λŠ₯ O(n log n) or O(n) with three-way partition -- 평균 O(n log n) - -###### View the algorithm in [action][quick-toptal] - -### Selection(선택 μ •λ ¬) - -![alt text][selection-image] - -From [Wikipedia][selection-wiki]: μ•Œκ³ λ¦¬μ¦˜ μž…λ ₯ 리슀트λ₯Ό 두 λΆ€λΆ„μœΌλ‘œ λ‚˜λˆˆλ‹€ : 첫 뢀뢄은 μ•„μ΄ν…œλ“€μ΄ 이미 μ™Όμͺ½μ—μ„œ 였λ₯Έμͺ½μœΌλ‘œ μ •λ ¬λ˜μ—ˆλ‹€. 그리고 남은 λΆ€λΆ„μ˜ μ•„μ΄ν…œλ“€μ€ λ‚˜λ¨Έμ§€ ν•­λͺ©μ„ μ°¨μ§€ν•˜λŠ” λ¦¬μŠ€νŠΈμ΄λ‹€. μ²˜μŒμ—λŠ” μ •λ ¬λœ λ¦¬μŠ€νŠΈλŠ” 곡백이고 λ‚˜λ¨Έμ§€κ°€ 전뢀이닀. 였λ₯΄μ°¨μˆœ(λ˜λŠ” λ‚΄λ¦Όμ°¨μˆœ) μ•Œκ³ λ¦¬μ¦˜μ€ κ°€μž₯ μž‘μ€ μš”μ†Œλ₯Ό μ •λ ¬λ˜μ§€ μ•Šμ€ λ¦¬μŠ€νŠΈμ—μ„œ μ°Ύκ³  정렬이 μ•ˆλœ κ°€μž₯ μ™Όμͺ½(μ •λ ¬λœ 리슀트) λ¦¬μŠ€νŠΈμ™€ λ°”κΎΌλ‹€. μ΄λ ‡κ²Œ 였λ₯Έμͺ½μœΌλ‘œ λ‚˜μ•„κ°„λ‹€. - -**속성** - -- μ΅œμ•…μ˜ μ„±λŠ₯ O(n^2) -- 졜고의 μ„±λŠ₯ O(n^2) -- 평균 O(n^2) - -###### View the algorithm in [action][selection-toptal] - -### Shell(μ‰˜ μ •λ ¬) - -![alt text][shell-image] - -From [Wikipedia][shell-wiki]: μ‰˜ 정렬은 멀리 λ–¨μ–΄μ Έ μžˆλŠ” ν•­λͺ©μ˜ κ΅ν™˜μ„ ν—ˆμš©ν•˜λŠ” μ‚½μž… μ’…λ₯˜μ˜ μΌλ°˜ν™”μ΄λ‹€. κ·Έ μ•„μ΄λ””μ–΄λŠ” λͺ¨λ“  n번째 μš”μ†Œκ°€ μ •λ ¬λœ λͺ©λ‘μ„ μ œκ³΅ν•œλ‹€λŠ” 것을 κ³ λ €ν•˜μ—¬ μ–΄λŠ κ³³μ—μ„œλ“ μ§€ μ‹œμž‘ν•˜λ„λ‘ μš”μ†Œμ˜ λͺ©λ‘μ„ λ°°μ—΄ν•˜λŠ” 것이닀. μ΄λŸ¬ν•œ λͺ©λ‘μ€ h-sorted둜 μ•Œλ €μ Έ μžˆλ‹€. λ§ˆμ°¬κ°€μ§€λ‘œ, 각각 κ°œλ³„μ μœΌλ‘œ μ •λ ¬λœ h μΈν„°λ¦¬λΈŒ λͺ©λ‘μœΌλ‘œ κ°„μ£Όν•  수 μžˆλ‹€. - -**속성** - -- μ΅œμ•…μ˜ μ„±λŠ₯ O(nlog2 2n) -- 졜고의 μ„±λŠ₯ O(n log n) -- Average case performance depends on gap sequence - -###### View the algorithm in [action][shell-toptal] - -### μ‹œκ°„ λ³΅μž‘μ„± κ·Έλž˜ν”„ - -μ •λ ¬ μ•Œκ³ λ¦¬μ¦˜μ˜ λ³΅μž‘μ„± 비ꡐ (버블 μ •λ ¬, μ‚½μž… μ •λ ¬, 선택 μ •λ ¬) - -[λ³΅μž‘μ„± κ·Έλž˜ν”„](https://github.com/prateekiiest/Python/blob/master/sorts/sortinggraphs.png) - ---- - -## 검색 μ•Œκ³ λ¦¬μ¦˜ - -### Linear (μ„ ν˜• 탐색) - -![alt text][linear-image] - -From [Wikipedia][linear-wiki]: μ„ ν˜• 탐색 λ˜λŠ” 순차 탐색은 λͺ©λ‘ λ‚΄μ—μ„œ λͺ©ν‘œκ°’을 μ°ΎλŠ” 방법이닀. 일치 ν•­λͺ©μ΄ λ°œκ²¬λ˜κ±°λ‚˜ λͺ¨λ“  μš”μ†Œκ°€ 탐색될 λ•ŒκΉŒμ§€ λͺ©λ‘μ˜ 각 μš”μ†Œμ— λŒ€ν•΄ λͺ©ν‘œκ°’을 순차적으둜 κ²€μ‚¬ν•œλ‹€. -μ„ ν˜• 검색은 μ΅œμ•…μ˜ μ„ ν˜• μ‹œκ°„μœΌλ‘œ μ‹€ν–‰λ˜λ©° μ΅œλŒ€ n개의 λΉ„κ΅μ—μ„œ 이루어진닀. μ—¬κΈ°μ„œ n은 λͺ©λ‘μ˜ 길이닀. - -**속성** - -- μ΅œμ•…μ˜ μ„±λŠ₯ O(n) -- 졜고의 μ„±λŠ₯ O(1) -- 평균 O(n) -- μ΅œμ•…μ˜ 경우 곡간 λ³΅μž‘μ„± O(1) iterative - -### Binary (이진 탐색) - -![alt text][binary-image] - -From [Wikipedia][binary-wiki]: 이진 탐색, (also known as half-interval search or logarithmic search), 은 μ •λ ¬λœ λ°°μ—΄ λ‚΄μ—μ„œ λͺ©ν‘œκ°’μ˜ μœ„μΉ˜λ₯Ό μ°ΎλŠ” 검색 μ•Œκ³ λ¦¬μ¦˜μ΄λ‹€. λͺ©ν‘œκ°’을 λ°°μ—΄μ˜ 쀑간 μš”μ†Œμ™€ λΉ„κ΅ν•œλ‹€; λ§Œμ•½ λͺ©ν‘œκ°’이 λ™μΌν•˜μ§€ μ•ŠμœΌλ©΄, λͺ©ν‘œλ¬Όμ˜ 절반이 제거되고 검색이 성곡할 λ•ŒκΉŒμ§€ λ‚˜λ¨Έμ§€ μ ˆλ°˜μ—μ„œ μ†λœλ‹€. - -**속성** - -- μ΅œμ•…μ˜ μ„±λŠ₯ O(log n) -- 졜고의 μ„±λŠ₯ O(1) -- 평균 O(log n) -- μ΅œμ•…μ˜ 경우 곡간 λ³΅μž‘μ„± O(1) - -[bubble-toptal]: https://www.toptal.com/developers/sorting-algorithms/bubble-sort -[bubble-wiki]: https://en.wikipedia.org/wiki/Bubble_sort -[bubble-image]: https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Bubblesort-edited-color.svg/220px-Bubblesort-edited-color.svg.png "Bubble Sort" -[insertion-toptal]: https://www.toptal.com/developers/sorting-algorithms/insertion-sort -[insertion-wiki]: https://en.wikipedia.org/wiki/Insertion_sort -[insertion-image]: https://upload.wikimedia.org/wikipedia/commons/7/7e/Insertionsort-edited.png "Insertion Sort" -[quick-toptal]: https://www.toptal.com/developers/sorting-algorithms/quick-sort -[quick-wiki]: https://en.wikipedia.org/wiki/Quicksort -[quick-image]: https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif "Quick Sort" -[merge-toptal]: https://www.toptal.com/developers/sorting-algorithms/merge-sort -[merge-wiki]: https://en.wikipedia.org/wiki/Merge_sort -[merge-image]: https://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif "Merge Sort" -[selection-toptal]: https://www.toptal.com/developers/sorting-algorithms/selection-sort -[selection-wiki]: https://en.wikipedia.org/wiki/Selection_sort -[selection-image]: https://upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Selection_sort_animation.gif/250px-Selection_sort_animation.gif "Selection Sort Sort" -[shell-toptal]: https://www.toptal.com/developers/sorting-algorithms/shell-sort -[shell-wiki]: https://en.wikipedia.org/wiki/Shellsort -[shell-image]: https://upload.wikimedia.org/wikipedia/commons/d/d8/Sorting_shellsort_anim.gif "Shell Sort" -[linear-wiki]: https://en.wikipedia.org/wiki/Linear_search -[linear-image]: http://www.tutorialspoint.com/data_structures_algorithms/images/linear_search.gif -[binary-wiki]: https://en.wikipedia.org/wiki/Binary_search_algorithm -[binary-image]: https://upload.wikimedia.org/wikipedia/commons/f/f7/Binary_search_into_array.png - ---- - -## λ‚˜λ¨Έμ§€ μ•Œκ³ λ¦¬μ¦˜μ— λŒ€ν•œ 링크 - -| μ „ν™˜ | λ‹€μ΄λ‚˜λ―Ήν”„λ‘œκ·Έλž˜λ°(DP) | μ•”ν˜Έ | κ·Έ μ™Έ 것듀 | -| --------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------ | -| [Any Base to Any Base](Conversions/AnyBaseToAnyBase.java) | [Coin Change](DynamicProgramming/CoinChange.java) | [Caesar](Ciphers/Caesar.java) | [Heap Sort](Sorts/HeapSort.java) | -| [Any Base to Decimal](Conversions/AnyBaseToDecimal.java) | [Egg Dropping](DynamicProgramming/EggDropping.java) | [Columnar Transposition Cipher](Ciphers/ColumnarTranspositionCipher.java) | [Palindromic Prime Checker](Misc/PalindromePrime.java) | -| [Binary to Decimal](Conversions/BinaryToDecimal.java) | [Fibonacci](DynamicProgramming/Fibonacci.java) | [RSA](Ciphers/RSA.java) | More soon... | -| [Binary to HexaDecimal](Conversions/BinaryToHexadecimal.java) | [Kadane Algorithm](DynamicProgramming/KadaneAlgorithm.java) | more coming soon... | -| [Binary to Octal](Conversions/BinaryToOctal.java) | [Knapsack](DynamicProgramming/Knapsack.java) | -| [Decimal To Any Base](Conversions/DecimalToAnyBase.java) | [Longest Common Subsequence](DynamicProgramming/LongestCommonSubsequence.java) | -| [Decimal To Binary](Conversions/DecimalToBinary.java) | [Longest Increasing Subsequence](DynamicProgramming/LongestIncreasingSubsequence.java) | -| [Decimal To Hexadecimal](Conversions/DecimalToHexaDecimal.java) | [Rod Cutting](DynamicProgramming/RodCutting.java) | -| and much more... | and more... | - -### 자료 ꡬ쑰 - -| κ·Έλž˜ν”„ | νž™ | 리슀트 | 큐 | -| ------------------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------- | --------------------------------------------------------------------------- | -| | [빈 νž™ μ˜ˆμ™Έμ²˜λ¦¬](DataStructures/Heaps/EmptyHeapException.java) | [μ›ν˜• μ—°κ²°λ¦¬μŠ€νŠΈ](DataStructures/Lists/CircleLinkedList.java) | [μ œλ„ˆλ¦­ μ–΄λ ˆμ΄ 리슀트 큐](DataStructures/Queues/GenericArrayListQueue.java) | -| | [νž™](DataStructures/Heaps/Heap.java) | [이쀑 μ—°κ²°λ¦¬μŠ€νŠΈ](DataStructures/Lists/DoublyLinkedList.java) | [큐](DataStructures/Queues/Queues.java) | -| [κ·Έλž˜ν”„](DataStructures/Graphs/Graphs.java) | [νž™ μš”μ†Œ](DataStructures/Heaps/HeapElement.java) | [λ‹¨μˆœ μ—°κ²°λ¦¬μŠ€νŠΈ](DataStructures/Lists/SinglyLinkedList.java) | -| [크루슀칼 μ•Œκ³ λ¦¬μ¦˜](DataStructures/Graphs/Kruskal.java) | [μ΅œλŒ€νž™](DataStructures/Heaps/MaxHeap.java) | -| [ν–‰λ ¬ κ·Έλž˜ν”„](DataStructures/Graphs/MatrixGraphs.java) | [μ΅œμ†Œνž™](DataStructures/Heaps/MinHeap.java) | -| [ν”„λ¦Ό μ΅œμ†Œμ‹ μž₯트리](DataStructures/Graphs/PrimMST.java) | - -| μŠ€νƒ | 트리 | -| --------------------------------------------------------------- | ------------------------------------------------- | -| [λ…Έλ“œ μŠ€νƒ](DataStructures/Stacks/NodeStack.java) | [AVL 트리](DataStructures/Trees/AVLTree.java) | -| [μ—°κ²°λ¦¬μŠ€νŠΈ μŠ€νƒ](DataStructures/Stacks/StackOfLinkedList.java) | [이진 트리](DataStructures/Trees/BinaryTree.java) | -| [μŠ€νƒ](DataStructures/Stacks) | And much more... | - -- [Bags](DataStructures/Bags/Bag.java) -- [Buffer](DataStructures/Buffers/CircularBuffer.java) -- [HashMap](DataStructures/HashMap/Hashing/HashMap.java) -- diff --git a/pom.xml b/pom.xml index 73869d6dd942..f13169cece97 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ UTF-8 21 21 - 3.27.6 + 3.27.7 @@ -20,7 +20,7 @@ org.junit junit-bom - 6.0.1 + 6.0.2 pom import @@ -69,7 +69,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.14.1 + 3.15.0 21 @@ -112,7 +112,7 @@ com.puppycrawl.tools checkstyle - 13.0.0 + 13.1.0 @@ -127,7 +127,7 @@ com.mebigfatguy.fb-contrib fb-contrib - 7.7.2 + 7.7.4 com.h3xstream.findsecbugs diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml index 3e2f1ff84ca8..1390387bacdf 100644 --- a/spotbugs-exclude.xml +++ b/spotbugs-exclude.xml @@ -207,6 +207,12 @@ + + + + + + diff --git a/src/main/java/com/thealgorithms/ciphers/ElGamalCipher.java b/src/main/java/com/thealgorithms/ciphers/ElGamalCipher.java new file mode 100644 index 000000000000..6383caa59b1f --- /dev/null +++ b/src/main/java/com/thealgorithms/ciphers/ElGamalCipher.java @@ -0,0 +1,174 @@ +package com.thealgorithms.ciphers; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/** + * ElGamal Encryption Algorithm Implementation. + * + *

+ * ElGamal is an asymmetric key encryption algorithm for public-key cryptography + * based on the Diffie–Hellman key exchange. It relies on the difficulty + * of computing discrete logarithms in a cyclic group. + *

+ * + *

+ * Key Features: + *

    + *
  • Uses Safe Primes (p = 2q + 1) to ensure group security.
  • + *
  • Verifies the generator is a primitive root modulo p.
  • + *
  • Stateless design using Java Records.
  • + *
  • SecureRandom for all cryptographic operations.
  • + *
+ *

+ * + * @author Chahat Sandhu, singhc7 + * @see ElGamal Encryption (Wikipedia) + * @see Safe Primes + */ +public final class ElGamalCipher { + + private static final SecureRandom RANDOM = new SecureRandom(); + private static final int PRIME_CERTAINTY = 40; + private static final int MIN_BIT_LENGTH = 256; + + private ElGamalCipher() { + } + + /** + * A container for the Public and Private keys. + * + * @param p The prime modulus. + * @param g The generator (primitive root). + * @param y The public key component (g^x mod p). + * @param x The private key. + */ + public record KeyPair(BigInteger p, BigInteger g, BigInteger y, BigInteger x) { + } + + /** + * Container for the encryption result. + * + * @param a The first component (g^k mod p). + * @param b The second component (y^k * m mod p). + */ + public record CipherText(BigInteger a, BigInteger b) { + } + + /** + * Generates a valid ElGamal KeyPair using a Safe Prime. + * + * @param bitLength The bit length of the prime modulus p. Must be at least 256. + * @return A valid KeyPair (p, g, y, x). + * @throws IllegalArgumentException if bitLength is too small. + */ + public static KeyPair generateKeys(int bitLength) { + if (bitLength < MIN_BIT_LENGTH) { + throw new IllegalArgumentException("Bit length must be at least " + MIN_BIT_LENGTH + " for security."); + } + + BigInteger p; + BigInteger q; + BigInteger g; + BigInteger x; + BigInteger y; + + // Generate Safe Prime p = 2q + 1 + do { + q = new BigInteger(bitLength - 1, PRIME_CERTAINTY, RANDOM); + p = q.multiply(BigInteger.TWO).add(BigInteger.ONE); + } while (!p.isProbablePrime(PRIME_CERTAINTY)); + + // Find a Generator g (Primitive Root modulo p) + do { + g = new BigInteger(bitLength, RANDOM).mod(p.subtract(BigInteger.TWO)).add(BigInteger.TWO); + } while (!isValidGenerator(g, p, q)); + + // Generate Private Key x in range [2, p-2] + do { + x = new BigInteger(bitLength, RANDOM); + } while (x.compareTo(BigInteger.TWO) < 0 || x.compareTo(p.subtract(BigInteger.TWO)) > 0); + + // Compute Public Key y = g^x mod p + y = g.modPow(x, p); + + return new KeyPair(p, g, y, x); + } + + /** + * Encrypts a message using the public key. + * + * @param message The message converted to BigInteger. + * @param p The prime modulus. + * @param g The generator. + * @param y The public key component. + * @return The CipherText pair (a, b). + * @throws IllegalArgumentException if inputs are null, negative, or message >= p. + */ + public static CipherText encrypt(BigInteger message, BigInteger p, BigInteger g, BigInteger y) { + if (message == null || p == null || g == null || y == null) { + throw new IllegalArgumentException("Inputs cannot be null."); + } + if (message.compareTo(BigInteger.ZERO) < 0) { + throw new IllegalArgumentException("Message must be non-negative."); + } + if (message.compareTo(p) >= 0) { + throw new IllegalArgumentException("Message must be smaller than the prime modulus p."); + } + + BigInteger k; + BigInteger pMinus1 = p.subtract(BigInteger.ONE); + + // Select ephemeral key k such that 1 < k < p-1 and gcd(k, p-1) = 1 + do { + k = new BigInteger(p.bitLength(), RANDOM); + } while (k.compareTo(BigInteger.ONE) <= 0 || k.compareTo(pMinus1) >= 0 || !k.gcd(pMinus1).equals(BigInteger.ONE)); + + BigInteger a = g.modPow(k, p); + BigInteger b = y.modPow(k, p).multiply(message).mod(p); + + return new CipherText(a, b); + } + + /** + * Decrypts a ciphertext using the private key. + * + * @param cipher The CipherText (a, b). + * @param x The private key. + * @param p The prime modulus. + * @return The decrypted message as BigInteger. + * @throws IllegalArgumentException if inputs are null. + */ + public static BigInteger decrypt(CipherText cipher, BigInteger x, BigInteger p) { + if (cipher == null || x == null || p == null) { + throw new IllegalArgumentException("Inputs cannot be null."); + } + + BigInteger a = cipher.a(); + BigInteger b = cipher.b(); + + BigInteger s = a.modPow(x, p); + BigInteger sInverse = s.modInverse(p); + + return b.multiply(sInverse).mod(p); + } + + /** + * Verifies if g is a valid generator for safe prime p = 2q + 1. + * + * @param g The candidate generator. + * @param p The safe prime. + * @param q The Sophie Germain prime (p-1)/2. + * @return True if g is a primitive root, False otherwise. + */ + private static boolean isValidGenerator(BigInteger g, BigInteger p, BigInteger q) { + // Fix: Must use braces {} for all if statements + if (g.equals(BigInteger.ONE)) { + return false; + } + if (g.modPow(BigInteger.TWO, p).equals(BigInteger.ONE)) { + return false; + } + return !g.modPow(q, p).equals(BigInteger.ONE); + } +} diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/Readme.md b/src/main/java/com/thealgorithms/datastructures/hashmap/Readme.md index 252b06ea59b0..4400a97d8128 100644 --- a/src/main/java/com/thealgorithms/datastructures/hashmap/Readme.md +++ b/src/main/java/com/thealgorithms/datastructures/hashmap/Readme.md @@ -2,6 +2,8 @@ A hash map organizes data so you can quickly look up values for a given key. +> Note: The term β€œhash map” refers to the data structure concept, while `HashMap` refers specifically to Java’s implementation. + ## Strengths: - **Fast lookups**: Lookups take O(1) time on average. - **Flexible keys**: Most data types can be used for keys, as long as they're hashable. diff --git a/src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java new file mode 100644 index 000000000000..0ee788db2ff9 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java @@ -0,0 +1,46 @@ +package com.thealgorithms.datastructures.lists; + +/** + * Returns the middle node of a singly linked list using the two-pointer technique. + * + *

The {@code slow} pointer advances by one node per iteration while {@code fast} advances by two. + * When {@code fast == null} or {@code fast.next == null}, {@code slow} points to the middle node. + * For even-length lists, this returns the second middle node.

+ * + *

This method does not modify the input list.

+ * + *

Reference: https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare

+ * + *

Complexity:

+ *
    + *
  • Time: {@code O(n)}
  • + *
  • Space: {@code O(1)}
  • + *
+ */ +public final class MiddleOfLinkedList { + + private MiddleOfLinkedList() { + } + + /** + * Returns the middle node of the list. + * + * @param head the head of the singly linked list; may be {@code null} + * @return the middle node (second middle for even-sized lists), or {@code null} if {@code head} is {@code null} + */ + public static SinglyLinkedListNode middleNode(final SinglyLinkedListNode head) { + if (head == null) { + return null; + } + + SinglyLinkedListNode slow = head; + SinglyLinkedListNode fast = head; + + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + } + + return slow; + } +} diff --git a/src/main/java/com/thealgorithms/maths/BellNumbers.java b/src/main/java/com/thealgorithms/maths/BellNumbers.java new file mode 100644 index 000000000000..d4dc1014f48b --- /dev/null +++ b/src/main/java/com/thealgorithms/maths/BellNumbers.java @@ -0,0 +1,59 @@ +package com.thealgorithms.maths; + +/** + * The Bell numbers count the number of partitions of a set. + * The n-th Bell number is the number of ways a set of n elements can be partitioned + * into nonempty subsets. + * + *

+ * This implementation uses the Bell Triangle (Aitken's array) method. + * Time Complexity: O(n^2) + * Space Complexity: O(n^2) + *

+ * + * @author Chahat Sandhu, singhc7 + * @see Bell Number (Wikipedia) + */ +public final class BellNumbers { + + private BellNumbers() { + } + + /** + * Calculates the n-th Bell number using the Bell Triangle. + * + * @param n the index of the Bell number (must be non-negative) + * @return the n-th Bell number + * @throws IllegalArgumentException if n is negative or n > 25 + */ + public static long compute(int n) { + if (n < 0) { + throw new IllegalArgumentException("n must be non-negative"); + } + if (n == 0) { + return 1; + } + if (n > 25) { + throw new IllegalArgumentException("n must be <= 25. For larger n, use BigInteger implementation."); + } + + // We use a 2D array to visualize the Bell Triangle + long[][] bellTriangle = new long[n + 1][n + 1]; + + // Base case: The triangle starts with 1 + bellTriangle[0][0] = 1; + + for (int i = 1; i <= n; i++) { + // Rule 1: The first number in a new row is the LAST number of the previous row + bellTriangle[i][0] = bellTriangle[i - 1][i - 1]; + + // Rule 2: Fill the rest of the row by adding the previous neighbor and the upper-left neighbor + for (int j = 1; j <= i; j++) { + bellTriangle[i][j] = bellTriangle[i][j - 1] + bellTriangle[i - 1][j - 1]; + } + } + + // The Bell number B_n is the first number in the n-th row + return bellTriangle[n][0]; + } +} diff --git a/src/main/java/com/thealgorithms/maths/DistanceBetweenTwoPoints.java b/src/main/java/com/thealgorithms/maths/DistanceBetweenTwoPoints.java new file mode 100644 index 000000000000..cd1c9205b328 --- /dev/null +++ b/src/main/java/com/thealgorithms/maths/DistanceBetweenTwoPoints.java @@ -0,0 +1,33 @@ +package com.thealgorithms.maths; + +/** + * Distance Between Two Points in 2D Space. + * + *

This class provides a method to calculate the Euclidean distance between two points in a + * two-dimensional plane. + * + *

Formula: d = sqrt((x2 - x1)^2 + (y2 - y1)^2) + * + *

Reference: https://en.wikipedia.org/wiki/Euclidean_distance + */ +public final class DistanceBetweenTwoPoints { + + private DistanceBetweenTwoPoints() { + // Utility class; prevent instantiation + } + + /** + * Calculate the Euclidean distance between two points. + * + * @param x1 x-coordinate of the first point + * @param y1 y-coordinate of the first point + * @param x2 x-coordinate of the second point + * @param y2 y-coordinate of the second point + * @return Euclidean distance between the two points + */ + public static double calculate(final double x1, final double y1, final double x2, final double y2) { + final double deltaX = x2 - x1; + final double deltaY = y2 - y1; + return Math.sqrt(deltaX * deltaX + deltaY * deltaY); + } +} diff --git a/src/main/java/com/thealgorithms/maths/PerfectSquare.java b/src/main/java/com/thealgorithms/maths/PerfectSquare.java index e9318bd7d805..aec43062121a 100644 --- a/src/main/java/com/thealgorithms/maths/PerfectSquare.java +++ b/src/main/java/com/thealgorithms/maths/PerfectSquare.java @@ -15,6 +15,9 @@ private PerfectSquare() { * false */ public static boolean isPerfectSquare(final int number) { + if (number < 0) { + return false; + } final int sqrt = (int) Math.sqrt(number); return sqrt * sqrt == number; } @@ -27,6 +30,9 @@ public static boolean isPerfectSquare(final int number) { * {@code false} */ public static boolean isPerfectSquareUsingPow(long number) { + if (number < 0) { + return false; + } long a = (long) Math.pow(number, 1.0 / 2); return a * a == number; } diff --git a/src/main/java/com/thealgorithms/others/cn/HammingDistance.java b/src/main/java/com/thealgorithms/others/cn/HammingDistance.java deleted file mode 100644 index c8239d53d606..000000000000 --- a/src/main/java/com/thealgorithms/others/cn/HammingDistance.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.thealgorithms.others.cn; - -public final class HammingDistance { - private HammingDistance() { - } - - private static void checkChar(char inChar) { - if (inChar != '0' && inChar != '1') { - throw new IllegalArgumentException("Input must be a binary string."); - } - } - - public static int compute(char charA, char charB) { - checkChar(charA); - checkChar(charB); - return charA == charB ? 0 : 1; - } - - public static int compute(String bitsStrA, String bitsStrB) { - if (bitsStrA.length() != bitsStrB.length()) { - throw new IllegalArgumentException("Input strings must have the same length."); - } - - int totalErrorBitCount = 0; - - for (int i = 0; i < bitsStrA.length(); i++) { - totalErrorBitCount += compute(bitsStrA.charAt(i), bitsStrB.charAt(i)); - } - - return totalErrorBitCount; - } -} diff --git a/src/main/java/com/thealgorithms/prefixsum/DifferenceArray.java b/src/main/java/com/thealgorithms/prefixsum/DifferenceArray.java new file mode 100644 index 000000000000..1be55039cff0 --- /dev/null +++ b/src/main/java/com/thealgorithms/prefixsum/DifferenceArray.java @@ -0,0 +1,87 @@ +package com.thealgorithms.prefixsum; + +/** + * Implements the Difference Array algorithm. + * + *

+ * The Difference Array is an auxiliary data structure that enables efficient range update operations. + * It is based on the mathematical concept of Finite Differences. + *

+ * + *

+ * Key Operations: + *

    + *
  • Range Update (Add value to [L, R]): O(1)
  • + *
  • Reconstruction (Prefix Sum): O(N)
  • + *
+ *

+ * + * @see Finite Difference (Wikipedia) + * @see Prefix Sum (Wikipedia) + * @author Chahat Sandhu, singhc7 + */ +public class DifferenceArray { + + private final long[] differenceArray; + private final int n; + + /** + * Initializes the Difference Array from a given integer array. + * + * @param inputArray The initial array. Cannot be null or empty. + * @throws IllegalArgumentException if the input array is null or empty. + */ + public DifferenceArray(int[] inputArray) { + if (inputArray == null || inputArray.length == 0) { + throw new IllegalArgumentException("Input array cannot be null or empty."); + } + this.n = inputArray.length; + // Size n + 1 allows for branchless updates at the right boundary (r + 1). + this.differenceArray = new long[n + 1]; + initializeDifferenceArray(inputArray); + } + + private void initializeDifferenceArray(int[] inputArray) { + differenceArray[0] = inputArray[0]; + for (int i = 1; i < n; i++) { + differenceArray[i] = inputArray[i] - inputArray[i - 1]; + } + } + + /** + * Adds a value to all elements in the range [l, r]. + * + *

+ * This method uses a branchless approach by allocating an extra element at the end + * of the array, avoiding the conditional check for the right boundary. + *

+ * + * @param l The starting index (inclusive). + * @param r The ending index (inclusive). + * @param val The value to add. + * @throws IllegalArgumentException if the range is invalid. + */ + public void update(int l, int r, int val) { + if (l < 0 || r >= n || l > r) { + throw new IllegalArgumentException(String.format("Invalid range: [%d, %d] for array of size %d", l, r, n)); + } + + differenceArray[l] += val; + differenceArray[r + 1] -= val; + } + + /** + * Reconstructs the final array using prefix sums. + * + * @return The resulting array after all updates. Returns long[] to handle potential overflows. + */ + public long[] getResultArray() { + long[] result = new long[n]; + result[0] = differenceArray[0]; + + for (int i = 1; i < n; i++) { + result[i] = differenceArray[i] + result[i - 1]; + } + return result; + } +} diff --git a/src/main/java/com/thealgorithms/prefixsum/PrefixSum.java b/src/main/java/com/thealgorithms/prefixsum/PrefixSum.java new file mode 100644 index 000000000000..47f6366e2924 --- /dev/null +++ b/src/main/java/com/thealgorithms/prefixsum/PrefixSum.java @@ -0,0 +1,54 @@ +package com.thealgorithms.prefixsum; + +/** + * A class that implements the Prefix Sum algorithm. + * + *

Prefix Sum is a technique used to preprocess an array such that + * range sum queries can be answered in O(1) time. + * The preprocessing step takes O(N) time. + * + *

This implementation uses a long array for the prefix sums to prevent + * integer overflow when the sum of elements exceeds Integer.MAX_VALUE. + * + * @see Prefix Sum (Wikipedia) + * @author Chahat Sandhu, singhc7 + */ +public class PrefixSum { + + private final long[] prefixSums; + + /** + * Constructor to preprocess the input array. + * + * @param array The input integer array. + * @throws IllegalArgumentException if the array is null. + */ + public PrefixSum(int[] array) { + if (array == null) { + throw new IllegalArgumentException("Input array cannot be null"); + } + this.prefixSums = new long[array.length + 1]; + this.prefixSums[0] = 0; + + for (int i = 0; i < array.length; i++) { + // Automatically promotes int to long during addition + this.prefixSums[i + 1] = this.prefixSums[i] + array[i]; + } + } + + /** + * Calculates the sum of elements in the range [left, right]. + * Indices are 0-based. + * + * @param left The starting index (inclusive). + * @param right The ending index (inclusive). + * @return The sum of elements from index left to right as a long. + * @throws IndexOutOfBoundsException if indices are out of valid range. + */ + public long sumRange(int left, int right) { + if (left < 0 || right >= prefixSums.length - 1 || left > right) { + throw new IndexOutOfBoundsException("Invalid range indices"); + } + return prefixSums[right + 1] - prefixSums[left]; + } +} diff --git a/src/main/java/com/thealgorithms/prefixsum/PrefixSum2D.java b/src/main/java/com/thealgorithms/prefixsum/PrefixSum2D.java new file mode 100644 index 000000000000..9c168bc6bcc4 --- /dev/null +++ b/src/main/java/com/thealgorithms/prefixsum/PrefixSum2D.java @@ -0,0 +1,64 @@ +package com.thealgorithms.prefixsum; + +/** + * A class that implements the 2D Prefix Sum algorithm. + * + *

2D Prefix Sum is a technique used to preprocess a 2D matrix such that + * sub-matrix sum queries can be answered in O(1) time. + * The preprocessing step takes O(N*M) time. + * + *

This implementation uses a long array for the prefix sums to prevent + * integer overflow. + * + * @see Summed-area table (Wikipedia) + * @author Chahat Sandhu, singhc7 + */ +public class PrefixSum2D { + + private final long[][] prefixSums; + + /** + * Constructor to preprocess the input matrix. + * + * @param matrix The input integer matrix. + * @throws IllegalArgumentException if the matrix is null or empty. + */ + public PrefixSum2D(int[][] matrix) { + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { + throw new IllegalArgumentException("Input matrix cannot be null or empty"); + } + + int rows = matrix.length; + int cols = matrix[0].length; + this.prefixSums = new long[rows + 1][cols + 1]; + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + // P[i+1][j+1] = current + above + left - diagonal_overlap + this.prefixSums[i + 1][j + 1] = matrix[i][j] + this.prefixSums[i][j + 1] + this.prefixSums[i + 1][j] - this.prefixSums[i][j]; + } + } + } + + /** + * Calculates the sum of the sub-matrix defined by (row1, col1) to (row2, col2). + * Indices are 0-based. + * + * @param row1 Top row index. + * @param col1 Left column index. + * @param row2 Bottom row index. + * @param col2 Right column index. + * @return The sum of the sub-matrix. + * @throws IndexOutOfBoundsException if indices are invalid. + */ + public long sumRegion(int row1, int col1, int row2, int col2) { + if (row1 < 0 || row2 >= prefixSums.length - 1 || row2 < row1) { + throw new IndexOutOfBoundsException("Invalid row indices"); + } + if (col1 < 0 || col2 >= prefixSums[0].length - 1 || col2 < col1) { + throw new IndexOutOfBoundsException("Invalid column indices"); + } + + return prefixSums[row2 + 1][col2 + 1] - prefixSums[row1][col2 + 1] - prefixSums[row2 + 1][col1] + prefixSums[row1][col1]; + } +} diff --git a/src/main/java/com/thealgorithms/prefixsum/SubarraySumEqualsK.java b/src/main/java/com/thealgorithms/prefixsum/SubarraySumEqualsK.java new file mode 100644 index 000000000000..d6a6bbc01663 --- /dev/null +++ b/src/main/java/com/thealgorithms/prefixsum/SubarraySumEqualsK.java @@ -0,0 +1,72 @@ +package com.thealgorithms.prefixsum; + +import java.util.HashMap; +import java.util.Map; + +/** + * Implements an algorithm to count the number of continuous subarrays + * whose sum equals a given value k. + * + *

+ * This algorithm uses the Prefix Sum technique combined with a HashMap + * to achieve O(N) time complexity. + *

+ * + *

+ * Let prefixSum[i] be the sum of elements from index 0 to i. + * A subarray (j + 1) to i has sum k if: + * + *

+ * prefixSum[i] - prefixSum[j] = k
+ * 
+ *

+ * + *

+ * The HashMap stores the frequency of each prefix sum encountered so far. + *

+ * + *

+ * Time Complexity: O(N)
+ * Space Complexity: O(N) + *

+ * + * @see Prefix Sum (Wikipedia) + * @author Ruturaj Jadhav, ruturajjadhav07 + */ +public final class SubarraySumEqualsK { + + private SubarraySumEqualsK() { + // Utility class; prevent instantiation + } + + /** + * Counts the number of subarrays whose sum equals k. + * + * @param nums The input integer array. + * @param k The target sum. + * @return The number of continuous subarrays summing to k. + * @throws IllegalArgumentException if nums is null. + */ + public static int countSubarrays(int[] nums, int k) { + if (nums == null) { + throw new IllegalArgumentException("Input array cannot be null"); + } + + Map prefixSumFrequency = new HashMap<>(); + prefixSumFrequency.put(0L, 1); + + long prefixSum = 0; + int count = 0; + + for (int num : nums) { + prefixSum += num; + + long requiredSum = prefixSum - k; + count += prefixSumFrequency.getOrDefault(requiredSum, 0); + + prefixSumFrequency.put(prefixSum, prefixSumFrequency.getOrDefault(prefixSum, 0) + 1); + } + + return count; + } +} diff --git a/src/main/java/com/thealgorithms/recursion/FibonacciSeries.java b/src/main/java/com/thealgorithms/recursion/FibonacciSeries.java index 9bc6da2f7443..9c809858099e 100644 --- a/src/main/java/com/thealgorithms/recursion/FibonacciSeries.java +++ b/src/main/java/com/thealgorithms/recursion/FibonacciSeries.java @@ -1,16 +1,26 @@ package com.thealgorithms.recursion; -/* - The Fibonacci series is a sequence of numbers where each number is the sum of the two preceding ones, - starting with 0 and 1. - NUMBER 0 1 2 3 4 5 6 7 8 9 10 ... - FIBONACCI 0 1 1 2 3 5 8 13 21 34 55 ... -*/ +/** + * The Fibonacci series is a sequence of numbers where each number is the sum of the two preceding ones, + * starting with 0 and 1. + *

+ * Example: + * 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ... + *

+ */ public final class FibonacciSeries { private FibonacciSeries() { throw new UnsupportedOperationException("Utility class"); } + + /** + * Calculates the nth term in the Fibonacci sequence using recursion. + * + * @param n the position in the Fibonacci sequence (must be non-negative) + * @return the nth Fibonacci number + * @throws IllegalArgumentException if n is negative + */ public static int fibonacci(int n) { if (n < 0) { throw new IllegalArgumentException("n must be a non-negative integer"); diff --git a/src/main/java/com/thealgorithms/searches/BinarySearch.java b/src/main/java/com/thealgorithms/searches/BinarySearch.java index bedad1667f33..7a5361b280ea 100644 --- a/src/main/java/com/thealgorithms/searches/BinarySearch.java +++ b/src/main/java/com/thealgorithms/searches/BinarySearch.java @@ -3,12 +3,32 @@ import com.thealgorithms.devutils.searches.SearchAlgorithm; /** - * Binary search is one of the most popular algorithms The algorithm finds the - * position of a target value within a sorted array + * Binary Search Algorithm Implementation * - *

- * Worst-case performance O(log n) Best-case performance O(1) Average - * performance O(log n) Worst-case space complexity O(1) + *

Binary search is one of the most efficient searching algorithms for finding a target element + * in a SORTED array. It works by repeatedly dividing the search space in half, eliminating half of + * the remaining elements in each step. + * + *

IMPORTANT: This algorithm ONLY works correctly if the input array is sorted in ascending + * order. + * + *

Algorithm Overview: 1. Start with the entire array (left = 0, right = array.length - 1) 2. + * Calculate the middle index 3. Compare the middle element with the target: - If middle element + * equals target: Found! Return the index - If middle element is less than target: Search the right + * half - If middle element is greater than target: Search the left half 4. Repeat until element is + * found or search space is exhausted + * + *

Performance Analysis: - Best-case time complexity: O(1) - Element found at middle on first + * try - Average-case time complexity: O(log n) - Most common scenario - Worst-case time + * complexity: O(log n) - Element not found or at extreme end - Space complexity: O(1) - Only uses + * a constant amount of extra space + * + *

Example Walkthrough: Array: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] Target: 7 + * + *

Step 1: left=0, right=9, mid=4, array[4]=9 (9 > 7, search left half) Step 2: left=0, + * right=3, mid=1, array[1]=3 (3 < 7, search right half) Step 3: left=2, right=3, mid=2, + * array[2]=5 (5 < 7, search right half) Step 4: left=3, right=3, mid=3, array[3]=7 (Found! + * Return index 3) * * @author Varun Upadhyay (https://github.com/varunu28) * @author Podshivalov Nikita (https://github.com/nikitap492) @@ -18,38 +38,89 @@ class BinarySearch implements SearchAlgorithm { /** - * @param array is an array where the element should be found - * @param key is an element which should be found - * @param is any comparable type - * @return index of the element + * Generic method to perform binary search on any comparable type. This is the main entry point + * for binary search operations. + * + *

Example Usage: + *

+     * Integer[] numbers = {1, 3, 5, 7, 9, 11};
+     * int result = new BinarySearch().find(numbers, 7);
+     * // result will be 3 (index of element 7)
+     *
+     * int notFound = new BinarySearch().find(numbers, 4);
+     * // notFound will be -1 (element 4 does not exist)
+     * 
+ * + * @param The type of elements in the array (must be Comparable) + * @param array The sorted array to search in (MUST be sorted in ascending order) + * @param key The element to search for + * @return The index of the key if found, -1 if not found or if array is null/empty */ @Override public > int find(T[] array, T key) { + // Handle edge case: empty array + if (array == null || array.length == 0) { + return -1; + } + + // Delegate to the core search implementation return search(array, key, 0, array.length - 1); } /** - * This method implements the Generic Binary Search + * Core recursive implementation of binary search algorithm. This method divides the problem + * into smaller subproblems recursively. + * + *

How it works: + *

    + *
  1. Calculate the middle index to avoid integer overflow
  2. + *
  3. Check if middle element matches the target
  4. + *
  5. If not, recursively search either left or right half
  6. + *
  7. Base case: left > right means element not found
  8. + *
+ * + *

Time Complexity: O(log n) because we halve the search space each time. + * Space Complexity: O(log n) due to recursive call stack. * - * @param array The array to make the binary search - * @param key The number you are looking for - * @param left The lower bound - * @param right The upper bound - * @return the location of the key + * @param The type of elements (must be Comparable) + * @param array The sorted array to search in + * @param key The element we're looking for + * @param left The leftmost index of current search range (inclusive) + * @param right The rightmost index of current search range (inclusive) + * @return The index where key is located, or -1 if not found */ private > int search(T[] array, T key, int left, int right) { + // Base case: Search space is exhausted + // This happens when left pointer crosses right pointer if (right < left) { - return -1; // this means that the key not found + return -1; // Key not found in the array } - // find median - int median = (left + right) >>> 1; + + // Calculate middle index + // Using (left + right) / 2 could cause integer overflow for large arrays + // So we use: left + (right - left) / 2 which is mathematically equivalent + // but prevents overflow + int median = (left + right) >>> 1; // Unsigned right shift is faster division by 2 + + // Get the value at middle position for comparison int comp = key.compareTo(array[median]); + // Case 1: Found the target element at middle position if (comp == 0) { - return median; - } else if (comp < 0) { + return median; // Return the index where element was found + } + // Case 2: Target is smaller than middle element + // This means if target exists, it must be in the LEFT half + else if (comp < 0) { + // Recursively search the left half + // New search range: [left, median - 1] return search(array, key, left, median - 1); - } else { + } + // Case 3: Target is greater than middle element + // This means if target exists, it must be in the RIGHT half + else { + // Recursively search the right half + // New search range: [median + 1, right] return search(array, key, median + 1, right); } } diff --git a/src/main/java/com/thealgorithms/searches/LinearSearch.java b/src/main/java/com/thealgorithms/searches/LinearSearch.java index c7b70edb5112..cb483d8dfedc 100644 --- a/src/main/java/com/thealgorithms/searches/LinearSearch.java +++ b/src/main/java/com/thealgorithms/searches/LinearSearch.java @@ -1,21 +1,26 @@ package com.thealgorithms.searches; import com.thealgorithms.devutils.searches.SearchAlgorithm; - /** - * Linear search is the easiest search algorithm It works with sorted and - * unsorted arrays (an binary search works only with sorted array) This - * algorithm just compares all elements of an array to find a value + * Linear Search is a simple searching algorithm that checks + * each element of the array sequentially until the target + * value is found or the array ends. + * + * It works for both sorted and unsorted arrays. * - *

- * Worst-case performance O(n) Best-case performance O(1) Average performance - * O(n) Worst-case space complexity + * Time Complexity: + * - Best case: O(1) + * - Average case: O(n) + * - Worst case: O(n) * - * @author Varun Upadhyay (https://github.com/varunu28) - * @author Podshivalov Nikita (https://github.com/nikitap492) + * Space Complexity: O(1) + * + * @author Varun Upadhyay + * @author Podshivalov Nikita * @see BinarySearch * @see SearchAlgorithm */ + public class LinearSearch implements SearchAlgorithm { /** diff --git a/src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java b/src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java deleted file mode 100644 index 495e2e41bc5b..000000000000 --- a/src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.thealgorithms.searches; - -import com.thealgorithms.devutils.searches.SearchAlgorithm; - -/** - * Binary search is one of the most popular algorithms The algorithm finds the - * position of a target value within a sorted array - * - *

- * Worst-case performance O(log n) Best-case performance O(1) Average - * performance O(log n) Worst-case space complexity O(1) - * - * @author D Sunil (https://github.com/sunilnitdgp) - * @see SearchAlgorithm - */ - -public class PerfectBinarySearch implements SearchAlgorithm { - - /** - * @param array is an array where the element should be found - * @param key is an element which should be found - * @param is any comparable type - * @return index of the element - */ - @Override - public > int find(T[] array, T key) { - return search(array, key, 0, array.length - 1); - } - - /** - * This method implements the Generic Binary Search iteratively. - * - * @param array The array to make the binary search - * @param key The number you are looking for - * @return the location of the key, or -1 if not found - */ - private static > int search(T[] array, T key, int left, int right) { - while (left <= right) { - int median = (left + right) >>> 1; - int comp = key.compareTo(array[median]); - - if (comp == 0) { - return median; // Key found - } - - if (comp < 0) { - right = median - 1; // Adjust the right bound - } else { - left = median + 1; // Adjust the left bound - } - } - return -1; // Key not found - } -} diff --git a/src/main/java/com/thealgorithms/searches/RotatedBinarySearch.java b/src/main/java/com/thealgorithms/searches/RotatedBinarySearch.java new file mode 100644 index 000000000000..86099b2fa2fa --- /dev/null +++ b/src/main/java/com/thealgorithms/searches/RotatedBinarySearch.java @@ -0,0 +1,60 @@ +package com.thealgorithms.searches; + +import com.thealgorithms.devutils.searches.SearchAlgorithm; + +/** + * Searches for a key in a sorted array that has been rotated at an unknown pivot. + * + *

+ * Example: + * {@code [8, 9, 10, 1, 2, 3, 4, 5, 6, 7]} + * + *

+ * This is a modified binary search. When the array contains no duplicates, the + * time complexity is {@code O(log n)}. With duplicates, the algorithm still + * works but may degrade to {@code O(n)} in the worst case. + * + * @see Search in rotated sorted array + * @see SearchAlgorithm + */ +public final class RotatedBinarySearch implements SearchAlgorithm { + + @Override + public > int find(T[] array, T key) { + int left = 0; + int right = array.length - 1; + + while (left <= right) { + int middle = (left + right) >>> 1; + int cmp = key.compareTo(array[middle]); + if (cmp == 0) { + return middle; + } + + // Handle duplicates: if we cannot determine which side is sorted. + if (array[left].compareTo(array[middle]) == 0 && array[middle].compareTo(array[right]) == 0) { + left++; + right--; + continue; + } + + // Left half is sorted. + if (array[left].compareTo(array[middle]) <= 0) { + if (array[left].compareTo(key) <= 0 && key.compareTo(array[middle]) < 0) { + right = middle - 1; + } else { + left = middle + 1; + } + } else { + // Right half is sorted. + if (array[middle].compareTo(key) < 0 && key.compareTo(array[right]) <= 0) { + left = middle + 1; + } else { + right = middle - 1; + } + } + } + + return -1; + } +} diff --git a/src/main/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearch.java b/src/main/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearch.java deleted file mode 100644 index 6a2a46c2821f..000000000000 --- a/src/main/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearch.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.thealgorithms.searches; -public final class SortOrderAgnosticBinarySearch { - private SortOrderAgnosticBinarySearch() { - } - public static int find(int[] arr, int key) { - int start = 0; - int end = arr.length - 1; - boolean arrDescending = arr[start] > arr[end]; // checking for Array is in ascending order or descending order. - while (start <= end) { - int mid = end - start / 2; - if (arr[mid] == key) { - return mid; - } - if (arrDescending) { // boolean is true then our array is in descending order - if (key < arr[mid]) { - start = mid + 1; - } else { - end = mid - 1; - } - } else { // otherwise our array is in ascending order - if (key > arr[mid]) { - start = mid + 1; - } else { - end = mid - 1; - } - } - } - return -1; - } -} diff --git a/src/main/java/com/thealgorithms/slidingwindow/CountNiceSubarrays.java b/src/main/java/com/thealgorithms/slidingwindow/CountNiceSubarrays.java new file mode 100644 index 000000000000..46f8deeb58dd --- /dev/null +++ b/src/main/java/com/thealgorithms/slidingwindow/CountNiceSubarrays.java @@ -0,0 +1,99 @@ +package com.thealgorithms.slidingwindow; + +/** + * Counts the number of "nice subarrays". + * A nice subarray is a contiguous subarray that contains exactly k odd numbers. + * + * This implementation uses the sliding window technique. + * + * Reference: + * https://leetcode.com/problems/count-number-of-nice-subarrays/ + * + * Time Complexity: O(n) + * Space Complexity: O(n) + */ +public final class CountNiceSubarrays { + + // Private constructor to prevent instantiation + private CountNiceSubarrays() { + } + + /** + * Returns the count of subarrays containing exactly k odd numbers. + * + * @param nums input array of integers + * @param k number of odd elements required in the subarray + * @return number of nice subarrays + */ + public static int countNiceSubarrays(int[] nums, int k) { + + int n = nums.length; + + // Left pointer of the sliding window + int left = 0; + + // Tracks number of odd elements in the current window + int oddCount = 0; + + // Final answer: total number of nice subarrays + int result = 0; + + /* + * memo[i] stores how many valid starting positions exist + * when the left pointer is at index i. + * + * This avoids recomputing the same values again. + */ + int[] memo = new int[n]; + + // Right pointer moves forward to expand the window + for (int right = 0; right < n; right++) { + + // If current element is odd, increment odd count + if ((nums[right] & 1) == 1) { + oddCount++; + } + + /* + * If oddCount exceeds k, shrink the window from the left + * until oddCount becomes valid again. + */ + if (oddCount > k) { + left += memo[left]; + oddCount--; + } + + /* + * When the window contains exactly k odd numbers, + * count all possible valid subarrays starting at `left`. + */ + if (oddCount == k) { + + /* + * If this left index hasn't been processed before, + * count how many consecutive even numbers follow it. + */ + if (memo[left] == 0) { + int count = 0; + int temp = left; + + // Count consecutive even numbers + while ((nums[temp] & 1) == 0) { + count++; + temp++; + } + + /* + * Number of valid subarrays starting at `left` + * is (count of even numbers + 1) + */ + memo[left] = count + 1; + } + + // Add number of valid subarrays for this left position + result += memo[left]; + } + } + return result; + } +} diff --git a/src/main/java/com/thealgorithms/sorts/SmoothSort.java b/src/main/java/com/thealgorithms/sorts/SmoothSort.java new file mode 100644 index 000000000000..c45d6f1f02b2 --- /dev/null +++ b/src/main/java/com/thealgorithms/sorts/SmoothSort.java @@ -0,0 +1,168 @@ +package com.thealgorithms.sorts; + +/** + * Smooth Sort is an in-place, comparison-based sorting algorithm proposed by Edsger W. Dijkstra (1981). + * + *

It can be viewed as a variant of heapsort that maintains a forest of heap-ordered Leonardo trees + * (trees whose sizes are Leonardo numbers). The algorithm is adaptive: when the input is already + * sorted or nearly sorted, the heap invariants are often satisfied and the expensive rebalancing + * operations do little work, yielding near-linear behavior. + * + *

Time Complexity: + *

    + *
  • Best case: O(n) for already sorted input
  • + *
  • Average case: O(n log n)
  • + *
  • Worst case: O(n log n)
  • + *
+ * + *

Space Complexity: O(1) auxiliary space (in-place). + * + * @see Smoothsort + * @see Leonardo numbers + * @see SortAlgorithm + */ +public class SmoothSort implements SortAlgorithm { + + /** + * Leonardo numbers (L(0) = L(1) = 1, L(k+2) = L(k+1) + L(k) + 1) up to the largest value that + * fits into a signed 32-bit integer. + */ + private static final int[] LEONARDO = {1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337, + 126491971, 204668309, 331160281, 535828591, 866988873, 1402817465}; + + /** + * Sorts the given array in ascending order using Smooth Sort. + * + * @param array the array to sort + * @param the element type + * @return the sorted array + */ + @Override + public > T[] sort(final T[] array) { + if (array.length < 2) { + return array; + } + + final int last = array.length - 1; + + // The forest shape is encoded as (p, pshift): p is a bit-vector of present tree orders, + // shifted right by pshift. pshift is the order of the rightmost (current) Leonardo tree. + long p = 1L; + int pshift = 1; + + int head = 0; + while (head < last) { + if ((p & 3L) == 3L) { + sift(array, pshift, head); + p >>>= 2; + pshift += 2; + } else { + // Add a new singleton tree; if it will not be merged anymore, we must fully trinkle. + if (LEONARDO[pshift - 1] >= last - head) { + trinkle(array, p, pshift, head, false); + } else { + // This tree will be merged later, so it is enough to restore its internal heap property. + sift(array, pshift, head); + } + + if (pshift == 1) { + // If L(1) is used, the new singleton is L(0). + p <<= 1; + pshift = 0; + } else { + // Otherwise, shift to order 1 and append a singleton of order 1. + p <<= (pshift - 1); + pshift = 1; + } + } + + p |= 1L; + head++; + } + + trinkle(array, p, pshift, head, false); + + // Repeatedly remove the maximum (always at head) by shrinking the heap region. + while (pshift != 1 || p != 1L) { + if (pshift <= 1) { + // Rightmost tree is a singleton (order 0 or 1). Move to the previous tree root. + final long mask = p & ~1L; + final int shift = Long.numberOfTrailingZeros(mask); + p >>>= shift; + pshift += shift; + } else { + // Split a tree of order (pshift) into two children trees of orders (pshift-1) and (pshift-2). + p <<= 2; + p ^= 7L; + pshift -= 2; + + trinkle(array, p >>> 1, pshift + 1, head - LEONARDO[pshift] - 1, true); + trinkle(array, p, pshift, head - 1, true); + } + + head--; + } + + return array; + } + + private static > void sift(final T[] array, int order, int root) { + final T value = array[root]; + + while (order > 1) { + final int right = root - 1; + final int left = root - 1 - LEONARDO[order - 2]; + + if (!SortUtils.less(value, array[left]) && !SortUtils.less(value, array[right])) { + break; + } + + if (!SortUtils.less(array[left], array[right])) { + array[root] = array[left]; + root = left; + order -= 1; + } else { + array[root] = array[right]; + root = right; + order -= 2; + } + } + + array[root] = value; + } + + private static > void trinkle(final T[] array, long p, int order, int root, boolean trusty) { + final T value = array[root]; + + while (p != 1L) { + final int stepson = root - LEONARDO[order]; + + if (!SortUtils.less(value, array[stepson])) { + break; + } + + if (!trusty && order > 1) { + final int right = root - 1; + final int left = root - 1 - LEONARDO[order - 2]; + + if (!SortUtils.less(array[right], array[stepson]) || !SortUtils.less(array[left], array[stepson])) { + break; + } + } + + array[root] = array[stepson]; + root = stepson; + + final long mask = p & ~1L; + final int shift = Long.numberOfTrailingZeros(mask); + p >>>= shift; + order += shift; + trusty = false; + } + + if (!trusty) { + array[root] = value; + sift(array, order, root); + } + } +} diff --git a/src/main/java/com/thealgorithms/sorts/TournamentSort.java b/src/main/java/com/thealgorithms/sorts/TournamentSort.java new file mode 100644 index 000000000000..ec51a1e2c0a9 --- /dev/null +++ b/src/main/java/com/thealgorithms/sorts/TournamentSort.java @@ -0,0 +1,84 @@ +package com.thealgorithms.sorts; + +import java.util.Arrays; + +/** + * Tournament Sort algorithm implementation. + * + * Tournament sort builds a winner tree (a complete binary tree storing the index + * of the smallest element in each subtree). It then repeatedly extracts the + * winner (minimum) and updates the path from the removed leaf to the root. + * + * Time Complexity: + * - Best case: O(n log n) + * - Average case: O(n log n) + * - Worst case: O(n log n) + * + * Space Complexity: O(n) – additional winner-tree storage + * + * @see Tournament Sort Algorithm + * @see SortAlgorithm + */ +public class TournamentSort implements SortAlgorithm { + + @Override + public > T[] sort(T[] array) { + if (array == null || array.length < 2) { + return array; + } + + final int n = array.length; + final int leafCount = nextPowerOfTwo(n); + + // Winner tree represented as an array: + // - Leaves live at [leafCount .. 2*leafCount) + // - Internal nodes live at [1 .. leafCount) + // Each node stores an index into the original array or -1 for "empty". + final int[] tree = new int[2 * leafCount]; + Arrays.fill(tree, -1); + + for (int i = 0; i < n; i++) { + tree[leafCount + i] = i; + } + + for (int node = leafCount - 1; node >= 1; node--) { + tree[node] = winnerIndex(array, tree[node * 2], tree[node * 2 + 1]); + } + + final T[] result = array.clone(); + for (int out = 0; out < n; out++) { + final int winner = tree[1]; + result[out] = array[winner]; + + int node = leafCount + winner; + tree[node] = -1; + + for (node /= 2; node >= 1; node /= 2) { + tree[node] = winnerIndex(array, tree[node * 2], tree[node * 2 + 1]); + } + } + + System.arraycopy(result, 0, array, 0, n); + return array; + } + + private static int nextPowerOfTwo(int n) { + int power = 1; + while (power < n) { + power <<= 1; + } + return power; + } + + private static > int winnerIndex(T[] array, int leftIndex, int rightIndex) { + if (leftIndex == -1) { + return rightIndex; + } + if (rightIndex == -1) { + return leftIndex; + } + + // If equal, prefer the left element to keep ordering deterministic. + return SortUtils.less(array[rightIndex], array[leftIndex]) ? rightIndex : leftIndex; + } +} diff --git a/src/main/java/com/thealgorithms/strings/KMP.java b/src/main/java/com/thealgorithms/strings/KMP.java index 07d3b0415006..0317abe6f39a 100644 --- a/src/main/java/com/thealgorithms/strings/KMP.java +++ b/src/main/java/com/thealgorithms/strings/KMP.java @@ -1,5 +1,8 @@ package com.thealgorithms.strings; +import java.util.ArrayList; +import java.util.List; + /** * Implementation of Knuth–Morris–Pratt algorithm Usage: see the main function * for an example @@ -8,16 +11,19 @@ public final class KMP { private KMP() { } - // a working example - - public static void main(String[] args) { - final String haystack = "AAAAABAAABA"; // This is the full string - final String needle = "AAAA"; // This is the substring that we want to find - kmpMatcher(haystack, needle); - } + /** + * find the starting index in string haystack[] that matches the search word P[] + * + * @param haystack The text to be searched + * @param needle The pattern to be searched for + * @return A list of starting indices where the pattern is found + */ + public static List kmpMatcher(final String haystack, final String needle) { + List occurrences = new ArrayList<>(); + if (haystack == null || needle == null || needle.isEmpty()) { + return occurrences; + } - // find the starting index in string haystack[] that matches the search word P[] - public static void kmpMatcher(final String haystack, final String needle) { final int m = haystack.length(); final int n = needle.length(); final int[] pi = computePrefixFunction(needle); @@ -32,10 +38,11 @@ public static void kmpMatcher(final String haystack, final String needle) { } if (q == n) { - System.out.println("Pattern starts: " + (i + 1 - n)); + occurrences.add(i + 1 - n); q = pi[q - 1]; } } + return occurrences; } // return the prefix function diff --git a/src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java b/src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java deleted file mode 100644 index ca500357ba77..000000000000 --- a/src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.thealgorithms.strings; - -final class LongestPalindromicSubstring { - private LongestPalindromicSubstring() { - } - - /** - * Finds the longest palindromic substring in the given string. - * - * @param s the input string - * @return the longest palindromic substring - */ - public static String longestPalindrome(String s) { - if (s == null || s.isEmpty()) { - return ""; - } - String maxStr = ""; - for (int i = 0; i < s.length(); ++i) { - for (int j = i; j < s.length(); ++j) { - if (isValid(s, i, j) && (j - i + 1 > maxStr.length())) { - maxStr = s.substring(i, j + 1); - } - } - } - return maxStr; - } - - private static boolean isValid(String s, int lo, int hi) { - int n = hi - lo + 1; - for (int i = 0; i < n / 2; ++i) { - if (s.charAt(lo + i) != s.charAt(hi - i)) { - return false; - } - } - return true; - } -} diff --git a/src/main/java/com/thealgorithms/strings/MyAtoi.java b/src/main/java/com/thealgorithms/strings/MyAtoi.java index 5a7c2ce53b1c..92de4039a582 100644 --- a/src/main/java/com/thealgorithms/strings/MyAtoi.java +++ b/src/main/java/com/thealgorithms/strings/MyAtoi.java @@ -45,7 +45,9 @@ public static int myAtoi(String s) { int number = 0; while (index < length) { char ch = s.charAt(index); - if (!Character.isDigit(ch)) { + + // Accept only ASCII digits + if (ch < '0' || ch > '9') { break; } diff --git a/src/main/java/com/thealgorithms/strings/RabinKarp.java b/src/main/java/com/thealgorithms/strings/RabinKarp.java index bb8df3358453..be17f87c3656 100644 --- a/src/main/java/com/thealgorithms/strings/RabinKarp.java +++ b/src/main/java/com/thealgorithms/strings/RabinKarp.java @@ -1,32 +1,30 @@ package com.thealgorithms.strings; -import java.util.Scanner; +import java.util.ArrayList; +import java.util.List; /** * @author Prateek Kumar Oraon (https://github.com/prateekKrOraon) * - An implementation of Rabin-Karp string matching algorithm - Program will simply end if there is no match + * An implementation of Rabin-Karp string matching algorithm + * Program will simply end if there is no match */ public final class RabinKarp { private RabinKarp() { } - public static Scanner scanner = null; - public static final int ALPHABET_SIZE = 256; + private static final int ALPHABET_SIZE = 256; - public static void main(String[] args) { - scanner = new Scanner(System.in); - System.out.println("Enter String"); - String text = scanner.nextLine(); - System.out.println("Enter pattern"); - String pattern = scanner.nextLine(); - - int q = 101; - searchPat(text, pattern, q); + public static List search(String text, String pattern) { + return search(text, pattern, 101); } - private static void searchPat(String text, String pattern, int q) { + public static List search(String text, String pattern, int q) { + List occurrences = new ArrayList<>(); + if (text == null || pattern == null || pattern.isEmpty()) { + return occurrences; + } + int m = pattern.length(); int n = text.length(); int t = 0; @@ -35,48 +33,42 @@ private static void searchPat(String text, String pattern, int q) { int j = 0; int i = 0; - h = (int) Math.pow(ALPHABET_SIZE, m - 1) % q; + if (m > n) { + return new ArrayList<>(); + } + + // h = pow(ALPHABET_SIZE, m-1) % q + for (i = 0; i < m - 1; i++) { + h = h * ALPHABET_SIZE % q; + } for (i = 0; i < m; i++) { - // hash value is calculated for each character and then added with the hash value of the - // next character for pattern as well as the text for length equal to the length of - // pattern p = (ALPHABET_SIZE * p + pattern.charAt(i)) % q; t = (ALPHABET_SIZE * t + text.charAt(i)) % q; } for (i = 0; i <= n - m; i++) { - // if the calculated hash value of the pattern and text matches then - // all the characters of the pattern is matched with the text of length equal to length - // of the pattern if all matches then pattern exist in string if not then the hash value - // of the first character of the text is subtracted and hash value of the next character - // after the end of the evaluated characters is added if (p == t) { - // if hash value matches then the individual characters are matched for (j = 0; j < m; j++) { - // if not matched then break out of the loop if (text.charAt(i + j) != pattern.charAt(j)) { break; } } - // if all characters are matched then pattern exist in the string if (j == m) { - System.out.println("Pattern found at index " + i); + occurrences.add(i); } } - // if i - * A string is considered valid if: - *

    - *
  • Open brackets are closed by the same type of brackets.
  • - *
  • Brackets are closed in the correct order.
  • - *
  • Every closing bracket has a corresponding open bracket of the same type.
  • - *
- * - * Allowed characters: '(', ')', '{', '}', '[', ']' - */ -public final class ValidParentheses { - private ValidParentheses() { - } - - private static final Map BRACKET_PAIRS = Map.of(')', '(', '}', '{', ']', '['); - - /** - * Checks if the input string has valid parentheses. - * - * @param s the string containing only bracket characters - * @return true if valid, false otherwise - * @throws IllegalArgumentException if the string contains invalid characters or is null - */ - public static boolean isValid(String s) { - if (s == null) { - throw new IllegalArgumentException("Input string cannot be null"); - } - - Deque stack = new ArrayDeque<>(); - - for (char c : s.toCharArray()) { - if (BRACKET_PAIRS.containsValue(c)) { - stack.push(c); // opening bracket - } else if (BRACKET_PAIRS.containsKey(c)) { - if (stack.isEmpty() || stack.pop() != BRACKET_PAIRS.get(c)) { - return false; - } - } else { - throw new IllegalArgumentException("Unexpected character: " + c); - } - } - - return stack.isEmpty(); - } -} diff --git a/src/test/java/com/thealgorithms/backtracking/CombinationTest.java b/src/test/java/com/thealgorithms/backtracking/CombinationTest.java index a9d1163f3ecd..5d2f99ccadf8 100644 --- a/src/test/java/com/thealgorithms/backtracking/CombinationTest.java +++ b/src/test/java/com/thealgorithms/backtracking/CombinationTest.java @@ -28,16 +28,16 @@ void testNoElement() { @Test void testLengthOne() { List> result = Combination.combination(new Integer[] {1, 2}, 1); - assertTrue(result.get(0).iterator().next() == 1); - assertTrue(result.get(1).iterator().next() == 2); + assertEquals(1, result.get(0).iterator().next()); + assertEquals(2, result.get(1).iterator().next()); } @Test void testLengthTwo() { List> result = Combination.combination(new Integer[] {1, 2}, 2); Integer[] arr = result.get(0).toArray(new Integer[2]); - assertTrue(arr[0] == 1); - assertTrue(arr[1] == 2); + assertEquals(1, arr[0]); + assertEquals(2, arr[1]); } @Test diff --git a/src/test/java/com/thealgorithms/backtracking/PermutationTest.java b/src/test/java/com/thealgorithms/backtracking/PermutationTest.java index 76a714829109..54747e5e73a1 100644 --- a/src/test/java/com/thealgorithms/backtracking/PermutationTest.java +++ b/src/test/java/com/thealgorithms/backtracking/PermutationTest.java @@ -12,13 +12,13 @@ public class PermutationTest { @Test void testNoElement() { List result = Permutation.permutation(new Integer[] {}); - assertEquals(result.get(0).length, 0); + assertEquals(0, result.get(0).length); } @Test void testSingleElement() { List result = Permutation.permutation(new Integer[] {1}); - assertEquals(result.get(0)[0], 1); + assertEquals(1, result.get(0)[0]); } @Test diff --git a/src/test/java/com/thealgorithms/ciphers/ECCTest.java b/src/test/java/com/thealgorithms/ciphers/ECCTest.java index 701f801af1c8..b78ba51f7c3e 100644 --- a/src/test/java/com/thealgorithms/ciphers/ECCTest.java +++ b/src/test/java/com/thealgorithms/ciphers/ECCTest.java @@ -37,7 +37,7 @@ void testEncrypt() { System.out.println("Base Point G: " + curve.getBasePoint()); // Verify that the ciphertext is not empty - assertEquals(cipherText.length, 2); // Check if the ciphertext contains two points (R and S) + assertEquals(2, cipherText.length); // Check if the ciphertext contains two points (R and S) // Output the encrypted coordinate points System.out.println("Encrypted Points:"); diff --git a/src/test/java/com/thealgorithms/ciphers/ElGamalCipherTest.java b/src/test/java/com/thealgorithms/ciphers/ElGamalCipherTest.java new file mode 100644 index 000000000000..63dec4846bbc --- /dev/null +++ b/src/test/java/com/thealgorithms/ciphers/ElGamalCipherTest.java @@ -0,0 +1,145 @@ +package com.thealgorithms.ciphers; + +import java.math.BigInteger; +import java.util.stream.Stream; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +/** + * Unit tests for ElGamalCipher. + * Includes property-based testing (homomorphism), probabilistic checks, + * and boundary validation. + */ +class ElGamalCipherTest { + + private static ElGamalCipher.KeyPair sharedKeys; + + @BeforeAll + static void setup() { + // Generate 256-bit keys for efficient unit testing + sharedKeys = ElGamalCipher.generateKeys(256); + } + + @Test + @DisplayName("Test Key Generation Validity") + void testKeyGeneration() { + Assertions.assertNotNull(sharedKeys.p()); + Assertions.assertNotNull(sharedKeys.g()); + Assertions.assertNotNull(sharedKeys.x()); + Assertions.assertNotNull(sharedKeys.y()); + + // Verify generator bounds: 1 < g < p + Assertions.assertTrue(sharedKeys.g().compareTo(BigInteger.ONE) > 0); + Assertions.assertTrue(sharedKeys.g().compareTo(sharedKeys.p()) < 0); + + // Verify private key bounds: 1 < x < p-1 + Assertions.assertTrue(sharedKeys.x().compareTo(BigInteger.ONE) > 0); + Assertions.assertTrue(sharedKeys.x().compareTo(sharedKeys.p().subtract(BigInteger.ONE)) < 0); + } + + @Test + @DisplayName("Security Check: Probabilistic Encryption") + void testSemanticSecurity() { + // Encrypting the same message twice MUST yield different ciphertexts + // due to the random ephemeral key 'k'. + BigInteger message = new BigInteger("123456789"); + + ElGamalCipher.CipherText c1 = ElGamalCipher.encrypt(message, sharedKeys.p(), sharedKeys.g(), sharedKeys.y()); + ElGamalCipher.CipherText c2 = ElGamalCipher.encrypt(message, sharedKeys.p(), sharedKeys.g(), sharedKeys.y()); + + // Check that the ephemeral keys (and thus 'a' components) were different + Assertions.assertNotEquals(c1.a(), c2.a(), "Ciphertexts must be randomized (Semantic Security violation)"); + Assertions.assertNotEquals(c1.b(), c2.b()); + + // But both must decrypt to the original message + Assertions.assertEquals(ElGamalCipher.decrypt(c1, sharedKeys.x(), sharedKeys.p()), message); + Assertions.assertEquals(ElGamalCipher.decrypt(c2, sharedKeys.x(), sharedKeys.p()), message); + } + + @ParameterizedTest + @MethodSource("provideMessages") + @DisplayName("Parameterized Test: Encrypt and Decrypt various messages") + void testEncryptDecrypt(String messageStr) { + BigInteger message = new BigInteger(messageStr.getBytes()); + + // Skip if message exceeds the test key size (256 bits) + if (message.compareTo(sharedKeys.p()) >= 0) { + return; + } + + ElGamalCipher.CipherText ciphertext = ElGamalCipher.encrypt(message, sharedKeys.p(), sharedKeys.g(), sharedKeys.y()); + BigInteger decrypted = ElGamalCipher.decrypt(ciphertext, sharedKeys.x(), sharedKeys.p()); + + Assertions.assertEquals(message, decrypted, "Decrypted BigInteger must match original"); + Assertions.assertEquals(messageStr, new String(decrypted.toByteArray()), "Decrypted string must match original"); + } + + static Stream provideMessages() { + return Stream.of("Hello World", "TheAlgorithms", "A", "1234567890", "!@#$%^&*()"); + } + + @Test + @DisplayName("Edge Case: Message equals 0") + void testMessageZero() { + BigInteger zero = BigInteger.ZERO; + ElGamalCipher.CipherText ciphertext = ElGamalCipher.encrypt(zero, sharedKeys.p(), sharedKeys.g(), sharedKeys.y()); + BigInteger decrypted = ElGamalCipher.decrypt(ciphertext, sharedKeys.x(), sharedKeys.p()); + + Assertions.assertEquals(zero, decrypted, "Should successfully encrypt/decrypt zero"); + } + + @Test + @DisplayName("Edge Case: Message equals p-1") + void testMessageMaxBound() { + BigInteger pMinus1 = sharedKeys.p().subtract(BigInteger.ONE); + ElGamalCipher.CipherText ciphertext = ElGamalCipher.encrypt(pMinus1, sharedKeys.p(), sharedKeys.g(), sharedKeys.y()); + BigInteger decrypted = ElGamalCipher.decrypt(ciphertext, sharedKeys.x(), sharedKeys.p()); + + Assertions.assertEquals(pMinus1, decrypted, "Should successfully encrypt/decrypt p-1"); + } + + @Test + @DisplayName("Negative Test: Message >= p should fail") + void testMessageTooLarge() { + BigInteger tooLarge = sharedKeys.p(); + Assertions.assertThrows(IllegalArgumentException.class, () -> ElGamalCipher.encrypt(tooLarge, sharedKeys.p(), sharedKeys.g(), sharedKeys.y())); + } + + @Test + @DisplayName("Negative Test: Decrypt with wrong private key") + void testWrongKeyDecryption() { + BigInteger message = new BigInteger("99999"); + ElGamalCipher.CipherText ciphertext = ElGamalCipher.encrypt(message, sharedKeys.p(), sharedKeys.g(), sharedKeys.y()); + + // Generate a fake private key + BigInteger wrongX = sharedKeys.x().add(BigInteger.ONE); + + BigInteger decrypted = ElGamalCipher.decrypt(ciphertext, wrongX, sharedKeys.p()); + + Assertions.assertNotEquals(message, decrypted, "Decryption with wrong key must yield incorrect result"); + } + + @Test + @DisplayName("Property Test: Multiplicative Homomorphism") + void testHomomorphism() { + BigInteger m1 = new BigInteger("50"); + BigInteger m2 = BigInteger.TEN; // Fix: Replaced new BigInteger("10") with BigInteger.TEN + + ElGamalCipher.CipherText c1 = ElGamalCipher.encrypt(m1, sharedKeys.p(), sharedKeys.g(), sharedKeys.y()); + ElGamalCipher.CipherText c2 = ElGamalCipher.encrypt(m2, sharedKeys.p(), sharedKeys.g(), sharedKeys.y()); + + // Multiply ciphertexts component-wise: (a1*a2, b1*b2) + BigInteger aNew = c1.a().multiply(c2.a()).mod(sharedKeys.p()); + BigInteger bNew = c1.b().multiply(c2.b()).mod(sharedKeys.p()); + ElGamalCipher.CipherText cCombined = new ElGamalCipher.CipherText(aNew, bNew); + + BigInteger decrypted = ElGamalCipher.decrypt(cCombined, sharedKeys.x(), sharedKeys.p()); + BigInteger expected = m1.multiply(m2).mod(sharedKeys.p()); + + Assertions.assertEquals(expected, decrypted, "Cipher must satisfy multiplicative homomorphism"); + } +} diff --git a/src/test/java/com/thealgorithms/ciphers/PermutationCipherTest.java b/src/test/java/com/thealgorithms/ciphers/PermutationCipherTest.java index 4ba6787cc97e..ecb7455c1ba2 100644 --- a/src/test/java/com/thealgorithms/ciphers/PermutationCipherTest.java +++ b/src/test/java/com/thealgorithms/ciphers/PermutationCipherTest.java @@ -1,6 +1,7 @@ package com.thealgorithms.ciphers; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.Test; @@ -121,8 +122,8 @@ void testNullString() { String decrypted = cipher.decrypt(encrypted, key); // then - assertEquals(null, encrypted); - assertEquals(null, decrypted); + assertNull(encrypted); + assertNull(decrypted); } @Test diff --git a/src/test/java/com/thealgorithms/compression/LZ78Test.java b/src/test/java/com/thealgorithms/compression/LZ78Test.java index 7889b50b76f3..da1fd8d23318 100644 --- a/src/test/java/com/thealgorithms/compression/LZ78Test.java +++ b/src/test/java/com/thealgorithms/compression/LZ78Test.java @@ -1,7 +1,6 @@ package com.thealgorithms.compression; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.List; @@ -286,7 +285,6 @@ void testTokenStructure() { // All tokens should have valid indices (>= 0) for (LZ78.Token token : compressed) { assertTrue(token.index() >= 0); - assertNotNull(token.nextChar()); } String decompressed = LZ78.decompress(compressed); diff --git a/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/MapTest.java b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/MapTest.java index 44551a8adac6..ef7739a2e8a9 100644 --- a/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/MapTest.java +++ b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/MapTest.java @@ -81,19 +81,19 @@ void containsTest() { @Test void sizeTest() { Map map = getMap(); - assertEquals(map.size(), 0); + assertEquals(0, map.size()); for (int i = -100; i < 100; i++) { map.put(i, String.valueOf(i)); } - assertEquals(map.size(), 200); + assertEquals(200, map.size()); for (int i = -50; i < 50; i++) { map.delete(i); } - assertEquals(map.size(), 100); + assertEquals(100, map.size()); } @Test diff --git a/src/test/java/com/thealgorithms/datastructures/heaps/HeapElementTest.java b/src/test/java/com/thealgorithms/datastructures/heaps/HeapElementTest.java index d04a9de8a94b..792969200c82 100644 --- a/src/test/java/com/thealgorithms/datastructures/heaps/HeapElementTest.java +++ b/src/test/java/com/thealgorithms/datastructures/heaps/HeapElementTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import org.junit.jupiter.api.Test; @@ -39,7 +40,7 @@ void testEquals() { assertEquals(element1, element2); // Same key and info assertNotEquals(element1, element3); // Different key - assertNotEquals(null, element1); // Check for null + assertNotNull(element1); assertNotEquals("String", element1); // Check for different type } diff --git a/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java new file mode 100644 index 000000000000..ba5614a07916 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java @@ -0,0 +1,74 @@ +package com.thealgorithms.datastructures.lists; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.Objects; +import org.junit.jupiter.api.Test; + +public class MiddleOfLinkedListTest { + + private static SinglyLinkedListNode listOf(int firstValue, int... remainingValues) { + SinglyLinkedListNode head = new SinglyLinkedListNode(firstValue); + SinglyLinkedListNode current = head; + + for (int i = 0; i < remainingValues.length; i++) { + current.next = new SinglyLinkedListNode(remainingValues[i]); + current = current.next; + } + return head; + } + + @Test + void middleNodeOddLength() { + SinglyLinkedListNode head = listOf(1, 2, 3, 4, 5); + SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(head)); + assertEquals(3, middle.value); + } + + @Test + void middleNodeEvenLengthReturnsSecondMiddle() { + SinglyLinkedListNode head = listOf(1, 2, 3, 4, 5, 6); + SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(head)); + assertEquals(4, middle.value); + } + + @Test + void middleNodeSingleElement() { + SinglyLinkedListNode head = listOf(42); + SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(head)); + assertEquals(42, middle.value); + } + + @Test + void middleNodeTwoElementsReturnsSecond() { + SinglyLinkedListNode head = listOf(10, 20); + SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(head)); + assertEquals(20, middle.value); + } + + @Test + void middleNodeNullHead() { + assertNull(MiddleOfLinkedList.middleNode(null)); + } + + @Test + void middleNodeDoesNotModifyListStructure() { + SinglyLinkedListNode first = new SinglyLinkedListNode(1); + SinglyLinkedListNode second = new SinglyLinkedListNode(2); + SinglyLinkedListNode third = new SinglyLinkedListNode(3); + SinglyLinkedListNode fourth = new SinglyLinkedListNode(4); + + first.next = second; + second.next = third; + third.next = fourth; + + SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(first)); + assertEquals(3, middle.value); + + assertEquals(second, first.next); + assertEquals(third, second.next); + assertEquals(fourth, third.next); + assertNull(fourth.next); + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java b/src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java index e97fe091c556..3bb8bbabb761 100644 --- a/src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java +++ b/src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java @@ -9,14 +9,14 @@ class PriorityQueuesTest { void testPQInsertion() { PriorityQueue myQueue = new PriorityQueue(4); myQueue.insert(2); - Assertions.assertEquals(myQueue.peek(), 2); + Assertions.assertEquals(2, myQueue.peek()); myQueue.insert(5); myQueue.insert(3); - Assertions.assertEquals(myQueue.peek(), 5); + Assertions.assertEquals(5, myQueue.peek()); myQueue.insert(10); - Assertions.assertEquals(myQueue.peek(), 10); + Assertions.assertEquals(10, myQueue.peek()); } @Test @@ -28,32 +28,32 @@ void testPQDeletion() { myQueue.insert(10); myQueue.remove(); - Assertions.assertEquals(myQueue.peek(), 5); + Assertions.assertEquals(5, myQueue.peek()); myQueue.remove(); myQueue.remove(); - Assertions.assertEquals(myQueue.peek(), 2); + Assertions.assertEquals(2, myQueue.peek()); } @Test void testPQExtra() { PriorityQueue myQueue = new PriorityQueue(4); - Assertions.assertEquals(myQueue.isEmpty(), true); - Assertions.assertEquals(myQueue.isFull(), false); + Assertions.assertTrue(myQueue.isEmpty()); + Assertions.assertFalse(myQueue.isFull()); myQueue.insert(2); myQueue.insert(5); - Assertions.assertEquals(myQueue.isFull(), false); + Assertions.assertFalse(myQueue.isFull()); myQueue.insert(3); myQueue.insert(10); - Assertions.assertEquals(myQueue.isEmpty(), false); - Assertions.assertEquals(myQueue.isFull(), true); + Assertions.assertFalse(myQueue.isEmpty()); + Assertions.assertTrue(myQueue.isFull()); myQueue.remove(); - Assertions.assertEquals(myQueue.getSize(), 3); - Assertions.assertEquals(myQueue.peek(), 5); + Assertions.assertEquals(3, myQueue.getSize()); + Assertions.assertEquals(5, myQueue.peek()); myQueue.remove(); myQueue.remove(); - Assertions.assertEquals(myQueue.peek(), 2); - Assertions.assertEquals(myQueue.getSize(), 1); + Assertions.assertEquals(2, myQueue.peek()); + Assertions.assertEquals(1, myQueue.getSize()); } @Test diff --git a/src/test/java/com/thealgorithms/datastructures/trees/TreapTest.java b/src/test/java/com/thealgorithms/datastructures/trees/TreapTest.java index 09ada594faca..52b74a7a1faf 100644 --- a/src/test/java/com/thealgorithms/datastructures/trees/TreapTest.java +++ b/src/test/java/com/thealgorithms/datastructures/trees/TreapTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; import org.junit.jupiter.api.Test; @@ -30,7 +31,7 @@ public void searchAndNotFound() { treap.insert(3); treap.insert(8); treap.insert(1); - assertEquals(null, treap.search(4)); + assertNull(treap.search(4)); } @Test diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java index 40bbdff15ca6..91169c4cc9d8 100644 --- a/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java +++ b/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java @@ -1,6 +1,7 @@ package com.thealgorithms.dynamicprogramming; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import org.junit.jupiter.api.Test; @@ -55,27 +56,24 @@ public void testLCSWithBothEmptyStrings() { 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); + assertNull(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); + assertNull(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); + assertNull(result); } @Test diff --git a/src/test/java/com/thealgorithms/io/BufferedReaderTest.java b/src/test/java/com/thealgorithms/io/BufferedReaderTest.java index 891c3066058e..088e86f8f7c5 100644 --- a/src/test/java/com/thealgorithms/io/BufferedReaderTest.java +++ b/src/test/java/com/thealgorithms/io/BufferedReaderTest.java @@ -17,15 +17,15 @@ public void testPeeks() throws IOException { BufferedReader reader = new BufferedReader(input); // read the first letter - assertEquals(reader.read(), 'H'); + assertEquals('H', reader.read()); len--; - assertEquals(reader.available(), len); + assertEquals(len, reader.available()); // position: H[e]llo!\nWorld! // reader.read() will be == 'e' - assertEquals(reader.peek(1), 'l'); - assertEquals(reader.peek(2), 'l'); // second l - assertEquals(reader.peek(3), 'o'); + assertEquals('l', reader.peek(1)); + assertEquals('l', reader.peek(2)); // second l + assertEquals('o', reader.peek(3)); } @Test @@ -38,21 +38,21 @@ public void testMixes() throws IOException { BufferedReader reader = new BufferedReader(input); // read the first letter - assertEquals(reader.read(), 'H'); // first letter + assertEquals('H', reader.read()); // first letter len--; - assertEquals(reader.peek(1), 'l'); // third later (second letter after 'H') - assertEquals(reader.read(), 'e'); // second letter + assertEquals('l', reader.peek(1)); // third later (second letter after 'H') + assertEquals('e', reader.read()); // second letter len--; - assertEquals(reader.available(), len); + assertEquals(len, reader.available()); // position: H[e]llo!\nWorld! - assertEquals(reader.peek(2), 'o'); // second l - assertEquals(reader.peek(3), '!'); - assertEquals(reader.peek(4), '\n'); + assertEquals('o', reader.peek(2)); // second l + assertEquals('!', reader.peek(3)); + assertEquals('\n', reader.peek(4)); - assertEquals(reader.read(), 'l'); // third letter - assertEquals(reader.peek(1), 'o'); // fourth letter + assertEquals('l', reader.read()); // third letter + assertEquals('o', reader.peek(1)); // fourth letter for (int i = 0; i < 6; i++) { reader.read(); @@ -74,23 +74,23 @@ public void testBlockPractical() throws IOException { ByteArrayInputStream input = new ByteArrayInputStream(bytes); BufferedReader reader = new BufferedReader(input); - assertEquals(reader.peek(), 'H'); - assertEquals(reader.read(), '!'); // read the first letter + assertEquals('H', reader.peek()); + assertEquals('!', reader.read()); // read the first letter len--; // this only reads the next 5 bytes (Hello) because // the default buffer size = 5 - assertEquals(new String(reader.readBlock()), "Hello"); + assertEquals("Hello", new String(reader.readBlock())); len -= 5; assertEquals(reader.available(), len); // maybe kind of a practical demonstration / use case if (reader.read() == '\n') { - assertEquals(reader.read(), 'W'); - assertEquals(reader.read(), 'o'); + assertEquals('W', reader.read()); + assertEquals('o', reader.read()); // the rest of the blocks - assertEquals(new String(reader.readBlock()), "rld!"); + assertEquals("rld!", new String(reader.readBlock())); } else { // should not reach throw new IOException("Something not right"); diff --git a/src/test/java/com/thealgorithms/maths/BellNumbersTest.java b/src/test/java/com/thealgorithms/maths/BellNumbersTest.java new file mode 100644 index 000000000000..8dd83cf0f7a9 --- /dev/null +++ b/src/test/java/com/thealgorithms/maths/BellNumbersTest.java @@ -0,0 +1,53 @@ +package com.thealgorithms.maths; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class BellNumbersTest { + + @Test + void testStandardCases() { + // Base cases and small numbers + assertEquals(1, BellNumbers.compute(0)); + assertEquals(1, BellNumbers.compute(1)); + assertEquals(2, BellNumbers.compute(2)); + assertEquals(5, BellNumbers.compute(3)); + assertEquals(15, BellNumbers.compute(4)); + assertEquals(52, BellNumbers.compute(5)); + } + + @Test + void testMediumNumber() { + // B10 = 115,975 + assertEquals(115975, BellNumbers.compute(10)); + // B15 = 1,382,958,545 + assertEquals(1382958545L, BellNumbers.compute(15)); + } + + @Test + void testLargeNumber() { + // B20 = 51,724,158,235,372 + // We use the 'L' suffix to tell Java this is a long literal + assertEquals(51724158235372L, BellNumbers.compute(20)); + } + + @Test + void testMaxLongCapacity() { + // B25 is the largest Bell number that fits in a Java long (signed 64-bit) + // B25 = 4,638,590,332,229,999,353 + assertEquals(4638590332229999353L, BellNumbers.compute(25)); + } + + @Test + void testNegativeInput() { + assertThrows(IllegalArgumentException.class, () -> BellNumbers.compute(-1)); + } + + @Test + void testOverflowProtection() { + // We expect an exception if the user asks for the impossible + assertThrows(IllegalArgumentException.class, () -> BellNumbers.compute(26)); + } +} diff --git a/src/test/java/com/thealgorithms/maths/DistanceBetweenTwoPointsTest.java b/src/test/java/com/thealgorithms/maths/DistanceBetweenTwoPointsTest.java new file mode 100644 index 000000000000..6bd124629740 --- /dev/null +++ b/src/test/java/com/thealgorithms/maths/DistanceBetweenTwoPointsTest.java @@ -0,0 +1,23 @@ +package com.thealgorithms.maths; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class DistanceBetweenTwoPointsTest { + + @Test + void testDistanceSimple() { + assertEquals(5.0, DistanceBetweenTwoPoints.calculate(0, 0, 3, 4), 1e-9); + } + + @Test + void testDistanceNegativeCoordinates() { + assertEquals(5.0, DistanceBetweenTwoPoints.calculate(-1, -1, 2, 3), 1e-9); + } + + @Test + void testSamePoint() { + assertEquals(0.0, DistanceBetweenTwoPoints.calculate(2, 2, 2, 2), 1e-9); + } +} diff --git a/src/test/java/com/thealgorithms/maths/DistanceFormulaTest.java b/src/test/java/com/thealgorithms/maths/DistanceFormulaTest.java index 3a14b80dd4f9..66f3b7b03938 100644 --- a/src/test/java/com/thealgorithms/maths/DistanceFormulaTest.java +++ b/src/test/java/com/thealgorithms/maths/DistanceFormulaTest.java @@ -9,78 +9,78 @@ public class DistanceFormulaTest { @Test void euclideanTest1() { - Assertions.assertEquals(DistanceFormula.euclideanDistance(1, 1, 2, 2), 1.4142135623730951); + Assertions.assertEquals(1.4142135623730951, DistanceFormula.euclideanDistance(1, 1, 2, 2)); } @Test void euclideanTest2() { - Assertions.assertEquals(DistanceFormula.euclideanDistance(1, 3, 8, 0), 7.0710678118654755); + Assertions.assertEquals(7.0710678118654755, DistanceFormula.euclideanDistance(1, 3, 8, 0)); } @Test void euclideanTest3() { - Assertions.assertEquals(DistanceFormula.euclideanDistance(2.4, 9.1, 55.1, 100), 110.91911467371168); + Assertions.assertEquals(110.91911467371168, DistanceFormula.euclideanDistance(2.4, 9.1, 55.1, 100)); } @Test void euclideanTest4() { - Assertions.assertEquals(DistanceFormula.euclideanDistance(1000, 13, 20000, 84), 19022.067605809836); + Assertions.assertEquals(19022.067605809836, DistanceFormula.euclideanDistance(1000, 13, 20000, 84)); } @Test public void manhattantest1() { - assertEquals(DistanceFormula.manhattanDistance(1, 2, 3, 4), 4); + assertEquals(4, DistanceFormula.manhattanDistance(1, 2, 3, 4)); } @Test public void manhattantest2() { - assertEquals(DistanceFormula.manhattanDistance(6.5, 8.4, 20.1, 13.6), 18.8); + assertEquals(18.8, DistanceFormula.manhattanDistance(6.5, 8.4, 20.1, 13.6)); } @Test public void manhattanTest3() { - assertEquals(DistanceFormula.manhattanDistance(10.112, 50, 8, 25.67), 26.442); + assertEquals(26.442, DistanceFormula.manhattanDistance(10.112, 50, 8, 25.67)); } @Test public void hammingTest1() { int[] array1 = {1, 1, 1, 1}; int[] array2 = {0, 0, 0, 0}; - assertEquals(DistanceFormula.hammingDistance(array1, array2), 4); + assertEquals(4, DistanceFormula.hammingDistance(array1, array2)); } @Test public void hammingTest2() { int[] array1 = {1, 1, 1, 1}; int[] array2 = {1, 1, 1, 1}; - assertEquals(DistanceFormula.hammingDistance(array1, array2), 0); + assertEquals(0, DistanceFormula.hammingDistance(array1, array2)); } @Test public void hammingTest3() { int[] array1 = {1, 0, 0, 1, 1, 0, 1, 1, 0}; int[] array2 = {0, 1, 0, 0, 1, 1, 1, 0, 0}; - assertEquals(DistanceFormula.hammingDistance(array1, array2), 5); + assertEquals(5, DistanceFormula.hammingDistance(array1, array2)); } @Test public void minkowskiTest1() { double[] array1 = {1, 3, 8, 5}; double[] array2 = {4, 2, 6, 9}; - assertEquals(DistanceFormula.minkowskiDistance(array1, array2, 1), 10); + assertEquals(10, DistanceFormula.minkowskiDistance(array1, array2, 1)); } @Test public void minkowskiTest2() { double[] array1 = {1, 3, 8, 5}; double[] array2 = {4, 2, 6, 9}; - assertEquals(DistanceFormula.minkowskiDistance(array1, array2, 2), 5.477225575051661); + assertEquals(5.477225575051661, DistanceFormula.minkowskiDistance(array1, array2, 2)); } @Test public void minkowskiTest3() { double[] array1 = {1, 3, 8, 5}; double[] array2 = {4, 2, 6, 9}; - assertEquals(DistanceFormula.minkowskiDistance(array1, array2, 3), 4.641588833612778); + assertEquals(4.641588833612778, DistanceFormula.minkowskiDistance(array1, array2, 3)); } } diff --git a/src/test/java/com/thealgorithms/maths/FactorialTest.java b/src/test/java/com/thealgorithms/maths/FactorialTest.java index b38dc45589ee..3ff7097b8113 100644 --- a/src/test/java/com/thealgorithms/maths/FactorialTest.java +++ b/src/test/java/com/thealgorithms/maths/FactorialTest.java @@ -11,7 +11,7 @@ public class FactorialTest { @Test public void testWhenInvalidInoutProvidedShouldThrowException() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> Factorial.factorial(-1)); - assertEquals(exception.getMessage(), EXCEPTION_MESSAGE); + assertEquals(EXCEPTION_MESSAGE, exception.getMessage()); } @Test diff --git a/src/test/java/com/thealgorithms/maths/LinearDiophantineEquationsSolverTest.java b/src/test/java/com/thealgorithms/maths/LinearDiophantineEquationsSolverTest.java index c4205985dbfd..885382e29ca2 100644 --- a/src/test/java/com/thealgorithms/maths/LinearDiophantineEquationsSolverTest.java +++ b/src/test/java/com/thealgorithms/maths/LinearDiophantineEquationsSolverTest.java @@ -176,7 +176,7 @@ void testSolutionEquality() { assertEquals(solution1, solution2); assertNotEquals(solution3, solution1); assertEquals(solution1, solution1); - assertNotEquals(null, solution1); + assertNotNull(solution1); assertNotEquals("string", solution1); } @@ -217,7 +217,7 @@ void testGcdSolutionWrapperEquality() { assertEquals(wrapper1, wrapper2); assertNotEquals(wrapper3, wrapper1); assertEquals(wrapper1, wrapper1); - assertNotEquals(null, wrapper1); + assertNotNull(wrapper1); assertNotEquals("string", wrapper1); } diff --git a/src/test/java/com/thealgorithms/maths/NthUglyNumberTest.java b/src/test/java/com/thealgorithms/maths/NthUglyNumberTest.java index 3fe58dadf8a5..1ee437b190c5 100644 --- a/src/test/java/com/thealgorithms/maths/NthUglyNumberTest.java +++ b/src/test/java/com/thealgorithms/maths/NthUglyNumberTest.java @@ -48,22 +48,22 @@ public void testGetWithSameObject() { var uglyNumbers = new NthUglyNumber(new int[] {7, 2, 5, 3}); for (final var tc : testCases.entrySet()) { - assertEquals(uglyNumbers.get(tc.getKey()), tc.getValue()); + assertEquals(tc.getValue(), uglyNumbers.get(tc.getKey())); } - assertEquals(uglyNumbers.get(999), 385875); + assertEquals(385875, uglyNumbers.get(999)); } @Test public void testGetWithBase1() { var uglyNumbers = new NthUglyNumber(new int[] {1}); - assertEquals(uglyNumbers.get(10), 1); + assertEquals(1, uglyNumbers.get(10)); } @Test public void testGetWithBase2() { var uglyNumbers = new NthUglyNumber(new int[] {2}); - assertEquals(uglyNumbers.get(5), 32); + assertEquals(32, uglyNumbers.get(5)); } @Test diff --git a/src/test/java/com/thealgorithms/maths/PalindromeNumberTest.java b/src/test/java/com/thealgorithms/maths/PalindromeNumberTest.java index a70100c0b913..4e4bd85d07b5 100644 --- a/src/test/java/com/thealgorithms/maths/PalindromeNumberTest.java +++ b/src/test/java/com/thealgorithms/maths/PalindromeNumberTest.java @@ -25,6 +25,6 @@ public void testNumbersAreNotPalindromes() { @Test public void testIfNegativeInputThenExceptionExpected() { IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> PalindromeNumber.isPalindrome(-1)); - Assertions.assertEquals(exception.getMessage(), "Input parameter must not be negative!"); + Assertions.assertEquals("Input parameter must not be negative!", exception.getMessage()); } } diff --git a/src/test/java/com/thealgorithms/maths/ParseIntegerTest.java b/src/test/java/com/thealgorithms/maths/ParseIntegerTest.java index 7649e21eb231..a9b78be88042 100644 --- a/src/test/java/com/thealgorithms/maths/ParseIntegerTest.java +++ b/src/test/java/com/thealgorithms/maths/ParseIntegerTest.java @@ -14,13 +14,13 @@ public class ParseIntegerTest { @Test public void testNullInput() { IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> ParseInteger.parseInt(null)); - Assertions.assertEquals(exception.getMessage(), NULL_PARAMETER_MESSAGE); + Assertions.assertEquals(NULL_PARAMETER_MESSAGE, exception.getMessage()); } @Test public void testEmptyInput() { IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> ParseInteger.parseInt("")); - Assertions.assertEquals(exception.getMessage(), EMPTY_PARAMETER_MESSAGE); + Assertions.assertEquals(EMPTY_PARAMETER_MESSAGE, exception.getMessage()); } @Test diff --git a/src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java b/src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java index a2046511ddf5..a6552d56783c 100644 --- a/src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java +++ b/src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java @@ -14,10 +14,10 @@ public void testSolveEquationRealRoots() { double c = 1.9; ComplexNumber[] roots = quadraticEquationSolver.solveEquation(a, b, c); - Assertions.assertEquals(roots.length, 2); - Assertions.assertEquals(roots[0].real, -0.27810465435684306); + Assertions.assertEquals(2, roots.length, 2); + Assertions.assertEquals(-0.27810465435684306, roots[0].real); Assertions.assertNull(roots[0].imaginary); - Assertions.assertEquals(roots[1].real, -1.6266572504050616); + Assertions.assertEquals(-1.6266572504050616, roots[1].real); Assertions.assertNull(roots[1].imaginary); } @@ -29,8 +29,8 @@ public void testSolveEquationEqualRoots() { double c = 1; ComplexNumber[] roots = quadraticEquationSolver.solveEquation(a, b, c); - Assertions.assertEquals(roots.length, 1); - Assertions.assertEquals(roots[0].real, -1); + Assertions.assertEquals(1, roots.length); + Assertions.assertEquals(-1, roots[0].real); } @Test @@ -41,10 +41,10 @@ public void testSolveEquationComplexRoots() { double c = 5.6; ComplexNumber[] roots = quadraticEquationSolver.solveEquation(a, b, c); - Assertions.assertEquals(roots.length, 2); - Assertions.assertEquals(roots[0].real, -0.8695652173913044); - Assertions.assertEquals(roots[0].imaginary, 1.2956229935435948); - Assertions.assertEquals(roots[1].real, -0.8695652173913044); - Assertions.assertEquals(roots[1].imaginary, -1.2956229935435948); + Assertions.assertEquals(2, roots.length); + Assertions.assertEquals(-0.8695652173913044, roots[0].real); + Assertions.assertEquals(1.2956229935435948, roots[0].imaginary); + Assertions.assertEquals(-0.8695652173913044, roots[1].real); + Assertions.assertEquals(-1.2956229935435948, roots[1].imaginary); } } diff --git a/src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java b/src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java index c744614e5cfa..c5d47f2213a9 100644 --- a/src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java +++ b/src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java @@ -29,19 +29,19 @@ public TestCase(final int[] inInputArray, final int inSecondMin, final int inSec @Test public void testForEmptyInputArray() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> SecondMinMax.findSecondMin(new int[] {})); - assertEquals(exception.getMessage(), EXP_MSG_ARR_LEN_LESS_2); + assertEquals(EXP_MSG_ARR_LEN_LESS_2, exception.getMessage()); } @Test public void testForArrayWithSingleElement() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> SecondMinMax.findSecondMax(new int[] {1})); - assertEquals(exception.getMessage(), EXP_MSG_ARR_LEN_LESS_2); + assertEquals(EXP_MSG_ARR_LEN_LESS_2, exception.getMessage()); } @Test public void testForArrayWithSameElements() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> SecondMinMax.findSecondMin(new int[] {1, 1, 1, 1})); - assertEquals(exception.getMessage(), EXP_MSG_ARR_SAME_ELE); + assertEquals(EXP_MSG_ARR_SAME_ELE, exception.getMessage()); } @ParameterizedTest diff --git a/src/test/java/com/thealgorithms/maths/StandardDeviationTest.java b/src/test/java/com/thealgorithms/maths/StandardDeviationTest.java index 2c10d2d14f3e..4716d389a4ca 100644 --- a/src/test/java/com/thealgorithms/maths/StandardDeviationTest.java +++ b/src/test/java/com/thealgorithms/maths/StandardDeviationTest.java @@ -8,19 +8,19 @@ public class StandardDeviationTest { @Test void test1() { double[] t1 = new double[] {1, 1, 1, 1, 1}; - Assertions.assertEquals(StandardDeviation.stdDev(t1), 0.0); + Assertions.assertEquals(0.0, StandardDeviation.stdDev(t1)); } @Test void test2() { double[] t2 = new double[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - Assertions.assertEquals(StandardDeviation.stdDev(t2), 2.8722813232690143); + Assertions.assertEquals(2.8722813232690143, StandardDeviation.stdDev(t2)); } @Test void test3() { double[] t3 = new double[] {1.1, 8.5, 20.3, 2.4, 6.2}; - Assertions.assertEquals(StandardDeviation.stdDev(t3), 6.8308125431752265); + Assertions.assertEquals(6.8308125431752265, StandardDeviation.stdDev(t3)); } @Test @@ -32,6 +32,6 @@ void test4() { 100.00045, 56.7, }; - Assertions.assertEquals(StandardDeviation.stdDev(t4), 38.506117353865775); + Assertions.assertEquals(38.506117353865775, StandardDeviation.stdDev(t4)); } } diff --git a/src/test/java/com/thealgorithms/maths/StandardScoreTest.java b/src/test/java/com/thealgorithms/maths/StandardScoreTest.java index 436b1fd011c6..6858b87ad2c6 100644 --- a/src/test/java/com/thealgorithms/maths/StandardScoreTest.java +++ b/src/test/java/com/thealgorithms/maths/StandardScoreTest.java @@ -7,21 +7,21 @@ public class StandardScoreTest { @Test void test1() { - Assertions.assertEquals(StandardScore.zScore(2, 0, 5), 0.4); + Assertions.assertEquals(0.4, StandardScore.zScore(2, 0, 5)); } @Test void test2() { - Assertions.assertEquals(StandardScore.zScore(1, 1, 1), 0.0); + Assertions.assertEquals(0.0, StandardScore.zScore(1, 1, 1)); } @Test void test3() { - Assertions.assertEquals(StandardScore.zScore(2.5, 1.8, 0.7), 1.0); + Assertions.assertEquals(1.0, StandardScore.zScore(2.5, 1.8, 0.7)); } @Test void test4() { - Assertions.assertEquals(StandardScore.zScore(8.9, 3, 4.2), 1.4047619047619049); + Assertions.assertEquals(1.4047619047619049, StandardScore.zScore(8.9, 3, 4.2)); } } diff --git a/src/test/java/com/thealgorithms/maths/VolumeTest.java b/src/test/java/com/thealgorithms/maths/VolumeTest.java index 7cd0c6716147..af882eef7563 100644 --- a/src/test/java/com/thealgorithms/maths/VolumeTest.java +++ b/src/test/java/com/thealgorithms/maths/VolumeTest.java @@ -1,6 +1,6 @@ package com.thealgorithms.maths; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; @@ -10,30 +10,30 @@ public class VolumeTest { public void volume() { /* test cube */ - assertTrue(Volume.volumeCube(7) == 343.0); + assertEquals(343.0, Volume.volumeCube(7)); /* test cuboid */ - assertTrue(Volume.volumeCuboid(2, 5, 7) == 70.0); + assertEquals(70.0, Volume.volumeCuboid(2, 5, 7)); /* test sphere */ - assertTrue(Volume.volumeSphere(7) == 1436.7550402417319); + assertEquals(1436.7550402417319, Volume.volumeSphere(7)); /* test cylinder */ - assertTrue(Volume.volumeCylinder(3, 7) == 197.92033717615698); + assertEquals(197.92033717615698, Volume.volumeCylinder(3, 7)); /* test hemisphere */ - assertTrue(Volume.volumeHemisphere(7) == 718.3775201208659); + assertEquals(718.3775201208659, Volume.volumeHemisphere(7)); /* test cone */ - assertTrue(Volume.volumeCone(3, 7) == 65.97344572538566); + assertEquals(65.97344572538566, Volume.volumeCone(3, 7)); /* test prism */ - assertTrue(Volume.volumePrism(10, 2) == 20.0); + assertEquals(20.0, Volume.volumePrism(10, 2)); /* test pyramid */ - assertTrue(Volume.volumePyramid(10, 3) == 10.0); + assertEquals(10.0, Volume.volumePyramid(10, 3)); /* test frustum */ - assertTrue(Volume.volumeFrustumOfCone(3, 5, 7) == 359.188760060433); + assertEquals(359.188760060433, Volume.volumeFrustumOfCone(3, 5, 7)); } } diff --git a/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java b/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java index f41953035846..c4a74af0ba8b 100644 --- a/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java +++ b/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java @@ -17,7 +17,7 @@ public class MedianOfRunningArrayTest { public void testWhenInvalidInoutProvidedShouldThrowException() { var stream = new MedianOfRunningArrayInteger(); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, stream::getMedian); - assertEquals(exception.getMessage(), EXCEPTION_MESSAGE); + assertEquals(EXCEPTION_MESSAGE, exception.getMessage()); } @Test diff --git a/src/test/java/com/thealgorithms/misc/ShuffleArrayTest.java b/src/test/java/com/thealgorithms/misc/ShuffleArrayTest.java index 915b83e376b6..c1adafa18d9f 100644 --- a/src/test/java/com/thealgorithms/misc/ShuffleArrayTest.java +++ b/src/test/java/com/thealgorithms/misc/ShuffleArrayTest.java @@ -1,6 +1,7 @@ package com.thealgorithms.misc; import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -67,7 +68,7 @@ void testShuffleRetainsElements() { ShuffleArray.shuffle(arr); // Check that the shuffled array contains the same elements - assertTrue(arr.length == 5); + assertEquals(5, arr.length); for (int i = 1; i <= 5; i++) { assertTrue(contains(arr, i)); } diff --git a/src/test/java/com/thealgorithms/others/NewManShanksPrimeTest.java b/src/test/java/com/thealgorithms/others/NewManShanksPrimeTest.java deleted file mode 100644 index 3b657e441b1c..000000000000 --- a/src/test/java/com/thealgorithms/others/NewManShanksPrimeTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.thealgorithms.others; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.thealgorithms.dynamicprogramming.NewManShanksPrime; -import org.junit.jupiter.api.Test; - -public class NewManShanksPrimeTest { - - @Test - void testOne() { - assertTrue(NewManShanksPrime.nthManShanksPrime(1, 1)); - } - - @Test - void testTwo() { - assertTrue(NewManShanksPrime.nthManShanksPrime(2, 3)); - } - - @Test - void testThree() { - assertTrue(NewManShanksPrime.nthManShanksPrime(3, 7)); - } - - @Test - void testFour() { - assertTrue(NewManShanksPrime.nthManShanksPrime(4, 17)); - } - - @Test - void testFive() { - assertTrue(NewManShanksPrime.nthManShanksPrime(5, 41)); - } - - @Test - void testSix() { - assertTrue(NewManShanksPrime.nthManShanksPrime(6, 99)); - } - - @Test - void testSeven() { - assertTrue(NewManShanksPrime.nthManShanksPrime(7, 239)); - } - - @Test - void testEight() { - assertTrue(NewManShanksPrime.nthManShanksPrime(8, 577)); - } -} diff --git a/src/test/java/com/thealgorithms/others/PasswordGenTest.java b/src/test/java/com/thealgorithms/others/PasswordGenTest.java index 76492556e75f..4dcdf6b9cf4f 100644 --- a/src/test/java/com/thealgorithms/others/PasswordGenTest.java +++ b/src/test/java/com/thealgorithms/others/PasswordGenTest.java @@ -17,7 +17,7 @@ public void failGenerationWithSameMinMaxLengthTest() { @Test public void generateOneCharacterPassword() { String tempPassword = PasswordGen.generatePassword(1, 2); - assertTrue(tempPassword.length() == 1); + assertEquals(1, tempPassword.length()); } @Test diff --git a/src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java b/src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java deleted file mode 100644 index 669f928cd247..000000000000 --- a/src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.thealgorithms.others.cn; - -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.Test; - -public class HammingDistanceTest { - @Test - public void checkForDifferentBits() { - int answer = HammingDistance.compute("000", "011"); - Assertions.assertThat(answer).isEqualTo(2); - } - - /* - - 1 0 1 0 1 - 1 1 1 1 0 - ---------- - 0 1 0 1 1 - - - */ - @Test - public void checkForDifferentBitsLength() { - int answer = HammingDistance.compute("10101", "11110"); - Assertions.assertThat(answer).isEqualTo(3); - } - - @Test - public void checkForSameBits() { - String someBits = "111"; - int answer = HammingDistance.compute(someBits, someBits); - Assertions.assertThat(answer).isEqualTo(0); - } - - @Test - public void checkForLongDataBits() { - int answer = HammingDistance.compute("10010101101010000100110100", "00110100001011001100110101"); - Assertions.assertThat(answer).isEqualTo(7); - } - - @Test - public void mismatchDataBits() { - Exception ex = org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> { HammingDistance.compute("100010", "00011"); }); - - Assertions.assertThat(ex.getMessage()).contains("must have the same length"); - } - - @Test - public void mismatchDataBits2() { - Exception ex = org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> { HammingDistance.compute("1", "11"); }); - - Assertions.assertThat(ex.getMessage()).contains("must have the same length"); - } - - @Test - public void checkForLongDataBitsSame() { - String someBits = "10010101101010000100110100"; - int answer = HammingDistance.compute(someBits, someBits); - Assertions.assertThat(answer).isEqualTo(0); - } - - @Test - public void checkForEmptyInput() { - String someBits = ""; - int answer = HammingDistance.compute(someBits, someBits); - Assertions.assertThat(answer).isEqualTo(0); - } - - @Test - public void checkForInputOfLength1() { - String someBits = "0"; - int answer = HammingDistance.compute(someBits, someBits); - Assertions.assertThat(answer).isEqualTo(0); - } - - @Test - public void computeThrowsExceptionWhenInputsAreNotBitStrs() { - Exception ex = org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> { HammingDistance.compute("1A", "11"); }); - - Assertions.assertThat(ex.getMessage()).contains("must be a binary string"); - } -} diff --git a/src/test/java/com/thealgorithms/prefixsum/DifferenceArrayTest.java b/src/test/java/com/thealgorithms/prefixsum/DifferenceArrayTest.java new file mode 100644 index 000000000000..88a480f25f1a --- /dev/null +++ b/src/test/java/com/thealgorithms/prefixsum/DifferenceArrayTest.java @@ -0,0 +1,110 @@ +package com.thealgorithms.prefixsum; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class DifferenceArrayTest { + + @Test + void testStandardRangeUpdate() { + int[] input = {10, 20, 30, 40, 50}; + DifferenceArray da = new DifferenceArray(input); + + da.update(1, 3, 5); + + long[] expected = {10, 25, 35, 45, 50}; + assertArrayEquals(expected, da.getResultArray()); + } + + @Test + void testMultipleOverlappingUpdates() { + int[] input = {10, 10, 10, 10, 10}; + DifferenceArray da = new DifferenceArray(input); + + da.update(0, 2, 10); + da.update(2, 4, 20); + + long[] expected = {20, 20, 40, 30, 30}; + assertArrayEquals(expected, da.getResultArray()); + } + + @Test + void testIntegerOverflowSafety() { + int[] input = {Integer.MAX_VALUE, 100}; + DifferenceArray da = new DifferenceArray(input); + + da.update(0, 0, 100); + + long[] result = da.getResultArray(); + long expectedVal = (long) Integer.MAX_VALUE + 100; + + assertEquals(expectedVal, result[0]); + } + + @Test + void testFullRangeUpdate() { + int[] input = {1, 2, 3}; + DifferenceArray da = new DifferenceArray(input); + + da.update(0, 2, 100); + + long[] expected = {101, 102, 103}; + assertArrayEquals(expected, da.getResultArray()); + } + + @Test + void testBoundaryWriteOptimization() { + int[] input = {5, 5}; + DifferenceArray da = new DifferenceArray(input); + + da.update(1, 1, 5); + + long[] expected = {5, 10}; + + assertArrayEquals(expected, da.getResultArray()); + } + + @Test + void testLargeMassiveUpdate() { + int[] input = {0}; + DifferenceArray da = new DifferenceArray(input); + + int iterations = 100000; + for (int i = 0; i < iterations; i++) { + da.update(0, 0, 1); + } + + assertEquals(100000L, da.getResultArray()[0]); + } + + @Test + void testNullInputThrowsException() { + assertThrows(IllegalArgumentException.class, () -> new DifferenceArray(null)); + } + + @Test + void testEmptyInputThrowsException() { + assertThrows(IllegalArgumentException.class, () -> new DifferenceArray(new int[] {})); + } + + @Test + void testInvalidRangeNegativeIndex() { + DifferenceArray da = new DifferenceArray(new int[] {1, 2, 3}); + assertThrows(IllegalArgumentException.class, () -> da.update(-1, 1, 5)); + } + + @Test + void testInvalidRangeOutOfBounds() { + DifferenceArray da = new DifferenceArray(new int[] {1, 2, 3}); + assertThrows(IllegalArgumentException.class, () -> da.update(0, 3, 5)); + } + + @Test + void testInvalidRangeStartGreaterThanEnd() { + DifferenceArray da = new DifferenceArray(new int[] {1, 2, 3}); + assertThrows(IllegalArgumentException.class, () -> da.update(2, 1, 5)); + } +} diff --git a/src/test/java/com/thealgorithms/prefixsum/PrefixSum2DTest.java b/src/test/java/com/thealgorithms/prefixsum/PrefixSum2DTest.java new file mode 100644 index 000000000000..87feff859356 --- /dev/null +++ b/src/test/java/com/thealgorithms/prefixsum/PrefixSum2DTest.java @@ -0,0 +1,92 @@ +package com.thealgorithms.prefixsum; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PrefixSum2DTest { + + @Test + @DisplayName("Test basic 3x3 square matrix") + void testStandardSquare() { + int[][] matrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + PrefixSum2D ps = new PrefixSum2D(matrix); + + // Sum of top-left 2x2: {1,2, 4,5} -> 12 + assertEquals(12L, ps.sumRegion(0, 0, 1, 1)); + // Sum of bottom-right 2x2: {5,6, 8,9} -> 28 + assertEquals(28L, ps.sumRegion(1, 1, 2, 2)); + // Full matrix -> 45 + assertEquals(45L, ps.sumRegion(0, 0, 2, 2)); + } + + @Test + @DisplayName("Test rectangular matrix (more cols than rows)") + void testRectangularWide() { + int[][] matrix = {{1, 1, 1, 1}, {2, 2, 2, 2}}; + PrefixSum2D ps = new PrefixSum2D(matrix); + + // Sum of first 3 columns of both rows -> (1*3) + (2*3) = 9 + assertEquals(9L, ps.sumRegion(0, 0, 1, 2)); + } + + @Test + @DisplayName("Test rectangular matrix (more rows than cols)") + void testRectangularTall() { + int[][] matrix = {{1}, {2}, {3}, {4}}; + PrefixSum2D ps = new PrefixSum2D(matrix); + + // Sum of middle two elements -> 2+3 = 5 + assertEquals(5L, ps.sumRegion(1, 0, 2, 0)); + } + + @Test + @DisplayName("Test single element matrix") + void testSingleElement() { + int[][] matrix = {{100}}; + PrefixSum2D ps = new PrefixSum2D(matrix); + + assertEquals(100L, ps.sumRegion(0, 0, 0, 0)); + } + + @Test + @DisplayName("Test large numbers for overflow (Integer -> Long)") + void testLargeNumbers() { + // 2 billion. Two of these sum to > MAX_INT + int val = 2_000_000_000; + int[][] matrix = {{val, val}, {val, val}}; + PrefixSum2D ps = new PrefixSum2D(matrix); + + // 4 * 2B = 8 Billion + assertEquals(8_000_000_000L, ps.sumRegion(0, 0, 1, 1)); + } + + @Test + @DisplayName("Test invalid inputs") + void testInvalidInputs() { + assertThrows(IllegalArgumentException.class, () -> new PrefixSum2D(null)); + assertThrows(IllegalArgumentException.class, () -> new PrefixSum2D(new int[][] {})); // empty + assertThrows(IllegalArgumentException.class, () -> new PrefixSum2D(new int[][] {{}})); // empty row + } + + @Test + @DisplayName("Test invalid query ranges") + void testInvalidRanges() { + int[][] matrix = {{1, 2}, {3, 4}}; + PrefixSum2D ps = new PrefixSum2D(matrix); + + // Negative indices + assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRegion(-1, 0, 0, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRegion(0, -1, 0, 0)); + + // Out of bounds + assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRegion(0, 0, 2, 0)); // row2 too big + assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRegion(0, 0, 0, 2)); // col2 too big + + // Inverted ranges (start > end) + assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRegion(1, 0, 0, 0)); // row1 > row2 + assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRegion(0, 1, 0, 0)); // col1 > col2 + } +} diff --git a/src/test/java/com/thealgorithms/prefixsum/PrefixSumTest.java b/src/test/java/com/thealgorithms/prefixsum/PrefixSumTest.java new file mode 100644 index 000000000000..a421b62e9306 --- /dev/null +++ b/src/test/java/com/thealgorithms/prefixsum/PrefixSumTest.java @@ -0,0 +1,80 @@ +package com.thealgorithms.prefixsum; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PrefixSumTest { + + @Test + @DisplayName("Test basic sum with positive integers") + void testStandardCase() { + int[] input = {1, 2, 3, 4, 5}; + PrefixSum ps = new PrefixSum(input); + + // Sum of range [0, 4] -> 15 + assertEquals(15L, ps.sumRange(0, 4)); + + // Sum of range [1, 3] -> 9 + assertEquals(9L, ps.sumRange(1, 3)); + } + + @Test + @DisplayName("Test array with negative numbers and zeros") + void testNegativeAndZeros() { + int[] input = {-2, 0, 3, -5, 2, -1}; + PrefixSum ps = new PrefixSum(input); + + assertEquals(1L, ps.sumRange(0, 2)); + assertEquals(-1L, ps.sumRange(2, 5)); + assertEquals(0L, ps.sumRange(1, 1)); + } + + @Test + @DisplayName("Test with large integers to verify overflow handling") + void testLargeNumbers() { + // Two values that fit in int, but their sum exceeds Integer.MAX_VALUE + // Integer.MAX_VALUE is approx 2.14 billion. + int val = 2_000_000_000; + int[] input = {val, val, val}; + PrefixSum ps = new PrefixSum(input); + + // Sum of three 2 billion values is 6 billion (fits in long, overflows int) + assertEquals(6_000_000_000L, ps.sumRange(0, 2)); + } + + @Test + @DisplayName("Test single element array") + void testSingleElement() { + int[] input = {42}; + PrefixSum ps = new PrefixSum(input); + assertEquals(42L, ps.sumRange(0, 0)); + } + + @Test + @DisplayName("Test constructor with null input") + void testNullInput() { + assertThrows(IllegalArgumentException.class, () -> new PrefixSum(null)); + } + + @Test + @DisplayName("Test empty array behavior") + void testEmptyArray() { + int[] input = {}; + PrefixSum ps = new PrefixSum(input); + assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRange(0, 0)); + } + + @Test + @DisplayName("Test invalid range indices") + void testInvalidIndices() { + int[] input = {10, 20, 30}; + PrefixSum ps = new PrefixSum(input); + + assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRange(-1, 1)); + assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRange(0, 3)); + assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRange(2, 1)); + } +} diff --git a/src/test/java/com/thealgorithms/prefixsum/SubarraySumEqualskTest.java b/src/test/java/com/thealgorithms/prefixsum/SubarraySumEqualskTest.java new file mode 100644 index 000000000000..68f85b713046 --- /dev/null +++ b/src/test/java/com/thealgorithms/prefixsum/SubarraySumEqualskTest.java @@ -0,0 +1,59 @@ +package com.thealgorithms.prefixsum; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +/** + * Tests for {@link SubarraySumEqualsK}. + */ +class SubarraySumEqualsKTest { + + @Test + void testBasicExample() { + int[] nums = {1, 1, 1}; + int k = 2; + assertEquals(2, SubarraySumEqualsK.countSubarrays(nums, k)); + } + + @Test + void testWithNegativeNumbers() { + int[] nums = {1, -1, 0}; + int k = 0; + assertEquals(3, SubarraySumEqualsK.countSubarrays(nums, k)); + } + + @Test + void testSingleElementEqualToK() { + int[] nums = {5}; + int k = 5; + assertEquals(1, SubarraySumEqualsK.countSubarrays(nums, k)); + } + + @Test + void testSingleElementNotEqualToK() { + int[] nums = {5}; + int k = 3; + assertEquals(0, SubarraySumEqualsK.countSubarrays(nums, k)); + } + + @Test + void testAllZeros() { + int[] nums = {0, 0, 0}; + int k = 0; + assertEquals(6, SubarraySumEqualsK.countSubarrays(nums, k)); + } + + @Test + void testEmptyArray() { + int[] nums = {}; + int k = 0; + assertEquals(0, SubarraySumEqualsK.countSubarrays(nums, k)); + } + + @Test + void testNullArrayThrowsException() { + assertThrows(IllegalArgumentException.class, () -> SubarraySumEqualsK.countSubarrays(null, 0)); + } +} diff --git a/src/test/java/com/thealgorithms/searches/BinarySearch2dArrayTest.java b/src/test/java/com/thealgorithms/searches/BinarySearch2dArrayTest.java index 18f0afc6a0a6..dec2c86de9c7 100644 --- a/src/test/java/com/thealgorithms/searches/BinarySearch2dArrayTest.java +++ b/src/test/java/com/thealgorithms/searches/BinarySearch2dArrayTest.java @@ -117,7 +117,7 @@ public void binarySearch2dArrayTestTargetInMiddle() { int target = 8; // Assert that the requirement, that the target is in the middle row and middle column, is // fulfilled. - assertEquals(arr[arr.length / 2][arr[0].length / 2], target); + assertEquals(target, arr[arr.length / 2][arr[0].length / 2]); int[] ans = BinarySearch2dArray.binarySearch(arr, target); System.out.println(Arrays.toString(ans)); assertEquals(1, ans[0]); @@ -135,8 +135,8 @@ public void binarySearch2dArrayTestTargetAboveMiddleRowInMiddleColumn() { // Assert that the requirement, that he target is in the middle column, // in an array with an even number of columns, and on the row "above" the middle row. - assertEquals(arr[0].length % 2, 0); - assertEquals(arr[arr.length / 2 - 1][arr[0].length / 2], target); + assertEquals(0, arr[0].length % 2); + assertEquals(target, arr[arr.length / 2 - 1][arr[0].length / 2]); int[] ans = BinarySearch2dArray.binarySearch(arr, target); System.out.println(Arrays.toString(ans)); assertEquals(0, ans[0]); diff --git a/src/test/java/com/thealgorithms/searches/KMPSearchTest.java b/src/test/java/com/thealgorithms/searches/KMPSearchTest.java index cb804ac6a6a3..216c5fcd7d2c 100644 --- a/src/test/java/com/thealgorithms/searches/KMPSearchTest.java +++ b/src/test/java/com/thealgorithms/searches/KMPSearchTest.java @@ -14,7 +14,7 @@ public void kmpSearchTestLast() { KMPSearch kmpSearch = new KMPSearch(); int value = kmpSearch.kmpSearch(pat, txt); System.out.println(value); - assertEquals(value, 10); + assertEquals(10, value); } @Test @@ -25,7 +25,7 @@ public void kmpSearchTestFront() { KMPSearch kmpSearch = new KMPSearch(); int value = kmpSearch.kmpSearch(pat, txt); System.out.println(value); - assertEquals(value, 0); + assertEquals(0, value); } @Test @@ -36,7 +36,7 @@ public void kmpSearchTestMiddle() { KMPSearch kmpSearch = new KMPSearch(); int value = kmpSearch.kmpSearch(pat, txt); System.out.println(value); - assertEquals(value, 4); + assertEquals(4, value); } @Test @@ -47,7 +47,7 @@ public void kmpSearchTestNotFound() { KMPSearch kmpSearch = new KMPSearch(); int value = kmpSearch.kmpSearch(pat, txt); System.out.println(value); - assertEquals(value, 4); + assertEquals(4, value); } @Test @@ -58,6 +58,6 @@ public void kmpSearchTest4() { KMPSearch kmpSearch = new KMPSearch(); int value = kmpSearch.kmpSearch(pat, txt); System.out.println(value); - assertEquals(value, -1); + assertEquals(-1, value); } } diff --git a/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java b/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java deleted file mode 100644 index 6eab20f45467..000000000000 --- a/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.thealgorithms.searches; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; - -/** - * @author D Sunil (https://github.com/sunilnitdgp) - * @see PerfectBinarySearch - */ -public class PerfectBinarySearchTest { - - @Test - public void testIntegerBinarySearch() { - Integer[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - PerfectBinarySearch binarySearch = new PerfectBinarySearch<>(); - - // Test cases for elements present in the array - assertEquals(0, binarySearch.find(array, 1)); // First element - assertEquals(4, binarySearch.find(array, 5)); // Middle element - assertEquals(9, binarySearch.find(array, 10)); // Last element - assertEquals(6, binarySearch.find(array, 7)); // Element in the middle - - // Test cases for elements not in the array - assertEquals(-1, binarySearch.find(array, 0)); // Element before the array - assertEquals(-1, binarySearch.find(array, 11)); // Element after the array - assertEquals(-1, binarySearch.find(array, 100)); // Element not in the array - } - - @Test - public void testStringBinarySearch() { - String[] array = {"apple", "banana", "cherry", "date", "fig"}; - PerfectBinarySearch binarySearch = new PerfectBinarySearch<>(); - - // Test cases for elements not in the array - assertEquals(-1, binarySearch.find(array, "apricot")); // Element not in the array - assertEquals(-1, binarySearch.find(array, "bananaa")); // Element not in the array - - // Test cases for elements present in the array - assertEquals(0, binarySearch.find(array, "apple")); // First element - assertEquals(2, binarySearch.find(array, "cherry")); // Middle element - assertEquals(4, binarySearch.find(array, "fig")); // Last element - } -} diff --git a/src/test/java/com/thealgorithms/searches/QuickSelectTest.java b/src/test/java/com/thealgorithms/searches/QuickSelectTest.java index cf160b0ff4b5..4c96be76861a 100644 --- a/src/test/java/com/thealgorithms/searches/QuickSelectTest.java +++ b/src/test/java/com/thealgorithms/searches/QuickSelectTest.java @@ -172,7 +172,7 @@ void quickSelect70thPercentileOfManyElements() { void quickSelectMedianOfThreeCharacters() { List elements = Arrays.asList('X', 'Z', 'Y'); char actual = QuickSelect.select(elements, 1); - assertEquals(actual, 'Y'); + assertEquals('Y', actual); } @Test diff --git a/src/test/java/com/thealgorithms/searches/RotatedBinarySearchTest.java b/src/test/java/com/thealgorithms/searches/RotatedBinarySearchTest.java new file mode 100644 index 000000000000..1e6ab4c37fcc --- /dev/null +++ b/src/test/java/com/thealgorithms/searches/RotatedBinarySearchTest.java @@ -0,0 +1,53 @@ +package com.thealgorithms.searches; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class RotatedBinarySearchTest { + + @Test + void shouldFindElementInRotatedArrayLeftSide() { + RotatedBinarySearch search = new RotatedBinarySearch(); + Integer[] array = {8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7}; + assertEquals(2, search.find(array, 10)); + } + + @Test + void shouldFindElementInRotatedArrayRightSide() { + RotatedBinarySearch search = new RotatedBinarySearch(); + Integer[] array = {8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7}; + assertEquals(6, search.find(array, 2)); + } + + @Test + void shouldFindElementInNotRotatedArray() { + RotatedBinarySearch search = new RotatedBinarySearch(); + Integer[] array = {1, 2, 3, 4, 5, 6, 7}; + assertEquals(4, search.find(array, 5)); + } + + @Test + void shouldReturnMinusOneWhenNotFound() { + RotatedBinarySearch search = new RotatedBinarySearch(); + Integer[] array = {4, 5, 6, 7, 0, 1, 2}; + assertEquals(-1, search.find(array, 3)); + } + + @Test + void shouldHandleWhenMiddleIsGreaterThanKeyInRightSortedHalf() { + RotatedBinarySearch search = new RotatedBinarySearch(); + Integer[] array = {6, 7, 0, 1, 2, 3, 4, 5}; + assertEquals(2, search.find(array, 0)); + } + + @Test + void shouldHandleDuplicates() { + RotatedBinarySearch search = new RotatedBinarySearch(); + Integer[] array = {2, 2, 2, 3, 4, 2}; + int index = search.find(array, 3); + assertTrue(index >= 0 && index < array.length); + assertEquals(3, array[index]); + } +} diff --git a/src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java b/src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java deleted file mode 100644 index e2917733d1d9..000000000000 --- a/src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.thealgorithms.searches; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; - -public class SortOrderAgnosticBinarySearchTest { - - @Test - public void testAscending() { - int[] arr = {1, 2, 3, 4, 5}; // for ascending order. - int target = 2; - int ans = SortOrderAgnosticBinarySearch.find(arr, target); - int excepted = 1; - assertEquals(excepted, ans); - } - - @Test - public void testDescending() { - int[] arr = {5, 4, 3, 2, 1}; // for descending order. - int target = 2; - int ans = SortOrderAgnosticBinarySearch.find(arr, target); - int excepted = 3; - assertEquals(excepted, ans); - } -} diff --git a/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java b/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java new file mode 100644 index 000000000000..71bf24cc9e30 --- /dev/null +++ b/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java @@ -0,0 +1,55 @@ +package com.thealgorithms.slidingwindow; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class CountNiceSubarraysTest { + @Test + void testExampleCase() { + int[] nums = {1, 1, 2, 1, 1}; + assertEquals(2, CountNiceSubarrays.countNiceSubarrays(nums, 3)); + } + + @Test + void testAllEvenNumbers() { + int[] nums = {2, 4, 6, 8}; + assertEquals(0, CountNiceSubarrays.countNiceSubarrays(nums, 1)); + } + + @Test + void testSingleOdd() { + int[] nums = {1}; + assertEquals(1, CountNiceSubarrays.countNiceSubarrays(nums, 1)); + } + + @Test + void testMultipleChoices() { + int[] nums = {2, 2, 1, 2, 2, 1, 2}; + assertEquals(6, CountNiceSubarrays.countNiceSubarrays(nums, 2)); + } + + @Test + void testTrailingEvenNumbers() { + int[] nums = {1, 2, 2, 2}; + assertEquals(4, CountNiceSubarrays.countNiceSubarrays(nums, 1)); + } + + @Test + void testMultipleWindowShrinks() { + int[] nums = {1, 1, 1, 1}; + assertEquals(3, CountNiceSubarrays.countNiceSubarrays(nums, 2)); + } + + @Test + void testEvensBetweenOdds() { + int[] nums = {2, 1, 2, 1, 2}; + assertEquals(4, CountNiceSubarrays.countNiceSubarrays(nums, 2)); + } + + @Test + void testShrinkWithTrailingEvens() { + int[] nums = {2, 2, 1, 2, 2, 1, 2, 2}; + assertEquals(9, CountNiceSubarrays.countNiceSubarrays(nums, 2)); + } +} diff --git a/src/test/java/com/thealgorithms/sorts/SmoothSortTest.java b/src/test/java/com/thealgorithms/sorts/SmoothSortTest.java new file mode 100644 index 000000000000..8df0502e80e7 --- /dev/null +++ b/src/test/java/com/thealgorithms/sorts/SmoothSortTest.java @@ -0,0 +1,8 @@ +package com.thealgorithms.sorts; + +public class SmoothSortTest extends SortingAlgorithmTest { + @Override + SortAlgorithm getSortAlgorithm() { + return new SmoothSort(); + } +} diff --git a/src/test/java/com/thealgorithms/sorts/TopologicalSortTest.java b/src/test/java/com/thealgorithms/sorts/TopologicalSortTest.java index d5588b2b968e..e19f5b928263 100644 --- a/src/test/java/com/thealgorithms/sorts/TopologicalSortTest.java +++ b/src/test/java/com/thealgorithms/sorts/TopologicalSortTest.java @@ -58,7 +58,7 @@ public void failureTest() { Exception exception = assertThrows(RuntimeException.class, () -> TopologicalSort.sort(graph)); String expected = "This graph contains a cycle. No linear ordering is possible. " + "Back edge: 6 -> 2"; - assertEquals(exception.getMessage(), expected); + assertEquals(expected, exception.getMessage()); } @Test void testEmptyGraph() { diff --git a/src/test/java/com/thealgorithms/sorts/TournamentSortTest.java b/src/test/java/com/thealgorithms/sorts/TournamentSortTest.java new file mode 100644 index 000000000000..91da746447a8 --- /dev/null +++ b/src/test/java/com/thealgorithms/sorts/TournamentSortTest.java @@ -0,0 +1,19 @@ +package com.thealgorithms.sorts; + +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Test; + +public class TournamentSortTest extends SortingAlgorithmTest { + + @Test + void shouldAcceptWhenNullArrayIsPassed() { + Integer[] array = null; + assertNull(getSortAlgorithm().sort(array)); + } + + @Override + SortAlgorithm getSortAlgorithm() { + return new TournamentSort(); + } +} diff --git a/src/test/java/com/thealgorithms/strings/KMPTest.java b/src/test/java/com/thealgorithms/strings/KMPTest.java new file mode 100644 index 000000000000..9fa5f398d420 --- /dev/null +++ b/src/test/java/com/thealgorithms/strings/KMPTest.java @@ -0,0 +1,29 @@ +package com.thealgorithms.strings; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import org.junit.jupiter.api.Test; + +public class KMPTest { + + @Test + public void testNullInputs() { + assertEquals(List.of(), KMP.kmpMatcher(null, "A")); + assertEquals(List.of(), KMP.kmpMatcher("A", null)); + assertEquals(List.of(), KMP.kmpMatcher(null, null)); + } + + @Test + public void testKMPMatcher() { + assertEquals(List.of(0, 1), KMP.kmpMatcher("AAAAABAAABA", "AAAA")); + assertEquals(List.of(0, 3), KMP.kmpMatcher("ABCABC", "ABC")); + assertEquals(List.of(10), KMP.kmpMatcher("ABABDABACDABABCABAB", "ABABCABAB")); + assertEquals(List.of(), KMP.kmpMatcher("ABCDE", "FGH")); + assertEquals(List.of(), KMP.kmpMatcher("A", "AA")); + assertEquals(List.of(0, 1, 2), KMP.kmpMatcher("AAA", "A")); + assertEquals(List.of(0), KMP.kmpMatcher("A", "A")); + assertEquals(List.of(), KMP.kmpMatcher("", "A")); + assertEquals(List.of(), KMP.kmpMatcher("A", "")); + } +} diff --git a/src/test/java/com/thealgorithms/strings/LongestPalindromicSubstringTest.java b/src/test/java/com/thealgorithms/strings/LongestPalindromicSubstringTest.java deleted file mode 100644 index aa13c0f4a474..000000000000 --- a/src/test/java/com/thealgorithms/strings/LongestPalindromicSubstringTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.thealgorithms.strings; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class LongestPalindromicSubstringTest { - - @ParameterizedTest - @MethodSource("provideTestCasesForLongestPalindrome") - void testLongestPalindrome(String input, String expected) { - assertEquals(expected, LongestPalindromicSubstring.longestPalindrome(input)); - } - - private static Stream provideTestCasesForLongestPalindrome() { - return Stream.of(Arguments.of("babad", "bab"), Arguments.of("cbbd", "bb"), Arguments.of("a", "a"), Arguments.of("", ""), Arguments.of("abc", "a"), Arguments.of(null, ""), Arguments.of("aaaaa", "aaaaa")); - } -} diff --git a/src/test/java/com/thealgorithms/strings/RabinKarpTest.java b/src/test/java/com/thealgorithms/strings/RabinKarpTest.java new file mode 100644 index 000000000000..6dfd099e9bca --- /dev/null +++ b/src/test/java/com/thealgorithms/strings/RabinKarpTest.java @@ -0,0 +1,46 @@ +package com.thealgorithms.strings; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import org.junit.jupiter.api.Test; + +public class RabinKarpTest { + + @Test + public void testNullInputs() { + assertEquals(List.of(), RabinKarp.search(null, "A")); + assertEquals(List.of(), RabinKarp.search("A", null)); + assertEquals(List.of(), RabinKarp.search(null, null)); + } + + @Test + public void testHashCollision() { + // 'a' = 97. (char)198 % 101 = 97. + // For length 1, h = 1. p = 97. t = 198 % 101 = 97. + // Collision occurs, loop checks characters: 198 != 97, breaks. + char collisionChar = (char) 198; + String text = String.valueOf(collisionChar); + String pattern = "a"; + assertEquals(List.of(), RabinKarp.search(text, pattern)); + } + + @Test + public void testSearchWithCustomQ() { + // Using a different prime + assertEquals(List.of(0, 1), RabinKarp.search("AAAA", "AAA", 13)); + } + + @Test + public void testRabinKarpSearch() { + assertEquals(List.of(0, 1), RabinKarp.search("AAAAABAAABA", "AAAA")); + assertEquals(List.of(0, 3), RabinKarp.search("ABCABC", "ABC")); + assertEquals(List.of(10), RabinKarp.search("ABABDABACDABABCABAB", "ABABCABAB")); + assertEquals(List.of(), RabinKarp.search("ABCDE", "FGH")); + assertEquals(List.of(), RabinKarp.search("A", "AA")); + assertEquals(List.of(0, 1, 2), RabinKarp.search("AAA", "A")); + assertEquals(List.of(0), RabinKarp.search("A", "A")); + assertEquals(List.of(), RabinKarp.search("", "A")); + assertEquals(List.of(), RabinKarp.search("A", "")); + } +} diff --git a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java b/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java deleted file mode 100644 index 411b11e743b8..000000000000 --- a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.thealgorithms.strings; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -public class ValidParenthesesTest { - - @ParameterizedTest(name = "Input: \"{0}\" β†’ Expected: {1}") - @CsvSource({"'()', true", "'()[]{}', true", "'(]', false", "'{[]}', true", "'([{}])', true", "'([)]', false", "'', true", "'(', false", "')', false", "'{{{{}}}}', true", "'[({})]', true", "'[(])', false", "'[', false", "']', false", "'()()()()', true", "'(()', false", "'())', false", - "'{[()()]()}', true"}) - void - testIsValid(String input, boolean expected) { - assertEquals(expected, ValidParentheses.isValid(input)); - } - - @Test - void testNullInputThrows() { - IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> ValidParentheses.isValid(null)); - assertEquals("Input string cannot be null", ex.getMessage()); - } - - @ParameterizedTest(name = "Input: \"{0}\" β†’ throws IllegalArgumentException") - @CsvSource({"'a'", "'()a'", "'[123]'", "'{hello}'", "'( )'", "'\t'", "'\n'", "'@#$%'"}) - void testInvalidCharactersThrow(String input) { - IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> ValidParentheses.isValid(input)); - assertTrue(ex.getMessage().startsWith("Unexpected character")); - } -} diff --git a/src/test/java/com/thealgorithms/strings/WordLadderTest.java b/src/test/java/com/thealgorithms/strings/WordLadderTest.java index 221953411da7..c029940abfb0 100644 --- a/src/test/java/com/thealgorithms/strings/WordLadderTest.java +++ b/src/test/java/com/thealgorithms/strings/WordLadderTest.java @@ -24,7 +24,7 @@ public class WordLadderTest { public void testWordLadder() { List wordList1 = Arrays.asList("hot", "dot", "dog", "lot", "log", "cog"); - assertEquals(WordLadder.ladderLength("hit", "cog", wordList1), 5); + assertEquals(5, WordLadder.ladderLength("hit", "cog", wordList1)); } /** @@ -39,7 +39,7 @@ public void testWordLadder() { public void testWordLadder2() { List wordList2 = Arrays.asList("hot", "dot", "dog", "lot", "log"); - assertEquals(WordLadder.ladderLength("hit", "cog", wordList2), 0); + assertEquals(0, WordLadder.ladderLength("hit", "cog", wordList2)); } /** @@ -54,7 +54,7 @@ public void testWordLadder2() { public void testWordLadder3() { List wordList3 = emptyList(); - assertEquals(WordLadder.ladderLength("hit", "cog", wordList3), 0); + assertEquals(0, WordLadder.ladderLength("hit", "cog", wordList3)); } @ParameterizedTest diff --git a/src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java b/src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java index 2cbbfe3d2dd8..9bf118c9b844 100644 --- a/src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java +++ b/src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java @@ -9,8 +9,8 @@ public class ZigZagPatternTest { public void testZigZagPattern() { String input1 = "HelloWorldFromJava"; String input2 = "javaIsAProgrammingLanguage"; - Assertions.assertEquals(ZigZagPattern.encode(input1, 4), "HooeWrrmalolFJvlda"); - Assertions.assertEquals(ZigZagPattern.encode(input2, 4), "jAaLgasPrmgaaevIrgmnnuaoig"); + Assertions.assertEquals("HooeWrrmalolFJvlda", ZigZagPattern.encode(input1, 4)); + Assertions.assertEquals("jAaLgasPrmgaaevIrgmnnuaoig", ZigZagPattern.encode(input2, 4)); // Edge cases Assertions.assertEquals("ABC", ZigZagPattern.encode("ABC", 1)); // Single row Assertions.assertEquals("A", ZigZagPattern.encode("A", 2)); // numRows > length of string