├── .gitattributes ├── .github └── workflows │ └── execute.yml ├── .gitignore ├── LICENSE ├── README.md ├── _config.yml ├── build.gradle.kts ├── generate_docs.py ├── generate_file_history.py ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── python-run.sh ├── python ├── __init__.py ├── addTwoNumbers.py ├── codinginterview │ ├── delete_duplicates.py │ ├── delete_middle.py │ ├── find_intersection_linked_list.py │ ├── forward_sum_of_nodes.py │ ├── is_linked_list_circular.py │ ├── is_linked_list_palindrome.py │ ├── is_palindrome_permutation.py │ ├── kth_to_last.py │ ├── matrix_rotation.py │ ├── merge_sort.py │ ├── one_or_zero_edits_away.py │ ├── quick_sort.py │ ├── shared │ │ ├── __init__.py │ │ ├── __init__.pyc │ │ ├── base_linked_list.py │ │ ├── circular_linked_list.py │ │ ├── linked_list.py │ │ ├── node.py │ │ └── reversed_linked_list.py │ ├── string_compression.py │ ├── string_rotation.py │ ├── sum_of_nodes_of_linked_list.py │ └── zero_matrix.py ├── hard │ ├── __init__.py │ ├── baby_names.py │ ├── baby_names_optimal │ ├── count_of_2s.py │ └── letters_and_numbers.py ├── longest_palindrome.py ├── longestsubstr.py ├── moderate │ ├── __init__.py │ ├── bisect_squares.py │ ├── calculator.py │ ├── continuous_sequence.py │ ├── count_pairs_with_difference.py │ ├── diving_board.py │ ├── english_int.py │ ├── factorial_zeros.py │ ├── intersection.py │ ├── langton_ant.py │ ├── living_people.py │ ├── master_mind.py │ ├── operation.py │ ├── pairs_with_sum.py │ ├── pattern_matching.py │ ├── pond_sizes.py │ ├── smallest_difference.py │ ├── sub_sort.py │ ├── swap_sum.py │ ├── tic_tac.py │ └── xml_encoding.py ├── multiply.py ├── needle.py ├── paritysort.py ├── python-run.sh ├── remove_element.py ├── reverseint.py ├── stacksqueues │ ├── __init__.py │ ├── animal_shelter.py │ ├── queueviastacks.py │ ├── sort_stack.py │ ├── stack.py │ ├── stack_min.py │ └── stack_of_plates.py ├── sumEvenAfterQueries.py ├── three_sums.py └── valid_paranthesis.py ├── run.sh ├── settings.gradle.kts ├── src ├── _utils │ └── DocumentUtils.kt ├── algorithmdesignmanualbook │ ├── Utilities.kt │ ├── datastructures │ │ ├── BalancedParentheses.kt │ │ ├── BinarySearchTree.kt │ │ ├── CutoutsToGenerateString.kt │ │ ├── DynamicGrowShrinkArray.java │ │ ├── FlattenBSTIntoLinkedList.kt │ │ ├── IdenticalBinaryTree.kt │ │ ├── LargestOccuringOrderedPair.kt │ │ ├── MatrixMultiplication.kt │ │ ├── MiddleNodeOfLinkedList.kt │ │ ├── MultiplicativeArray.kt │ │ ├── NoInitializationArray.kt │ │ ├── Node.kt │ │ ├── O1DataStructure.kt │ │ ├── ReverseLinkedList.kt │ │ ├── ReverseSentence.kt │ │ ├── SmallestNumberInRange.kt │ │ └── StringPatternMatching.kt │ ├── dynamic │ │ ├── EditDistance.kt │ │ └── MinDifferenceBetweenSubsets.kt │ ├── graph │ │ ├── BreadthFirstTraversal.kt │ │ ├── Graph.kt │ │ ├── GraphInit.kt │ │ ├── PrimMinSpanningTree.kt │ │ ├── SimpleGraph.kt │ │ └── UnionFind.kt │ ├── heuristics │ │ └── backtrack │ │ │ ├── AllSubsets.kt │ │ │ └── Permutation.kt │ ├── partialsum │ │ ├── PartialSumUsingCumulativeSum.kt │ │ └── PartialSumUsingFenwickTree.kt │ ├── searching │ │ ├── MagicIndexSearch.kt │ │ └── SmallestMissingNumber.kt │ └── sorting │ │ ├── ArrangeNegativeThenPositiveNumber.kt │ │ ├── BucketSort.kt │ │ ├── ColorSort.kt │ │ ├── ColorSortLinearTime.kt │ │ ├── FastMedian.kt │ │ ├── FindNumberOfOccurrence.kt │ │ ├── FindTransitionIndex.kt │ │ ├── HeapSort.kt │ │ ├── InsertionSort.kt │ │ ├── KSortedListMerge.kt │ │ ├── KSum.kt │ │ ├── MergeSort.kt │ │ ├── QuickSort.kt │ │ ├── SelectionSort.kt │ │ └── TwoPairSum.kt ├── algorithmsinanutshell │ ├── AVLTree.kt │ ├── ConvexHullScanUsingGrahamScan.kt │ ├── DijkstraAlgorithm.kt │ ├── FloydWarshallAlgorithm.kt │ ├── Graph.kt │ ├── GraphTraversal.kt │ ├── GreatestCommonDivisor.kt │ ├── IntersectionOfLines.kt │ ├── LineModel.kt │ ├── LineSweepAlgorithm.kt │ ├── OrientationOf3Points.kt │ ├── PrimMinSpanningTreeAlgorithm.kt │ ├── TreeTraversal.kt │ ├── networkflow │ │ ├── FordFulkersonAlgorithm.kt │ │ └── Network.kt │ └── spatialtree │ │ ├── KDTree.kt │ │ ├── KnapSack01.kt │ │ ├── NearestNeighbourQueries.kt │ │ └── QuadTree.kt ├── arraysandstrings │ ├── IsOneStringPermutationOfOther.java │ ├── IsPermutationOfStringAPalindrome.kt │ ├── MatrixRotation.kt │ ├── OneAway.kt │ ├── StringCompression.kt │ ├── StringRotation.kt │ ├── URLify.kt │ └── UniqueCharacters.java ├── bigo │ ├── PermutationCount.java │ └── PowerOf2.java ├── bits │ ├── BinaryToString.java │ ├── Conversion.java │ ├── FlipBitToWin.java │ ├── Insertion.java │ ├── PairwiseSwap.java │ └── commons │ │ └── BitUtils.java ├── dynamic │ ├── BooleanEvaluation.java │ ├── Coins.java │ ├── EightQueens.java │ ├── PaintFill.java │ ├── Parens.java │ ├── PermutationWithDuplicates.java │ ├── PermutationWithoutDuplicates.java │ ├── RecursiveMultiply.java │ └── TowerOfHanoi.java ├── graphs │ ├── BuildOrder.java │ ├── CheckBST.java │ ├── CheckBalanced.java │ ├── CheckIfSubTree.java │ ├── FirstCommonAncestor.java │ ├── ListOfDepth.java │ ├── MinimalTree.java │ ├── PathWithSum.java │ ├── PickRandomNode.java │ ├── RoutesBetweenNodes.java │ └── commons │ │ ├── BidirectionalTree.java │ │ ├── Graph.java │ │ ├── Node.java │ │ ├── State.java │ │ └── Tree.java ├── handbook │ ├── GeneratePermutations.kt │ └── GenerateSubsets.kt ├── hard │ ├── AddWithoutPlus.java │ ├── RandomSet.java │ └── Shuffle.java ├── linkedlists │ ├── LinkedList.kt │ ├── LinkedListDuplicate.kt │ └── SumLists.kt ├── questions │ ├── AddBinary.kt │ ├── AddStrings.kt │ ├── ArrangingCoins.kt │ ├── ArrayPartitionI.kt │ ├── AssignCookies.kt │ ├── BSTFromPreorder.kt │ ├── BestTimeStock.kt │ ├── BestTimeStockII.kt │ ├── BinaryStringWithSubstringsRep1ToN.kt │ ├── BuddyString.kt │ ├── CanPlaceFlowers.kt │ ├── ClimbingStairs.kt │ ├── ContainerWithMostWater.kt │ ├── ContainsDuplicate.kt │ ├── ContainsDuplicateII.kt │ ├── ConvertToHex.kt │ ├── CountAndSay.kt │ ├── CountCompleteTreeNode.kt │ ├── CountingBits.kt │ ├── CousinsBinaryTree.kt │ ├── CustomSortString.kt │ ├── DailyTemperatures.kt │ ├── DayOfTheYear.kt │ ├── DegreeOfAnArray.kt │ ├── DesignHashMap.kt │ ├── DesignHashset.kt │ ├── DesignSkipList.kt │ ├── DetectCapital.kt │ ├── DiameterOfBinaryTree.kt │ ├── DivideTwoIntegers.kt │ ├── ExcelSheetColumnTitle.kt │ ├── FindAllAnagrams.kt │ ├── FindDuplicateNumber.kt │ ├── FindTheDifference.kt │ ├── FirstBadVersion.kt │ ├── FirstUniqueCharacter.kt │ ├── FormatPhoneNumber.kt │ ├── GenerateParentheses.kt │ ├── HammingDistance.kt │ ├── HappyNumber.kt │ ├── InsertInterval.kt │ ├── IntegerToRoman.kt │ ├── IntersectionOfTwoArrays.kt │ ├── IsSubsequence.kt │ ├── IslandPerimeter.kt │ ├── IsomorphicStrings.kt │ ├── IteratorForCombination.kt │ ├── KDiffPairs.kt │ ├── KeyboardRow.kt │ ├── LargestDivisibleSubset.kt │ ├── LengthOfLastWord.kt │ ├── LengthOfLongestIncreasingSubSeq.kt │ ├── LetterCombinationsOfPhoneNumber.kt │ ├── LicenseKeyFormatting.kt │ ├── LinkedListCycle.kt │ ├── LongestAbsoluteFilePath.kt │ ├── LongestCommonPrefix.kt │ ├── LongestIncreasingSubSeq.kt │ ├── LongestPalindrome.kt │ ├── MajorityElement.kt │ ├── MaxAreaOfIsland.kt │ ├── MaxDepthOfBinaryTree.kt │ ├── MaxNumberOfBalloons.kt │ ├── MaxProductSubArray.kt │ ├── MaxSubarray.kt │ ├── MergeIntervals.kt │ ├── MergeSortedLists.kt │ ├── MergeTwoSortedList.kt │ ├── MinDeletionUniqueFrequency.kt │ ├── MinIndexOfSumLists.kt │ ├── MinLengthAfterDeletingSimilarEnds.kt │ ├── MinStack.kt │ ├── MinTotalInTriangle.kt │ ├── MissingNumber.kt │ ├── MoveZeroes.kt │ ├── NextGreaterElement.kt │ ├── NextGreaterElementII.kt │ ├── NimGame.kt │ ├── NumberOf1Bits.kt │ ├── PalindromeInteger.kt │ ├── PascalTriangle.kt │ ├── PascalTriangleII.kt │ ├── PathSum.kt │ ├── PivotIndex.kt │ ├── PlusOne.kt │ ├── PowerOf4.kt │ ├── RandomizedSet.kt │ ├── RangeSumQuery.kt │ ├── RangeSumQueryMutable.kt │ ├── RansomNote.kt │ ├── RegionsCutBySlashes.kt │ ├── RemoveDuplicateFromSortedArray.kt │ ├── RemoveDuplicatesFromSortedList.kt │ ├── ReorderList.kt │ ├── RepeatedSubstringPattern.kt │ ├── ReshapeTheMatrix.kt │ ├── RestoreIPAddresses.kt │ ├── ReverseBits.kt │ ├── ReversePolishNotation.kt │ ├── ReverseString.kt │ ├── ReverseStringII.kt │ ├── ReverseVowel.kt │ ├── ReverseWords.kt │ ├── ReverseWordsInStringIII.kt │ ├── RomanToInteger.kt │ ├── RotateImage.kt │ ├── SameTree.kt │ ├── SearchContact.kt │ ├── SearchInsertPosition.kt │ ├── SearchRange.kt │ ├── SetMismatch.kt │ ├── SimplifiedFraction.kt │ ├── SingleElementInSortedArray.kt │ ├── SingleNumber.kt │ ├── SingleNumberII.kt │ ├── SingleNumberIII.kt │ ├── SortCharByFrequency.kt │ ├── SortLinkedList.kt │ ├── SpiralMatrix.kt │ ├── SpiralMatrixII.kt │ ├── Sqrtx.kt │ ├── StackUsingQueues.kt │ ├── SumOfLeftLeaves.kt │ ├── SumRootToLeafNumber.kt │ ├── SummaryRanges.kt │ ├── SurroundedRegions.kt │ ├── SwapAdjacentNodes.kt │ ├── SymmetricTree.kt │ ├── ThirdMaximumNumber.kt │ ├── ThreeSumClosest.kt │ ├── TopKFrequent.kt │ ├── TotalHammingDistance.kt │ ├── TwoSumII.kt │ ├── UglyNumber.kt │ ├── UniquePaths.kt │ ├── UniquePathsII.kt │ ├── ValidAnagram.kt │ ├── ValidPalindrome.kt │ ├── WildcardSearchDS.kt │ ├── WordBreak.kt │ ├── WordPattern.kt │ ├── WordSearch.kt │ ├── ZigZagConversion.kt │ └── common │ │ ├── ClassInvoker.kt │ │ ├── LeetNode.kt │ │ └── LeetTreeNode.kt ├── sortingandsearch │ ├── GroupAnagrams.java │ ├── PeaksAndValley.java │ ├── RankFromStream.java │ ├── SortedMatrixSearch.java │ ├── SortedMerge.java │ ├── SortedSearchNoSize.java │ └── SparseSearch.java ├── threads │ └── FizzBuzz.java └── utils │ ├── Assertions.kt │ └── PrintUtils.java └── test ├── questions └── common │ └── ClassInvokerTest.kt └── utils └── AssertionsTest.kt /.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # These are explicitly windows files and should use crlf 5 | *.bat text eol=crlf 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .pytest_cache 3 | __pycache__ 4 | .idea 5 | .venv 6 | .vscode 7 | .pytest_cache 8 | */__pycache__ 9 | *.class 10 | *.iml 11 | python/venv 12 | target/**d 13 | python/*/venv/ 14 | target 15 | src/python/*/venv 16 | target/* 17 | 18 | 19 | python/*/venv/* 20 | python/moderate/venv/ 21 | /lib/ 22 | 23 | # Ignore Gradle project-specific cache directory 24 | .gradle 25 | 26 | # Ignore Gradle build output directory 27 | build 28 | *.txt 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Prashant Barahi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-dinky -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | java 3 | kotlin("jvm") version "1.5.31" 4 | } 5 | 6 | repositories { 7 | jcenter() 8 | } 9 | 10 | sourceSets { 11 | this.main { 12 | java { 13 | srcDir("src") 14 | } 15 | } 16 | this.test { 17 | java { 18 | srcDir("test") 19 | } 20 | } 21 | } 22 | 23 | buildscript { 24 | dependencies { 25 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31") 26 | } 27 | } 28 | 29 | dependencies { 30 | implementation("org.jetbrains.kotlin:kotlin-stdlib:1.5.31") 31 | implementation("org.jetbrains.kotlin:kotlin-test:1.5.31") 32 | implementation("org.jetbrains.kotlin:kotlin-reflect:1.5.31") 33 | testImplementation("org.junit.jupiter:junit-jupiter:5.8.1")!! 34 | .because("For writing tests for assertion methods") 35 | testImplementation("org.jetbrains.kotlin:kotlin-test-junit:1.5.31")!! 36 | .because("For writing tests for assertion methods") 37 | } 38 | 39 | tasks.getByName("test") { 40 | useJUnitPlatform() 41 | } 42 | 43 | tasks.create("execClass", type = JavaExec::class) { 44 | val javaExec = this 45 | javaExec.isIgnoreExitValue = true 46 | sourceSets.main { 47 | javaExec.classpath = runtimeClasspath 48 | } 49 | jvmArgs = listOf("-ea") 50 | main = project.properties["mainClass"].toString() 51 | 52 | doLast { 53 | if (executionResult.get().exitValue != 0) { 54 | println(">>> Execution failed") 55 | 56 | val logs = File("jvm-logs.txt") 57 | if (!logs.exists()) { 58 | logs.createNewFile() 59 | } 60 | logs.appendText("Execution failed ${project.properties["mainClass"].toString()}\n") 61 | executionResult.get().rethrowFailure() 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /generate_file_history.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | 4 | def git_generate_history(): 5 | path_to_modified_date_map = {} 6 | cmd = ''' 7 | git ls-tree -r --name-only HEAD | while read filename; do 8 | echo "$(git log --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M:%S' -- $filename | tail -1) $filename" 9 | done 10 | ''' 11 | p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 12 | for line in p.stdout.readlines(): 13 | modified_date, path = line.decode().rstrip().split(' ') 14 | path_to_modified_date_map[path] = modified_date 15 | return path_to_modified_date_map 16 | 17 | 18 | if __name__ == '__main__': 19 | print(git_generate_history()) 20 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realpacific/algorithms/22eef528ef1bea9b9831178b64ff2f5b1f61a51f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /python-run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | isPythonMainFile() { 4 | echo "$( 5 | grep -q "if __name__" "$1" 6 | echo $? 7 | )" 8 | } 9 | 10 | home="$(pwd)" 11 | logFile="$home/python-logs.txt" 12 | rm $logFile || true 13 | 14 | 15 | cd python 16 | 17 | for i in $(git ls-files | grep .py); do 18 | filename="$i" 19 | isRunnable=$(isPythonMainFile "$i") 20 | if [[ "$isRunnable" == "0" ]]; then 21 | echo ">>>>> Executing file $filename" 22 | python3 $filename || echo "Execution failed $filename" >> "$logFile" 23 | else 24 | echo ">>>>> Skipping $i" 25 | fi 26 | done 27 | -------------------------------------------------------------------------------- /python/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realpacific/algorithms/22eef528ef1bea9b9831178b64ff2f5b1f61a51f/python/__init__.py -------------------------------------------------------------------------------- /python/addTwoNumbers.py: -------------------------------------------------------------------------------- 1 | class ListNode: 2 | def __init__(self, x): 3 | self.val = x 4 | self.next = None 5 | 6 | def __str__(self): 7 | l = "" 8 | head = self 9 | while head is not None: 10 | l += str(head.val) 11 | head = head.next 12 | 13 | return l 14 | 15 | 16 | class Solution: 17 | def addTwoNumbers(self, l1, l2): 18 | p = l1 19 | q = l2 20 | dummy = ListNode(0) 21 | head = dummy 22 | carry = 0 23 | while p is not None or q is not None: 24 | sum = (0 if p is None else p.val) + (0 if q is None else q.val) + carry 25 | carry = int(sum / 10) 26 | head.next = ListNode(sum % 10) 27 | head = head.next 28 | print(head.val, carry) 29 | if p is not None: 30 | p = p.next 31 | if q is not None: 32 | q = q.next 33 | 34 | if carry > 0: 35 | head.next = ListNode(carry) 36 | return dummy.next 37 | 38 | 39 | def traverse(l1): 40 | res = "" 41 | head = l1 42 | 43 | condition = True 44 | while condition: 45 | res += str(head.val) 46 | head = head.next 47 | condition = head is not None 48 | return res 49 | 50 | 51 | if __name__ == "__main__": 52 | l1 = ListNode(1) 53 | l2 = ListNode(2) 54 | l3 = ListNode(3) 55 | 56 | l1.next = l2 57 | l2.next = l3 58 | 59 | l3 = ListNode(7) 60 | l4 = ListNode(7) 61 | # l5 = ListNode(8) 62 | 63 | l3.next = l4 64 | # l4.next = l5 65 | 66 | print(l1) 67 | print(l3) 68 | s = Solution() 69 | print('sum', s.addTwoNumbers(l1, l3)) 70 | -------------------------------------------------------------------------------- /python/codinginterview/delete_duplicates.py: -------------------------------------------------------------------------------- 1 | from shared.linked_list import LinkedList 2 | from shared.node import Node 3 | 4 | 5 | def delete_duplicates(linked_list: LinkedList): 6 | """ 7 | Delete duplicate node from a Linked List 8 | 9 | Parameters: 10 | linked_list: The list to be deleted from 11 | """ 12 | current = linked_list.node 13 | if current is None: 14 | return 15 | record = set() 16 | record.add(current.data) 17 | while current.next is not None: 18 | # Duplicate if data is present in [record] 19 | if current.next.data in record: 20 | current.next = current.next.next 21 | else: 22 | record.add(current.next.data) 23 | current = current.next 24 | 25 | 26 | if __name__ == "__main__": 27 | linked = LinkedList() 28 | linked.add(Node(1)) 29 | linked.add(Node(2)) 30 | linked.add(Node(2)) 31 | linked.add(Node(2)) 32 | linked.add(Node(3)) 33 | linked.add(Node(4)) 34 | linked.add(Node(5)) 35 | linked.add(Node(1)) 36 | linked.add(Node(6)) 37 | linked.add(Node(7)) 38 | delete_duplicates(linked) 39 | linked.print() 40 | assert len(linked) == 7 41 | # Linked list must contain 1 to 7 in order 42 | for [node, num] in zip(linked, range(1, 8)): 43 | assert node.data == num 44 | -------------------------------------------------------------------------------- /python/codinginterview/delete_middle.py: -------------------------------------------------------------------------------- 1 | from shared.linked_list import Node, LinkedList 2 | 3 | 4 | def delete_middle(linked_: LinkedList, k: int): 5 | """ 6 | Delete kth node from linked list 7 | 8 | Parameters: 9 | linked_ (LinkedList): a Linked List 10 | k (int): the kth position 11 | 12 | """ 13 | if k > len(linked_): 14 | return 15 | count = 0 16 | current = linked_.node 17 | while current.next is not None: 18 | if (k - 1) == count: 19 | prev = current 20 | prev.next = current.next.next 21 | current = current.next 22 | count += 1 23 | 24 | 25 | if __name__ == "__main__": 26 | linked = LinkedList() 27 | linked.add(Node(0)) 28 | linked.add(Node(1)) 29 | linked.add(Node(2)) 30 | linked.add(Node(3)) 31 | linked.add(Node(4)) 32 | linked.add(Node(5)) 33 | linked.add(Node(6)) 34 | linked.add(Node(7)) 35 | linked.add(Node(8)) 36 | linked.add(Node(9)) 37 | 38 | original_length = len(linked) 39 | delete_middle(linked, 4) 40 | 41 | assert original_length - 1 == len(linked) 42 | 43 | expected_data_ = [i for i in range(0, 10) if i != 4] 44 | for [node, num] in zip(linked, expected_data_): 45 | assert node.data == num 46 | -------------------------------------------------------------------------------- /python/codinginterview/is_linked_list_circular.py: -------------------------------------------------------------------------------- 1 | from shared.circular_linked_list import CircularLinkedList 2 | from shared.node import Node 3 | 4 | 5 | def is_linked_list_circular(linked_list_): 6 | """ 7 | Detect if a Linked List is circular 8 | """ 9 | 10 | current = linked_list_.node 11 | registry = set() 12 | while current is not None: 13 | # The linked list is circular if one of its element points to previous element 14 | if current in registry: 15 | return True 16 | registry.add(current) 17 | current = current.next 18 | return False 19 | 20 | 21 | if __name__ == "__main__": 22 | l1 = CircularLinkedList() 23 | l1.add(Node(1)) 24 | l1.add(Node(2)) 25 | l1.add(Node(3)) 26 | l1.add(Node(4), join=True) 27 | 28 | assert is_linked_list_circular(l1) 29 | 30 | l2 = CircularLinkedList() 31 | l2.add(Node(1)) 32 | l2.add(Node(2)) 33 | l2.add(Node(3)) 34 | l2.add(Node(4)) 35 | 36 | assert not is_linked_list_circular(l2) 37 | -------------------------------------------------------------------------------- /python/codinginterview/is_linked_list_palindrome.py: -------------------------------------------------------------------------------- 1 | from shared.linked_list import LinkedList 2 | from shared.node import Node 3 | from shared.reversed_linked_list import RLinkedList 4 | 5 | 6 | def is_linked_list_palindrome(linked_list: LinkedList): 7 | """ 8 | Check if a linked list is a palindrome 9 | """ 10 | 11 | if linked_list is None: 12 | return True 13 | current = linked_list.node 14 | r_linked_list = RLinkedList() 15 | while current is not None: 16 | r_linked_list.add(Node(current.data)) 17 | current = current.next 18 | 19 | for i, j in zip(r_linked_list, linked_list): 20 | if i.data != j.data: 21 | return False 22 | return True 23 | 24 | 25 | if __name__ == "__main__": 26 | l1 = LinkedList() 27 | l1.add(Node(1)) 28 | l1.add(Node(0)) 29 | l1.add(Node(5)) 30 | l1.add(Node(0)) 31 | l1.add(Node(1)) 32 | assert is_linked_list_palindrome(l1) 33 | 34 | l2 = LinkedList() 35 | l2.add(Node(1)) 36 | assert is_linked_list_palindrome(l2) 37 | 38 | l3 = LinkedList() 39 | l3.add(Node(1)) 40 | l3.add(Node(2)) 41 | l3.add(Node(3)) 42 | assert is_linked_list_palindrome(l3) == False 43 | -------------------------------------------------------------------------------- /python/codinginterview/kth_to_last.py: -------------------------------------------------------------------------------- 1 | from shared.linked_list import Node, LinkedList 2 | 3 | 4 | def kth_to_last(linked_list_: LinkedList, k): 5 | """ 6 | Get all nodes from kth position to the end 7 | """ 8 | result = None 9 | current = linked_list_.node 10 | count = 0 11 | while current.next is not None: 12 | if count == k: 13 | return current 14 | current = current.next 15 | count += 1 16 | 17 | 18 | if __name__ == "__main__": 19 | linked = LinkedList() 20 | first_node = Node(1) 21 | linked.add(first_node) 22 | linked.add(Node(2)) 23 | linked.add(Node(10)) 24 | linked.add(Node(12)) 25 | linked.add(Node(22)) 26 | linked.add(Node(0)) 27 | linked.add(Node(3)) 28 | linked.add(Node(4)) 29 | linked.add(Node(5)) 30 | linked.add(Node(1)) 31 | linked.add(Node(6)) 32 | linked.add(Node(7)) 33 | assert kth_to_last(linked, 22) is None 34 | assert kth_to_last(linked, 5).data == 0 35 | for [node, num] in zip(LinkedList.create(kth_to_last(linked, 9)), [1, 6, 7]): 36 | assert node.data == num 37 | for [node, expected_node] in zip(LinkedList.create(kth_to_last(linked, 0)), LinkedList.create(first_node)): 38 | assert node.data == expected_node.data 39 | -------------------------------------------------------------------------------- /python/codinginterview/matrix_rotation.py: -------------------------------------------------------------------------------- 1 | def rotate_matrix(matrix): 2 | """ 3 | https://www.geeksforgeeks.org/inplace-rotate-square-matrix-by-90-degrees/ 4 | """ 5 | n = len(matrix[0]) 6 | for x in range(0, int(n / 2)): 7 | for y in range(x, n - 1 - x): 8 | temp = matrix[x][y] 9 | matrix[x][y] = matrix[y][n - 1 - x] 10 | matrix[y][n - 1 - x] = matrix[n - 1 - x][n - 1 - y] 11 | matrix[n - 1 - x][n - 1 - y] = matrix[n - 1 - y][x] 12 | matrix[n - 1 - y][x] = temp 13 | return matrix 14 | 15 | 16 | if __name__ == "__main__": 17 | assert rotate_matrix([ 18 | [1, 2, 3, 4], 19 | [5, 6, 7, 8], 20 | [9, 10, 11, 12], 21 | [13, 14, 15, 16]] 22 | ) == [[4, 8, 12, 16], 23 | [3, 7, 11, 15], 24 | [2, 6, 10, 14], 25 | [1, 5, 9, 13]] 26 | 27 | assert rotate_matrix([ 28 | [1, 2, 3, 4, 5], 29 | [6, 7, 8, 9, 10], 30 | [11, 12, 13, 14, 15], 31 | [16, 17, 18, 19, 20], 32 | [21, 22, 23, 24, 25]] 33 | ) == [[5, 10, 15, 20, 25], 34 | [4, 9, 14, 19, 24], 35 | [3, 8, 13, 18, 23], 36 | [2, 7, 12, 17, 22], 37 | [1, 6, 11, 16, 21]] 38 | -------------------------------------------------------------------------------- /python/codinginterview/merge_sort.py: -------------------------------------------------------------------------------- 1 | def merge_sort(arr): 2 | if len(arr) > 1: 3 | mid = len(arr) // 2 4 | left = arr[:mid] 5 | right = arr[mid:] 6 | 7 | merge_sort(left) 8 | merge_sort(right) 9 | 10 | i = j = k = 0 11 | 12 | while i < len(left) and j < len(right): 13 | if left[i] < right[j]: 14 | arr[k] = left[i] 15 | i += 1 16 | else: 17 | arr[k] = right[j] 18 | j += 1 19 | k += 1 20 | 21 | while i < len(left): 22 | arr[k] = left[i] 23 | i += 1 24 | k += 1 25 | 26 | while j < len(right): 27 | arr[k] = right[j] 28 | j += 1 29 | k += 1 30 | 31 | 32 | if __name__ == "__main__": 33 | array = [9, 8, 3, 4, 6, 5] 34 | expectation = sorted(array) 35 | merge_sort(array) 36 | print(array) 37 | assert array == expectation 38 | -------------------------------------------------------------------------------- /python/codinginterview/one_or_zero_edits_away.py: -------------------------------------------------------------------------------- 1 | def one_or_zero_edits_away(original, given): 2 | """ 3 | 199. One Away: There are three types of edits that can be performed on strings: insert a character, 4 | remove a character, or replace a character. Given two strings, write a function to check if they are one edit(or 5 | zero edits) away. 6 | """ 7 | records_from_original = {} 8 | leftover_from_given = [] 9 | for i in original: 10 | records_from_original.setdefault(i, 0) 11 | records_from_original[i] = records_from_original[i] + 1 12 | for i in given: 13 | if records_from_original.get(i) is None: 14 | leftover_from_given.append(i) 15 | else: 16 | records_from_original[i] = records_from_original[i] - 1 17 | 18 | print(records_from_original, leftover_from_given) 19 | return 0 <= sum(list(records_from_original.values())) <= 1 \ 20 | and len(leftover_from_given) <= 1 \ 21 | and min(list(records_from_original.values())) >= 0 22 | 23 | 24 | if __name__ == "__main__": 25 | assert one_or_zero_edits_away('pale', 'ple') 26 | assert one_or_zero_edits_away('pales', 'pale') 27 | assert one_or_zero_edits_away('pale', 'bale') 28 | assert one_or_zero_edits_away('pbbb', 'bbpb') 29 | assert one_or_zero_edits_away('pale', 'bae') is False 30 | assert one_or_zero_edits_away('pbbb', 'bpbp') is False 31 | assert one_or_zero_edits_away('apple', 'aple') 32 | -------------------------------------------------------------------------------- /python/codinginterview/quick_sort.py: -------------------------------------------------------------------------------- 1 | def quick_sort(arr, low, high): 2 | if low == high: 3 | return 4 | max_ = partition(arr, low, high) 5 | quick_sort(arr, low, max_) 6 | quick_sort(arr, max_ + 1, high) 7 | 8 | 9 | def partition(arr, low, high): 10 | pivot = arr[low] 11 | i = low 12 | j = high 13 | while i <= j: 14 | while True: 15 | i += 1 16 | if i >= len(arr) or arr[i] > pivot: 17 | break 18 | 19 | while True: 20 | j -= 1 21 | if j < 0 or arr[j] <= pivot: 22 | break 23 | 24 | if i < j: 25 | arr[i], arr[j] = arr[j], arr[i] 26 | 27 | arr[low], arr[j] = arr[j], arr[low] 28 | return j 29 | 30 | 31 | def test_1(): 32 | array = [1000, 10, 16, 8, 12, 15, 6, 3, 9, 5, 1000000] 33 | expected = sorted(array) 34 | quick_sort(array, 0, len(array)) 35 | assert array == expected 36 | 37 | 38 | def test_2(): 39 | array = [1000, 5, 100, 8, 0, 1000000, 9] 40 | expected = sorted(array) 41 | quick_sort(array, 0, len(array)) 42 | assert array == expected 43 | 44 | 45 | def test_3(): 46 | array = [1000, 5, 100, 8, 0, 1, 4, 9] 47 | expected = sorted(array) 48 | quick_sort(array, 0, len(array)) 49 | assert array == expected 50 | 51 | 52 | def test_4(): 53 | array = [90, 5, 100] 54 | expected = sorted(array) 55 | quick_sort(array, 0, len(array)) 56 | assert array == expected 57 | 58 | 59 | def test_5(): 60 | array = [90, 100] 61 | expected = sorted(array) 62 | quick_sort(array, 0, len(array)) 63 | assert array == expected 64 | 65 | 66 | if __name__ == "__main__": 67 | test_1() 68 | test_2() 69 | test_3() 70 | test_4() 71 | test_5() 72 | -------------------------------------------------------------------------------- /python/codinginterview/shared/__init__.py: -------------------------------------------------------------------------------- 1 | from .node import Node 2 | -------------------------------------------------------------------------------- /python/codinginterview/shared/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realpacific/algorithms/22eef528ef1bea9b9831178b64ff2f5b1f61a51f/python/codinginterview/shared/__init__.pyc -------------------------------------------------------------------------------- /python/codinginterview/shared/base_linked_list.py: -------------------------------------------------------------------------------- 1 | from .node import Node 2 | 3 | 4 | class BaseLinkedList: 5 | 6 | def __init__(self): 7 | self.node = None 8 | # length will not consider explicit deletes 9 | self.length = 0 10 | 11 | def __iter__(self): 12 | current = self.node 13 | while current is not None: 14 | yield current 15 | current = current.next 16 | 17 | def __str__(self): 18 | return f"{self.node}" 19 | 20 | def __len__(self): 21 | length = 0 22 | runner: Node = self.node 23 | while runner is not None: 24 | length += 1 25 | runner = runner.next 26 | return length 27 | 28 | def print(self): 29 | current = self.node 30 | while current is not None: 31 | print(current.data) 32 | current = current.next 33 | -------------------------------------------------------------------------------- /python/codinginterview/shared/circular_linked_list.py: -------------------------------------------------------------------------------- 1 | from .node import Node 2 | from .base_linked_list import BaseLinkedList 3 | 4 | 5 | class CircularLinkedList(BaseLinkedList): 6 | def __init__(self): 7 | super(CircularLinkedList, self).__init__() 8 | self.is_circular_yet = False 9 | self.first_element = None 10 | 11 | def add(self, data, join=False): 12 | if self.is_circular_yet: 13 | raise Exception("Cannot add any more") 14 | if not isinstance(data, Node): 15 | raise TypeError() 16 | 17 | if self.node is None: 18 | self.node = data 19 | self.first_element = data 20 | else: 21 | current = self.node 22 | while current.next is not None: 23 | current = current.next 24 | current.next = data 25 | if join: 26 | self.is_circular_yet = True 27 | current.next.next = self.first_element 28 | self.length += 1 29 | -------------------------------------------------------------------------------- /python/codinginterview/shared/linked_list.py: -------------------------------------------------------------------------------- 1 | from .base_linked_list import BaseLinkedList 2 | from .node import Node 3 | 4 | 5 | class LinkedList(BaseLinkedList): 6 | def __init__(self): 7 | super(LinkedList, self).__init__() 8 | 9 | def add(self, data: Node): 10 | if not isinstance(data, Node): 11 | raise TypeError() 12 | 13 | if self.node is None: 14 | self.node: Node = data 15 | else: 16 | current = self.node 17 | while current.next is not None: 18 | current = current.next 19 | current.next = data 20 | self.length += 1 21 | 22 | @classmethod 23 | def create(cls, node: Node) -> 'LinkedList': 24 | linked_list = LinkedList() 25 | if node is None: 26 | return linked_list 27 | current = node 28 | while current is not None: 29 | linked_list.add(Node(current.data)) 30 | current = current.next 31 | return linked_list 32 | -------------------------------------------------------------------------------- /python/codinginterview/shared/node.py: -------------------------------------------------------------------------------- 1 | class Node: 2 | def __init__(self, data): 3 | self.data = data 4 | self.next = None 5 | 6 | def __str__(self): 7 | return f"Node({self.data}, {self.next})" 8 | 9 | def __repr__(self): 10 | return str(self) 11 | -------------------------------------------------------------------------------- /python/codinginterview/shared/reversed_linked_list.py: -------------------------------------------------------------------------------- 1 | from .base_linked_list import BaseLinkedList 2 | from .node import Node 3 | 4 | 5 | class RLinkedList(BaseLinkedList): 6 | def __init__(self): 7 | super().__init__() 8 | 9 | def add(self, data): 10 | if not isinstance(data, Node): 11 | raise TypeError() 12 | 13 | if self.node is None: 14 | self.node = data 15 | else: 16 | data.next = self.node 17 | self.node = data 18 | self.length += 1 19 | -------------------------------------------------------------------------------- /python/codinginterview/string_compression.py: -------------------------------------------------------------------------------- 1 | def string_compression(string): 2 | """String Compression: Implement a method to perform basic string compression using the counts of repeated 3 | characters. For example, the string aabcccccaaa would become a2blc5a3. If the "compressed" string would not 4 | become smaller than the original string, your method should return the original string.You can assume the string 5 | has only uppercase and lowercase letters (a - z). """ 6 | if string is None or len(string) <= 1: 7 | return string 8 | compressed_string = '' 9 | current = None 10 | count = 0 11 | for i in string: 12 | if i == current or current is None: 13 | count += 1 14 | else: 15 | compressed_string = compressed_string + current + (str(count) if count > 1 else '') 16 | count = 1 17 | current = i 18 | compressed_string = compressed_string + current + str(count) 19 | print(compressed_string, len(compressed_string), string, len(string)) 20 | 21 | if len(compressed_string) >= len(string): 22 | return string 23 | return compressed_string 24 | 25 | 26 | if __name__ == "__main__": 27 | assert string_compression('aaaabbbbcccccaaa') == 'a4b4c5a3' 28 | assert string_compression('abcdef') == 'abcdef' 29 | assert string_compression('abababaeeee') == 'abababae4' 30 | assert string_compression('aaaaaa') == 'a6' 31 | assert string_compression('baba') == 'baba' 32 | assert string_compression('a') == 'a' 33 | assert string_compression('') == '' 34 | assert string_compression('aaaaaaaaaaaaaaaaabaaaaaaaaaa') == 'a17ba10' 35 | -------------------------------------------------------------------------------- /python/codinginterview/string_rotation.py: -------------------------------------------------------------------------------- 1 | def string_rotation(original, test): 2 | """ 3 | Check if one string is formed by rotating the other string eg: abcd, dabc, cdab, bcda 4 | """ 5 | if len(original) != len(test): 6 | return False 7 | return _is_substring(test + test, original) 8 | 9 | 10 | def _is_substring(s1, s2): 11 | return s2 in s1 12 | 13 | 14 | if __name__ == "__main__": 15 | assert string_rotation('waterbottle', 'bottlewater') 16 | assert string_rotation('waterbottle', 'aterbottlew') 17 | assert string_rotation('abcd', 'dabc') 18 | assert string_rotation('abcd', 'dabc') 19 | assert string_rotation('abcd', 'cdab') 20 | assert string_rotation('abcd', 'bcda') 21 | assert string_rotation('abcd', 'efgh') is False 22 | assert string_rotation('xxxx', 'yyyy') is False 23 | -------------------------------------------------------------------------------- /python/codinginterview/sum_of_nodes_of_linked_list.py: -------------------------------------------------------------------------------- 1 | from shared.linked_list import LinkedList 2 | from shared.node import Node 3 | 4 | 5 | def sum_of_nodes_of_linked_list(l1_: Node, l2_: Node, carry: int = 0): 6 | """ 7 | Sum value of nodes 8 | 7 -> 1 -> 6 + 5 -> 9 -> 2 = 617+295 = 2 -> 1 -> 9 9 | """ 10 | if l1_ is None and l2_ is None and carry == 0: 11 | return 12 | 13 | value = carry 14 | if l1_ is not None: 15 | value += l1_.data 16 | if l2_ is not None: 17 | value += l2_.data 18 | 19 | # Store the Digit at one 20 | node = Node(value % 10) 21 | 22 | if l1_ is not None or l2_ is not None: 23 | more = sum_of_nodes_of_linked_list(l1_.next if l1_ is not None else None, 24 | l2_.next if l2_ is not None else None, 25 | 1 if value >= 10 else 0) 26 | if more is not None: 27 | node.next = more if more is not None else None 28 | 29 | return node 30 | 31 | 32 | def __collect_node_value(node: Node): 33 | linked_list = LinkedList.create(node) 34 | value = "" 35 | for i in linked_list: 36 | value += str(i.data) 37 | return int(value) 38 | 39 | 40 | if __name__ == "__main__": 41 | l1 = LinkedList() 42 | l1.add(Node(7)) 43 | l1.add(Node(1)) 44 | l1.add(Node(6)) 45 | 46 | l2 = LinkedList() 47 | l2.add(Node(5)) 48 | l2.add(Node(9)) 49 | l2.add(Node(2)) 50 | 51 | assert __collect_node_value(sum_of_nodes_of_linked_list(l1.node, l2.node)) == 219 52 | -------------------------------------------------------------------------------- /python/codinginterview/zero_matrix.py: -------------------------------------------------------------------------------- 1 | def zero_matrix(matrix): 2 | """ 3 | Make INPLACE row and column of a matrix 0 iff that row contains a 0 4 | """ 5 | position_of_zeros = [] 6 | row = len(matrix) 7 | col = len(matrix[0]) 8 | for i in range(0, row): 9 | for j in range(0, col): 10 | if matrix[i][j] == 0: 11 | position_of_zeros.append((i, j)) 12 | 13 | for (i, j) in position_of_zeros: 14 | for k in range(0, col): 15 | matrix[i][k] = 0 16 | for k in range(0, row): 17 | matrix[k][j] = 0 18 | 19 | return matrix 20 | 21 | 22 | if __name__ == "__main__": 23 | matrix_1 = zero_matrix([[0, 2, 3, 4], [5, 6, 7, 8], [9, 10, 0, 12], [13, 14, 15, 16]]) 24 | assert matrix_1 == [[0, 0, 0, 0], [0, 6, 0, 8], [0, 0, 0, 0], [0, 14, 0, 16]] 25 | 26 | matrix_2 = zero_matrix([[0, 2, 3, 4], [5, 6, 7, 8], [9, 10, 0, 12], [13, 14, 15, 16], [1, 2, 3, 0]]) 27 | assert matrix_2 == [[0, 0, 0, 0], [0, 6, 0, 0], [0, 0, 0, 0], [0, 14, 0, 0], [0, 0, 0, 0]] 28 | -------------------------------------------------------------------------------- /python/hard/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realpacific/algorithms/22eef528ef1bea9b9831178b64ff2f5b1f61a51f/python/hard/__init__.py -------------------------------------------------------------------------------- /python/hard/count_of_2s.py: -------------------------------------------------------------------------------- 1 | def count_of_2_at_digit(number: int, digit: int) -> int: 2 | power_of_10 = 10 ** digit 3 | next_power_of_10 = power_of_10 * 10 4 | 5 | round_down = number - (number % next_power_of_10) 6 | round_up = round_down + next_power_of_10 7 | 8 | digit = (int(number / power_of_10)) % 10 9 | 10 | if digit > 2: 11 | return int(round_up / 10) 12 | elif digit < 2: 13 | return int(round_down / 10) 14 | else: 15 | right_part = number % power_of_10 16 | return int(round_down / 10) + right_part + 1 17 | 18 | 19 | def find_digit_count(num: int) -> int: 20 | _number = num 21 | count = 0 22 | while int(_number / 10) > 0: 23 | count += 1 24 | _number = _number / 10 25 | return count + 1 26 | 27 | 28 | def count_of_2s(number: int) -> int: 29 | """ 30 | Find the number of 2s in between 0 and n 31 | :param number: the max value (inclusive) 32 | :return: Number of 2s 33 | """ 34 | digit_length = find_digit_count(number) 35 | result = 0 36 | for i in range(0, digit_length): 37 | result += count_of_2_at_digit(number, digit=i) 38 | print(f"# of 2s in {number} = ", result) 39 | return result 40 | 41 | 42 | if __name__ == "__main__": 43 | assert count_of_2s(120) == 23 44 | # In between 20..29 there are 11 2s as 22 exits 45 | assert count_of_2s(30) == 13 46 | assert count_of_2s(50) == 15 47 | -------------------------------------------------------------------------------- /python/longest_palindrome.py: -------------------------------------------------------------------------------- 1 | def longest_palindrome(s): 2 | longest_one = "" 3 | window = 1 4 | 5 | if is_palindrome(s): 6 | return s 7 | 8 | while window < len(s): 9 | for i in range(len(s)): 10 | current = s[i: i + window] 11 | if is_palindrome(current): 12 | if len(current) > len(longest_one): 13 | longest_one = current 14 | window = window + 1 15 | 16 | print(longest_one) 17 | return longest_one 18 | 19 | 20 | def is_palindrome(s): 21 | return s == s[::-1] 22 | 23 | 24 | if __name__ == "__main__": 25 | # assert (longest_palindrome("lababa") == "aba") 26 | longest_palindrome("lababa") 27 | print("---------------") 28 | longest_palindrome("labaaba") 29 | longest_palindrome("zznitinzx") 30 | longest_palindrome("xxxabazzlevexxxxx") 31 | longest_palindrome("a") 32 | longest_palindrome("ac") 33 | -------------------------------------------------------------------------------- /python/longestsubstr.py: -------------------------------------------------------------------------------- 1 | def lengthOfLongestSubstring(s): 2 | """ 3 | :type s: str 4 | :rtype: int 5 | """ 6 | substring = "" 7 | previous = "" 8 | length = 0 9 | for char in s: 10 | if char not in substring: 11 | print(char, 'not in ', substring) 12 | substring += char 13 | length = len(substring) if length < len(substring) else length 14 | else: 15 | previous = substring 16 | length = len(substring) if length < len(substring) else length 17 | substring = "" 18 | try: 19 | substring = previous[previous.rindex(char) + 1:] 20 | substring += char 21 | print(substring, "try") 22 | except: 23 | substring += char 24 | print(substring, "catch") 25 | 26 | print(length, previous, substring) 27 | 28 | return length 29 | 30 | 31 | if __name__ == "__main__": 32 | assert (lengthOfLongestSubstring("pwwkew") == 3) 33 | assert (lengthOfLongestSubstring("abcabcbb") == 3) 34 | assert (lengthOfLongestSubstring("bbbbb") == 1) 35 | assert (lengthOfLongestSubstring("aab") == 2) 36 | assert (lengthOfLongestSubstring("dvdf") == 3) 37 | assert (lengthOfLongestSubstring("anviaj") == 5) 38 | -------------------------------------------------------------------------------- /python/moderate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realpacific/algorithms/22eef528ef1bea9b9831178b64ff2f5b1f61a51f/python/moderate/__init__.py -------------------------------------------------------------------------------- /python/moderate/continuous_sequence.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | 4 | def continuous_sequence(array: List[int]): 5 | max_sum = 0 6 | current_sum = 0 7 | for i in array: 8 | current_sum += i 9 | if max_sum < current_sum: 10 | max_sum = current_sum 11 | elif current_sum < 0: 12 | current_sum = 0 13 | print(max_sum) 14 | return max_sum 15 | 16 | 17 | if __name__ == '__main__': 18 | continuous_sequence([2, -8, 3, -2, 4, -10]) 19 | continuous_sequence([2, 3, -8, -1, 2, 4, -2, 3]) 20 | -------------------------------------------------------------------------------- /python/moderate/count_pairs_with_difference.py: -------------------------------------------------------------------------------- 1 | import timeit 2 | 3 | 4 | def count_pairs_with_difference(k, a): 5 | a_sort = sorted(a) 6 | count = 0 7 | x = timeit.timeit() 8 | length = len(a_sort) 9 | for i in range(0, length): 10 | required = i + k 11 | try: 12 | first_index = a.index(required) 13 | count += 1 14 | for item in range(first_index + 1, length): 15 | if item == required: 16 | count += 1 17 | else: 18 | continue 19 | except ValueError: 20 | continue 21 | 22 | print(count, x - timeit.timeit()) 23 | return count 24 | 25 | 26 | if __name__ == '__main__': 27 | count_pairs_with_difference(3, [1, 6, 8, 2, 4, 9, 12]) 28 | -------------------------------------------------------------------------------- /python/moderate/diving_board.py: -------------------------------------------------------------------------------- 1 | SHORTER_LENGTH = 10 2 | LONG_LENGTH = 18 3 | 4 | 5 | def diving_board(k: int, result: set, memo: set, total_length: int = 0, ): 6 | if k == 0: 7 | result.add(total_length) 8 | return result 9 | 10 | # this path has already been visited 11 | key = str(k) + "_" + str(total_length) 12 | if key in memo: 13 | return 14 | else: 15 | memo.add(key) 16 | 17 | diving_board(k - 1, total_length=SHORTER_LENGTH + total_length, result=result, memo=memo) 18 | diving_board(k - 1, total_length=LONG_LENGTH + total_length, result=result, memo=memo) 19 | 20 | 21 | def optimal(k: int) -> set: 22 | """ 23 | Arranging k planks end-to-end means that arranging (k short, 0 long), (k-1 short, 1 long), (k-2 short, 2 long)... 24 | :param k: the number of planks 25 | :return: the all possible length of arrangements 26 | """ 27 | result = set() 28 | for i in range(0, k + 1): 29 | length = SHORTER_LENGTH * i + LONG_LENGTH * (k - i) 30 | result.add(length) 31 | return result 32 | 33 | 34 | if __name__ == '__main__': 35 | res = set() 36 | visited_records = set() 37 | diving_board(k=100, result=res, memo=visited_records) 38 | 39 | print('-----') 40 | optimal_res = optimal(k=100) 41 | 42 | print(res - optimal_res) 43 | print(res) 44 | assert len(res) == len(optimal_res) 45 | -------------------------------------------------------------------------------- /python/moderate/factorial_zeros.py: -------------------------------------------------------------------------------- 1 | def convert_to_closest_value_divisible_by_5(num): 2 | """ 3 | :param num: input 4 | :return: either ?5 or ?0 for two-digit number 5 | """ 6 | last_digit = int(num % 10) 7 | 8 | base = num - last_digit 9 | 10 | if last_digit >= 5: 11 | base += 5 12 | return base 13 | 14 | 15 | def find_factorial_zeros(num): 16 | count = 0 17 | base = convert_to_closest_value_divisible_by_5(num) 18 | if num == 0: 19 | return 1 20 | while base > 0: 21 | current = base 22 | # while it is divisible by 5, increase count by 1 23 | while current % 5 == 0 and current > 0: 24 | count += 1 25 | current /= 5 26 | base -= 5 27 | 28 | return count 29 | 30 | 31 | if __name__ == '__main__': 32 | assert convert_to_closest_value_divisible_by_5(18) == 15 33 | assert convert_to_closest_value_divisible_by_5(20) == 20 34 | assert convert_to_closest_value_divisible_by_5(13) == 10 35 | assert convert_to_closest_value_divisible_by_5(10) == 10 36 | 37 | assert find_factorial_zeros(20) == 4 38 | assert find_factorial_zeros(19) == 3 39 | assert find_factorial_zeros(10) == 2 40 | assert find_factorial_zeros(5) == 1 41 | assert find_factorial_zeros(0) == 1 42 | assert find_factorial_zeros(1) == 0 43 | -------------------------------------------------------------------------------- /python/moderate/living_people.py: -------------------------------------------------------------------------------- 1 | from random import Random 2 | 3 | 4 | class Person: 5 | def __init__(self, date_of_birth, date_of_death): 6 | self.birth = date_of_birth 7 | self.death = date_of_death 8 | 9 | def __str__(self): 10 | return f"Person({birth}, {death})" 11 | 12 | 13 | if __name__ == '__main__': 14 | people = [] 15 | rand = Random() 16 | for i in range(0, 10): 17 | birth = rand.randint(1900, 2000) 18 | death = 2000 if birth == 2000 else rand.randint(birth, 2000) 19 | person = Person(birth, death) 20 | people.append(person) 21 | print(person) 22 | 23 | birth_years = sorted(list(map(lambda x: x.birth, people))) 24 | death_years = sorted(list(map(lambda x: x.death, people))) 25 | print(birth_years) 26 | print(death_years) 27 | death_count = 0 28 | birth_count = 0 29 | 30 | max_alive = (1900, 0) 31 | 32 | number_of_alive = 0 33 | birth_year_index = 0 34 | death_years_index = 0 35 | 36 | while birth_year_index < len(people): 37 | if birth_years[birth_year_index] < death_years[death_years_index]: 38 | number_of_alive += 1 39 | if number_of_alive > max_alive[1]: 40 | max_alive = (birth_years[birth_year_index], number_of_alive) 41 | birth_year_index += 1 42 | else: 43 | number_of_alive -= 1 44 | death_years_index += 1 45 | 46 | print(max_alive) 47 | -------------------------------------------------------------------------------- /python/moderate/master_mind.py: -------------------------------------------------------------------------------- 1 | def code(char: str): 2 | if char == 'B': 3 | return 0 4 | if char == 'Y': 5 | return 1 6 | if char == 'R': 7 | return 2 8 | if char == 'G': 9 | return 3 10 | else: 11 | return -0 12 | 13 | 14 | def calculate(guess: str, solution: str): 15 | hits = 0 16 | psuedo_hits = 0 17 | 18 | indices = [] 19 | for i in range(0, len(solution)): 20 | if guess[i] == solution[i]: 21 | indices.append(i) 22 | hits += 1 23 | 24 | for i in range(0, len(solution)): 25 | if guess[i] in solution and i not in indices: 26 | psuedo_hits += 1 27 | indices.append(i) 28 | 29 | return hits, psuedo_hits 30 | 31 | 32 | if __name__ == '__main__': 33 | assert calculate(guess='RGYB', solution='BGRR') == (1, 2) 34 | assert calculate(guess='GRBG', solution='GRBG') == (4, 0) 35 | assert calculate(guess='RRRR', solution='BBBB') == (0, 0) 36 | assert calculate(guess='RGBY', solution='RGBY') == (4, 0) 37 | assert calculate(guess='BGRY', solution='GBYR') == (0, 4) 38 | assert calculate(guess='BRGY', solution='BRYY') == (3, 0) 39 | -------------------------------------------------------------------------------- /python/moderate/pairs_with_sum.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | 4 | def pairs_with_sum(array: List, required_sum: int): 5 | result = [] 6 | array.sort() 7 | 8 | first = 0 9 | last = len(array) - 1 10 | 11 | while first < last: 12 | s = array[first] + array[last] 13 | if s == required_sum: 14 | result.append((array[first], array[last])) 15 | first += 1 16 | last -= 1 17 | elif s > required_sum: 18 | last -= 1 19 | elif s < required_sum: 20 | first += 1 21 | print(result) 22 | return result 23 | 24 | 25 | if __name__ == '__main__': 26 | pairs_with_sum([-2, -1, 0, 3, 5, 6, 7, 9, 13, 14], required_sum=11) 27 | -------------------------------------------------------------------------------- /python/moderate/smallest_difference.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | 4 | def smallest_diff(a, b): 5 | a.sort() 6 | b.sort() 7 | result = sys.maxsize 8 | 9 | a_index = 0 10 | b_index = 0 11 | while a_index < len(a) and b_index < len(b): 12 | if abs(a[a_index] - b[b_index]) < result: 13 | result = abs(a[a_index] - b[b_index]) 14 | if a[a_index] < b[b_index]: 15 | a_index += 1 16 | else: 17 | b_index += 1 18 | return result 19 | 20 | 21 | if __name__ == '__main__': 22 | assert smallest_diff([1, 3, 2, 11, 15], [23, 127, 235, 19, 8]) == 3 23 | -------------------------------------------------------------------------------- /python/moderate/sub_sort.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | 4 | def sub_sort(array: List[int]): 5 | # Get the subsection where the elements are not sorted 6 | left_ordered_till = 0 7 | right_ordered_till = 0 8 | for i in range(1, len(array)): 9 | if array[i - 1] > array[i]: 10 | right_ordered_till = i - 1 11 | break 12 | for i in range(len(array) - 2, -1, -1): 13 | if array[i + 1] < array[i]: 14 | left_ordered_till = i + 1 15 | break 16 | # The elements are not sorted between left_ordered_till and right_ordered_till 17 | print(right_ordered_till, left_ordered_till) 18 | 19 | # The unsorted section 20 | unsorted_section = array[right_ordered_till:left_ordered_till + 1] 21 | smallest = min(unsorted_section) 22 | largest = max(unsorted_section) 23 | print(smallest, largest, unsorted_section) 24 | 25 | # Find where the smallest and largest element from the unsorted section lies in 26 | m = 0 27 | n = 0 28 | for i in range(1, len(array)): 29 | if array[i] > smallest: 30 | m = i 31 | break 32 | for i in range(len(array) - 1, -1, -1): 33 | if array[i] < largest: 34 | n = i 35 | break 36 | print(m, n) 37 | 38 | 39 | if __name__ == '__main__': 40 | arr = [1, 2, 4, 7, 10, 11, 7, 12, 6, 7, 16, 18, 19] 41 | sub_sort(arr) 42 | print(arr) 43 | -------------------------------------------------------------------------------- /python/moderate/swap_sum.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, List, Optional 2 | 3 | 4 | def swap_sum(arr_a: List[int], arr_b: List[int]) -> Optional[Tuple]: 5 | sum_a = sum(arr_a) 6 | sum_b = sum(arr_b) 7 | 8 | # sum_a - a + b = sum_b - b + a 9 | # a - b = (sum_a - sum_b) / 2 10 | diff = sum_a - sum_b 11 | if diff % 2 != 0: 12 | return None 13 | target = int(diff / 2) 14 | 15 | for i in arr_a: 16 | for j in arr_b: 17 | if i - j == target: 18 | return i, j 19 | return None 20 | 21 | 22 | def __check_swap(swap: Tuple, arr_a: List[int], arr_b: List[int]): 23 | assert sum(arr_a) - swap[0] + swap[1] == sum(arr_b) - swap[1] + swap[0] 24 | 25 | 26 | if __name__ == '__main__': 27 | a = [4, 1, 2, 1, 1, 2] 28 | b = [3, 6, 3, 3] 29 | __check_swap(swap_sum(a, b), a, b) 30 | -------------------------------------------------------------------------------- /python/multiply.py: -------------------------------------------------------------------------------- 1 | def multiply(num1: str, num2: str): 2 | total_sum = 0 3 | lenght1 = len(num1) 4 | lenght2 = len(num2) 5 | 6 | for i in range(lenght2 - 1, -1, -1): 7 | session_res = 0 8 | session_sum = 0 9 | carry = 0 10 | for j in range(lenght1 - 1, -1, -1): 11 | mul = (int(num1[j]) * int(num2[i])) + carry 12 | # Do not calculate carry when j == 0 eg 36*4 13 | if j > 0: 14 | rem = mul % 10 15 | carry = int(mul / 10) 16 | else: 17 | rem = mul 18 | carry = 0 19 | # Multiply remainder based on its position i.e ones, tens, hundred ... 20 | session_sum += rem * (10 ** ((lenght1 - 1) - j)) 21 | 22 | # Append 0's to last of the result of multiplication 23 | session_res = session_sum * (10 ** (lenght2 - 1 - i)) 24 | print(session_res) 25 | # Use the remainder carry 26 | if carry != 0: 27 | session_res = (carry * 10 ** (len(str(session_res)))) + session_res 28 | print(session_res, carry) 29 | total_sum += session_res 30 | # 31 | # print(num1, "*", num2, "=", total_sum) 32 | # print("---------------------------") 33 | return total_sum 34 | 35 | 36 | def test(num1, num2): 37 | assert multiply(num1, num2) == int(num1) * int(num2) 38 | 39 | 40 | if __name__ == "__main__": 41 | test("12", "34") 42 | test("123", "434") 43 | test("120", "340") 44 | test("1234", "67890") 45 | test("56789", "0") 46 | test("1", "2333333") 47 | test("0", "0") 48 | test("0123", "123123") 49 | multiply("34567890", "987653") 50 | multiply("36", "3") 51 | -------------------------------------------------------------------------------- /python/needle.py: -------------------------------------------------------------------------------- 1 | # def strStr(haystack: str, needle: str) -> int: 2 | # ned_len = len(needle) 3 | # if ned_len == 0 or needle == haystack: 4 | # return 0 5 | # if ned_len > len(haystack): 6 | # return -1 7 | # for i in range(0, len(haystack)): 8 | # if haystack[i: i + ned_len] == needle: 9 | # return i 10 | # return -1 11 | 12 | 13 | def strStr(haystack: str, needle: str) -> int: 14 | ned_len = len(needle) 15 | if ned_len == 0 or needle == haystack: 16 | return 0 17 | if ned_len > len(haystack): 18 | return -1 19 | i = 0 20 | while i < len(haystack): 21 | window = haystack[i: i + ned_len] 22 | if window == needle: 23 | return i 24 | elif window.find(needle[0]) > 0: 25 | i = i + window.find(needle[0]) 26 | else: 27 | i += 1 28 | 29 | # for i in range(0, len(haystack)): 30 | # if haystack[i: i + ned_len] == needle: 31 | # return i 32 | return -1 33 | 34 | 35 | if __name__ == "__main__": 36 | print(strStr("hellove", 'lov')) 37 | print(strStr("hellove", 'e')) 38 | print(strStr("hellove", 'ov')) 39 | print(strStr("hello", 'zzzzzzzll')) 40 | print(strStr("hello", 'hello')) 41 | print(strStr(haystack="aaaaa", needle="bba")) 42 | -------------------------------------------------------------------------------- /python/paritysort.py: -------------------------------------------------------------------------------- 1 | def sortArrayByParity(A): 2 | result = [] 3 | even_counts = 0 4 | for i in A: 5 | result.append(i) 6 | if i % 2 == 0: 7 | print(even_counts) 8 | if len(result) > 1: 9 | result[even_counts], result[-1] = result[-1], result[even_counts] 10 | even_counts += 1 11 | return result 12 | 13 | 14 | def sortArrayByParity2(A): 15 | index_of_oldest_odd = 0 16 | for i in range(0, len(A)): 17 | if A[i] % 2 == 0: 18 | A[index_of_oldest_odd], A[i] = A[i], A[index_of_oldest_odd] 19 | index_of_oldest_odd += 1 20 | 21 | return A 22 | 23 | 24 | if __name__ == "__main__": 25 | print(sortArrayByParity2([4, 2, 3, 1])) 26 | 27 | print(sortArrayByParity2([4])) 28 | print(sortArrayByParity2([3])) 29 | print(sortArrayByParity2([4, 2])) 30 | print(sortArrayByParity2([3, 4])) 31 | print(sortArrayByParity2([4, 4])) 32 | print(sortArrayByParity2([3, 1, 2, 4, 5])) 33 | print(sortArrayByParity2([3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 1, 2, 4, 5, 5, 5, 0])) 34 | -------------------------------------------------------------------------------- /python/python-run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | isPythonMainFile() { 4 | echo "$( 5 | grep -q "if __name__" "$1" 6 | echo $? 7 | )" 8 | } 9 | 10 | logFile="python-logs.txt" 11 | rm $logFile || true 12 | 13 | for i in $(git ls-files | grep .py); do 14 | filename="$i" 15 | isRunnable=$(isPythonMainFile "$i") 16 | if [[ "$isRunnable" == "0" ]]; then 17 | echo ">>>>> Executing file $filename" 18 | python3 $filename || echo "Execution failed $filename" >> "$logFile" 19 | else 20 | echo ">>>>> Skipping $i" 21 | fi 22 | done 23 | -------------------------------------------------------------------------------- /python/remove_element.py: -------------------------------------------------------------------------------- 1 | # https://leetcode.com/problems/remove-element/ 2 | from timeit import default_timer as timer 3 | 4 | 5 | def remove_element(nums, val): 6 | start = timer() 7 | i = 0 8 | while True: 9 | if i >= len(nums): 10 | break 11 | if nums[i] == val: 12 | del nums[i] 13 | i -= 1 14 | if i < 0: 15 | i = 0 16 | else: 17 | i += 1 18 | print(nums, timer() - start) 19 | 20 | 21 | if __name__ == "__main__": 22 | remove_element([3, 2, 2, 3], 3) 23 | remove_element([0, 1, 2, 2, 3, 0, 4, 2], 2) 24 | remove_element([3, 2, 2, 3, 2, 3, 3, 3, 3, 33, 3, 3, 3, 3, 3, 32, 2, 2, 2, 1, 1, 1], 3) 25 | -------------------------------------------------------------------------------- /python/reverseint.py: -------------------------------------------------------------------------------- 1 | def reverse_int(x): 2 | if x < 0: 3 | x = x * -1 4 | isNeg = True 5 | else: 6 | isNeg = False 7 | string = str(x) 8 | result = int(string[::-1]) if not isNeg else (-1 * int(string[::-1])) 9 | return result if (-2 ** 31 <= result <= 2 ** 31 - 1) else 0 10 | 11 | 12 | if __name__ == "__main__": 13 | print(reverse_int(110)) 14 | print(reverse_int(900)) 15 | print(reverse_int(789090)) 16 | print(reverse_int(-100)) 17 | print(reverse_int(-1)) 18 | print(reverse_int(-123)) 19 | assert (reverse_int(1534236469) == 0) 20 | -------------------------------------------------------------------------------- /python/stacksqueues/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realpacific/algorithms/22eef528ef1bea9b9831178b64ff2f5b1f61a51f/python/stacksqueues/__init__.py -------------------------------------------------------------------------------- /python/stacksqueues/queueviastacks.py: -------------------------------------------------------------------------------- 1 | from .stack import Stack 2 | 3 | 4 | class QueueViaStack: 5 | def __init__(self): 6 | self._backup_stack = Stack() 7 | self.stack = Stack() 8 | 9 | def first_element(self): 10 | if self.stack.isempty(): 11 | return None 12 | return self.stack.data[0] 13 | 14 | def __len__(self): 15 | return len(self.stack) 16 | 17 | def enqueue(self, value): 18 | self.stack.push(value) 19 | 20 | def dequeue(self): 21 | if self.stack.isempty(): 22 | return None 23 | # Backup every element except the last element in the stack 24 | while len(self.stack) != 1: 25 | self._backup_stack.push(self.stack.pop()) 26 | # Pop the last element out to return it 27 | popped_value = self.stack.pop() 28 | # Re-fill the popped elements back 29 | while not self._backup_stack.isempty(): 30 | self.stack.push(self._backup_stack.pop()) 31 | return popped_value 32 | 33 | def __str__(self): 34 | return f"QueueViaStack({self.stack})" 35 | 36 | def __repr__(self): 37 | return str(self) 38 | 39 | 40 | queue = QueueViaStack() 41 | assert queue.dequeue() is None 42 | queue.enqueue(1) 43 | queue.enqueue(2) 44 | queue.enqueue(3) 45 | assert queue.stack.data[-1] == 3 46 | assert queue.stack.data[0] == 1 47 | queue.enqueue(4) 48 | assert queue.stack.data[-1] == 4 49 | queue.enqueue(5) 50 | assert queue.stack.data[-1] == 5 51 | queue.dequeue() 52 | assert queue.stack.data[0] == 2 53 | queue.dequeue() 54 | queue.dequeue() 55 | assert queue.stack.data[0] == 4 56 | -------------------------------------------------------------------------------- /python/stacksqueues/sort_stack.py: -------------------------------------------------------------------------------- 1 | from .stack import Stack 2 | 3 | 4 | class SortedStack: 5 | def __init__(self): 6 | self.stack = Stack() 7 | self._temp = Stack() 8 | 9 | def push(self, value): 10 | # Pop out all the smaller values and store it into temp stack 11 | while not self.stack.isempty() and self.stack.peek() > value: 12 | top_value = self.stack.pop() 13 | self._temp.push(top_value) 14 | # Push the current value 15 | self.stack.push(value) 16 | # Move all the values from temp stack to current stack 17 | while not self._temp.isempty(): 18 | self.stack.push(self._temp.pop()) 19 | 20 | 21 | sorted_stack = SortedStack() 22 | sorted_stack.push(1) 23 | assert sorted_stack.stack.peek() == 1 24 | sorted_stack.push(2) 25 | assert sorted_stack.stack.peek() == 2 26 | sorted_stack.push(10) 27 | assert sorted_stack.stack.peek() == 10 28 | sorted_stack.push(5) 29 | assert sorted_stack.stack.peek() != 5 30 | assert sorted_stack.stack.data[-2] == 5 31 | sorted_stack.push(0) 32 | assert sorted_stack.stack.data[0] == 0 33 | sorted_stack.push(3) 34 | assert sorted_stack.stack.data[3] == 3 35 | -------------------------------------------------------------------------------- /python/stacksqueues/stack.py: -------------------------------------------------------------------------------- 1 | class Stack: 2 | def __init__(self): 3 | self.data = [] 4 | 5 | def peek(self): 6 | if len(self.data) == 0: 7 | return None 8 | return self.data[-1] 9 | 10 | def push(self, value): 11 | self.data.append(value) 12 | 13 | def isempty(self): 14 | return len(self) == 0 15 | 16 | def pop(self): 17 | if len(self.data) > 0: 18 | return self.data.pop() 19 | return None 20 | 21 | def __len__(self): 22 | return len(self.data) 23 | 24 | def __str__(self): 25 | return f"Stack({self.data})" 26 | 27 | def __repr__(self): 28 | return str(self) 29 | -------------------------------------------------------------------------------- /python/stacksqueues/stack_of_plates.py: -------------------------------------------------------------------------------- 1 | class StackWithThreshold: 2 | def __init__(self): 3 | self.stack = [] 4 | self.threshold = 6 5 | 6 | def push(self, data): 7 | self.stack.append(data) 8 | 9 | def pop(self): 10 | if len(self.stack) > 0: 11 | return self.stack.pop() 12 | return None 13 | 14 | def __len__(self): 15 | return len(self.stack) 16 | 17 | def __str__(self): 18 | return f"StackWithThreshold({self.stack})" 19 | 20 | def __repr__(self): 21 | return str(self) 22 | 23 | 24 | class StackOfPlates: 25 | def __init__(self): 26 | self.stack_with_plates = [] 27 | 28 | def push(self, data): 29 | latest_stack = None 30 | if len(self.stack_with_plates) > 0: 31 | latest_stack = self.peek() 32 | if latest_stack is None or len(latest_stack) >= latest_stack.threshold: 33 | self.stack_with_plates.append(StackWithThreshold()) 34 | self.peek().push(data) 35 | 36 | def pop(self): 37 | if len(self) == 0: 38 | return None 39 | latest_stack = self.peek() 40 | latest_stack.pop() 41 | if len(self.peek()) == 0: 42 | self.stack_with_plates.pop() 43 | 44 | def peek(self): 45 | return self.stack_with_plates[-1] 46 | 47 | def __len__(self): 48 | return len(self.stack_with_plates) 49 | 50 | def __str__(self): 51 | return f"StackOfPlates({self.stack_with_plates})" 52 | 53 | def __repr__(self): 54 | return str(self) 55 | 56 | 57 | sop = StackOfPlates() 58 | for i in range(1, 20): 59 | sop.push(i) 60 | print(sop) 61 | print('popping-----') 62 | for i in range(0, 10): 63 | sop.pop() 64 | sop.pop() 65 | sop.pop() 66 | sop.pop() 67 | sop.pop() 68 | print(sop) 69 | -------------------------------------------------------------------------------- /python/sumEvenAfterQueries.py: -------------------------------------------------------------------------------- 1 | def sumEvenAfterQueries(A, queries): 2 | s = sum(i for i in A if i % 2 == 0) 3 | result = [] 4 | for i in range(len(queries)): 5 | val = queries[i][0] 6 | index = queries[i][1] 7 | 8 | if A[index] % 2 == 0: 9 | s -= A[index] 10 | A[index] += val 11 | 12 | if A[index] % 2 == 0: 13 | s += A[index] 14 | 15 | result.append(s) 16 | print("finally", result) 17 | 18 | 19 | def sumEvenAfterQueries_new(A, queries): 20 | s = sum(i for i in A if i % 2 == 0) 21 | r = [] 22 | for val, i in queries: 23 | A[i] += val 24 | if A[i] % 2 == 0: 25 | s += val if val % 2 == 0 else A[i] 26 | else: 27 | s -= val % 2 and A[i] - val 28 | r += s, 29 | print(r) 30 | return r 31 | 32 | 33 | def sumOfEven(A): 34 | sum = 0 35 | for i in A: 36 | if i % 2 == 0: 37 | print("Even", i) 38 | sum += i 39 | return sum 40 | 41 | 42 | if __name__ == "__main__": 43 | sumEvenAfterQueries(A=[1, 2, 3, 4], queries=[[1, 0], [-3, 1], [-4, 0], [2, 3]]) 44 | print([8, 6, 2, 4]) 45 | -------------------------------------------------------------------------------- /python/valid_paranthesis.py: -------------------------------------------------------------------------------- 1 | def is_valid(s): 2 | if len(s) % 2 != 0: 3 | print("Caught by length check") 4 | return False 5 | opening = ("(", "{", "[") 6 | closing = (")", "}", "]") 7 | stack = [] 8 | for i in s: 9 | if i in opening: 10 | stack.append(i) 11 | elif i in closing: 12 | try: 13 | popped = stack.pop() 14 | except Exception: 15 | return False 16 | print(popped, i) 17 | if opening.index(popped) != closing.index(i): 18 | return False 19 | if len(stack) == 0: 20 | return True 21 | else: 22 | return False 23 | 24 | 25 | if __name__ == "__main__": 26 | print(is_valid("(({}))")) 27 | print(is_valid("([][][])")) 28 | print(is_valid("({}{}[})")) 29 | print(is_valid("{")) 30 | print(is_valid("}}")) 31 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | isJavaMainClass() { 4 | echo "$( 5 | grep -q "public static void main" "$1" 6 | echo $? 7 | )" 8 | } 9 | 10 | isKotlinMainClass() { 11 | echo "$( 12 | grep -q "fun main()" "$1" 13 | echo $? 14 | )" 15 | } 16 | 17 | removeExtension() { 18 | echo "$(echo "$1" | cut -f 1 -d '.')" 19 | } 20 | 21 | find . -type f -name "*.class" -exec rm -f {} \; 22 | 23 | rm jvm-logs.txt || true 24 | 25 | for i in $(git ls-files | grep .kt); do 26 | filename=$(removeExtension "$i") 27 | isMainClass=$(isKotlinMainClass "$i") 28 | if [[ "$isMainClass" == "0" ]]; then 29 | kotlinFileName="$filename"'Kt' 30 | kotlinFileName="${kotlinFileName#src/}" 31 | echo ">>>>> Executing file $kotlinFileName" 32 | ./gradlew -PmainClass="$kotlinFileName" execClass -q -Dorg.gradle.console=plain --warning-mode=summary 33 | else 34 | echo ">>>>> Skipping $i" 35 | fi 36 | done 37 | 38 | for i in $(git ls-files | grep .java); do 39 | filename=$(removeExtension "$i") 40 | isMainClass=$(isJavaMainClass "$i") 41 | if [[ "$isMainClass" == "0" ]]; then 42 | echo ">>>>> Executing file $i" 43 | filename="${filename#src/}" 44 | ./gradlew -PmainClass="$filename" execClass -q -Dorg.gradle.console=plain --warning-mode=summary 45 | else 46 | echo ">>>>> Skipping $i" 47 | fi 48 | done 49 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * 6 | * Detailed information about configuring a multi-project build in Gradle can be found 7 | * in the user manual at https://docs.gradle.org/6.3/userguide/multi_project_builds.html 8 | */ 9 | 10 | rootProject.name = "leetcode" 11 | -------------------------------------------------------------------------------- /src/_utils/DocumentUtils.kt: -------------------------------------------------------------------------------- 1 | package _utils 2 | 3 | /** 4 | * Ignore normal procedure of extracting JavaDocs or Kotlin Docs 5 | * and instead use [value] 6 | */ 7 | annotation class Document(val value: String) 8 | 9 | @Target( 10 | AnnotationTarget.ANNOTATION_CLASS, 11 | AnnotationTarget.CLASS, 12 | AnnotationTarget.FUNCTION 13 | ) 14 | annotation class UseCommentAsDocumentation() 15 | 16 | /** 17 | * Skip the file containing this annotation 18 | */ 19 | annotation class SkipDocumentation() 20 | -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/Utilities.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook 2 | 3 | import _utils.SkipDocumentation 4 | import java.util.* 5 | 6 | @SkipDocumentation 7 | 8 | inline fun withPrint(msg: String, block: () -> T): T { 9 | println("${"-".repeat(4)} $msg ${"-".repeat(4)}") 10 | val result = block() 11 | return result 12 | } 13 | 14 | fun T.print(msg: String? = null, printer: ((T) -> Any)? = null): T { 15 | kotlin.io.print("${msg ?: "Result"}: ") 16 | val value = printer?.invoke(this) ?: this 17 | 18 | if (printer == null) { 19 | when (this) { 20 | is Array<*> -> { 21 | println(Arrays.toString(this)) 22 | return this 23 | } 24 | is IntArray -> { 25 | println(this.toList()) 26 | return this 27 | } 28 | } 29 | } 30 | 31 | println(value) 32 | return this 33 | } 34 | 35 | fun String.padLeft(count: Int = 3) = " ".repeat(count) + this -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/datastructures/FlattenBSTIntoLinkedList.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.datastructures 2 | 3 | import algorithmdesignmanualbook.print 4 | import utils.assertIterableSameInAnyOrder 5 | import java.util.* 6 | 7 | class FlattenBSTIntoLinkedList(private val bst: BinarySearchTree) { 8 | 9 | fun flatten(): LinkedList { 10 | val linkedList = LinkedList() 11 | inOrderTraversal(bst.getNode(), linkedList) 12 | return linkedList 13 | } 14 | 15 | private fun inOrderTraversal(currentNode: Node?, holder: LinkedList) { 16 | if (currentNode == null) { 17 | return 18 | } 19 | inOrderTraversal(currentNode.left, holder) 20 | holder.add(currentNode.value) 21 | inOrderTraversal(currentNode.right, holder) 22 | } 23 | } 24 | 25 | 26 | fun main() { 27 | val bst1 = createBST() 28 | // 10 29 | // 6 15 30 | // 4 7 12 19 31 | bst1.print() 32 | val flatten = FlattenBSTIntoLinkedList(bst1).flatten() 33 | flatten.print() 34 | 35 | assertIterableSameInAnyOrder(actual = flatten, expected = listOf(4, 6, 7, 10, 12, 15, 19)) 36 | } 37 | -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/datastructures/IdenticalBinaryTree.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.datastructures 2 | 3 | import java.util.* 4 | import kotlin.test.assertFalse 5 | import kotlin.test.assertTrue 6 | 7 | /** 8 | * Given two binary tree, find if they are identical i.e. same value at the same position & same structure 9 | */ 10 | class IdenticalBinaryTree(private val bst1: BinarySearchTree, private val bst2: BinarySearchTree) { 11 | 12 | fun areIdentical(): Boolean { 13 | val queue1 = LinkedList() 14 | val queue2 = LinkedList() 15 | queue1.add(bst1.getNode()) 16 | queue2.add(bst2.getNode()) 17 | 18 | // Breadth-first traversal 19 | while (queue1.isNotEmpty() || queue2.isNotEmpty()) { 20 | val node1 = queue1.pop() 21 | val node2 = queue2.pop() 22 | 23 | if (node1.left?.value != node2.left?.value) { 24 | return false 25 | } 26 | 27 | if (node1.right?.value != node2.right?.value) { 28 | return false 29 | } 30 | 31 | node1.left?.let(queue1::addLast) 32 | node1.right?.let(queue1::addLast) 33 | 34 | node2.left?.let(queue2::addLast) 35 | node2.right?.let(queue2::addLast) 36 | } 37 | 38 | return queue1.isEmpty() && queue2.isEmpty() 39 | } 40 | } 41 | 42 | 43 | fun main() { 44 | val bst1 = createBST() 45 | val bst2 = createBST() 46 | assertTrue { IdenticalBinaryTree(bst1, bst2).areIdentical() } 47 | 48 | val bst3 = createBST() 49 | bst3.add(Node(100)) 50 | assertFalse { IdenticalBinaryTree(bst1, bst3).areIdentical() } 51 | 52 | bst1.add(Node(100)) 53 | assertTrue { IdenticalBinaryTree(bst1, bst3).areIdentical() } 54 | } 55 | -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/datastructures/MatrixMultiplication.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.datastructures 2 | 3 | import utils.PrintUtils 4 | import kotlin.test.assertFails 5 | 6 | typealias Matrix = Array> 7 | typealias Dimen = Pair 8 | 9 | fun main() { 10 | val matA = arrayOf(arrayOf(1, 2, 3), arrayOf(3, 3, 3), arrayOf(5, 4, 3)) 11 | val matB = arrayOf(arrayOf(1, 3), arrayOf(2, 3), arrayOf(3, 3)) 12 | 13 | multiplyMatrix(matA, matB) 14 | 15 | val matA2 = arrayOf(arrayOf(1, 2, 3), arrayOf(3, 3, 3)) 16 | val matB2 = arrayOf(arrayOf(1, 3), arrayOf(3, 3)) 17 | 18 | assertFails { multiplyMatrix(matA2, matB2) } 19 | } 20 | 21 | /** 22 | * Complexity of this algorithm = O(xyz) i.e. CUBIC 23 | */ 24 | fun multiplyMatrix(matA: Matrix, matB: Matrix): Matrix { 25 | PrintUtils.printArr(matA.toList()) 26 | println("x") 27 | PrintUtils.printArr(matB.toList()) 28 | 29 | require(matA[0].size == matB.size) { 30 | "Matrix multiplication not possible between ${matA.dimension().str()} & ${matB.dimension().str()}" 31 | } 32 | 33 | val result = Array(matA[0].size) { 34 | Array(matB[0].size) { 0 } 35 | } 36 | 37 | for (i in 0..matA[0].lastIndex) { 38 | for (j in 0..matB[0].lastIndex) { 39 | result[i][j] = 0 40 | for (k in 0..matA.lastIndex) { 41 | result[i][j] += matA[i][k] * matB[k][j] 42 | } 43 | } 44 | 45 | } 46 | return result.also { 47 | PrintUtils.printArr(result.toList()) 48 | println() 49 | } 50 | } 51 | 52 | 53 | private fun Matrix.dimension(): Dimen = Pair(this.size, this[0].size) 54 | 55 | private fun Dimen.str(): String = "${first}x${second} " 56 | -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/datastructures/MiddleNodeOfLinkedList.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.datastructures 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import kotlin.test.assertTrue 5 | 6 | /** 7 | * Given a singly-linked list, find its middle node. 8 | * 9 | * Solution: Fast pointer-slow pointer approach 10 | * Use two pointer, one traverses one step ahead and another by 2 steps. 11 | * When the fast pointer reaches the end, the slow pointer is at middle. 12 | */ 13 | @UseCommentAsDocumentation 14 | private fun LinkedListNode.getMiddleNode(): LinkedListNode { 15 | var slowPointer: LinkedListNode = this 16 | var fastPointer: LinkedListNode? = this 17 | 18 | while (fastPointer?.next != null) { 19 | slowPointer = slowPointer.next!! 20 | fastPointer = fastPointer.next?.next 21 | } 22 | return slowPointer 23 | } 24 | 25 | 26 | fun main() { 27 | val list = LinkedListNode(1) 28 | list.add(2) 29 | list.add(3) 30 | list.add(4) 31 | list.add(5) 32 | list.add(6) 33 | list.add(7) 34 | list.add(8) 35 | list.add(9) 36 | list.getMiddleNode() 37 | assertTrue { 38 | list.getMiddleNode().value == 5 39 | } 40 | } -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/datastructures/Node.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.datastructures 2 | 3 | data class Node(val value: Int) { 4 | var parent: Node? = null 5 | var left: Node? = null 6 | var right: Node? = null 7 | 8 | companion object { 9 | fun create(value: Int) = Node(value) 10 | } 11 | 12 | override fun toString(): String { 13 | return "Node(value:$value, left:${left}, right=${right}, parent:${parent?.value})" 14 | } 15 | 16 | fun toBST() = BinarySearchTree(this) 17 | 18 | fun isLeafNode() = left == null && right == null 19 | } -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/datastructures/ReverseLinkedList.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.datastructures 2 | 3 | import _utils.UseCommentAsDocumentation 4 | 5 | 6 | data class LinkedListNode(val value: Int) { 7 | var next: LinkedListNode? = null 8 | private set 9 | 10 | fun add(value: Int) { 11 | var current: LinkedListNode? = this 12 | while (current?.next != null) { 13 | current = current.next 14 | } 15 | current!!.next = LinkedListNode(value) 16 | } 17 | 18 | fun print() { 19 | val sb = StringBuilder() 20 | var current: LinkedListNode? = this 21 | while (current != null) { 22 | sb.append("${current.value}").append(" -> ") 23 | current = current.next 24 | } 25 | println(sb.removeSuffix(" -> ").toString()) 26 | } 27 | 28 | /** 29 | * [link here](https://leetcode.com/problems/reverse-linked-list) 30 | */ 31 | @UseCommentAsDocumentation 32 | fun reverse(): LinkedListNode? { 33 | var prev: LinkedListNode? = null 34 | var current: LinkedListNode? = this 35 | if (current?.next == null) { 36 | return this 37 | } 38 | while (current != null) { 39 | val temp = current.next 40 | current.next = prev 41 | prev = current 42 | current = temp 43 | } 44 | return prev 45 | } 46 | } 47 | 48 | fun main() { 49 | val list = LinkedListNode(1) 50 | list.reverse()?.print() 51 | 52 | list.add(2) 53 | list.add(3) 54 | list.add(4) 55 | list.add(5) 56 | 57 | list.print() 58 | 59 | list.reverse()?.print() 60 | } -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/datastructures/ReverseSentence.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.datastructures 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import algorithmdesignmanualbook.print 5 | import kotlin.test.assertEquals 6 | 7 | /** 8 | * Reverse the words in a sentence—i.e., “My name is Chris” becomes “Chris is name My.” 9 | */ 10 | @UseCommentAsDocumentation 11 | private fun reverse(str: String): String { 12 | val split = str.split(" ") 13 | if (split.size <= 1) { 14 | return "$str." 15 | } 16 | val sb = StringBuilder(str.length + 1) 17 | for (i in split.lastIndex downTo 0) { 18 | sb.append(split[i]) 19 | if (i != 0) { 20 | sb.append(" ") 21 | } 22 | } 23 | sb.append(".") 24 | return sb.toString().print() 25 | } 26 | 27 | fun main() { 28 | assertEquals(expected = "Chris is name My.", actual = reverse("My name is Chris")) 29 | } -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/dynamic/MinDifferenceBetweenSubsets.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.dynamic 2 | 3 | import algorithmdesignmanualbook.print 4 | import kotlin.math.abs 5 | 6 | 7 | private fun findMinRec(array: Array, i: Int, sumCalculated: Int, sumTotal: Int): Int { 8 | // If we have reached last element. 9 | // Sum of one subset is sumCalculated, 10 | // sum of other subset is sumTotal-sumCalculated. 11 | // Return absolute difference of two sums. 12 | if (i == 0) { 13 | return abs((sumTotal - sumCalculated) - sumCalculated) 14 | } 15 | 16 | // For every item arr[i], we have two choices 17 | // (1) We do not include it first set 18 | // (2) We include it in first set 19 | // We return minimum of two choices 20 | return minOf( 21 | findMinRec(array, i - 1, sumCalculated + array[i - 1], sumTotal), 22 | findMinRec(array, i - 1, sumCalculated, sumTotal), 23 | ) 24 | } 25 | 26 | 27 | fun main() { 28 | val array = arrayOf(1, 6, 11, 5) 29 | findMinRec(array, array.size, 0, array.sum()).print("Min diff betn subset is: ") 30 | } -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/graph/BreadthFirstTraversal.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.graph 2 | 3 | import algorithmdesignmanualbook.withPrint 4 | import java.util.* 5 | import kotlin.test.assertFalse 6 | import kotlin.test.assertTrue 7 | 8 | private fun breadthFirstTraversal(graph: Graph) { 9 | val start = graph.getRandomVertex() 10 | val queue = LinkedList() 11 | 12 | queue.addLast(start) 13 | 14 | while (queue.isNotEmpty()) { 15 | val first = queue.removeFirst() 16 | if (first.state == Graph.State.PROCESSED) { 17 | continue 18 | } 19 | first.edges.forEach { 20 | if (it.endVertex.state == Graph.State.UNDISCOVERED) { 21 | queue.addLast(it.endVertex) 22 | it.endVertex.state = Graph.State.DISCOVERED 23 | } 24 | } 25 | println(first.value) 26 | first.state = Graph.State.PROCESSED 27 | } 28 | } 29 | 30 | fun main() { 31 | withPrint("Graph 1") { 32 | val graph1 = Graph.getDefaultDirected() 33 | breadthFirstTraversal(graph1) 34 | } 35 | 36 | withPrint("Graph 2") { 37 | val graph2 = Graph.getDefaultUnDirected() 38 | breadthFirstTraversal(graph2) 39 | } 40 | } -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/graph/GraphInit.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.graph 2 | 3 | import _utils.SkipDocumentation 4 | import kotlin.test.assertFalse 5 | import kotlin.test.assertTrue 6 | 7 | @SkipDocumentation 8 | 9 | fun main() { 10 | val graph = Graph(true) 11 | val v1 = graph.addVertex("1") 12 | val v2 = graph.addVertex("2") 13 | val v3 = graph.addVertex("3") 14 | graph.join(v2, v3) 15 | graph.join(v1, v2) 16 | graph.join(v1, v3) 17 | println(graph) 18 | 19 | assertTrue { graph.isIn(v1.value) } 20 | assertTrue { graph.isIn(v2.value) } 21 | 22 | graph.join(v2, v3) 23 | graph.join(v2, v3) 24 | graph.join(v3, v2) 25 | 26 | assertTrue { graph.isConnected(v1.value, v2.value) } 27 | assertTrue { graph.isConnected(v1.value, v3.value) } 28 | assertFalse { graph.isConnected(v2.value, v1.value) } 29 | assertFalse { graph.isConnected(v3.value, v1.value) } 30 | } -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/graph/SimpleGraph.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.graph 2 | 3 | 4 | class SimpleGraph(val vertexCount: Int, val edgesCount: Int) { 5 | 6 | class Edge(var src: Int, var dest: Int, var weight: Int) 7 | 8 | val edges = Array(edgesCount) { null } 9 | } -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/heuristics/backtrack/AllSubsets.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.heuristics.backtrack 2 | 3 | class AllSubsets(private val nums: Array) { 4 | 5 | private val result = mutableListOf>() 6 | 7 | fun execute(): List> { 8 | if (nums.isEmpty()) { 9 | return result 10 | } 11 | backtrack(0, mutableListOf()) 12 | return result 13 | } 14 | 15 | private fun backtrack(index: Int, current: MutableList) { 16 | result.add(ArrayList(current)) 17 | for (i in index..nums.lastIndex) { 18 | println("adding " + nums[i]) 19 | current.add(nums[i]) 20 | backtrack(i + 1, current) 21 | current.removeLastOrNull().also { 22 | println("rm " + it) 23 | } 24 | } 25 | } 26 | } 27 | 28 | 29 | fun main() { 30 | run { 31 | val solution = AllSubsets(arrayOf(1, 2, 3)) 32 | solution.execute().forEach { 33 | println(it) 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/heuristics/backtrack/Permutation.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.heuristics.backtrack 2 | 3 | import utils.assertIterableSameInAnyOrder 4 | 5 | class Permutation(val str: String) { 6 | val result = mutableListOf() 7 | 8 | fun execute(): List { 9 | if (str.isEmpty()) { 10 | result.add("") 11 | return result 12 | } 13 | permutation(str, "") 14 | return result 15 | } 16 | 17 | private fun permutation(current: String, prefix: String) { 18 | if (current.isEmpty()) { 19 | result.add(prefix) 20 | } 21 | for (i in 0..current.lastIndex) { 22 | val remainder = current.substring(0, i) + current.substring(i + 1) 23 | permutation(remainder, prefix + current[i]) 24 | } 25 | } 26 | } 27 | 28 | fun main() { 29 | assertIterableSameInAnyOrder( 30 | actual = Permutation("").execute(), 31 | expected = listOf("") 32 | ) 33 | assertIterableSameInAnyOrder( 34 | actual = Permutation("abc").execute(), 35 | expected = listOf("abc", "acb", "bac", "bca", "cab", "cba") 36 | ) 37 | 38 | assertIterableSameInAnyOrder( 39 | actual = Permutation("ab").execute(), 40 | expected = listOf("ab", "ba") 41 | ) 42 | } -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/searching/MagicIndexSearch.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.searching 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import algorithmdesignmanualbook.print 5 | import kotlin.test.assertTrue 6 | 7 | /** 8 | * [4-33] Algorithm to determine whether there exists an i index such as ai = i given array of {a1, a2, a3 ... an} 9 | * Sorted and distinct case: 10 | */ 11 | @UseCommentAsDocumentation 12 | fun findMagicIndex(array: IntArray, low: Int, high: Int): Int? { 13 | if (high < low) { 14 | return null 15 | } 16 | val mid = (low + high) / 2 17 | val middleElement = array[mid] 18 | return if (middleElement == mid + 1) { 19 | println("Element is at index $mid with value ${array[mid]}") 20 | mid + 1 21 | } else if (middleElement > mid + 1) { 22 | findMagicIndex(array, low, mid - 1) 23 | } else { 24 | findMagicIndex(array, mid + 1, high) 25 | } 26 | } 27 | 28 | 29 | fun main() { 30 | assertTrue { 31 | val array = intArrayOf(0, 2, 4, 5, 8, 10, 12, 19, 26) 32 | findMagicIndex(array, 0, array.lastIndex).print() == 2 33 | } 34 | assertTrue { 35 | val array = intArrayOf(0, 3, 4, 5, 8, 10, 12, 19, 26) 36 | findMagicIndex(array, 0, array.lastIndex).print() == null 37 | } 38 | 39 | assertTrue { 40 | val array = intArrayOf(-1, 0, 1, 3, 5, 10, 12, 19, 26) 41 | findMagicIndex(array, 0, array.lastIndex).print() == 5 42 | } 43 | } -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/sorting/InsertionSort.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.sorting 2 | 3 | import java.util.* 4 | import kotlin.collections.ArrayList 5 | import kotlin.test.assertEquals 6 | 7 | fun main() { 8 | val elements = "INSERTIONSORT".split("").filter(String::isNotBlank).also(::println) 9 | val input = elements.toTypedArray() 10 | 11 | insertionSort(input) 12 | println(Arrays.toString(input)) 13 | 14 | val expected = ArrayList(elements).sorted() 15 | expected.forEachIndexed { index, s -> 16 | assertEquals(expected = s, actual = expected[index]) 17 | } 18 | } 19 | 20 | /** 21 | * How does insertion sort work? 22 | * * Loop through elements 23 | * * At each element, compare it with element before it 24 | * * If smaller, swap places 25 | * * Repeat 26 | */ 27 | private fun insertionSort(array: Array) { 28 | for (i in 1..array.lastIndex) { 29 | var decrementingHead = i 30 | // Iterate till the start of list 31 | // The current element is always at the decrementingHead position 32 | while (decrementingHead > 0 && array[decrementingHead - 1] >= array[decrementingHead]) { 33 | // Swap place with element before it 34 | swap(array, decrementingHead - 1, decrementingHead) 35 | decrementingHead-- 36 | } 37 | } 38 | } 39 | 40 | 41 | private fun swap(array: Array, index1: Int, index2: Int) { 42 | require(index2 <= array.lastIndex && index1 <= index2) 43 | 44 | val temp = array[index1] 45 | array[index1] = array[index2] 46 | array[index2] = temp 47 | } -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/sorting/KSortedListMerge.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.sorting 2 | 3 | import algorithmdesignmanualbook.print 4 | import utils.assertArraysSame 5 | 6 | /** 7 | * Give an O(n log k)-time algorithm that merges k sorted lists with a total of n 8 | * elements into one sorted list. (Hint: use a heap to speed up the elementary O(kn)-time algorithm). 9 | */ 10 | private fun kSortedListMerge(arrays: Array>, n: Int): Array { 11 | val indices = Array(arrays.size) { 0 } 12 | // total size is the size of the result 13 | val result = Array(n) { null } 14 | // What if i load the [arrays] in a heap? 15 | // Comparison between smallest elements of heap will still take O(k) 16 | for (i in 0 until n) { // O(n) 17 | val currentValues = arrays.mapIndexed { index, array -> // O(k) 18 | // can run out of items 19 | Pair(array.getOrNull(indices.getOrNull(index) ?: -1), index) 20 | } 21 | // take the min value 22 | val minValue = currentValues.filter { it.first != null }.minByOrNull { it.first!! }!! 23 | result[i] = minValue.first 24 | // increase the index 25 | indices[minValue.second] += 1 26 | } 27 | return result 28 | } 29 | 30 | fun main() { 31 | val input1 = arrayOf(1, 2, 6, 8, 10, 11) 32 | val input2 = arrayOf(1, 2, 7, 9, 12) 33 | val input3 = arrayOf(-1, 0, 3, 5) 34 | val input4 = arrayOf(-2, -1, 12, 22) 35 | val input = arrayOf(input1, input2, input3, input4) 36 | assertArraysSame( 37 | expected = kSortedListMerge(input, n = input.map { it.size }.sum()).print(), 38 | actual = arrayOf(-2, -1, -1, 0, 1, 1, 2, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 12, 22) 39 | ) 40 | 41 | } -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/sorting/QuickSort.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.sorting 2 | 3 | import utils.assertArraysSame 4 | import java.util.* 5 | 6 | 7 | private fun swap(array: IntArray, index1: Int, index2: Int) { 8 | val temp = array[index1] 9 | array[index1] = array[index2] 10 | array[index2] = temp 11 | } 12 | 13 | private fun quickSort(array: IntArray, low: Int, high: Int) { 14 | if (low < high) { 15 | val j = partition(array, low, high) 16 | quickSort(array, low, j) 17 | quickSort(array, j + 1, high) 18 | } 19 | } 20 | 21 | private fun partition(array: IntArray, low: Int, high: Int): Int { 22 | val pivot = array[low] 23 | var i = low 24 | var j = high 25 | 26 | // stop when ----ji---- 27 | while (i < j) { 28 | // keep incrementing i till you find the element larger than pivot 29 | while (pivot >= array[i]) { 30 | i++ 31 | } 32 | // keep incrementing j till you find the element smaller than pivot 33 | while (pivot < array[j]) { 34 | j-- 35 | } 36 | 37 | // swap element at i and j 38 | if (i < j) { 39 | swap(array, i, j) 40 | } 41 | } 42 | // swap pivot and j 43 | swap(array, low, j) 44 | // return partition index 45 | return j 46 | } 47 | 48 | fun main() { 49 | val input1 = intArrayOf(6, 8, 1, 5, 2, 9, 11) 50 | quickSort(input1, 0, input1.lastIndex) 51 | println(Arrays.toString(input1)) 52 | assertArraysSame(expected = arrayOf(1, 2, 5, 6, 8, 9, 11), actual = input1.toTypedArray()) 53 | 54 | 55 | val input2 = intArrayOf(8, 1, 5, 2, 9, 11) 56 | quickSort(input2, 0, input2.lastIndex) 57 | println(Arrays.toString(input2)) 58 | assertArraysSame(expected = arrayOf(1, 2, 5, 8, 9, 11), actual = input2.toTypedArray()) 59 | } -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/sorting/SelectionSort.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.sorting 2 | 3 | import java.util.* 4 | 5 | fun main() { 6 | val elements = "SELECTIONSORT".split("").filter(String::isNotBlank) 7 | val input = elements.toTypedArray() 8 | selectionSort(input) 9 | println(Arrays.toString(input)) 10 | } 11 | 12 | /** 13 | * Identify the smallest element from unsorted portion and put it at the end of the sorted portion 14 | */ 15 | private fun selectionSort(array: Array) { 16 | for (i in 0..array.lastIndex) { 17 | var smallestElementIndex = i 18 | for (j in (i + 1)..array.lastIndex) { 19 | if (array[smallestElementIndex] > array[j]) { 20 | smallestElementIndex = j 21 | } 22 | } 23 | swap(array, i, smallestElementIndex) 24 | } 25 | } 26 | 27 | 28 | private fun swap(array: Array, index1: Int, index2: Int) { 29 | val temp = array[index1] 30 | array[index1] = array[index2] 31 | array[index2] = temp 32 | } -------------------------------------------------------------------------------- /src/algorithmdesignmanualbook/sorting/TwoPairSum.kt: -------------------------------------------------------------------------------- 1 | package algorithmdesignmanualbook.sorting 2 | 3 | import algorithmdesignmanualbook.print 4 | import kotlin.test.assertTrue 5 | 6 | /** 7 | * O(nlogn) algorithm for finding whether there exists a pair of elements, one from S1 and one 8 | * from S2, that add up to x 9 | */ 10 | private fun twoPairSum(array1: Array, array2: Array, x: Int): Pair? { 11 | // O(n) 12 | val map: Map = array1.associateBy { it } 13 | // O(n) 14 | array2.forEach { 15 | val diff = x - it 16 | // O(1) 17 | if (map.containsKey(diff)) { 18 | return Pair(diff, it) 19 | } 20 | } 21 | return null 22 | } 23 | 24 | 25 | fun main() { 26 | assertTrue { 27 | twoPairSum( 28 | arrayOf(4, 1, 3, 5, 1), 29 | arrayOf(-2, 2, -1, 0, 3), 30 | 1 31 | ).print() == Pair(3, -2) 32 | } 33 | assertTrue { 34 | twoPairSum( 35 | arrayOf(4, 1, 3, 5, 1), 36 | arrayOf(-2, 2, -1, 0, 3), 37 | 5 38 | ).print() == Pair(3, 2) 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /src/algorithmsinanutshell/GreatestCommonDivisor.kt: -------------------------------------------------------------------------------- 1 | package algorithmsinanutshell 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import kotlin.test.assertEquals 5 | 6 | /** 7 | * Greatest common divisor using Euclidean Algorithm 8 | * 9 | * [Link](https://www.freecodecamp.org/news/euclidian-gcd-algorithm-greatest-common-divisor/) 10 | */ 11 | @UseCommentAsDocumentation 12 | private fun calculateGcd(a: Int, b: Int): Int { 13 | var (low, high) = if (a < b) Pair(a, b) else Pair(b, a) 14 | while ((high % low) > 0) { 15 | val remainder = high % low 16 | if (remainder == 0) { 17 | return low 18 | } 19 | high = low 20 | low = remainder 21 | } 22 | return low 23 | } 24 | 25 | fun main() { 26 | assertEquals(4, calculateGcd(1220, 516)) 27 | assertEquals(10, calculateGcd(30, 20)) 28 | assertEquals(3, calculateGcd(9, 6)) 29 | assertEquals(4, calculateGcd(4, 12)) 30 | } -------------------------------------------------------------------------------- /src/algorithmsinanutshell/LineModel.kt: -------------------------------------------------------------------------------- 1 | package algorithmsinanutshell 2 | 3 | import _utils.SkipDocumentation 4 | import kotlin.math.atan 5 | 6 | @SkipDocumentation 7 | 8 | data class Line(val p1: Point, val p2: Point) 9 | 10 | 11 | infix fun Int.fromTo(y: Int) = Point(this, y) 12 | 13 | 14 | data class Point(val x: Int, val y: Int) { 15 | 16 | fun angle(point: Point): Double { 17 | val slope = (point.y - y).toDouble() / (point.x - x) 18 | // tanß = p/b 19 | var angle = Math.toDegrees(atan(slope)) 20 | if (angle < 0) { 21 | angle += 360 22 | } 23 | return angle 24 | } 25 | } 26 | 27 | enum class Orientation { 28 | CW, ACW, COLINEAR 29 | } -------------------------------------------------------------------------------- /src/algorithmsinanutshell/TreeTraversal.kt: -------------------------------------------------------------------------------- 1 | package algorithmsinanutshell 2 | 3 | import algorithmdesignmanualbook.datastructures.Node 4 | import algorithmdesignmanualbook.datastructures.createBST 5 | import java.util.* 6 | 7 | private fun traverseDepthFirst(node: Node?) { 8 | if (node != null) { 9 | traverseDepthFirst(node.left) 10 | println(node.value) 11 | traverseDepthFirst(node.right) 12 | } 13 | } 14 | 15 | 16 | private fun traverseBreadthFirst(node: Node?) { 17 | val queue = LinkedList() 18 | queue.addLast(node) 19 | while (queue.isNotEmpty()) { 20 | val current = queue.removeFirst() 21 | if (current != null) { 22 | println(current.value) 23 | queue.addLast(current.left) 24 | queue.addLast(current.right) 25 | } 26 | } 27 | } 28 | 29 | fun main() { 30 | // 10 31 | // 6 15 32 | // 4 7 12 19 33 | val tree = createBST() 34 | tree.print() 35 | println("Depth first") 36 | traverseDepthFirst(tree.getNode()) 37 | 38 | println("Breadth first") 39 | traverseBreadthFirst(tree.getNode()) 40 | } -------------------------------------------------------------------------------- /src/arraysandstrings/IsOneStringPermutationOfOther.java: -------------------------------------------------------------------------------- 1 | 2 | package arraysandstrings; 3 | 4 | import java.util.Arrays; 5 | 6 | public class IsOneStringPermutationOfOther { 7 | public static void main(String[] args) { 8 | assert !isOneStringPermutationOfOther("abc", "dog"); 9 | assert isOneStringPermutationOfOther("god", "dog"); 10 | assert !isOneStringPermutationOfOther("god ", "dog"); 11 | assert !isOneStringPermutationOfOther("123", "dog"); 12 | } 13 | 14 | private static boolean isOneStringPermutationOfOther(String str1, String str2) { 15 | if (str1.length() != str2.length()) { 16 | return false; 17 | } 18 | char[] content1 = str1.toCharArray(); 19 | char[] content2 = str2.toCharArray(); 20 | 21 | Arrays.sort(content1); 22 | Arrays.sort(content2); 23 | 24 | return Arrays.toString(content1).equals(Arrays.toString(content2)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/arraysandstrings/IsPermutationOfStringAPalindrome.kt: -------------------------------------------------------------------------------- 1 | package arraysandstrings 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import arraysandstrings.IsPermutationOfStringAPalindrome.isPalindrome 5 | import kotlin.test.assertFalse 6 | import kotlin.test.assertTrue 7 | 8 | private object IsPermutationOfStringAPalindrome { 9 | 10 | 11 | /** 12 | * A string's permutation is a palindrome 13 | * if 14 | * for a odd length string, there must be only one odd # of character (the middle one) 15 | * for a even length string, all chars must have even # of occurrence 16 | */ 17 | @UseCommentAsDocumentation 18 | fun isPalindrome(str: String): Boolean { 19 | val input = str.toLowerCase().replace(" ", "") 20 | val charCount = mutableMapOf() 21 | for (s in input) { 22 | charCount[s] = (charCount[s] ?: 0) + 1 23 | } 24 | return if (input.length % 2 == 0) { 25 | charCount.values.all { it % 2 == 0 } 26 | } else { 27 | val oddOccurrence = charCount.values.filter { it % 2 == 1 } 28 | oddOccurrence.size == 1 29 | } 30 | } 31 | } 32 | 33 | fun main() { 34 | assertTrue(isPalindrome("Tact Coa")) 35 | assertTrue(isPalindrome("level")) 36 | assertTrue(isPalindrome("noon")) 37 | assertFalse(isPalindrome("noon2a")) 38 | } -------------------------------------------------------------------------------- /src/arraysandstrings/StringCompression.kt: -------------------------------------------------------------------------------- 1 | package arraysandstrings 2 | 3 | import kotlin.test.assertEquals 4 | 5 | fun main() { 6 | assertEquals(compress("aabcccccaaa"), "a2b1c5a3") 7 | assertEquals(compress("abc"), "abc") 8 | } 9 | 10 | private fun compress(str: String): String { 11 | val sb = StringBuilder(str.length) 12 | 13 | var occurrenceCount = 0 14 | var prevCharacter: Char = str[0] 15 | 16 | for (currentChar in str) { 17 | if (prevCharacter != currentChar) { 18 | sb.append(prevCharacter).append(occurrenceCount) 19 | occurrenceCount = 0 20 | } 21 | prevCharacter = currentChar 22 | occurrenceCount += 1 23 | } 24 | sb.append(prevCharacter).append(occurrenceCount) 25 | val compressedString = sb.toString() 26 | return if (compressedString.length < str.length) return compressedString else str 27 | } 28 | -------------------------------------------------------------------------------- /src/arraysandstrings/StringRotation.kt: -------------------------------------------------------------------------------- 1 | package arraysandstrings 2 | 3 | import kotlin.test.assertTrue 4 | 5 | fun main() { 6 | assertTrue(isRotation("waterbottle", "erbottlewat")) 7 | } 8 | 9 | private fun isRotation(s1: String, s2: String): Boolean { 10 | val concat = s2 + s2 11 | return (concat.contains(s1)) 12 | } -------------------------------------------------------------------------------- /src/arraysandstrings/URLify.kt: -------------------------------------------------------------------------------- 1 | package arraysandstrings 2 | 3 | import kotlin.test.assertEquals 4 | 5 | fun main() { 6 | assertEquals("Mr%20John%20Smith", urlify("Mr John Smith ")) 7 | assertEquals(expected = "", actual = urlify(" ")) 8 | assertEquals("Prashant%20Barahi", urlify("Prashant Barahi ")) 9 | } 10 | 11 | private fun urlify(str: String): String { 12 | return str.split(" ").filter { it.isNotBlank() }.joinToString("%20") 13 | } 14 | -------------------------------------------------------------------------------- /src/arraysandstrings/UniqueCharacters.java: -------------------------------------------------------------------------------- 1 | package arraysandstrings; 2 | 3 | import java.util.Arrays; 4 | 5 | public class UniqueCharacters { 6 | 7 | public static void main(String[] args) { 8 | assert !hasUniqueCharacters("abca"); 9 | assert hasUniqueCharacters("abcd"); 10 | assert hasUniqueCharacters("1234567890qwertyuiopasdfghjklzxcvbnm"); 11 | 12 | assert !hasUniqueCharactersSort("abca"); 13 | assert hasUniqueCharactersSort("abcd"); 14 | assert hasUniqueCharactersSort("1234567890qwertyuiopasdfghjklzxcvbnm"); 15 | 16 | } 17 | 18 | private static boolean hasUniqueCharacters(String str) { 19 | long count = str.chars().distinct().count(); 20 | int actualSize = str.length(); 21 | return count == actualSize; 22 | } 23 | 24 | 25 | private static boolean hasUniqueCharactersSort(String str) { 26 | char[] contents = str.toCharArray(); 27 | Arrays.sort(contents); 28 | boolean[] store = new boolean[128]; 29 | for (int c : contents) { 30 | if (store[c]) { 31 | return false; 32 | } 33 | store[c] = true; 34 | } 35 | return true; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/bigo/PermutationCount.java: -------------------------------------------------------------------------------- 1 | package bigo; 2 | 3 | public class PermutationCount { 4 | public static void main(String[] args) { 5 | String str = "abc"; 6 | permutation(str, 0, str.length() - 1); 7 | } 8 | 9 | private static void permutation(String str, String prefix) { 10 | if (str.length() == 0) { 11 | System.out.println(prefix); 12 | } else { 13 | for (int i = 0; i < str.length(); i++) { 14 | String remainder = str.substring(0, i) + str.substring(i + 1); 15 | permutation(remainder, prefix + str.charAt(i)); 16 | } 17 | } 18 | } 19 | 20 | private static void permutation(String str, int l, int r) { 21 | if (l == r) { 22 | System.out.println(str); 23 | } 24 | for (int i = l; i <= r; i++) { 25 | String swapped = swap(str, l, i); 26 | permutation(swapped, l + 1, r); 27 | } 28 | } 29 | 30 | private static String swap(String str, int i, int j) { 31 | char[] arr = str.toCharArray(); 32 | char temp = arr[j]; 33 | arr[j] = arr[i]; 34 | arr[i] = temp; 35 | return String.valueOf(arr); 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/bigo/PowerOf2.java: -------------------------------------------------------------------------------- 1 | package bigo; 2 | 3 | 4 | public class PowerOf2 { 5 | public static void main(String[] args) { 6 | powerOf2(64); 7 | // powerOf2Easy(4); 8 | } 9 | 10 | static int powerOf2(int n) { 11 | if (n < 1) { 12 | return 0; 13 | } else if (n == 1) { 14 | return 1; 15 | } else { 16 | int prev = powerOf2(n / 2); 17 | int curr = prev * 2; 18 | System.out.println(curr); 19 | return curr; 20 | } 21 | } 22 | 23 | static void powerOf2Easy(int n) { 24 | for (int i = 1; i <= n; i++) { 25 | System.out.println((int) Math.pow(2, i)); 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/bits/BinaryToString.java: -------------------------------------------------------------------------------- 1 | package bits; 2 | 3 | /** 4 | * Given a real number between 0 & 1 (eg. 0.72) that is passed in as double, print the binary representation. 5 | * If # cannot be expressed in binary with at most 32 bits, then throw ERROR. 6 | */ 7 | class BinaryToString { 8 | public static void main(String[] args) { 9 | System.out.println(binary(0.04)); 10 | } 11 | 12 | 13 | static String binary(double num) { 14 | if (num > 1 && num < 0) { 15 | throw new RuntimeException("ERROR"); 16 | } 17 | StringBuilder b = new StringBuilder("."); 18 | while (num > 0) { 19 | // if (b.length() >= 32) { 20 | // throw new RuntimeException("ERROR"); 21 | // } 22 | double r = num * 2; 23 | if (r >= 1) { 24 | b.append(1); 25 | num = r - 1; 26 | } else { 27 | b.append(0); 28 | num = r; 29 | } 30 | } 31 | return b.toString(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/bits/Conversion.java: -------------------------------------------------------------------------------- 1 | package bits; 2 | 3 | /** 4 | * Number of bits you have to flip to convert bits A to bits B 5 | */ 6 | public class Conversion { 7 | public static void main(String[] args) { 8 | assert numberOfBitsToFlip((byte) 0b11101, (byte) 0b01111) == 2; 9 | assert numberOfBitsToFlip((byte) 0b001100, (byte) 0b000000) == 2; 10 | assert numberOfBitsToFlip((byte) 0b1, (byte) 0b1) == 0; 11 | assert numberOfBitsToFlip((byte) 0b11111, (byte) 0b00000) == 5; 12 | assert numberOfBitsToFlip((byte) 0b0, (byte) 0b0) == 0; 13 | 14 | } 15 | 16 | private static int numberOfBitsToFlip(byte a, byte b) { 17 | // xor = both same then 0 else 1 18 | byte xor = (byte) (a ^ b); 19 | // counting the number of 1s will give the number of flipping needed 20 | int countOfOnes = 0; 21 | 22 | System.out.println(Integer.toBinaryString(xor)); 23 | // Check for integer value of xor. Do this until xor = 0000000; 24 | while (xor != 0) { 25 | // a & 00001 to get the least significant bit 26 | int lsb = xor & 1; 27 | if (lsb == 1) { 28 | countOfOnes++; 29 | } 30 | 31 | // Shift the byte by 1 to the right 32 | xor = (byte) (xor >> 1); 33 | } 34 | System.out.println(countOfOnes); 35 | return countOfOnes; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/bits/Insertion.java: -------------------------------------------------------------------------------- 1 | package bits; 2 | 3 | 4 | import bits.commons.BitUtils; 5 | 6 | public class Insertion { 7 | public static void main(String[] args) { 8 | byte m = 0b1011; 9 | // 0b100(1011)00 10 | byte n = (byte) 0b101001100; 11 | int i = 2; 12 | int j = 6; 13 | 14 | // Clear all the bits in range i~j 15 | for (int k = 0; k < 10; k++) { 16 | if (k >= i && k < j) { 17 | n = BitUtils.clearBit(n, k); 18 | } 19 | } 20 | assert n == (byte) 0b101000000; 21 | 22 | // Shift the bits to be inserted by i so that we get 1011(00) 23 | byte shifted = (byte) (m << i); 24 | 25 | // n OR shifted will give result 26 | assert (n | shifted) == (byte) 0b101101100; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/bits/commons/BitUtils.java: -------------------------------------------------------------------------------- 1 | package bits.commons; 2 | 3 | public class BitUtils { 4 | public static byte clearBit(byte value, int position) { 5 | byte b = (byte) (1 << position); 6 | return (byte) (value & ~b); 7 | } 8 | 9 | public static byte setBit(byte value, int position) { 10 | byte b = (byte) (1 << position); 11 | return (byte) (value | b); 12 | } 13 | 14 | public static void main(String[] args) { 15 | assert clearBit((byte) 0b111111, 2) == 0b111011; 16 | assert clearBit((byte) 0b111111, 3) == 0b110111; 17 | assert clearBit((byte) 0b111111, 4) == 0b101111; 18 | 19 | assert setBit((byte) 0b000011, 4) == 0b010011; 20 | assert setBit((byte) 0b0000, 2) == 0b0100; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/dynamic/BooleanEvaluation.java: -------------------------------------------------------------------------------- 1 | package dynamic; 2 | 3 | public class BooleanEvaluation { 4 | 5 | public static void main(String[] args) { 6 | String s = "1^0|0|1"; 7 | System.out.println(countEval(s, false)); 8 | } 9 | 10 | private static int countEval(String s, boolean result) { 11 | if (s.length() == 0) return 0; 12 | if (s.length() == 1) { 13 | return s.equals("1") == result ? 1 : 0; 14 | } 15 | int ways = 0; 16 | for (int i = 1; i < s.length(); i = i + 2) { 17 | char operator = s.charAt(i); 18 | String left = s.substring(0, i); 19 | String right = s.substring(i + 1); 20 | 21 | int leftFalse = countEval(left, false); 22 | int rightFalse = countEval(right, false); 23 | int leftTrue = countEval(left, true); 24 | int rightTrue = countEval(right, true); 25 | int total = (leftTrue + leftFalse) * (rightFalse + rightTrue); 26 | 27 | int totalTrue = 0; 28 | if (operator == '^') { 29 | totalTrue = leftTrue * rightFalse + leftFalse * rightTrue; 30 | } else if (operator == '&') { 31 | totalTrue = leftTrue * rightTrue; 32 | } else if (operator == '|') { 33 | totalTrue = leftTrue * rightTrue + leftFalse * rightTrue + leftTrue * rightFalse; 34 | } 35 | 36 | int subways = result ? totalTrue : total - totalTrue; 37 | ways += subways; 38 | } 39 | return ways; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/dynamic/Coins.java: -------------------------------------------------------------------------------- 1 | package dynamic; 2 | 3 | public class Coins { 4 | public static void main(String[] args) { 5 | int[] coins = {25, 10, 5, 1}; 6 | int amount = 10; 7 | System.out.println(calculateChange(coins, amount, 0)); 8 | } 9 | 10 | private static int calculateChange(int[] coins, int amount, int index) { 11 | if (index >= coins.length - 1) return 1; 12 | int currentCoin = coins[index]; 13 | int ways = 0; 14 | for (int i = 0; i * currentCoin <= amount; i++) { 15 | int remaining = amount - (i * currentCoin); 16 | ways += calculateChange(coins, remaining, index + 1); 17 | } 18 | return ways; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/dynamic/PermutationWithDuplicates.java: -------------------------------------------------------------------------------- 1 | package dynamic; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * [Video](https://www.youtube.com/watch?v=JF4QrlUJItk) 7 | */ 8 | public class PermutationWithDuplicates { 9 | public static void main(String[] args) { 10 | List result = new ArrayList<>(); 11 | String str = "aabc"; 12 | 13 | Map map = calculateFrequency(str); 14 | 15 | printPerms(map, "", str.length(), result); 16 | System.out.println(Arrays.toString(result.toArray())); 17 | } 18 | 19 | private static Map calculateFrequency(String str) { 20 | Map map = new HashMap<>(); 21 | for (char c : str.toCharArray()) { 22 | if (!map.containsKey(c)) { 23 | map.put(c, 1); 24 | } else { 25 | map.put(c, map.get(c) + 1); 26 | } 27 | } 28 | return map; 29 | } 30 | 31 | 32 | private static void printPerms(Map map, String prefix, int remaining, List result) { 33 | if (remaining == 0) { 34 | result.add(prefix); 35 | return; 36 | } 37 | for (Character c : map.keySet()) { 38 | int count = map.get(c); 39 | if (count > 0) { 40 | map.put(c, count - 1); 41 | printPerms(map, prefix + c, remaining - 1, result); 42 | map.put(c, count); 43 | } 44 | } 45 | 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/dynamic/RecursiveMultiply.java: -------------------------------------------------------------------------------- 1 | package dynamic; 2 | 3 | /** 4 | * Multiply without using *. 5 | */ 6 | public class RecursiveMultiply { 7 | public static void main(String[] args) { 8 | assert multiply(10, 10) == 100; 9 | assert multiply(10, 0) == 0; 10 | assert multiply(11, 10) == 110; 11 | assert multiply(11, 11) == 121; 12 | assert multiply(1, 1) == 1; 13 | assert multiply(2, 2) == 4; 14 | } 15 | 16 | static int multiply(int val1, int val2) { 17 | int bigger = Math.max(val1, val2); 18 | int smaller = Math.min(val1, val2); 19 | if (smaller == 0) { 20 | return 0; 21 | } 22 | int sum = 0; 23 | boolean isEven = (smaller % 2 == 0); 24 | 25 | // 20,11 ==> 20 * (10 + 1) ==> 20 * (5 * 2 + 1) 26 | int numberOfLoops = isEven ? smaller / 2 : (smaller - 1) / 2; 27 | 28 | for (int i = 0; i < numberOfLoops; i++) { 29 | sum += bigger; 30 | } 31 | sum = sum << 1; 32 | if (!isEven) { 33 | sum = sum + bigger; 34 | } 35 | return sum; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/graphs/CheckBST.java: -------------------------------------------------------------------------------- 1 | package graphs; 2 | 3 | import graphs.commons.Tree; 4 | 5 | /** 6 | * left <= current < right 7 | */ 8 | class CheckBST { 9 | 10 | public static void main(String[] args) { 11 | 12 | Tree tree1 = new Tree(25); 13 | tree1.left = new Tree(20); 14 | tree1.left.left = new Tree(16); 15 | tree1.left.right = new Tree(22); 16 | tree1.right = new Tree(30); 17 | tree1.right.left = new Tree(29); 18 | tree1.right.right = new Tree(32); 19 | CheckBST bst = new CheckBST(); 20 | System.out.println(bst.checkBST(tree1, null, null)); 21 | 22 | Tree tree2 = new Tree(10); 23 | tree2.left = new Tree(22); 24 | tree2.right = new Tree(2); 25 | CheckBST bst2 = new CheckBST(); 26 | System.out.println(bst2.checkBST(tree2, null, null)); 27 | 28 | } 29 | 30 | boolean checkBST(Tree tree, Integer min, Integer max) { 31 | if (tree == null) 32 | return true; 33 | 34 | 35 | if((min != null && min > tree.data) || (max != null && max <= tree.data)) { 36 | return false; 37 | } 38 | 39 | // OR used so that both left & right gets checked; if one fails, then quit with false result 40 | if (!(checkBST(tree.left, min, tree.data)) || !(checkBST(tree.right, tree.data, max))) { 41 | return false; 42 | } 43 | return true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/graphs/CheckBalanced.java: -------------------------------------------------------------------------------- 1 | package graphs; 2 | 3 | import graphs.commons.Tree; 4 | 5 | class CheckBalanced { 6 | public static void main(String[] args) { 7 | final int[] array = new int[21]; 8 | for (int i = 0; i < array.length; i++) { 9 | array[i] = i; 10 | } 11 | // Generate binary tree 12 | final Tree binaryTree = MinimalTree.fromSortedArray(array); 13 | assert isBalanced(binaryTree); 14 | 15 | Tree notBinaryTree = new Tree(1); 16 | notBinaryTree.left = new Tree(2); 17 | notBinaryTree.left.left = new Tree(2); 18 | notBinaryTree.left.right = new Tree(2); 19 | notBinaryTree.left.left.left = new Tree(2); 20 | assert !isBalanced(notBinaryTree); 21 | 22 | } 23 | 24 | static int getHeight(Tree tree) { 25 | if (tree == null) { 26 | return 0; 27 | } 28 | // The height of a node at a level is the height of the node below it plus 1. 29 | // Binary tree has two leaves at most, so height of the deepest tree is counted 30 | return Math.max(getHeight(tree.left), getHeight(tree.right)) + 1; 31 | } 32 | 33 | static Boolean isBalanced(Tree tree) { 34 | return Math.abs(getHeight(tree.left) - getHeight(tree.right)) <= 1; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/graphs/ListOfDepth.java: -------------------------------------------------------------------------------- 1 | package graphs; 2 | 3 | import graphs.commons.Tree; 4 | 5 | import java.util.ArrayList; 6 | import java.util.LinkedList; 7 | import java.util.List; 8 | 9 | /** 10 | * Given a binary tree, design an algorithm which creates a linked list of all 11 | * the nodes at each depth (e.g., if you have a tree with depth D, you'll have D 12 | * linked lists). 13 | */ 14 | class ListOfDepth { 15 | public static void main(final String[] args) { 16 | final int[] array = new int[20]; 17 | for (int i = 0; i < array.length; i++) { 18 | array[i] = i; 19 | } 20 | // Generate binary tree 21 | final Tree binaryTree = MinimalTree.fromSortedArray(array); 22 | LinkedList current = new LinkedList<>(); 23 | final List> result = new ArrayList<>(); 24 | 25 | current.add(binaryTree); 26 | 27 | while (!current.isEmpty()) { 28 | result.add(current); 29 | final List parents = current; 30 | 31 | // At each level, load the children into current level's list 32 | current = new LinkedList<>(); 33 | for (final Tree t : parents) { 34 | if (t.left != null) 35 | current.add(t.left); 36 | 37 | if (t.right != null) 38 | current.add(t.right); 39 | } 40 | } 41 | for (final List list : result) { 42 | System.out.println("Size: " + list.size() + "; " + list); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/graphs/MinimalTree.java: -------------------------------------------------------------------------------- 1 | package graphs; 2 | 3 | import graphs.commons.Tree; 4 | 5 | /** 6 | * Given a sorted (increasing order) array with unique integer elements, write 7 | * an algorithm to create a binary search tree with minimal height. 8 | */ 9 | class MinimalTree { 10 | public static void main(String[] args) { 11 | int[] array = new int[10]; 12 | for (int i = 0; i < array.length; i++) { 13 | array[i] = i; 14 | } 15 | System.out.println(createMinimalTree(array, 0, array.length - 1)); 16 | } 17 | 18 | public static Tree fromSortedArray(int[] array) { 19 | return createMinimalTree(array, 0, array.length - 1); 20 | } 21 | 22 | private static Tree createMinimalTree(int[] array, int start, int end) { 23 | if (start > end) 24 | return null; 25 | int middle = (int) ((start + end) / 2); 26 | Tree tree = new Tree(array[middle]); 27 | tree.left = createMinimalTree(array, start, middle - 1); 28 | tree.right = createMinimalTree(array, middle + 1, end); 29 | return tree; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/graphs/PathWithSum.java: -------------------------------------------------------------------------------- 1 | package graphs; 2 | 3 | import graphs.commons.Tree; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | 9 | class PathWithSum { 10 | static int targetSum = 8; 11 | static int counter = 0; 12 | 13 | public static void main(String[] args) { 14 | Tree tree = new Tree(10); 15 | tree.left = new Tree(5); 16 | tree.left.left = new Tree(3); 17 | tree.left.right = new Tree(1); 18 | tree.left.right.right = new Tree(2); 19 | tree.left.left.left = new Tree(3); 20 | tree.left.left.right = new Tree(-2); 21 | tree.right = new Tree(-3); 22 | tree.right.right = new Tree(11); 23 | 24 | Map map = new HashMap<>(); 25 | dfsAndCollect(tree, map, 0); 26 | assert counter == 3; 27 | } 28 | 29 | static void dfsAndCollect(Tree tree, Map table, int level) { 30 | if (tree == null) 31 | return; 32 | System.out.print("level: " + level + " --> "); 33 | tree.printNode(); 34 | 35 | // At each level, get the sum of levels above it and add it to the current node 36 | table.put(level, table.getOrDefault(level - 1, 0) + tree.data); 37 | 38 | table.forEach((k, v) -> { 39 | // Cumulative sum - targetSum = value in table at previous indices, then there exists a pairs with sum 40 | if (k <= level && (table.get(level) - targetSum == v)) { 41 | System.out.print("Eureka! at level: " + level + " with node " ); 42 | tree.printNode(); 43 | counter++; 44 | } 45 | }); 46 | 47 | dfsAndCollect(tree.left, table, level + 1); 48 | dfsAndCollect(tree.right, table, level + 1); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/graphs/commons/BidirectionalTree.java: -------------------------------------------------------------------------------- 1 | package graphs.commons; 2 | 3 | public class BidirectionalTree { 4 | public BidirectionalTree parent; 5 | public BidirectionalTree left; 6 | public BidirectionalTree right; 7 | public Integer data; 8 | 9 | public BidirectionalTree(BidirectionalTree parent, Integer data) { 10 | this.parent = parent; 11 | this.data = data; 12 | } 13 | 14 | @Override 15 | public String toString() { 16 | return String.format("BidirectionalTree(%s)", data); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/graphs/commons/Graph.java: -------------------------------------------------------------------------------- 1 | package graphs.commons; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | public class Graph { 8 | public List vertices; 9 | 10 | public Graph() { 11 | vertices = new ArrayList<>(); 12 | } 13 | 14 | @Override 15 | public String toString() { 16 | return String.format("Graph(%s)", Arrays.toString(vertices.toArray())); 17 | } 18 | 19 | /** 20 | * The node in a graph 21 | */ 22 | public static class Vertex { 23 | public String value; 24 | public List edges = new ArrayList<>(); 25 | public State state = State.UNVISITED; 26 | 27 | public Vertex(String value) { 28 | this.value = value; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return String.format("Vertex(%s)", value); 34 | } 35 | } 36 | 37 | /** 38 | * The line between two nodes or vertices in graph 39 | */ 40 | public static class Edge { 41 | public Vertex start; 42 | public Vertex end; 43 | 44 | public Edge(Vertex start, Vertex end) { 45 | this.start = start; 46 | this.end = end; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return String.format("Edge(%s, %s)", start, end); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/graphs/commons/Node.java: -------------------------------------------------------------------------------- 1 | package graphs.commons; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Node { 7 | public int value; 8 | public List nodes; 9 | public State state; 10 | 11 | public Node(int value) { 12 | this.value = value; 13 | this.state = State.UNVISITED; 14 | nodes = new ArrayList<>(); 15 | } 16 | 17 | public Node deepCopy() { 18 | this.state = State.UNVISITED; 19 | for (Node n : this.nodes) { 20 | if (n.state != State.UNVISITED) { 21 | n.deepCopy(); 22 | } 23 | } 24 | return this; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/graphs/commons/State.java: -------------------------------------------------------------------------------- 1 | package graphs.commons; 2 | 3 | import _utils.SkipDocumentation; 4 | 5 | @SkipDocumentation 6 | 7 | public enum State { 8 | VISITED, VISITING, UNVISITED; 9 | } 10 | -------------------------------------------------------------------------------- /src/graphs/commons/Tree.java: -------------------------------------------------------------------------------- 1 | package graphs.commons; 2 | 3 | public class Tree { 4 | public Tree left; 5 | public Tree right; 6 | public Integer data; 7 | 8 | public Tree(Integer data) { 9 | this.data = data; 10 | } 11 | 12 | @Override 13 | public String toString() { 14 | return String.format("Node(%s, l=%s, r=%s)", data, left, right); 15 | } 16 | 17 | public void printNode() { 18 | System.out.println(String.format("Node(%s)", data)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/hard/AddWithoutPlus.java: -------------------------------------------------------------------------------- 1 | package hard; 2 | 3 | public class AddWithoutPlus { 4 | 5 | public static void main(String[] args) { 6 | System.out.println(add(759, 674)); 7 | } 8 | 9 | public static int add(int a, int b) { 10 | if (b == 0) return a; 11 | 12 | int sum = a ^ b; 13 | int carry = (a & b) << 1; 14 | 15 | return add(sum, carry); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/hard/RandomSet.java: -------------------------------------------------------------------------------- 1 | package hard; 2 | 3 | import java.util.Arrays; 4 | 5 | public class RandomSet { 6 | 7 | public static void main(String[] args) { 8 | int[] sets = new int[32]; 9 | for (int i = 0; i < sets.length; i++) { 10 | sets[i] = i; 11 | } 12 | pickMSubset(sets, 28); 13 | } 14 | 15 | private static void pickMSubset(int[] sets, int m) { 16 | int[] pick = new int[m]; 17 | 18 | for (int i = 0; i < pick.length; i++) { 19 | pick[i] = sets[i]; 20 | } 21 | 22 | for (int i = m; i < sets.length; i++) { 23 | int k = rand(0, i); 24 | if (k < m) { 25 | pick[k] = sets[i]; 26 | } 27 | } 28 | print(sets); 29 | print(pick); 30 | } 31 | 32 | private static void print(int[] pick) { 33 | System.out.println(Arrays.toString(pick)); 34 | } 35 | 36 | private static int rand(int low, int high) { 37 | return low + (int) (Math.random() * (high - low + 1)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/hard/Shuffle.java: -------------------------------------------------------------------------------- 1 | package hard; 2 | 3 | 4 | public class Shuffle { 5 | 6 | public static class Card { 7 | public String value; 8 | public String symbol; 9 | 10 | public Card(String value, String symbol) { 11 | this.value = value; 12 | this.symbol = symbol; 13 | } 14 | 15 | @Override 16 | public String toString() { 17 | return "Card{" + 18 | "value='" + value + '\'' + 19 | ", symbol='" + symbol + '\'' + 20 | '}'; 21 | } 22 | } 23 | 24 | public static void main(String[] args) { 25 | String[] values = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"}; 26 | String[] symbols = {"diamond", "spade", "tree", "hearts"}; 27 | Card[] cards = new Card[52]; 28 | for (int i = 0; i < values.length; i++) { 29 | for (int j = 0; j < symbols.length; j++) { 30 | cards[j + 4 * i] = new Card(values[i], symbols[j]); 31 | } 32 | } 33 | print(cards); 34 | 35 | shuffle(cards); 36 | } 37 | 38 | private static void shuffle(Card[] cards) { 39 | System.out.println("Shuffling..."); 40 | for (int i = 0; i < cards.length; i++) { 41 | int k = (int) (Math.random() * (i + 1)); 42 | Card temp = cards[k]; 43 | cards[k] = cards[i]; 44 | cards[i] = temp; 45 | } 46 | print(cards); 47 | } 48 | 49 | private static void print(Card[] cards) { 50 | for (Card card : cards) { 51 | System.out.println(card); 52 | } 53 | } 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/linkedlists/LinkedListDuplicate.kt: -------------------------------------------------------------------------------- 1 | package linkedlists 2 | 3 | import kotlin.test.assertFalse 4 | import kotlin.test.assertTrue 5 | 6 | 7 | fun main() { 8 | val list = LinkedList() 9 | list.addLast(Node(0)) 10 | list.addLast(Node(1)) 11 | list.addLast(Node(2)) 12 | list.addLast(Node(3)) 13 | list.addLast(Node(4)) 14 | assertFalse(list.hasDuplicates()) 15 | list.addLast(Node(1)) 16 | list.printAll() 17 | assertTrue(list.hasDuplicates()) 18 | list.subListFrom(2).also { 19 | println(it) 20 | assertTrue(it.isNotEmpty()) 21 | } 22 | list.subListFrom(100).also { 23 | println(it) 24 | assertTrue(it.isEmpty()) 25 | } 26 | 27 | list.deleteAt(2).also { 28 | assertTrue(it != null && it.value == 2) 29 | } 30 | list.printAll() 31 | 32 | list.deleteAt(100).also { 33 | assertTrue(it == null) 34 | } 35 | 36 | list.nodeAt(0).also { 37 | assertTrue(it != null && it.value == 0) 38 | } 39 | 40 | println("____REVERSE__") 41 | list.printAll() 42 | list.reverse().also { 43 | print("Reversed: ") 44 | it.printAll() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/linkedlists/SumLists.kt: -------------------------------------------------------------------------------- 1 | package linkedlists 2 | 3 | fun main() { 4 | val list1 = LinkedList() 5 | // 617 6 | list1.addLast(Node(7)) 7 | list1.addLast(Node(1)) 8 | list1.addLast(Node(6)) 9 | 10 | // 295 11 | val list2 = with(LinkedList()) { 12 | addLast(Node(5)) 13 | addLast(Node(9)) 14 | addLast(Node(2)) 15 | this 16 | } 17 | val result = LinkedList() 18 | addNode(list1.node, list2.node, carry = 0, result = result) 19 | result.printAll() 20 | } 21 | 22 | fun addNode(node1: Node?, node2: Node?, carry: Int, result: LinkedList) { 23 | if (node1 == null && node2 == null && carry == 0) { 24 | return 25 | } 26 | var value = carry 27 | if (node1 != null) { 28 | value += node1.value 29 | } 30 | if (node2 != null) { 31 | value += node2.value 32 | } 33 | val newNodeValue = value % 10 34 | val newCarry = value / 10 35 | result.addLast(Node(newNodeValue)) 36 | addNode(node1?.next, node2?.next, newCarry, result) 37 | 38 | } -------------------------------------------------------------------------------- /src/questions/AddStrings.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import kotlin.math.max 4 | import kotlin.test.assertEquals 5 | 6 | /** 7 | * Given two non-negative integers, num1 and num2 represented as string, return the sum of num1 and num2 as a string. 8 | * You must solve the problem without using any built-in library for handling large integers (such as BigInteger). 9 | * You must also not convert the inputs to integers directly. 10 | * 11 | * [Source](https://leetcode.com/problems/add-strings/) 12 | */ 13 | fun addStrings(num1: String, num2: String): String { 14 | val length = max(num1.length, num2.length) 15 | val num1_ = num1.padStart(length, '0') 16 | val num2_ = num2.padStart(length, '0') 17 | var result = "" 18 | var hasCarry = false 19 | for (i in length - 1 downTo 0) { 20 | // GOTCHA: DON'T USE toInt() as it returns char's ASCII value 21 | val sum = (Character.getNumericValue(num1_[i]) + Character.getNumericValue(num2_[i]) + if (hasCarry) 1 else 0) 22 | 23 | hasCarry = sum > 9 24 | result = if (hasCarry) { 25 | (sum % 10).toString() + result 26 | } else { 27 | sum.toString() + result 28 | } 29 | } 30 | // Remaining carry over 31 | if (hasCarry) { 32 | result = "1$result" 33 | } 34 | return result 35 | } 36 | 37 | fun main() { 38 | assertEquals("10", addStrings(num1 = "1", num2 = "9")) 39 | assertEquals("134", addStrings(num1 = "11", num2 = "123")) 40 | assertEquals("533", addStrings(num1 = "456", num2 = "77")) 41 | assertEquals("0", addStrings(num1 = "0", num2 = "0")) 42 | } -------------------------------------------------------------------------------- /src/questions/ArrangingCoins.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * You have `n` coins and you want to build a staircase with these coins. 8 | * The staircase consists of `k` rows where the `i`th row has exactly `i` coins. 9 | * The last row of the staircase may be incomplete. 10 | * Given the integer n, return the number of complete rows of the staircase you will build. 11 | * 12 | * [Source](https://leetcode.com/problems/arranging-coins/) 13 | */ 14 | @UseCommentAsDocumentation 15 | private fun arrangeCoins(n: Int): Int { 16 | if (n == 1) return 1 17 | var temp = n 18 | var col = 0 19 | while (temp > 0) { 20 | col++ 21 | temp -= col // load [col] number of coins on each column 22 | } 23 | var result = col 24 | 25 | // [temp] is -ve if last column remains unfilled 26 | // to fill this last column you can remove coins from last row and fill it 27 | // this will decrease the number of complete rows by 1 28 | if (temp < 0) { 29 | result-- 30 | } 31 | return result 32 | 33 | } 34 | 35 | fun main() { 36 | arrangeCoins(2) shouldBe 1 37 | arrangeCoins(1) shouldBe 1 38 | arrangeCoins(5) shouldBe 2 39 | arrangeCoins(8) shouldBe 3 40 | } -------------------------------------------------------------------------------- /src/questions/ArrayPartitionI.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given an integer array nums of 2n integers, group these integers into n pairs (a1, b1), (a2, b2), ..., (an, bn) 8 | * such that the sum of min(ai, bi) for all i is maximized. Return the maximized sum. 9 | * [Source](https://leetcode.com/problems/array-partition-i/) 10 | */ 11 | @UseCommentAsDocumentation 12 | private fun arrayPairSum(nums: IntArray): Int { 13 | nums.sort() // SORT 14 | var result = 0 15 | // pair max with maximum and min with other min 16 | for (i in 0 until nums.size / 2) { 17 | result += minOf(nums[2 * i], nums[2 * i + 1]) 18 | } 19 | return result 20 | } 21 | 22 | fun main() { 23 | // min(1, 2) + min(3, 4) = 1 + 3 = 4 24 | arrayPairSum(intArrayOf(1, 4, 3, 2)) shouldBe 4 25 | 26 | // The optimal pairing is (2, 1), (2, 5), (6, 6). min(2, 1) + min(2, 5) + min(6, 6) = 1 + 2 + 6 = 9. 27 | arrayPairSum(intArrayOf(6, 2, 6, 5, 1, 2)) shouldBe 9 28 | } -------------------------------------------------------------------------------- /src/questions/BSTFromPreorder.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import questions.common.TreeNode 5 | import kotlin.test.assertTrue 6 | 7 | /** 8 | * Given an array of integers preorder, which represents the preorder traversal of a BST (i.e., binary search tree), 9 | * construct the tree and return its root. 10 | * A preorder traversal of a binary tree displays the value of the node first, 11 | * then traverses `Node.left`, then traverses `Node.right`. 12 | * 13 | * [Source](https://leetcode.com/problems/construct-binary-search-tree-from-preorder-traversal/) 14 | */ 15 | @UseCommentAsDocumentation 16 | private fun bstFromPreorder(preorder: IntArray): TreeNode? { 17 | val node = TreeNode(preorder[0]) 18 | for (i in 1..preorder.lastIndex) { 19 | addToBST(node, preorder[i]) 20 | } 21 | return node 22 | } 23 | 24 | private fun addToBST(root: TreeNode, value: Int) { 25 | if (value < root.`val`) { 26 | if (root.left == null) { 27 | root.left = TreeNode(value) 28 | } else { 29 | addToBST(root.left!!, value) 30 | } 31 | } else if (value > root.`val`) { 32 | if (root.right == null) { 33 | root.right = TreeNode(value) 34 | } else { 35 | addToBST(root.right!!, value) 36 | } 37 | } 38 | } 39 | 40 | fun main() { 41 | run { 42 | assertTrue { 43 | // https://assets.leetcode.com/uploads/2019/03/06/1266.png 44 | val actual = bstFromPreorder(intArrayOf(8, 5, 1, 7, 10, 12))!! 45 | val expected = TreeNode.from(arrayOf(8, 5, 10, 1, 7, null, 12))!! 46 | actual.isSameAs(expected) 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/questions/BestTimeStock.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | import java.util.* 6 | 7 | /** 8 | * You are given an array prices where `prices[i]` is the price of a given stock on the ith day. 9 | * You want to maximize your profit by choosing a single day to buy one stock 10 | * and choosing a different day in the future to sell that stock. 11 | * Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return 0. 12 | * 13 | * [Source](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/) 14 | * @see [BestTimeStockII] 15 | */ 16 | @UseCommentAsDocumentation 17 | private object BestTimeStock 18 | 19 | private fun maxProfit(prices: IntArray): Int { 20 | val maxPossibleSellPrice = Array(prices.size) { -1 } 21 | for (index in prices.lastIndex downTo 0) { 22 | // find the max sell price possible by filling in from the end 23 | // comparing max price in future and current price 24 | // for [3, 2, 6, 5, 0, 3] -> [6, 6, 6, 5, 3, 3] 25 | maxPossibleSellPrice[index] = 26 | maxOf(maxPossibleSellPrice.getOrNull(index + 1) ?: -1, prices[index]) 27 | } 28 | 29 | var result = 0 30 | for (index in 0..prices.lastIndex) { 31 | val sellPrice = maxPossibleSellPrice[index] 32 | result = maxOf(sellPrice - prices[index], result) 33 | } 34 | return result 35 | } 36 | 37 | fun main() { 38 | maxProfit(intArrayOf(3, 2, 6, 5, 0, 3)) shouldBe 4 39 | maxProfit(intArrayOf(7, 1, 5, 3, 6, 4)) shouldBe 5 40 | maxProfit(intArrayOf(7, 6, 4, 3, 1)) shouldBe 0 41 | } -------------------------------------------------------------------------------- /src/questions/ClimbingStairs.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * You are climbing a staircase. It takes n steps to reach the top. 8 | * Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? 9 | * [Source](https://leetcode.com/problems/climbing-stairs/) 10 | */ 11 | @UseCommentAsDocumentation 12 | private fun climbStairs(n: Int): Int { 13 | val memo = Array(n + 1) { null } 14 | return climbStairs(n, memo) 15 | } 16 | 17 | private fun climbStairs(n: Int, memo: Array): Int { 18 | if (n <= 0) return 0 19 | if (n == 1) return 1 20 | if (n == 2) return 2 21 | val memoized = memo[n] 22 | if (memoized != null) { 23 | return memoized 24 | } 25 | val value = climbStairs(n - 1, memo) + climbStairs(n - 2, memo) 26 | memo[n] = value 27 | return value 28 | } 29 | 30 | 31 | fun main() { 32 | climbStairs(44) 33 | // 1 step + 1 step 34 | // 2 steps 35 | climbStairs(n = 2) shouldBe 2 36 | 37 | // 1 step +1 step +1 step 38 | // 1 step +2 steps 39 | // 2 steps +1 step 40 | climbStairs(n = 3) shouldBe 3 41 | 42 | } -------------------------------------------------------------------------------- /src/questions/ContainsDuplicate.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | 4 | import _utils.UseCommentAsDocumentation 5 | import utils.shouldBe 6 | 7 | /** 8 | * Given an integer array nums, return true if any value appears at least twice in the array, 9 | * and return false if every element is distinct. 10 | * [Source](https://leetcode.com/problems/contains-duplicate/) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun containsDuplicate(nums: IntArray): Boolean { 14 | if (nums.size == 1) { 15 | return false 16 | } 17 | val set = HashSet(nums.size) 18 | nums.forEach { 19 | if (set.contains(it)) { 20 | return true 21 | } 22 | set.add(it) 23 | } 24 | return false 25 | } 26 | 27 | private fun containsDuplicateFunc(nums: IntArray): Boolean { 28 | return nums.size != nums.distinct().size 29 | } 30 | 31 | fun main() { 32 | containsDuplicate(nums = intArrayOf(1, 2, 3, 1)) shouldBe true 33 | containsDuplicateFunc(nums = intArrayOf(1, 2, 3, 1)) shouldBe true 34 | 35 | containsDuplicate(nums = intArrayOf(1, 2, 3, 4)) shouldBe false 36 | containsDuplicateFunc(nums = intArrayOf(1, 2, 3, 4)) shouldBe false 37 | 38 | containsDuplicate(nums = intArrayOf(1, 1, 1, 3, 3, 4, 3, 2, 4, 2)) shouldBe true 39 | containsDuplicateFunc(nums = intArrayOf(1, 1, 1, 3, 3, 4, 3, 2, 4, 2)) shouldBe true 40 | } -------------------------------------------------------------------------------- /src/questions/ContainsDuplicateII.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given an integer array nums and an integer k, return true if there are two distinct indices i and j 8 | * in the array such that `nums[i] == nums[j]` and `abs(i - j) <= k`. 9 | * 10 | * [Source](https://leetcode.com/problems/contains-duplicate-ii/) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun containsNearbyDuplicate(nums: IntArray, k: Int): Boolean { 14 | // How about using hash set instead of window 15 | val hashSet = LinkedHashSet() 16 | for (i in 0..nums.lastIndex) { 17 | if (i > k) { // now start removing items 18 | // remove that element which is out of the window of width [k] 19 | val elemToBeRemoved = nums[i - (k + 1)] 20 | hashSet.remove(elemToBeRemoved) 21 | } 22 | 23 | val current = nums[i] 24 | // if the current window contains that element, then duplicate present 25 | if (hashSet.contains(current)) { 26 | return true 27 | } 28 | hashSet.add(current) 29 | } 30 | return false 31 | } 32 | 33 | fun main() { 34 | containsNearbyDuplicate(nums = intArrayOf(1, 2, 3, 9, 5, 6, 2), k = 3) shouldBe false 35 | containsNearbyDuplicate(nums = intArrayOf(1, 2, 3, 1), k = 3) shouldBe true 36 | containsNearbyDuplicate(nums = intArrayOf(1, 0, 1, 1), k = 1) shouldBe true 37 | containsNearbyDuplicate(nums = intArrayOf(1, 2, 3, 1, 2, 3), k = 2) shouldBe false 38 | containsNearbyDuplicate(nums = intArrayOf(1, 2, 3, 4, 1), k = 3) shouldBe false 39 | } -------------------------------------------------------------------------------- /src/questions/ConvertToHex.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given an integer num, return a string representing its hexadecimal representation. 8 | * For negative integers, two’s complement method is used. 9 | * All the letters in the answer string should be lowercase characters, 10 | * and there should not be any leading zeros in the answer except for the zero itself. 11 | * [Source](https://leetcode.com/problems/convert-a-number-to-hexadecimal/) – [solution](https://leetcode.com/problems/convert-a-number-to-hexadecimal/discuss/824192/Java-100-Time-with-Detailed-Explanation) 12 | */ 13 | @UseCommentAsDocumentation 14 | private fun toHex(num: Int): String { 15 | if (num in 0..9) { 16 | return "$num" 17 | } 18 | val hexMap = mapOf( 19 | 10 to 'a', 20 | 11 to 'b', 21 | 12 to 'c', 22 | 13 to 'd', 23 | 14 to 'e', 24 | 15 to 'f' 25 | ) 26 | var temp = num 27 | 28 | var result = "" 29 | for (i in 1..8) { 30 | if (temp == 0) { 31 | break 32 | } 33 | val last4bits = temp.and(0b1111) 34 | if (last4bits <= 9) { 35 | result = last4bits.toString() + result 36 | } else { 37 | result = hexMap[last4bits].toString() + result 38 | } 39 | temp = temp.shr(4) 40 | } 41 | return result 42 | } 43 | 44 | fun main() { 45 | toHex(26) shouldBe "1a" 46 | toHex(27) shouldBe "1b" 47 | toHex(10) shouldBe "a" 48 | toHex(1) shouldBe "1" 49 | toHex(-1) shouldBe "ffffffff" 50 | } -------------------------------------------------------------------------------- /src/questions/CountCompleteTreeNode.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import questions.common.TreeNode 5 | import utils.shouldBe 6 | import java.util.* 7 | 8 | /** 9 | * Given the root of a complete binary tree, return the number of the nodes in the tree. 10 | * Every level, except possibly the last, is completely filled in a complete binary tree, 11 | * and all nodes in the last level are as far left as possible. 12 | * It can have between 1 and 2h nodes inclusive at the last level h. 13 | * [Source](https://leetcode.com/problems/count-complete-tree-nodes/) 14 | */ 15 | @UseCommentAsDocumentation 16 | private fun countNodes(root: TreeNode?): Int { 17 | if (root == null) return 0 18 | return breadthFirstTraversal(root) 19 | } 20 | 21 | private fun breadthFirstTraversal(root: TreeNode?): Int { 22 | if (root == null) { 23 | return 0 24 | } 25 | val queue: Queue = LinkedList() 26 | queue.add(root) 27 | var count = 1 28 | while (queue.isNotEmpty()) { 29 | val first = queue.remove() 30 | if (first.left != null) { 31 | queue.add(first.left) 32 | count++ 33 | } 34 | if (first.right != null) { 35 | queue.add(first.right) 36 | count++ 37 | } 38 | } 39 | return count 40 | } 41 | 42 | fun main() { 43 | countNodes(TreeNode.from(1, 2, 3, 4, 5, 6)) shouldBe 6 44 | countNodes(TreeNode.from(1)) shouldBe 1 45 | } -------------------------------------------------------------------------------- /src/questions/CountingBits.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given an integer `n`, return an array `ans` of length `n + 1` such that for each `i` (0 <= i <= n), 8 | * `ans[i]` is the number of 1's in the binary representation of `i`. 9 | * 10 | * [Source](https://leetcode.com/problems/counting-bits/) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun countBits(n: Int): IntArray { 14 | val ans = IntArray(n + 1) { 0 } 15 | (0..n).forEach { 16 | ans[it] = countBitsOnDigit(it) 17 | } 18 | return ans 19 | } 20 | 21 | private fun countBitsOnDigit(n: Int): Int { 22 | var count = 0 23 | var num = n 24 | while (num != 0) { 25 | if (num.and(1) == 1) count++ // get LSB 26 | num = num.shr(1) 27 | } 28 | return count 29 | } 30 | 31 | fun main() { 32 | // 0 --> 0 33 | // 1 --> 1 34 | // 2 --> 10 35 | countBits(n = 2) shouldBe intArrayOf(0, 1, 1) 36 | 37 | // 0 --> 0 38 | // 1 --> 1 39 | // 2 --> 10 40 | // 3 --> 11 41 | // 4 --> 100 42 | // 5 --> 101 43 | countBits(n = 5) shouldBe intArrayOf(0, 1, 1, 2, 1, 2) 44 | } -------------------------------------------------------------------------------- /src/questions/CustomSortString.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * You are given two strings order and s. All the words of order are unique 8 | * and were sorted in some custom order previously. 9 | * Permute the characters of s so that they match the order that order was sorted. 10 | * More specifically, if a character x occurs before a character y in order, 11 | * then x should occur before y in the permuted string. 12 | * 13 | * Return any permutation of s that satisfies this property. 14 | * 15 | * [Source](https://leetcode.com/problems/custom-sort-string-kt/) 16 | */ 17 | @UseCommentAsDocumentation 18 | private fun customSortString(order: String, s: String): String { 19 | val countMap: MutableMap = s.groupingBy { it }.eachCount().toMutableMap() 20 | 21 | val sb = StringBuilder() 22 | for (i in order) { 23 | if (countMap.contains(i)) { 24 | sb.append(i.toString().repeat(countMap[i]!!)) 25 | countMap.remove(i) 26 | } 27 | } 28 | countMap.forEach { (key, count) -> 29 | sb.append(key.toString().repeat(count)) 30 | } 31 | return sb.toString() 32 | } 33 | 34 | fun main() { 35 | customSortString(order = "cba", s = "abcd") shouldBe "cbad" 36 | customSortString(order = "cbafg", s = "abcd") shouldBe "cbad" 37 | } -------------------------------------------------------------------------------- /src/questions/DayOfTheYear.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given a string date representing a Gregorian calendar date formatted as YYYY-MM-DD, return the day number of the year. 8 | * 9 | * [Source](https://leetcode.com/problems/day-of-the-year/) 10 | */ 11 | @UseCommentAsDocumentation 12 | private fun dayOfYear(date: String): Int { 13 | // https://en.wikipedia.org/wiki/Month#/media/File:Month_-_Knuckles_(en).svg 14 | val numberOfDaysArr = intArrayOf(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) 15 | val (year, month, day) = date.split('-').map { it.toInt() } 16 | 17 | // https://docs.microsoft.com/en-us/office/troubleshoot/excel/determine-a-leap-year 18 | // year evenly divisible by 100 must also be divisible by 400 19 | val isLeapYear = if (year % 100 == 0) year % 400 == 0 else year % 4 == 0 20 | 21 | if (isLeapYear) numberOfDaysArr[1] = 29 22 | var result = 0 23 | for (i in 1 until month) { 24 | result += numberOfDaysArr[i - 1] 25 | } 26 | result += day 27 | return result 28 | } 29 | 30 | fun main() { 31 | dayOfYear("1900-05-02") shouldBe 122 32 | dayOfYear("2019-01-09") shouldBe 9 33 | dayOfYear("2019-02-10") shouldBe 41 34 | } -------------------------------------------------------------------------------- /src/questions/DiameterOfBinaryTree.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import questions.common.TreeNode 5 | import utils.shouldBe 6 | 7 | /** 8 | * Given the root of a binary tree, return the length of the diameter of the tree. 9 | * The diameter of a binary tree is the length of the longest path between any two nodes in a tree. 10 | * This path may or may not pass through the root. 11 | * 12 | * [Source](https://leetcode.com/problems/diameter-of-binary-tree/) – [solution](https://leetcode.com/problems/diameter-of-binary-tree/discuss/101132/Java-Solution-MaxDepth) 13 | */ 14 | @UseCommentAsDocumentation 15 | private object DiameterOfBinaryTree { 16 | private var currentMax = 0 17 | 18 | fun diameterOfBinaryTree(root: TreeNode?): Int { 19 | maxDepth(root) 20 | return currentMax 21 | } 22 | 23 | 24 | private fun maxDepth(root: TreeNode?): Int { 25 | if (root == null) return 0 26 | val left = maxDepth(root.left) 27 | println("left ${root.left?.`val`} height:$left") 28 | val right = maxDepth(root.right) 29 | println("right ${root.right?.`val`} height:$right") 30 | currentMax = maxOf(currentMax, left + right) 31 | return 1 + maxOf(left, right) 32 | } 33 | 34 | } 35 | 36 | fun main() { 37 | // 1 38 | // 2 3 39 | // 4 5 40 | DiameterOfBinaryTree.diameterOfBinaryTree(TreeNode.from(1, 2, 3, 4, 5)) shouldBe 3 41 | } -------------------------------------------------------------------------------- /src/questions/ExcelSheetColumnTitle.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given an integer columnNumber, return its corresponding column title as it appears in an Excel sheet. 8 | * `A -> 1, B -> 2, C -> 3, Z -> 26, AA -> 27, AB -> 28` 9 | * 10 | * [Source](https://leetcode.com/problems/excel-sheet-column-title/) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun convertToTitle(columnNumber: Int): String { 14 | val characters = CharArray(26) { 15 | (it + 65).toChar() 16 | } 17 | if (columnNumber <= 26) { 18 | return characters[columnNumber - 1].toString() 19 | } 20 | 21 | var remaining = columnNumber 22 | var result = "" 23 | while (remaining > 0) { 24 | result += characters[(remaining - 1) % 26] 25 | remaining = (remaining - 1) / 26 26 | } 27 | return result.reversed() 28 | } 29 | 30 | fun main() { 31 | convertToTitle(columnNumber = 1) shouldBe "A" 32 | convertToTitle(columnNumber = 28) shouldBe "AB" 33 | convertToTitle(columnNumber = 701) shouldBe "ZY" 34 | convertToTitle(columnNumber = 702) shouldBe "ZZ" 35 | convertToTitle(columnNumber = 2147483647) shouldBe "FXSHRXW" 36 | } -------------------------------------------------------------------------------- /src/questions/FindTheDifference.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import kotlin.test.assertEquals 5 | 6 | /** 7 | * You are given two strings s and t. 8 | * String t is generated by random shuffling string s and then add one more letter at a random position. 9 | * Return the letter that was added to t. 10 | * 11 | * [Source](https://leetcode.com/problems/find-the-difference/) 12 | */ 13 | @UseCommentAsDocumentation 14 | private fun findTheDifference(s: String, t: String): Char { 15 | val record = mutableMapOf() 16 | for (i in s) { 17 | record[i] = (record[i] ?: 0) + 1 18 | } 19 | for (i in t) { 20 | if (!record.containsKey(i)) { 21 | // Found the newly added letter 22 | return i 23 | } 24 | record[i] = record[i]!! - 1 25 | if (record[i] == 0) { 26 | // remove if count == 0 27 | record.remove(i) 28 | } 29 | } 30 | // The matching letters were removed from the map so the key that remains is the answer 31 | return record.keys.first() 32 | } 33 | 34 | fun main() { 35 | assertEquals('e', findTheDifference(s = "abcd", t = "abcde")) 36 | assertEquals('y', findTheDifference(s = "", t = "y")) 37 | assertEquals('a', findTheDifference(s = "a", t = "aa")) 38 | } -------------------------------------------------------------------------------- /src/questions/FirstUniqueCharacter.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given a string s, find the first non-repeating character in it and return its index. If it does not exist, return -1. 8 | * [Source](https://leetcode.com/problems/first-unique-character-kt/) 9 | */ 10 | @UseCommentAsDocumentation 11 | fun firstUniqChar(s: String): Int { 12 | val orderedMap = LinkedHashMap() // char to its index map 13 | val removedSet = mutableSetOf() 14 | for (i in 0..s.lastIndex) { 15 | val char = s[i] 16 | if (removedSet.contains(char)) { 17 | continue 18 | } 19 | val index = orderedMap[char] 20 | if (index != null) { 21 | // [char] is not unique 22 | removedSet.add(char) 23 | orderedMap.remove(char) 24 | } else { 25 | // [char] has not been seen before 26 | orderedMap[char] = i 27 | } 28 | } 29 | val firstKey = orderedMap.keys.firstOrNull() ?: return -1 30 | return orderedMap[firstKey] ?: -1 // since [orderedMap] is well... ordered, the answer will be on first key 31 | } 32 | 33 | fun main() { 34 | firstUniqChar(s = "loveleetcode") shouldBe 2 35 | firstUniqChar(s = "leetcode") shouldBe 0 36 | firstUniqChar(s = "aabb") shouldBe -1 37 | } -------------------------------------------------------------------------------- /src/questions/HammingDistance.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * The Hamming distance between two integers is the number of positions at which the corresponding bits are different. 8 | * Given two integers x and y, return the Hamming distance between them. 9 | * [Source](https://leetcode.com/problems/hamming-distance/) 10 | */ 11 | @UseCommentAsDocumentation 12 | private fun hammingDistance(x: Int, y: Int): Int { 13 | var diff = x.xor(y) // xor = 1 when different else 0 14 | if (diff == 0) return 0 // both are same 15 | var count = 0 16 | while (diff > 0) { 17 | if (diff.and(1) == 1) { // diff AND 1 gives LSB 18 | count++ // count all LSB 19 | } 20 | diff = diff.shr(1) // shift [diff] right 21 | } 22 | return count 23 | } 24 | 25 | fun main() { 26 | hammingDistance(x = 1, y = 4) shouldBe 2 27 | hammingDistance(x = 3, y = 1) shouldBe 1 28 | } -------------------------------------------------------------------------------- /src/questions/HappyNumber.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import kotlin.test.assertFalse 5 | import kotlin.test.assertTrue 6 | 7 | /** 8 | * Write an algorithm to determine if a number n is happy. 9 | * A happy number is a number defined by the following process: 10 | * * Starting with any positive integer, replace the number by the sum of the squares of its digits. 11 | * Repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. 12 | * Those numbers for which this process ends in 1 are happy. 13 | * 14 | * [Source](https://leetcode.com/problems/happy-number) 15 | */ 16 | @UseCommentAsDocumentation 17 | private fun isHappy(n: Int): Boolean { 18 | if (n == 1) return true 19 | var digit = n 20 | val seen = mutableSetOf() 21 | while (digit != 1) { 22 | digit = sumOfSquareDigits(digit.toString()) 23 | if (digit == 1) { 24 | return true 25 | } else if (seen.contains(digit)) { 26 | return false 27 | } 28 | seen.add(digit) 29 | } 30 | return false 31 | } 32 | 33 | private fun sumOfSquareDigits(n: String): Int { 34 | var result = 0 35 | for (i in n) { 36 | val numericValue = Character.getNumericValue(i) 37 | result += numericValue * numericValue 38 | } 39 | return result 40 | } 41 | 42 | fun main() { 43 | assertTrue(isHappy(1)) 44 | 45 | // For 19: 46 | // 12 + 92 = 82 47 | //82 + 22 = 68 48 | //62 + 82 = 100 49 | //12 + 02 + 02 = 1 50 | assertTrue(isHappy(19)) 51 | 52 | assertFalse(isHappy(2)) 53 | } -------------------------------------------------------------------------------- /src/questions/IntersectionOfTwoArrays.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBeOneOf 5 | 6 | /** 7 | * Given two integer arrays nums1 and nums2, return an array of their intersection. 8 | * Each element in the result must be unique and you may return the result in any order. 9 | * 10 | * [Source](https://leetcode.com/problems/intersection-of-two-arrays/) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun intersection(nums1: IntArray, nums2: IntArray): IntArray { 14 | val result = mutableSetOf() 15 | val larger = if (nums1.size >= nums2.size) nums1 else nums2 16 | val smaller = if (larger === nums1) nums2 else nums1 17 | val positionMap = mutableMapOf>() 18 | smaller.forEachIndexed { index, i -> 19 | positionMap[i] = positionMap.getOrDefault(i, mutableListOf()).also { 20 | it.add(index) 21 | } 22 | } 23 | for (i in 0..larger.lastIndex) { 24 | val currentVal = larger[i] 25 | positionMap[currentVal]?.let { result.add(currentVal) } 26 | } 27 | return result.toIntArray() 28 | } 29 | 30 | 31 | fun main() { 32 | intersection(intArrayOf(1, 2), nums2 = intArrayOf(2, 1)) shouldBeOneOf listOf(intArrayOf(1, 2), intArrayOf(2, 1)) 33 | intersection(intArrayOf(1, 2, 2, 1), nums2 = intArrayOf(2, 2)) shouldBeOneOf listOf(intArrayOf(2)) 34 | intersection(intArrayOf(4, 9, 5), nums2 = intArrayOf(9, 4, 9, 8, 4)) shouldBeOneOf listOf( 35 | intArrayOf(9, 4), 36 | intArrayOf(4, 9) 37 | ) 38 | } -------------------------------------------------------------------------------- /src/questions/IsSubsequence.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given two strings s and t, return true if s is a subsequence of t, or false otherwise. 8 | * A subsequence of a string is a new string that is formed from the original string by deleting some (can be none) 9 | * of the characters without disturbing the relative positions of the remaining characters. 10 | * [Source](https://leetcode.com/problems/is-subsequence/) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun isSubsequence(s: String, t: String): Boolean { 14 | if (s.isEmpty()) return true 15 | val tBuilder = StringBuilder(t) 16 | var tIndex = 0 17 | for (i in 0..s.lastIndex) { 18 | val index = tBuilder.indexOf(s[i], tIndex) // try to find index in remaining substring 19 | if (index == -1) { 20 | return false 21 | } 22 | tIndex = index + 1 23 | } 24 | return true 25 | } 26 | 27 | fun main() { 28 | isSubsequence(s = "aaaaaa", t = "bbaaaa") shouldBe false 29 | isSubsequence(s = "ab", t = "baab") shouldBe true 30 | isSubsequence(s = "acb", t = "ahbgdc") shouldBe false 31 | isSubsequence(s = "ltc", t = "leetcode") shouldBe true 32 | isSubsequence(s = "ltf", t = "leetcode") shouldBe false 33 | isSubsequence(s = "abc", t = "ahbgdc") shouldBe true 34 | isSubsequence(s = "axc", t = "ahbgdc") shouldBe false 35 | } -------------------------------------------------------------------------------- /src/questions/IsomorphicStrings.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import kotlin.test.assertFalse 5 | import kotlin.test.assertTrue 6 | 7 | /** 8 | * Given two strings s and t, determine if they are isomorphic. 9 | * Two strings s and t are isomorphic if the characters in s can be replaced to get t. 10 | * 11 | * All occurrences of a character must be replaced with another character while preserving the order of characters. 12 | * No two characters may map to the same character, but a character may map to itself. 13 | * 14 | * [Source](https://leetcode.com/problems/isomorphic-strings/) 15 | */ 16 | @UseCommentAsDocumentation 17 | fun isIsomorphic(s: String, t: String): Boolean { 18 | val translateMap = mutableMapOf() 19 | val seen = mutableSetOf() 20 | for (i in 0..s.lastIndex) { 21 | val left = translateMap[s[i]] 22 | 23 | // Already seen value in s should be equal in t 24 | if (left != null && left != t[i]) { 25 | return false 26 | } 27 | // badc -> baba 28 | // d has no mapping but b is already mapped. That's why see if b is already "seen" 29 | if (seen.contains(t[i]) && !translateMap.containsKey(s[i])) { 30 | return false 31 | } 32 | seen.add(t[i]) 33 | translateMap[s[i]] = t[i] 34 | } 35 | return true 36 | } 37 | 38 | fun main() { 39 | assertTrue(isIsomorphic(s = "paper", t = "title")) 40 | assertFalse(isIsomorphic(s = "badc", t = "baba")) 41 | assertTrue(isIsomorphic(s = "egg", t = "add")) 42 | assertFalse(isIsomorphic(s = "foo", t = "bar")) 43 | } -------------------------------------------------------------------------------- /src/questions/KeyboardRow.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | 4 | import _utils.UseCommentAsDocumentation 5 | import utils.shouldBe 6 | 7 | /** 8 | * Given an array of strings words, return the words that can be typed 9 | * using letters of the alphabet on only one row of American keyboard. 10 | * [Source](https://leetcode.com/problems/keyboard-row/) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun findWords(words: Array): Array { 14 | val result = ArrayList(words.size) 15 | val rows = arrayOf("qwertyuiop", "asdfghjkl", "zxcvbnm") 16 | val charIndexMap = HashMap(26) 17 | rows.forEachIndexed { index, str -> 18 | str.toCharArray().forEach { 19 | charIndexMap[it] = index 20 | } 21 | } 22 | words.forEach { 23 | if (it.toCharArray().map { char -> charIndexMap[char.toLowerCase()] }.distinct().size == 1) { 24 | result.add(it) 25 | } 26 | } 27 | return result.toTypedArray() 28 | } 29 | 30 | fun main() { 31 | findWords(arrayOf("Hello", "Alaska", "Dad", "Peace")) shouldBe arrayOf("Alaska", "Dad") 32 | findWords(arrayOf("omk")) shouldBe arrayOf() 33 | findWords(arrayOf("adsdf", "sfd")) shouldBe arrayOf("adsdf", "sfd") 34 | } -------------------------------------------------------------------------------- /src/questions/LengthOfLastWord.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import kotlin.test.assertEquals 4 | 5 | /** 6 | * Given a string s consisting of some words separated by some number of spaces, return the length of the last word in the string. 7 | * A word is a maximal substring consisting of non-space characters only. 8 | * 9 | * [Source](https://leetcode.com/problems/length-of-last-word) 10 | */ 11 | fun lengthOfLastWord(s: String): Int { 12 | val lastIndex = s.lastIndex 13 | var result = 0 14 | for (i in lastIndex downTo 0) { 15 | if (s[i] != ' ') { 16 | result++ 17 | } else if (result != 0 && s[i] == ' ') { 18 | break 19 | } 20 | } 21 | return result 22 | } 23 | 24 | fun main() { 25 | assertEquals(5, lengthOfLastWord("Hello World")) 26 | assertEquals(4, lengthOfLastWord(" fly me to the moon ")) 27 | assertEquals(6, lengthOfLastWord("luffy is still joyboy")) 28 | } -------------------------------------------------------------------------------- /src/questions/LengthOfLongestIncreasingSubSeq.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given an integer array nums, return the length of the longest strictly increasing subsequence. 8 | * A subsequence is a sequence that can be derived from an array by deleting some or no elements 9 | * without changing the order of the remaining elements. 10 | * 11 | * [Source](https://leetcode.com/problems/longest-increasing-subsequence/) | [Explanation](https://www.youtube.com/watch?v=mouCn3CFpgg) 12 | * 13 | * @see LongestIncreasingSubSeq 14 | */ 15 | @UseCommentAsDocumentation 16 | private object LengthOfLongestIncreasingSubSeq 17 | 18 | private fun lengthOfLIS(nums: IntArray): Int { 19 | if (nums.size == 1) return 1 20 | var maxSubsequenceSize = 1 21 | val increasingSeq = IntArray(nums.size) { 1 } 22 | for (i in 1..nums.lastIndex) { 23 | for (j in 0 until i) { 24 | // (Is still increasing?) && (choose the best i.e. larger answer) 25 | if (nums[i] > nums[j] && increasingSeq[i] <= increasingSeq[j]) { 26 | increasingSeq[i] = 1 + increasingSeq[j] 27 | } 28 | } 29 | maxSubsequenceSize = maxOf(maxSubsequenceSize, increasingSeq[i]) 30 | } 31 | return maxSubsequenceSize 32 | } 33 | 34 | fun main() { 35 | 36 | val solutionFns: List<(IntArray) -> Int> = listOf(::lengthOfLIS) 37 | for (fn in solutionFns) { 38 | fn(intArrayOf(5, 8, 7, 1, 9)) shouldBe 3 39 | fn(intArrayOf(10, 9, 2, 5, 3, 7, 101, 18)) shouldBe 4 40 | fn(intArrayOf(0, 1, 0, 3, 2, 3)) shouldBe 4 41 | fn(intArrayOf(7, 7, 7, 7, 7, 7, 7)) shouldBe 1 42 | fn((10 downTo 1).toList().toIntArray()) shouldBe 1 43 | } 44 | } -------------------------------------------------------------------------------- /src/questions/LicenseKeyFormatting.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import java.lang.StringBuilder 4 | import kotlin.test.assertEquals 5 | 6 | /** 7 | * You are given a license key represented as a string s that consists of only alphanumeric characters and dashes. 8 | * The string is separated into n + 1 groups by n dashes. You are also given an integer k. 9 | * We want to reformat the string s such that each group contains exactly k characters, 10 | * except for the first group, which could be shorter than k but still must contain at least one character. 11 | * Furthermore, there must be a dash inserted between two groups, 12 | * and you should convert all lowercase letters to uppercase. Return the reformatted license key. 13 | * 14 | * [Source](https://leetcode.com/problems/license-key-formatting/) 15 | */ 16 | fun licenseKeyFormatting(s: String, k: Int): String { 17 | val sb = StringBuilder(s.length) 18 | val separator = '-' 19 | var count = 0 20 | for (i in s.lastIndex downTo 0) { 21 | if (s[i] == separator) continue // Ignore separators 22 | sb.append(s[i].toUpperCase()) 23 | count++ 24 | if (count % k == 0) sb.append(separator) // put '-' at every kth position 25 | } 26 | return sb.removeSuffix(separator.toString()).reversed().toString() 27 | } 28 | 29 | 30 | fun main() { 31 | assertEquals("AA-AA", licenseKeyFormatting(s = "--a-a-a-a--", k = 2)) 32 | assertEquals( 33 | "5F3Z-2E9W", licenseKeyFormatting(s = "5F3Z-2e-9-w", k = 4) 34 | ) 35 | assertEquals("2-5G-3J", licenseKeyFormatting(s = "2-5g-3-J", k = 2)) 36 | } -------------------------------------------------------------------------------- /src/questions/LongestCommonPrefix.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import kotlin.test.assertEquals 4 | 5 | /** 6 | * Write a function to find the longest common prefix string amongst an array of strings. 7 | * If there is no common prefix, return an empty string "". 8 | */ 9 | fun longestCommonPrefix(strs: Array): String { 10 | var result = "" 11 | var i = 0 12 | // Infinite loop: this way we don't have to find the shortest word 13 | while (true) { 14 | // Get element at index i 15 | val b = strs.map { it.getOrNull(i) }.toSet() 16 | // if contains null, then at least one of the element ran out of letters 17 | if (b.contains(null)) { 18 | break 19 | } 20 | // size of set == 1 then all contents same i.e. same character 21 | if (b.size == 1) { 22 | result += b.elementAt(0) 23 | i++ 24 | } else { 25 | break 26 | } 27 | } 28 | return result 29 | } 30 | 31 | fun main() { 32 | assertEquals("fl", longestCommonPrefix(arrayOf("flower", "flow", "flight"))) 33 | assertEquals("flo", longestCommonPrefix(arrayOf("flower", "flow", "floor"))) 34 | assertEquals("fl", longestCommonPrefix(arrayOf("flow", "flew", "flown"))) 35 | assertEquals("flower", longestCommonPrefix(arrayOf("flower", "flowers"))) 36 | assertEquals("", longestCommonPrefix(arrayOf("dog", "racecar", "car"))) 37 | assertEquals("", longestCommonPrefix(arrayOf("", ""))) 38 | assertEquals("", longestCommonPrefix(arrayOf(""))) 39 | } -------------------------------------------------------------------------------- /src/questions/LongestPalindrome.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given a string s which consists of lowercase or uppercase letters, 8 | * return the length of the longest palindrome that can be built with those letters. 9 | * 10 | * Letters are case sensitive, for example, "Aa" is not considered a palindrome here. 11 | * 12 | * [Source](https://leetcode.com/problems/longest-palindrome/) 13 | */ 14 | @UseCommentAsDocumentation 15 | private fun longestPalindrome(s: String): Int { 16 | if (s.length == 1) return 1 17 | val charCount = mutableMapOf() 18 | var result = 0 19 | for (i in s) { 20 | charCount[i] = charCount.getOrDefault(i, 0) + 1 21 | // A letter can be used in palindrome iff there are 2 of them i.e one on each side (eg: level) 22 | if (charCount[i]!! % 2 == 0) { 23 | result += 2 // increment the count 24 | charCount.remove(i) // remove it to make [charCount] loops efficient 25 | } 26 | } 27 | for (i in charCount.values) { 28 | if (i == 1) { 29 | // See if there is an element in the map with count of 1 30 | // this can be the letter in middle of the palindrome (eg: v in level) 31 | result += 1 32 | break 33 | } 34 | } 35 | return result 36 | } 37 | 38 | fun main() { 39 | longestPalindrome(s = "Aa") shouldBe 1 40 | longestPalindrome(s = "abccccdd") shouldBe 7 // dccaccd 41 | longestPalindrome(s = "a") shouldBe 1 42 | longestPalindrome(s = "bb") shouldBe 2 43 | } 44 | -------------------------------------------------------------------------------- /src/questions/MaxDepthOfBinaryTree.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import questions.common.TreeNode 5 | import kotlin.math.max 6 | import kotlin.test.assertEquals 7 | 8 | /** 9 | * Given the root of a binary tree, return its maximum depth. 10 | * A binary tree's maximum depth is the number of nodes along the longest path 11 | * from the root node down to the farthest leaf node. 12 | * 13 | * [Source](https://leetcode.com/problems/maximum-depth-of-binary-tree/) 14 | */ 15 | @UseCommentAsDocumentation 16 | private fun maxDepth(root: TreeNode?): Int { 17 | if (root == null) return 0 18 | return maxDepth(root, 0) 19 | } 20 | 21 | private fun maxDepth(root: TreeNode?, depth: Int): Int { 22 | if (root == null) return depth 23 | return max(maxDepth(root.left, depth + 1), maxDepth(root.right, depth + 1)) 24 | } 25 | 26 | 27 | fun main() { 28 | assertEquals(3, maxDepth(TreeNode.from(arrayOf(3, 9, 20, null, null, 15, 7)))) 29 | assertEquals(2, maxDepth(TreeNode.from(arrayOf(1, null, 2)))) 30 | assertEquals(0, maxDepth(TreeNode.from(arrayOf()))) 31 | assertEquals(1, maxDepth(TreeNode.from(arrayOf(0)))) 32 | } -------------------------------------------------------------------------------- /src/questions/MaxProductSubArray.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given an integer array nums, find a contiguous non-empty subarray within the array that has the largest product, 8 | * and return the product. 9 | * [Source](https://leetcode.com/problems/maximum-product-subarray/) – [Solution](https://leetcode.com/problems/maximum-product-subarray/discuss/48302/2-Passes-scan-beats-99) 10 | */ 11 | @UseCommentAsDocumentation 12 | private fun maxProduct(nums: IntArray): Int { 13 | var max = Integer.MIN_VALUE 14 | var prod = 1 15 | nums.forEach { 16 | prod *= it 17 | max = maxOf(prod, max) 18 | if (it == 0) { 19 | prod = 1 20 | } 21 | } 22 | 23 | prod = 1 24 | for (i in nums.lastIndex downTo 0) { 25 | prod *= nums[i] 26 | max = maxOf(max, prod) 27 | if (nums[i] == 0) { 28 | prod = 1 29 | } 30 | } 31 | return max 32 | } 33 | 34 | fun main() { 35 | maxProduct(intArrayOf(-3, 0, 1, -2)) shouldBe 1 36 | maxProduct(intArrayOf(-2, 0, -1)) shouldBe 0 37 | maxProduct(intArrayOf(0, 2)) shouldBe 2 38 | maxProduct(intArrayOf(-3, -1, -1)) shouldBe 3 39 | maxProduct(nums = intArrayOf(2, 3, -2, 4)) shouldBe 6 40 | 41 | } -------------------------------------------------------------------------------- /src/questions/MergeSortedLists.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import algorithmdesignmanualbook.print 5 | import questions.common.LeetNode 6 | import utils.assertIterableSame 7 | import utils.shouldBe 8 | 9 | /** 10 | * Merge two sorted linked lists and return it as a sorted list. 11 | * The list should be made by splicing together the nodes of the first two lists. 12 | * [Source](https://leetcode.com/problems/merge-two-sorted-lists/) 13 | */ 14 | @UseCommentAsDocumentation 15 | private fun mergeTwoLists(l1: LeetNode?, l2: LeetNode?): LeetNode? { 16 | return returnLowerNode(l1, l2) 17 | } 18 | 19 | private fun returnLowerNode(l1: LeetNode?, l2: LeetNode?): LeetNode? { 20 | if (l1 == null) return l2 21 | if (l2 == null) return l1 22 | return if (l1.`val` <= l2.`val`) { 23 | l1.next = returnLowerNode(l1.next, l2) 24 | l1 25 | } else { 26 | l2.next = returnLowerNode(l1, l2.next) 27 | l2 28 | } 29 | } 30 | 31 | fun main() { 32 | 33 | assertIterableSame( 34 | expected = LeetNode.from(1, 1, 1, 1, 2, 2).toList(), 35 | actual = mergeTwoLists( 36 | LeetNode.from(1, 1, 2), 37 | LeetNode.from(1, 1, 2) 38 | )!!.toList() 39 | ) 40 | 41 | mergeTwoLists( 42 | l1 = LeetNode.from(1, 2, 4), 43 | l2 = LeetNode.from(1, 3, 4) 44 | )!!.toList() shouldBe LeetNode.from(1, 1, 2, 3, 4, 4).toList() 45 | 46 | assertIterableSame( 47 | expected = LeetNode.from(1, 1, 2, 3, 4, 4).toList(), 48 | actual = mergeTwoLists(LeetNode.from(1, 2, 4), LeetNode.from(1, 3, 4))!!.toList() 49 | ) 50 | 51 | assertIterableSame( 52 | expected = LeetNode.from(1, 2, 2).toList(), 53 | actual = mergeTwoLists(LeetNode.from(1, 2), LeetNode.from(2))!!.toList() 54 | ) 55 | } -------------------------------------------------------------------------------- /src/questions/MinTotalInTriangle.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | import kotlin.math.min 6 | 7 | /** 8 | * Given a triangle array, return the minimum path sum from top to bottom. 9 | 10 | * For each step, you may move to an adjacent number of the row below. More formally, if you are on index i on the 11 | * current row, you may move to either index i or index i + 1 on the next row. 12 | * 13 | * [Source](https://leetcode.com/problems/triangle/) 14 | */ 15 | @UseCommentAsDocumentation 16 | fun minimumTotal(triangle: List>): Int { 17 | val minCumulativeSumTriangle = MutableList>(triangle.size) { 18 | MutableList(it + 1) { null } 19 | } 20 | minCumulativeSumTriangle[0][0] = triangle[0][0] // initialize 21 | for (row in 1..triangle.lastIndex) { 22 | for (col in 0..triangle.last().lastIndex) { 23 | val currentValue = triangle.getOrNull(row)?.getOrNull(col) ?: continue 24 | 25 | // get previous row's col-1 and col 26 | // then sum it with currentValue 27 | // take the minimum of the two 28 | val minCumulativeSumYet = min( 29 | minCumulativeSumTriangle[row - 1].getOrNull(col)?.plus(currentValue) ?: Int.MAX_VALUE, 30 | minCumulativeSumTriangle[row - 1].getOrNull(col - 1)?.plus(currentValue) ?: Int.MAX_VALUE 31 | ) 32 | minCumulativeSumTriangle[row][col] = minCumulativeSumYet 33 | } 34 | } 35 | // answer is minimum value in the last row 36 | return minCumulativeSumTriangle.last().filterNotNull().minOrNull()!! 37 | } 38 | 39 | fun main() { 40 | minimumTotal(listOf(listOf(2), listOf(3, 4), listOf(6, 5, 7), listOf(4, 1, 8, 3))) shouldBe 11 41 | minimumTotal(listOf(listOf(-10))) shouldBe -10 42 | } -------------------------------------------------------------------------------- /src/questions/MissingNumber.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given an array nums containing n distinct numbers in the range [0, n], 8 | * return the only number in the range that is missing from the array. 9 | * [Source](https://leetcode.com/problems/missing-number/) 10 | */ 11 | @UseCommentAsDocumentation 12 | fun missingNumber(nums: IntArray): Int { 13 | nums.sort() 14 | for (i in 0..nums.lastIndex) { 15 | if (i != nums[i]) { 16 | return i 17 | } 18 | } 19 | return nums.size 20 | } 21 | 22 | fun main() { 23 | missingNumber(intArrayOf(3, 0, 1)) shouldBe 2 24 | missingNumber(intArrayOf(1, 2)) shouldBe 0 25 | missingNumber(intArrayOf(0, 1, 2)) shouldBe 3 26 | } -------------------------------------------------------------------------------- /src/questions/MoveZeroes.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import algorithmdesignmanualbook.print 5 | import utils.shouldBe 6 | 7 | /** 8 | * Given an integer array nums, move all 0's to the end of it while maintaining 9 | * the relative order of the non-zero elements. 10 | * [Source](https://leetcode.com/problems/move-zeroes/) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun moveZeroes(nums: IntArray) { 14 | if (nums.size == 1) { 15 | return 16 | } 17 | var countOfZeros = 0 18 | for (i in 0..nums.lastIndex) { 19 | val current = nums[i] 20 | if (current == 0) { 21 | countOfZeros++ // count number of zeros 22 | continue 23 | } 24 | nums[i - countOfZeros] = current // move non-zero elements left by the total number of zeros encountered 25 | } 26 | while (countOfZeros > 0) { 27 | nums[nums.lastIndex - countOfZeros + 1] = 0 // start placing all zeros to the end 28 | countOfZeros-- 29 | } 30 | } 31 | 32 | fun main() { 33 | run { 34 | val input = intArrayOf(0, 1, 0, 3, 12) 35 | moveZeroes(input) 36 | input.print() shouldBe intArrayOf(1, 3, 12, 0, 0) 37 | } 38 | } -------------------------------------------------------------------------------- /src/questions/NumberOf1Bits.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Write a function that takes an unsigned integer and returns the number of '1' bits it has (also known as the Hamming weight). 8 | * [Source](https://leetcode.com/problems/number-of-1-bits/) 9 | */ 10 | @UseCommentAsDocumentation 11 | private fun hammingWeight(n: Int): Int { 12 | var temp = n 13 | var count = 0 14 | for (i in 0..31) { 15 | if (temp == 0) { 16 | return count 17 | } 18 | if (temp.and(1) == 1) { 19 | count++ 20 | } 21 | temp = temp.ushr(1) 22 | } 23 | return count 24 | } 25 | 26 | fun main() { 27 | hammingWeight(0b00000000000000000000000000001011) shouldBe 3 28 | hammingWeight(0b00000000000000000000000010000000) shouldBe 1 29 | } -------------------------------------------------------------------------------- /src/questions/PascalTriangleII.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given an integer rowIndex, return the rowIndexth (0-indexed) row of the Pascal's triangle. 8 | * 9 | * @see pascalTriangle 10 | * [Source](https://leetcode.com/problems/pascals-triangle-ii/) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun getRow(rowIndex: Int): List { 14 | if (rowIndex == 0) { 15 | return listOf(1) 16 | } 17 | return generateTriangle(1, rowIndex, previous = listOf(1)) 18 | } 19 | 20 | private fun generateTriangle(index: Int, rowIndex: Int, previous: List): List { 21 | if (index > rowIndex) { 22 | return previous 23 | } 24 | val currentRow = MutableList(index + 1) { 1 } 25 | 26 | for (i in 1..index) { // 0 and lastIndex is always 1 27 | // sum of the two numbers directly above it 28 | currentRow[i] = (previous.getOrNull(i - 1) ?: 0) + (previous.getOrNull(i) ?: 0) 29 | } 30 | return generateTriangle(index + 1, rowIndex, currentRow) 31 | } 32 | 33 | fun main() { 34 | getRow(rowIndex = 4) shouldBe listOf(1, 4, 6, 4, 1) 35 | getRow(rowIndex = 0) shouldBe listOf(1) 36 | getRow(rowIndex = 1) shouldBe listOf(1, 1) 37 | getRow(rowIndex = 2) shouldBe listOf(1, 2, 1) 38 | } -------------------------------------------------------------------------------- /src/questions/PivotIndex.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Calculate the pivot index of this array. 8 | * The pivot index is the index where the sum of all the numbers strictly to the left of the index 9 | * is equal to the sum of all the numbers strictly to the index's right. 10 | * Return the leftmost pivot index. If no such index exists, return -1. 11 | * [Source](https://leetcode.com/problems/pivot-index/) 12 | */ 13 | @UseCommentAsDocumentation 14 | private fun pivotIndex(nums: IntArray): Int { 15 | val cumulativeSumLeft = IntArray(nums.size) { 0 } 16 | val cumulativeSumRight = IntArray(nums.size) { 0 } 17 | for (i in 0..nums.lastIndex) { 18 | cumulativeSumLeft[i] = (cumulativeSumLeft.getOrNull(i - 1) ?: 0) + nums[i] 19 | cumulativeSumRight[nums.lastIndex - i] = 20 | (cumulativeSumRight.getOrNull(nums.lastIndex - i + 1) ?: 0) + nums[nums.lastIndex - i] 21 | } 22 | for (i in 0..nums.lastIndex) { 23 | if (cumulativeSumRight[i] == cumulativeSumLeft[i]) { 24 | return i 25 | } 26 | } 27 | return -1 28 | } 29 | 30 | fun main() { 31 | pivotIndex(intArrayOf(1, 7, 3, 6, 5, 6)) shouldBe 3 32 | pivotIndex(intArrayOf(1, 2, 3)) shouldBe -1 33 | pivotIndex(intArrayOf(2, 1, -1)) shouldBe 0 34 | } -------------------------------------------------------------------------------- /src/questions/PowerOf4.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given an integer n, return true if it is a power of four. Otherwise, return false. 8 | * An integer n is a power of four, if there exists an integer x such that n == 4x. 9 | * 10 | * [Source](https://leetcode.com/problems/power-of-four) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun isPowerOfFour(n: Int): Boolean { 14 | if (n == 1) return true 15 | var remainder = n 16 | while (remainder > 4) { 17 | if (remainder % 4 != 0) { 18 | return false 19 | } 20 | // remainder /= 4 21 | remainder = remainder.shr(2) 22 | } 23 | return remainder == 4 24 | } 25 | 26 | fun main() { 27 | isPowerOfFour(n = 17) shouldBe false 28 | isPowerOfFour(n = 16) shouldBe true 29 | isPowerOfFour(n = 4) shouldBe true 30 | isPowerOfFour(n = 8) shouldBe false 31 | isPowerOfFour(n = 1) shouldBe true 32 | } -------------------------------------------------------------------------------- /src/questions/RangeSumQuery.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given an integer array nums, handle multiple queries of the following type: 8 | * Calculate the sum of the elements of nums between indices left and right inclusive where left <= right. 9 | * [Source](https://leetcode.com/problems/range-sum-query-immutable/) 10 | */ 11 | @UseCommentAsDocumentation 12 | private class NumArray(nums: IntArray) { 13 | val sumArray = IntArray(nums.size) { 0 } 14 | val input = nums 15 | 16 | init { 17 | var cumulativeSum = 0 18 | nums.forEachIndexed { index, i -> 19 | cumulativeSum += i 20 | sumArray[index] = cumulativeSum 21 | } 22 | } 23 | 24 | fun sumRange(left: Int, right: Int): Int { 25 | val leftSum = sumArray[left] 26 | val rightSum = sumArray[right] 27 | return rightSum - leftSum + input[left] 28 | } 29 | } 30 | 31 | fun main() { 32 | run { 33 | val obj = NumArray(intArrayOf(-2, 0, 3, -5, 2, -1)) 34 | obj.sumRange(0, 2) shouldBe 1 35 | obj.sumRange(2, 5) shouldBe -1 36 | obj.sumRange(0, 5) shouldBe -3 37 | } 38 | } -------------------------------------------------------------------------------- /src/questions/RangeSumQueryMutable.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given an integer array nums, handle multiple queries of the following types: 8 | * * Update the value of an element in nums. 9 | * * Calculate the sum of the elements of nums between indices left and right inclusive where left <= right. 10 | * 11 | * [Source](https://leetcode.com/problems/range-sum-query-mutable/) 12 | */ 13 | @UseCommentAsDocumentation 14 | private class NumArrayMut(nums: IntArray) { 15 | val sumArray = IntArray(nums.size) { 0 } 16 | val input = nums 17 | 18 | init { 19 | var cumulativeSum = 0 20 | nums.forEachIndexed { index, i -> 21 | cumulativeSum += i 22 | sumArray[index] = cumulativeSum 23 | } 24 | } 25 | 26 | fun update(index: Int, `val`: Int) { 27 | input[index] = `val` 28 | var cumulativeSum = sumArray.getOrNull(index - 1) ?: 0 29 | for (i in index..input.lastIndex) { 30 | cumulativeSum += input[i] 31 | sumArray[i] = cumulativeSum 32 | } 33 | } 34 | 35 | fun sumRange(left: Int, right: Int): Int { 36 | val leftSum = sumArray[left] 37 | val rightSum = sumArray[right] 38 | return rightSum - leftSum + input[left] 39 | } 40 | } 41 | 42 | fun main() { 43 | run { 44 | val numArray = NumArrayMut(intArrayOf(1, 3, 5)) 45 | numArray.sumRange(0, 2) shouldBe 9 46 | numArray.update(1, 2); // nums = [1, 2, 5] 47 | numArray.sumRange(0, 2) shouldBe 8 48 | } 49 | } -------------------------------------------------------------------------------- /src/questions/RansomNote.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given two stings ransomNote and magazine, return true if ransomNote can be constructed from magazine and false otherwise. 8 | * Each letter in magazine can only be used once in ransomNote. 9 | * 10 | * [Source](https://leetcode.com/problems/ransom-note-kt/) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun canConstruct(ransomNote: String, magazine: String): Boolean { 14 | val charCount = mutableMapOf() 15 | for (i in ransomNote) { 16 | charCount[i] = charCount.getOrDefault(i, 0) + 1 17 | } 18 | for (i in magazine) { 19 | val counts = charCount[i] ?: continue 20 | if (counts - 1 == 0) { 21 | charCount.remove(i) 22 | } else { 23 | charCount[i] = counts - 1 24 | } 25 | if (charCount.isEmpty()) { 26 | return true 27 | } 28 | } 29 | return false 30 | } 31 | 32 | fun main() { 33 | canConstruct(ransomNote = "a", magazine = "b") shouldBe false 34 | canConstruct(ransomNote = "aa", magazine = "ab") shouldBe false 35 | canConstruct(ransomNote = "aa", magazine = "aab") shouldBe true 36 | } -------------------------------------------------------------------------------- /src/questions/RemoveDuplicatesFromSortedList.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import questions.common.LeetNode 5 | import utils.assertIterableSame 6 | 7 | 8 | 9 | /** 10 | * Given the head of a sorted linked list, delete all duplicates such 11 | * that each element appears only once. Return the linked list sorted as well. 12 | * 13 | * [source](https://leetcode.com/problems/remove-duplicates-from-sorted-list/) 14 | */ 15 | @UseCommentAsDocumentation 16 | private fun deleteDuplicates(head: LeetNode?): LeetNode? { 17 | if (head == null) return head 18 | 19 | var current: LeetNode? = head.next 20 | var prev: LeetNode? = head 21 | while (current != null) { 22 | if (prev!!.`val` == current.`val`) { 23 | prev.next = current.next 24 | current = prev.next 25 | } else { 26 | prev = current 27 | current = prev.next 28 | } 29 | } 30 | return head 31 | } 32 | 33 | fun main() { 34 | run { 35 | val node = LeetNode.from(intArrayOf(1, 1, 2, 2)) 36 | assertIterableSame(listOf(1, 2), deleteDuplicates(node)!!.toList()) 37 | } 38 | run { 39 | val node = LeetNode.from(intArrayOf(1, 1, 1)) 40 | assertIterableSame(listOf(1), deleteDuplicates(node)!!.toList()) 41 | } 42 | run { 43 | val node = LeetNode.from(intArrayOf(1, 1, 2, 3, 3)) 44 | assertIterableSame(listOf(1, 2, 3), deleteDuplicates(node)!!.toList()) 45 | } 46 | run { 47 | val node = LeetNode.from(intArrayOf(1, 1, 2)) 48 | assertIterableSame(listOf(1, 2), deleteDuplicates(node)!!.toList()) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/questions/RepeatedSubstringPattern.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given a string s, check if it can be constructed by taking a substring of it and appending 8 | * multiple copies of the substring together. 9 | * [Source](https://leetcode.com/problems/repeated-substring-pattern/) - [Solution](https://leetcode.com/problems/repeated-substring-pattern/discuss/94334/Easy-python-solution-with-explaination) 10 | */ 11 | @UseCommentAsDocumentation 12 | private fun repeatedSubstringPattern(s: String): Boolean { 13 | val ss = s + s // aba+aba abab+abab 14 | val subStr = ss.substring(1, ss.lastIndex) // baab bababa 15 | return subStr.contains(s) 16 | } 17 | 18 | fun main() { 19 | repeatedSubstringPattern(s = "aba") shouldBe false 20 | repeatedSubstringPattern(s = "abab") shouldBe true 21 | repeatedSubstringPattern(s = "abcabcabcabc") shouldBe true 22 | } -------------------------------------------------------------------------------- /src/questions/ReverseBits.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Reverse bits of a given 32 bits unsigned integer. 8 | * [Source](https://leetcode.com/problems/reverse-bits/) – [Solution](https://leetcode.com/problems/reverse-bits/discuss/54746/Java-Solution-and-Optimization) 9 | */ 10 | @UseCommentAsDocumentation 11 | fun reverseBits(n: Int): Int { 12 | var bit = n 13 | var result = 0b0 14 | for (i in 0..31) { 15 | result += bit.and(0b1) 16 | bit = bit ushr 1 17 | if (i < 31) 18 | result = result shl 1 19 | } 20 | return result 21 | } 22 | 23 | fun reverseBitsII(n: Int): Int { 24 | var bit = n 25 | var result = 0b0 26 | for (i in 0..31) { 27 | val lsb = bit.and(1) // get LSB 28 | bit = bit.shr(1) // shift right 29 | result = result.shl(1).or(lsb) // result shift left then or it with lsb 30 | } 31 | return result 32 | } 33 | 34 | fun main() { 35 | reverseBitsII(0b00000010100101000001111010011100) shouldBe 964176192 36 | reverseBits(0b00000010100101000001111010011100) shouldBe 964176192 37 | } -------------------------------------------------------------------------------- /src/questions/ReversePolishNotation.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | import java.util.* 6 | 7 | /** 8 | * You are given an array that contains an expression in Reverse Polish Notation. 9 | * Return the result from evaluating the expression. You can assume the expression will always be valid. 10 | * 11 | * Input - [“2”, “3”, “+”, “3”, “*”] Output - 15 because ( (2 + 3) * 3) 12 | * 13 | * [Source](https://leetcode.com/problems/evaluate-reverse-polish-notation/) 14 | */ 15 | @UseCommentAsDocumentation 16 | private fun reversePolishNotation(tokens: Array): Int { 17 | val operationFn: (String) -> (Int, Int) -> Int = { 18 | when (it) { 19 | "+" -> { left, right -> left + right } 20 | "-" -> { left, right -> left - right } 21 | "/" -> { left, right -> left / right } 22 | "*" -> { left, right -> left * right } 23 | else -> throw RuntimeException() 24 | } 25 | } 26 | val stack: Deque = LinkedList() 27 | for (item in tokens) { 28 | val operand = item.toIntOrNull() 29 | if (operand != null) stack.addLast(operand) 30 | else { 31 | val right = stack.removeLast() 32 | val left = stack.removeLast() 33 | val result = operationFn.invoke(item).invoke(left, right) 34 | stack.addLast(result) 35 | } 36 | } 37 | return stack.pop().toInt() 38 | } 39 | 40 | fun main() { 41 | reversePolishNotation(arrayOf("2", "1", "+", "3", "*")) shouldBe 9 42 | reversePolishNotation(arrayOf("4", "13", "5", "/", "+")) shouldBe 6 43 | reversePolishNotation(arrayOf("10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+")) shouldBe 22 44 | } -------------------------------------------------------------------------------- /src/questions/ReverseString.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import utils.shouldBe 4 | 5 | /** 6 | * Write a function that reverses a string. The input string is given as an array of characters s. 7 | * Do not allocate extra space for another array. 8 | * You must do this by modifying the input array in-place with O(1) extra memory. 9 | * 10 | * [Source](https://leetcode.com/problems/reverse-string/) 11 | */ 12 | private fun reverseString(s: CharArray) { 13 | val lastIndex = s.lastIndex 14 | // GOTCHA: only loop till half of the length 15 | for (i in 0..lastIndex / 2) { 16 | val temp = s[i] 17 | s[i] = s[lastIndex - i] 18 | s[lastIndex - i] = temp 19 | } 20 | } 21 | 22 | fun main() { 23 | run { 24 | val arr = charArrayOf('h', 'e', 'l', 'l', 'o') 25 | reverseString(arr) 26 | arr shouldBe charArrayOf('o', 'l', 'l', 'e', 'h') 27 | } 28 | 29 | run { 30 | val arr = charArrayOf('H', 'a', 'n', 'n', 'a', 'h') 31 | reverseString(arr) 32 | arr shouldBe charArrayOf('h', 'a', 'n', 'n', 'a', 'H') 33 | } 34 | } -------------------------------------------------------------------------------- /src/questions/ReverseStringII.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given a string `s` and an integer `k`, reverse the first `k` characters for every `2k` characters counting 8 | * from the start of the string. 9 | * 10 | * If there are fewer than `k` characters left, reverse all of them. 11 | * If there are less than `2k` but greater than or equal to `k` characters, 12 | * then reverse the first `k` characters and left the other as original. 13 | * 14 | * [Source](https://leetcode.com/problems/reverse-string-ii/) 15 | */ 16 | @UseCommentAsDocumentation 17 | private fun reverseStr(s: String, k: Int): String { 18 | val sb = StringBuilder(s) 19 | if (sb.length < k) { 20 | return sb.reverse().toString() 21 | } 22 | var startIndex = 0 23 | var endIndex = k - 1 24 | while (startIndex <= sb.lastIndex) { 25 | val remaining = sb.length - startIndex 26 | if (remaining < k) { 27 | val reverse = sb.subSequence(startIndex, sb.length).reversed().toString() 28 | sb.replace(startIndex, endIndex + 1, reverse) 29 | } else { 30 | val reverse = sb.subSequence(IntRange(startIndex, endIndex)).reversed() 31 | sb.replace(startIndex, endIndex + 1, reverse.toString()) 32 | } 33 | startIndex += 2 * k 34 | endIndex = startIndex + k - 1 35 | } 36 | 37 | return sb.toString() 38 | } 39 | 40 | fun main() { 41 | reverseStr(s = "abcdefg", 3) shouldBe "cbadefg" 42 | reverseStr("abcdefg", 2) shouldBe "bacdfeg" 43 | reverseStr(s = "abcd", k = 2) shouldBe "bacd" 44 | } -------------------------------------------------------------------------------- /src/questions/ReverseVowel.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given a string s, reverse only all the vowels in the string and return it. 8 | * The vowels are 'a', 'e', 'i', 'o', and 'u', and they can appear in both cases. 9 | * 10 | * [Source](https://leetcode.com/problems/reverse-vowels-of-a-string/) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun reverseVowels(s: String): String { 14 | if (s.length == 1) { 15 | return s 16 | } 17 | val arr = s.toCharArray() 18 | var front = 0 19 | var back = s.lastIndex 20 | 21 | while (true) { 22 | while (front <= arr.lastIndex && !isVowel(arr[front])) { 23 | front++ 24 | } 25 | while (back >= 0 && !isVowel(arr[back])) { 26 | if (back < 0) break 27 | back-- 28 | } 29 | if (front >= back) { 30 | break 31 | } 32 | swap(arr, front, back) 33 | front++ 34 | back-- 35 | } 36 | return arr.joinToString("") 37 | } 38 | 39 | private fun swap(arr: CharArray, i1: Int, i2: Int) { 40 | val temp: Char = arr[i1] 41 | arr[i1] = arr[i2] 42 | arr[i2] = temp 43 | } 44 | 45 | private fun isVowel(char: Char): Boolean { 46 | return char == 'a' || char == 'e' || char == 'i' || char == 'o' || char == 'u' || char == 'A' || char == 'E' || char == 'I' || char == 'O' || char == 'U' 47 | } 48 | 49 | fun main() { 50 | reverseVowels(s = "hello") shouldBe "holle" 51 | reverseVowels(s = "leetcode") shouldBe "leotcede" 52 | reverseVowels(s = ",.") shouldBe ",." 53 | } -------------------------------------------------------------------------------- /src/questions/SameTree.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import questions.common.TreeNode 5 | import kotlin.test.assertFalse 6 | import kotlin.test.assertTrue 7 | 8 | /** 9 | * 10 | * Given the roots of two binary trees p and q, write a function to check if they are the same or not. 11 | * 12 | * [Source](https://leetcode.com/problems/same-tree/) 13 | */ 14 | @UseCommentAsDocumentation 15 | private fun isSameTree(p: TreeNode?, q: TreeNode?): Boolean { 16 | return TreeNode.isSameAs(p, q) 17 | } 18 | 19 | fun main() { 20 | assertFalse(isSameTree(p = TreeNode.from(0), q = TreeNode.from(1))) 21 | assertTrue(isSameTree(p = TreeNode.from(1, 2, 3), q = TreeNode.from(1, 2, 3))) 22 | assertFalse(isSameTree(p = TreeNode.from(1, 2), q = TreeNode.from(arrayOf(1, null, 2)))) 23 | assertFalse(isSameTree(p = TreeNode.from(1, 2, 1), q = TreeNode.from(arrayOf(1, 1, 2)))) 24 | } -------------------------------------------------------------------------------- /src/questions/SearchContact.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import java.util.* 4 | import kotlin.test.assertTrue 5 | 6 | /** 7 | * Phone number substring search 8 | * If not found, return "NO_CONTACT" 9 | * IF multiple return the alphabetically lowest 10 | */ 11 | fun main() { 12 | val result = solution(arrayOf("amy", "fara", "ben", "nina", "jon"), arrayOf("9849000000", "9849000001", "9849002310", "9888022345", "334455661"), "9849") 13 | assertTrue(result == "amy") 14 | } 15 | 16 | 17 | private const val NO_CONTACT = "NO CONTACT" 18 | 19 | fun solution(A: Array, B: Array, P: String): String { 20 | // Max length of phone number is 9 21 | if (P.length > 9) { 22 | return NO_CONTACT 23 | } 24 | val mapOfPhoneToName = mutableMapOf() 25 | 26 | B.forEachIndexed { index, phone -> 27 | mapOfPhoneToName.put(phone, A[index]) 28 | } 29 | 30 | val phoneNumbers = B.filter { it.contains(P) } 31 | if (phoneNumbers.isEmpty()) { 32 | return NO_CONTACT 33 | } 34 | val results = TreeSet() 35 | phoneNumbers.forEach { 36 | results.add(mapOfPhoneToName[it]!!) 37 | } 38 | return results.first() 39 | } 40 | -------------------------------------------------------------------------------- /src/questions/SingleNumber.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import kotlin.test.assertEquals 4 | 5 | /** 6 | * Given a non-empty array of integers nums, every element appears twice except for one. Find that single one. 7 | * You must implement a solution with a linear runtime complexity and use only constant extra space. 8 | * 9 | * [Source](https://leetcode.com/problems/single-number/) 10 | */ 11 | private fun singleNumber(nums: IntArray): Int { 12 | if (nums.size == 1) { 13 | return nums[0] 14 | } 15 | val record = mutableSetOf() 16 | // forEach loop was slower 17 | for (i in 0..nums.lastIndex) { 18 | if (record.contains(nums[i])) record.remove(nums[i]) 19 | else record.add(nums[i]) 20 | } 21 | return record.first() 22 | } 23 | 24 | fun main() { 25 | assertEquals(1, singleNumber(intArrayOf(2, 2, 1))) 26 | assertEquals(4, singleNumber(intArrayOf(4, 1, 2, 1, 2))) 27 | assertEquals(1, singleNumber(intArrayOf(1))) 28 | } -------------------------------------------------------------------------------- /src/questions/SingleNumberII.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import kotlin.test.assertEquals 5 | 6 | /** 7 | * Given an integer array nums where every element appears three times except for one, which appears exactly once. 8 | * Find the single element and return it. 9 | * 10 | * [Source](https://leetcode.com/problems/single-number-ii/) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun singleNumber(nums: IntArray): Int { 14 | if (nums.size == 1) { 15 | return nums[0] 16 | } 17 | val record = mutableSetOf() 18 | 19 | // On 2nd occurrence, add it to seen 20 | val seen = mutableSetOf() 21 | for (i in 0..nums.lastIndex) { 22 | val element = nums[i] 23 | if (record.contains(element)) { 24 | // Since elements occur exactly thrice, remove it from record if it has already occurred 25 | record.remove(element) 26 | seen.add(element) 27 | } else { 28 | // No need to add if it's already "seen" 29 | if (!seen.contains(element)) { 30 | record.add(element) 31 | } 32 | } 33 | } 34 | return record.elementAt(0) 35 | } 36 | 37 | fun main() { 38 | assertEquals(3, singleNumber(intArrayOf(2, 2, 3, 2))) 39 | assertEquals(99, singleNumber(intArrayOf(0, 1, 0, 1, 0, 1, 99))) 40 | } -------------------------------------------------------------------------------- /src/questions/SingleNumberIII.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.assertIterableSameInAnyOrder 5 | 6 | /** 7 | * Given an integer array nums, in which exactly two elements appear only once and 8 | * all the other elements appear exactly twice. 9 | * Find the two elements that appear only once. You can return the answer in any order. 10 | * 11 | * [Source](https://leetcode.com/problems/single-number-iii/) 12 | */ 13 | @UseCommentAsDocumentation 14 | private fun singleNumber(nums: IntArray): IntArray { 15 | if (nums.size == 2) return nums 16 | val record = mutableSetOf() 17 | for (i in 0..nums.lastIndex) { 18 | val element = nums[i] 19 | if (record.contains(element)) { 20 | record.remove(element) 21 | } else { 22 | record.add(element) 23 | } 24 | } 25 | return intArrayOf(record.elementAt(0), record.elementAt(1)) 26 | } 27 | 28 | fun main() { 29 | assertIterableSameInAnyOrder(intArrayOf(3, 5).toList(), singleNumber(intArrayOf(1, 2, 1, 3, 2, 5)).toList()) 30 | assertIterableSameInAnyOrder(listOf(-1, 0), singleNumber(intArrayOf(-1, 0)).toList()) 31 | } -------------------------------------------------------------------------------- /src/questions/SortCharByFrequency.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBeOneOf 5 | import java.util.* 6 | 7 | /** 8 | * 9 | * Given a string s, sort it in decreasing order based on the frequency of the characters. 10 | * The frequency of a character is the number of times it appears in the string. 11 | * Return the sorted string. If there are multiple answers, return any of them. 12 | * [Source](https://leetcode.com/problems/sort-characters-by-frequency/) 13 | */ 14 | @UseCommentAsDocumentation 15 | fun frequencySort(s: String): String { 16 | if (s.length <= 2) return s 17 | // Maintains map of char to its count 18 | val charToCountMap = HashMap(s.length) 19 | for (i in 0..s.lastIndex) { 20 | charToCountMap[s[i]] = charToCountMap.getOrDefault(s[i], 0) + 1 21 | } 22 | // maintains SORTED map of count to the character with that frequency 23 | // sorted w.r.t frequency of occurrence in reverse order 24 | // eg: in "cccaaabb" -> 3: "cccaaa", 2: "bb" 25 | val countToCharMap = TreeMap(object : Comparator { 26 | override fun compare(o1: Int?, o2: Int?): Int { 27 | return o2!! - o1!! // This will be sorted in reverse order of frequency 28 | } 29 | }) 30 | charToCountMap.forEach { (k, count) -> 31 | countToCharMap[count] = countToCharMap.getOrDefault(count, "") + k.toString().repeat(count) 32 | } 33 | // [countToCharMap] is already sorted so just join the values 34 | return countToCharMap.values.joinToString("") 35 | } 36 | 37 | fun main() { 38 | frequencySort(s = "tree") shouldBeOneOf listOf("eert", "eetr") 39 | frequencySort(s = "cccaaa") shouldBeOneOf listOf("cccaaa", "aaaccc") 40 | frequencySort(s = "Aabb") shouldBeOneOf listOf("bbAa", "bbaA") 41 | } -------------------------------------------------------------------------------- /src/questions/Sqrtx.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * Given a non-negative integer x, compute and return the square root of x. 8 | * [Source](https://leetcode.com/problems/sqrtx/) 9 | */ 10 | @UseCommentAsDocumentation 11 | private fun mySqrt(x: Int): Int { 12 | if (x == 1) return x 13 | val xLong = x.toLong() // squaring x can't fit in Int it goes beyond Integer.MAX_VALUE 14 | var num: Long = xLong.shr(1) 15 | var prev: Long = xLong 16 | 17 | // Find the range of possible answers by dividing by 2 18 | // Given 40: 20 (20x20) -> 10 (10x10=100) -> 5 (5x5=25) 19 | // So answer must lie between 5 & 10 20 | while (num * num > x) { 21 | prev = num // prev is used to compensate for float to int conversions eg. sqrt(6) 22 | num = num.shr(1) 23 | } 24 | // Check if the answer is 5 25 | if (num * num == x.toLong()) { 26 | return num.toInt() 27 | } 28 | // else traverse from 5 to 10 29 | var low = num 30 | val high = prev 31 | // OR do binary search here 32 | while (low <= high) { 33 | val lowSq = low * low 34 | if (lowSq == xLong) { 35 | return low.toInt() 36 | } else if (lowSq < x) { 37 | low++ 38 | } else if (lowSq > x) { 39 | return (low - 1).toInt() 40 | } 41 | } 42 | return num.toInt() 43 | } 44 | 45 | fun main() { 46 | mySqrt(2147395599) shouldBe 46339 47 | mySqrt(6) shouldBe 2 48 | mySqrt(100) shouldBe 10 49 | mySqrt(50) shouldBe 7 50 | mySqrt(40) shouldBe 6 51 | mySqrt(25) shouldBe 5 52 | mySqrt(1) shouldBe 1 53 | mySqrt(64) shouldBe 8 54 | mySqrt(8) shouldBe 2 55 | mySqrt(4) shouldBe 2 56 | } -------------------------------------------------------------------------------- /src/questions/SumOfLeftLeaves.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import questions.common.TreeNode 5 | import utils.shouldBe 6 | 7 | /** 8 | * Given the root of a binary tree, return the sum of all left leaves. 9 | * 10 | * [Source](https://leetcode.com/problems/sum-of-left-leaves/) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun sumOfLeftLeaves(root: TreeNode?): Int { 14 | return traverse(root, 0, false) 15 | } 16 | 17 | private fun traverse(root: TreeNode?, sum: Int, isLeft: Boolean): Int { 18 | if (root == null) { 19 | return sum 20 | } 21 | val newSum = sum + if (isLeft && root.isLeaf()) root.`val` else 0 // is leaf check, add its value to sum 22 | return traverse(root.left, newSum, true) + traverse(root.right, sum, false) 23 | } 24 | 25 | 26 | fun main() { 27 | // There are two left leaves in the binary tree, with values 9 and 15 respectively. 28 | sumOfLeftLeaves(TreeNode.from(arrayOf(3, 9, 20, null, null, 15, 7))) shouldBe 24 29 | 30 | // 1 31 | // 2 3 32 | // 4 5 33 | sumOfLeftLeaves(TreeNode.from(arrayOf(1, 2, 3, 4, 5))) shouldBe 4 34 | } -------------------------------------------------------------------------------- /src/questions/SumRootToLeafNumber.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import questions.common.TreeNode 5 | import utils.shouldBe 6 | 7 | /** 8 | * 9 | * You are given the root of a binary tree containing digits from 0 to 9 only. 10 | * Each root-to-leaf path in the tree represents a number. 11 | * For example, the root-to-leaf path `1 -> 2 -> 3` represents the number 123. 12 | * Return the total sum of all root-to-leaf numbers. 13 | * 14 | * [Source](https://leetcode.com/problems/sum-root-to-leaf-numbers/) 15 | */ 16 | @UseCommentAsDocumentation 17 | private fun sumNumbers(root: TreeNode?): Int { 18 | if (root == null) return 0 19 | val pathValue = mutableListOf() 20 | depthFirstTraversal(root, 0, pathValue) // depth first traversal 21 | return pathValue.sum() 22 | } 23 | 24 | private fun depthFirstTraversal(root: TreeNode?, sum: Int, result: MutableList) { 25 | if (root == null) return 26 | val newSum = sum * 10 + root.`val` // increase the 10th place. 491 = 4*100 + 9*10 + 1 27 | if (root.left == null && root.right == null) { // if leaf node 28 | result.add(newSum) 29 | } 30 | depthFirstTraversal(root.left, newSum, result) 31 | depthFirstTraversal(root.right, newSum, result) 32 | } 33 | 34 | fun main() { 35 | // 4 36 | // 9 0 => 491+495+40 37 | // 5 1 38 | sumNumbers(TreeNode.from(4, 9, 0, 5, 1)) shouldBe 1026 39 | sumNumbers(TreeNode.from(1, 2, 3)) shouldBe 25 40 | } -------------------------------------------------------------------------------- /src/questions/SwapAdjacentNodes.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import questions.common.LeetNode 5 | import questions.common.LeetNode.Companion.from 6 | import utils.shouldBe 7 | 8 | /** 9 | * Given a linked list, swap every two adjacent nodes and return its head. 10 | * 11 | * 1 -> 2 -> 3 -> 4 -----> 2 -> 1 -> 4 -> 3 12 | */ 13 | @UseCommentAsDocumentation 14 | private fun swapAdjacent(node: LeetNode): LeetNode { 15 | if (node.next == null) { 16 | return node 17 | } 18 | var copy = node 19 | var prev: LeetNode? = null // in 1st node, prev=null 20 | var current: LeetNode? = node 21 | var next: LeetNode? = current?.next 22 | 23 | while (current != null) { 24 | if (next == null && prev != null) { // handle the last node of odd case [1,2,3,4,5] 25 | prev.next = current 26 | break 27 | } 28 | 29 | current.next = next?.next 30 | next?.next = current 31 | prev?.next = next 32 | if (prev == null) { // handle the first case 33 | copy = next!! 34 | } 35 | 36 | // move twice forward (1,2),3,4 -> (2,1),3,4 -> 2,1,(3,4) -> 2,1,4,3 37 | prev = next?.next 38 | next = current.next?.next 39 | current = prev?.next 40 | } 41 | 42 | return copy 43 | } 44 | 45 | fun main() { 46 | swapAdjacent(from(intArrayOf(1, 2, 3, 4, 5))).toList() shouldBe from(intArrayOf(2, 1, 4, 3, 5)).toList() 47 | swapAdjacent(from(intArrayOf(1))).toList() shouldBe from(intArrayOf(1)).toList() 48 | swapAdjacent(from(intArrayOf(1, 2, 3, 4))).toList() shouldBe from(intArrayOf(2, 1, 4, 3)).toList() 49 | swapAdjacent(from(intArrayOf(1, 2, 3, 4, 5, 6))) 50 | .toList() shouldBe from(intArrayOf(2, 1, 4, 3, 6, 5)).toList() 51 | } -------------------------------------------------------------------------------- /src/questions/ThirdMaximumNumber.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import java.util.* 5 | import kotlin.test.assertEquals 6 | 7 | /** 8 | * Given an integer array nums, return the third distinct maximum number 9 | * in this array. If the third maximum does not exist, return the maximum number. 10 | */ 11 | @UseCommentAsDocumentation 12 | fun thirdMax(nums: IntArray): Int { 13 | val set = TreeSet() // use sorted data structure 14 | for (i in 0..nums.lastIndex) { 15 | set.add(nums[i]) 16 | } 17 | return set.elementAtOrElse(set.size - 3) { 18 | set.elementAt(set.size - 1) // return max 19 | } 20 | } 21 | 22 | fun thirdMaxII(nums: IntArray): Int { 23 | var max1: Int? = null 24 | var max2: Int? = null 25 | var max3: Int? = null 26 | 27 | for (i in 0..nums.lastIndex) { 28 | val elem = nums[i] 29 | if (elem == max1 || elem == max2 || elem == max3) { 30 | continue 31 | } 32 | if (max3 == null) { 33 | max3 = elem 34 | } else if (elem > max3) { 35 | max1 = max2 36 | max2 = max3 37 | max3 = elem 38 | } else if (max2 == null || (elem in max2..max3)) { 39 | max1 = max2 40 | max2 = elem 41 | } else if (max1 == null || elem in max1..max2) { 42 | max1 = elem 43 | } 44 | } 45 | return max1 ?: max3!! 46 | } 47 | 48 | fun main() { 49 | assertEquals(4, thirdMaxII(intArrayOf(5, 2, 4, 1, 3, 6, 0))) 50 | assertEquals(1, thirdMaxII(intArrayOf(2, 2, 3, 1))) 51 | assertEquals(5, thirdMaxII(intArrayOf(5, 2, 2))) 52 | assertEquals(1, thirdMaxII(intArrayOf(3, 2, 1))) 53 | assertEquals(2, thirdMaxII(intArrayOf(1, 2))) 54 | } -------------------------------------------------------------------------------- /src/questions/UglyNumber.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | /** 7 | * 8 | * An ugly number is a positive integer whose prime factors are limited to 2, 3, and 5. 9 | * Given an integer n, return true if n is an ugly number. 10 | * [Source](https://leetcode.com/problems/ugly-number/) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun isUgly(n: Int): Boolean { 14 | if(n == 1) return true 15 | if(n == 0) return false 16 | var number = n 17 | while (number % 2 == 0) number = number.shr(1) 18 | while (number % 3 == 0) number /= 3 19 | while (number % 5 == 0) number /= 5 20 | return number == 1 21 | } 22 | 23 | fun main() { 24 | isUgly(n = -2147483648) shouldBe false 25 | isUgly(n = 6) shouldBe true 26 | isUgly(n = 8) shouldBe true 27 | isUgly(n = 14) shouldBe false 28 | } -------------------------------------------------------------------------------- /src/questions/ValidAnagram.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import utils.shouldBe 5 | 6 | 7 | /** 8 | * Given two strings s and t, return true if t is an anagram of s, and false otherwise. 9 | * 10 | * [Source](https://leetcode.com/problems/valid-anagram/) 11 | */ 12 | @UseCommentAsDocumentation 13 | private fun isAnagram(s: String, t: String): Boolean { 14 | if (s == t) return true 15 | if (s.length != t.length) return false 16 | val countMap = mutableMapOf() 17 | for ((i, j) in s.toCharArray().zip(t.toCharArray())) { 18 | countMap[i] = countMap.getOrDefault(i, 0) + 1 // increase count 19 | countMap[j] = countMap.getOrDefault(j, 0) - 1 // decrease count 20 | if (countMap[i] == 0) countMap.remove(i) 21 | if (countMap[j] == 0) countMap.remove(j) 22 | } 23 | return countMap.isEmpty() // since aggregates with 0 counts are removed, only check if empty 24 | } 25 | 26 | private fun isAnagramII(s: String, t: String): Boolean { 27 | if (s == t) return true 28 | if (s.length != t.length) return false 29 | return s.toCharArray().sorted() == t.toCharArray().sorted() // or simply check if their sorted values are equal 30 | } 31 | 32 | fun main() { 33 | isAnagramII(s = "anagram", t = "nagaram") shouldBe true 34 | isAnagramII(s = "cinema", t = "iceman") shouldBe true 35 | isAnagramII(s = "rat", t = "car") shouldBe false 36 | } -------------------------------------------------------------------------------- /src/questions/ValidPalindrome.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import _utils.UseCommentAsDocumentation 4 | import java.lang.StringBuilder 5 | import kotlin.test.assertFalse 6 | import kotlin.test.assertTrue 7 | 8 | 9 | /** 10 | * Given a string s, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases. 11 | */ 12 | @UseCommentAsDocumentation 13 | fun isPalindrome(s: String): Boolean { 14 | val reg = Regex("[^A-Za-z0-9]") 15 | // Remove all non-alphanumeric and ignore case 16 | val newString = reg.replace(s, "").toLowerCase() 17 | 18 | // return StringBuilder(newString).reverse().toString() == newString 19 | 20 | // compare i and (lastIndex-i) 21 | for (i in 0..newString.lastIndex) { 22 | if (newString[i] != newString[newString.lastIndex - i]) { 23 | return false 24 | } 25 | } 26 | return true 27 | } 28 | 29 | fun main() { 30 | assertTrue(isPalindrome("A man, a plan, a canal: Panama")) 31 | assertFalse(isPalindrome("race a car")) 32 | assertTrue(isPalindrome("race car")) 33 | assertTrue(isPalindrome("racecar")) 34 | } -------------------------------------------------------------------------------- /src/questions/WordPattern.kt: -------------------------------------------------------------------------------- 1 | package questions 2 | 3 | import utils.shouldBe 4 | 5 | /** 6 | * Given a pattern and a string s, find if s follows the same pattern. 7 | * Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty word in s. 8 | * 9 | * [Source](https://leetcode.com/problems/word-pattern/) 10 | */ 11 | private fun wordPattern(pattern: String, s: String): Boolean { 12 | val split = s.split(" ") 13 | if (pattern.length != split.size) return false 14 | val charToWordMap = mutableMapOf() 15 | val seen = mutableSetOf() 16 | 17 | for (i in 0..pattern.lastIndex) { 18 | val char = pattern[i] 19 | val word = split[i] 20 | if (!charToWordMap.containsKey(char)) { 21 | if (seen.contains(word)) { 22 | return false 23 | } 24 | charToWordMap[char] = word 25 | seen.add(word) 26 | } else { 27 | if (charToWordMap[char] != word) { 28 | return false 29 | } 30 | } 31 | } 32 | return true 33 | } 34 | 35 | 36 | fun main() { 37 | wordPattern(pattern = "a", s = "a") shouldBe true 38 | wordPattern(pattern = "abba", s = "dog cat cat dog") shouldBe true 39 | wordPattern(pattern = "abba", s = "dog cat cat fish") shouldBe false 40 | wordPattern(pattern = "aaaa", s = "dog cat cat dog") shouldBe false 41 | wordPattern(pattern = "abba", s = "dog dog dog dog") shouldBe false 42 | } -------------------------------------------------------------------------------- /src/questions/common/LeetNode.kt: -------------------------------------------------------------------------------- 1 | package questions.common 2 | 3 | import _utils.SkipDocumentation 4 | 5 | 6 | @SkipDocumentation 7 | 8 | /** 9 | * Seen typically in LeetCode 10 | */ 11 | class LeetNode(var `val`: Int) { 12 | var next: LeetNode? = null 13 | 14 | override fun toString(): String { 15 | return "LeetNode(${`val`})" 16 | } 17 | 18 | fun toList(): List { 19 | val list = mutableListOf() 20 | var current: LeetNode? = this 21 | while (current != null) { 22 | list.add(current.`val`) 23 | current = current.next 24 | } 25 | return list 26 | } 27 | 28 | companion object { 29 | fun from(arr: IntArray): LeetNode { 30 | val node = LeetNode(arr[0]) 31 | if (arr.size == 1) return node 32 | var current = node 33 | for (i in 1..arr.lastIndex) { 34 | current.next = LeetNode(arr[i]) 35 | current = current.next!! 36 | } 37 | return node 38 | } 39 | 40 | fun from(value: Int, vararg others: Int): LeetNode { 41 | return from(intArrayOf(value, *others.toTypedArray().toIntArray())) 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/utils/PrintUtils.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import _utils.SkipDocumentation; 4 | 5 | @SkipDocumentation 6 | 7 | public class PrintUtils { 8 | public static void printArr(Iterable it) { 9 | for (T[] t : it) { 10 | for (Object t1 : t) { 11 | System.out.print(t1 + " "); 12 | } 13 | System.out.println(); 14 | } 15 | } 16 | 17 | 18 | public static void printAnyArrWithCast(Iterable it, String cast) { 19 | for (T[] t : it) { 20 | for (T t1 : t) { 21 | System.out.print((t1 == null) ? " - " : String.format(" %s ", t1)); 22 | } 23 | System.out.println(); 24 | } 25 | } 26 | 27 | public static void printIntArrWithCast(Iterable it) { 28 | for (Integer[] t : it) { 29 | for (Integer t1 : t) { 30 | System.out.print(castToInfinity(t1) + " "); 31 | } 32 | System.out.println(); 33 | } 34 | } 35 | 36 | public static void println(Iterable it) { 37 | for (Object o : it) { 38 | System.out.println(o); 39 | } 40 | } 41 | 42 | public static void print(Iterable it) { 43 | for (Object o : it) { 44 | System.out.print(o + " "); 45 | } 46 | System.out.println(); 47 | } 48 | 49 | static String castToInfinity(Integer t) { 50 | if (t == Integer.MAX_VALUE) return "∞"; 51 | else return t.toString(); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /test/questions/common/ClassInvokerTest.kt: -------------------------------------------------------------------------------- 1 | package questions.common 2 | 3 | import _utils.SkipDocumentation 4 | import org.junit.jupiter.api.Test 5 | import org.junit.jupiter.api.assertDoesNotThrow 6 | import org.junit.jupiter.api.assertThrows 7 | 8 | @SkipDocumentation 9 | 10 | class TestClass { 11 | fun returnOne() = 1 12 | fun returnTwo() = 2 13 | fun returnThree() = 3 14 | fun returnArgs(arg: Int) = arg 15 | } 16 | 17 | class ClassInvokerTest { 18 | 19 | @Test 20 | fun testForClassInvoker() { 21 | val invoker = ClassInvoker( 22 | listOf("TestClass", "returnOne", "returnTwo", "returnOne", "returnArgs"), 23 | "questions.common" 24 | ) { 25 | it.getOrNull(0) 26 | } 27 | assertDoesNotThrow { 28 | invoker.invoke( 29 | listOf(intArrayOf(), intArrayOf(), intArrayOf(), intArrayOf(), intArrayOf(100)), 30 | listOf(null, 1, 2, 1, 100) 31 | ) 32 | } 33 | } 34 | 35 | @Test 36 | fun whenClassInvoker_IsInvocationValid() { 37 | val invoker = ClassInvoker( 38 | listOf("TestClass", "returnOne", "returnTwo", "returnOne", "returnArgs"), 39 | "questions.common" 40 | ) { 41 | it.getOrNull(0) 42 | } 43 | assertThrows { 44 | invoker.invoke( 45 | listOf(intArrayOf(), intArrayOf(), intArrayOf(), intArrayOf(), intArrayOf(100)), 46 | listOf( 47 | null, 48 | 1, 49 | 2, 50 | 1, 51 | 2 //should be 100 52 | ) 53 | ) 54 | } 55 | } 56 | } --------------------------------------------------------------------------------