├── .github └── PULL_REQUEST_TEMPLATE.md ├── .prettierignore ├── LICENSE.md ├── README.md └── solutions ├── 1. Two Sum └── TwoSum_HashTable.java ├── 100. Same Tree ├── SameTree_BFS.java └── SameTree_DFS.java ├── 1019. Next Greater Node In Linked List └── NextGreaterNodeInLinkedList.java ├── 102. Binary Tree Level Order Traversal └── BinaryTreeLevelOrderTraversal.java ├── 1026. Maximum Difference Between Node and Ancestor ├── MaximumDifferenceBetweenNodeAndAncestor_Iterative.java └── MaximumDifferenceBetweenNodeAndAncestor_Recursive.java ├── 103. Binary Tree Zigzag Level Order Traversal └── BinaryTreeZigzagLevelOrderTraversal.java ├── 1033. Moving Stones Until Consecutive └── MovingStonesUntilConsecutive.java ├── 1037. Valid Boomerang └── ValidBoomerang.java ├── 104. Maximum Depth of Binary Tree ├── MaximumDepthOfBinaryTree_BFS.java ├── MaximumDepthOfBinaryTree_DFS_Iterative.java └── MaximumDepthOfBinaryTree_DFS_Recursive.java ├── 1047. Remove All Adjacent Duplicates In String ├── RemoveAllAdjacentDuplicatesInString_Stack.java └── RemoveAllAdjacentDuplicatesInString_StringBuilder.java ├── 1051. Height Checker ├── HeightChecker_CountingSort.java └── HeightChecker_Sorting.java ├── 1061. Lexicographically Smallest Equivalent String └── LexicographicallySmallestEquivalentString.java ├── 107. Binary Tree Level Order Traversal II └── BinaryTreeLevelOrderTraversalII.java ├── 1071. Greatest Common Divisor of Strings └── GreatestCommonDivisorOfStrings.java ├── 1089. Duplicate Zeros ├── DuplicateZeros.java └── DuplicateZeros_TwoPointers.java ├── 110. Balanced Binary Tree └── BalancedBinaryTree.java ├── 1103. Distribute Candies to People └── DistributeCandiesToPeople.java ├── 111. Minimum Depth of Binary Tree ├── MinimumDepthOfBinaryTree_BFS.java ├── MinimumDepthOfBinaryTree_DFS_Iterative.java └── MinimumDepthOfBinaryTree_DFS_Recursive.java ├── 112. Path Sum ├── PathSum_BFS.java ├── PathSum_DFS_Iterative.java └── PathSum_DFS_Recursive.java ├── 1122. Relative Sort Array ├── RelativeSortArray_CountingSort_Sorting.java └── RelativeSortArray_HashTable.java ├── 113. Path Sum II ├── PathSumII_DFS_Iterative_Backtracking.java └── PathSumII_DFS_Recursive_Backtracking.java ├── 1137. N-th Tribonacci Number ├── NthTribonacciNumber_Iterative.java └── NthTribonacciNumber_Recursive.java ├── 114. Flatten Binary Tree to Linked List ├── FlattenBinaryTreeToLinkedList_Iterative.java └── FlattenBinaryTreeToLinkedList_Recursive.java ├── 1154. Day of the Year └── DayOfTheYear.java ├── 1155. Number of Dice Rolls With Target Sum ├── NumberOfDiceRollsWithTargetSum_Memoization.java └── NumberOfDiceRollsWithTargetSum_Tabulation.java ├── 12. Integer to Roman ├── IntegerToRoman_HashTable.java └── IntegerToRoman_WithoutHashTable.java ├── 1207. Unique Number of Occurrences ├── UniqueNumberOfOccurrences_Counting_Sorting.java └── UniqueNumberOfOccurrences_HashTable.java ├── 121. Best Time to Buy and Sell Stock ├── BestTimeToBuyAndSellStock.java └── BestTimeToBuyAndSellStock_DynamicProgramming.java ├── 1232. Check If It Is a Straight Line └── CheckIfItIsAStraightLine.java ├── 1239. Maximum Length of a Concatenated String with Unique Characters ├── MaximumLengthOfAConcatenatedStringWithUniqueCharacters_Backtracking.java └── MaximumLengthOfAConcatenatedStringWithUniqueCharacters_BitManipulation.java ├── 129. Sum Root to Leaf Numbers ├── SumRootToLeafNumbers_DFS_Iterative.java └── SumRootToLeafNumbers_DFS_Recursive.java ├── 1295. Find Numbers with Even Number of Digits └── FindNumbersWithEvenNumberOfDigits.java ├── 1299. Replace Elements with Greatest Element on Right Side └── ReplaceElementsWithGreatestElementOnRightSide.java ├── 13. Roman to Integer ├── RomanToInteger_HashMap.java └── RomanToInteger_WithoutHashMap.java ├── 130. Surrounded Regions ├── SurroundedRegions_BFS.java ├── SurroundedRegions_DFS.java └── SurroundedRegions_UnionFind.java ├── 1318. Minimum Flips to Make a OR b Equal to c └── MinimumFlipsToMakeAORBEqualToC.java ├── 1323. Maximum 69 Number ├── Maximum69Number_Math.java └── Maximum69Number_String.java ├── 1328. Break a Palindrome └── BreakAPalindrome.java ├── 1337. The K Weakest Rows in a Matrix ├── TheKWeakestRowsInAMatrix.java ├── TheKWeakestRowsInAMatrix_BinarySearch.java ├── TheKWeakestRowsInAMatrix_BinarySearch_PriorityQueue.java └── TheKWeakestRowsInAMatrix_BinarySearch_Sorting.java ├── 134. Gas Station └── GasStation.java ├── 1342. Numbers of Steps to Reduce a Number to Zero ├── NumberOfStepsToReduceANumberToZero_BitManipulation.java └── NumberOfStepsToReduceANumberToZero_Math.java ├── 1346. Check If N and Its Double Exist ├── CheckIfNAndItsDoubleExist_HashTable.java ├── CheckIfNAndItsDoubleExist_Sorting_BinarySearch.java └── CheckIfNAndItsDoubleExist_TwoPointers.java ├── 1351. Count Negative Numbers in a Sorted Matrix ├── CountNegativeNumbersInASortedMatrix.java └── CountNegativeNumbersInASortedMatrix_BinarySearch.java ├── 136. Single Number ├── SingleNumber.java └── SingleNumber_StreamReduce.java ├── 144. Binary Tree Preorder Traversal ├── BinaryTreePreorderTraversal_Iterative.java └── BinaryTreePreorderTraversal_Recursive.java ├── 1446. Consecutive Characters └── ConsecutiveCharacters.java ├── 145. Binary Tree Postorder Traversal ├── BinaryTreePostorderTraversal_Iterative.java └── BinaryTreePostorderTraversal_Recursive.java ├── 1457. Pseudo-Palindromic Paths in a Binary Tree ├── PseudoPalindromicPathsInABinaryTree_BFS.java ├── PseudoPalindromicPathsInABinaryTree_DFS_Iterative.java └── PseudoPalindromicPathsInABinaryTree_DFS_Recursive.java ├── 1470. Shuffle the Array └── ShuffleTheArray.java ├── 1480. Running Sum of 1D Array └── RunningSumOf1DArray.java ├── 1486. XOR Operation in an Array └── XOROperationInAnArray.java ├── 1497. Check If Array Pairs Are Divisible by k ├── CheckIfArrayPairsAreDivisibleByK_Counting.java └── CheckIfArrayPairsAreDivisibleByK_HashTable.java ├── 15. 3Sum └── ThreeSum.java ├── 151. Reverse Words in a String ├── ReverseWordsInAString_Collections.java ├── ReverseWordsInAString_StringBuilder.java └── ReverseWordsInAString_TwoPointers.java ├── 152. Maximum Product Subarray ├── MaximumProductSubarray.java └── MaximumProductSubarray_DynamicProgramming.java ├── 1523. Count Odd Numbers in an Interval Range └── CountOddNumbersInAnIntervalRange.java ├── 1534. Count Good Triplets └── CountGoodTriplets.java ├── 1544. Make The String Great └── MakeTheStringGreat_Stack.java ├── 1578. Minimum Time to Make Rope Colorful ├── MinimumTimeToMakeRopeColorful_DynamicProgramming.java └── MinimumTimeToMakeRopeColorful_Greedy.java ├── 1592. Rearrange Spaces Between Words └── RearrangeSpacesBetweenWords.java ├── 16. 3Sum Closest └── ThreeSumClosest.java ├── 1603. Design Parking System └── ParkingSystem.java ├── 1636. Sort Array by Increasing Frequency └── SortArrayByIncreasingFrequency.java ├── 1657. Determine if Two Strings Are Close ├── DetermineIfTwoStringsAreClose_Sorting.java └── DetermineIfTwoStringsAreClose_Sorting_HashTable.java ├── 1662. Check If Two String Arrays are Equivalent ├── CheckIfTwoStringArraysAreEquivalent_Pointers.java └── CheckIfTwoStringArraysAreEquivalent_String.java ├── 167. Two Sum II - Input Array is Sorted ├── TwoSumII_InputArrayIsSorted_BinarySearch.java └── TwoSumII_InputArrayIsSorted_TwoPointers.java ├── 1672. Richest Customer Wealth └── RichestCustomerWealth.java ├── 1679. Max Number of K-Sum Pairs ├── MaxNumberOfKSumPairs_HashTable.java └── MaxNumberOfKSumPairs_Sorting_TwoPointers.java ├── 1680. Concatenation of Consecutive Binary Numbers ├── ConcatenationOfConsecutiveBinaryNumbers_BitManipulation.java └── ConcatenationOfConsecutiveBinaryNumbers_Math.java ├── 169. Majority Element ├── MajorityElement_BoyerMooreVotingAlgorithm.java ├── MajorityElement_DivideAndConquer_Counting.java ├── MajorityElement_HashTable_Counting.java └── MajorityElement_Sorting.java ├── 1704. Determine if String Halves Are Alike └── DetermineIfStringHalvesAreAlike.java ├── 1711. Count Good Meals └── CountGoodMeals.java ├── 1732. Find the Highest Altitude └── FindTheHighestAltitude.java ├── 1775. Equal Sum Arrays With Minimum Number of Operations └── EqualSumArraysWithMinimumNumberOfOperations_Counting.java ├── 1814. Count Nice Pairs in an Array └── CountNicePairsInAnArray.java ├── 1832. Check if the Sentence Is Pangram ├── CheckIfTheSentenceIsPangram.java ├── CheckIfTheSentenceIsPangram_BitManipulation.java ├── CheckIfTheSentenceIsPangram_Counting.java └── CheckIfTheSentenceIsPangram_HashSet.java ├── 1833. Maximum Ice Cream Bars └── MaximumIceCreamBars.java ├── 1834. Single-Threaded CPU └── SingleThreadedCPU.java ├── 1865. Finding Pairs With a Certain Sum └── FindingPairsWithACertainSum.java ├── 1869. Longer Contiguous Segments of Ones than Zeros └── LongerContiguousSegmentsOfOnesThanZeros.java ├── 19. Remove Nth Node From End of List ├── RemoveNthNodeFromEndOfList_OnePass.java └── RemoveNthNodeFromEndOfList_TwoPasses.java ├── 1920. Build Array from Permutation └── BuildArrayFromPermutation.java ├── 1926. Nearest Exit from Entrance in Maze └── NearestExitFromEntranceInMaze.java ├── 1935. Maximum Number of Words You Can Type └── MaximumNumberOfWordsYouCanType.java ├── 1962. Remove Stones to Minimize the Total └── RemoveStonesToMinimizeTheTotal.java ├── 1971. Find if Path Exists in Graph ├── FindIfPathExistsInGraph_BFS.java ├── FindIfPathExistsInGraph_DFS_Iterative.java ├── FindIfPathExistsInGraph_DFS_Recursive.java └── FindIfPathExistsInGraph_UnionFind.java ├── 1979. Find Greatest Common Divisor of Array └── FindGreatestCommonDivisorOfArray.java ├── 1995. Count Special Quadruplets ├── CountSpecialQuadruplets.java └── CountSpecialQuadruplets_HashTable.java ├── 200. Number of Islands ├── NumberOfIslands_BFS.java ├── NumberOfIslands_DFS.java └── NumberOfIslands_UnionFind.java ├── 2006. Count Number of Pairs With Absolute Difference K ├── CountNumberOfPairsWithAbsoluteDifferenceK.java ├── CountNumberOfPairsWithAbsoluteDifferenceK_Counting.java └── CountNumberOfPairsWithAbsoluteDifferenceK_HashTable.java ├── 2007. Find Original Array From Doubled Array ├── FindOriginalArrayFromDoubledArray_Counting.java ├── FindOriginalArrayFromDoubledArray_HashMap_Sorting.java └── FindOriginalArrayFromDoubledArray_Queue_Sorting.java ├── 2023. Number of Pairs of Strings With Concatenation Equal to Target └── NumberOfPairsOfStringsWithConcatenationEqualToTarget_HashTable.java ├── 2028. Find Missing Observations └── FindMissingObservations.java ├── 205. Isomorphic Strings └── IsomorphicStrings.java ├── 206. Reverse Linked List ├── ReverseLinkedList.java ├── ReverseLinkedList_Iterative.java └── ReverseLinkedList_Recursive.java ├── 2095. Delete the Middle Node of a Linked List └── DeleteTheMiddleNodeOfALinkedList.java ├── 2129. Capitalize the Title └── CapitalizeTheTitle.java ├── 2130. Maximum Twin Sum of a Linked List ├── MaximumTwinSumOfALinkedList_TwoPointers.java └── MaximumTwinSumOfALinkedList_TwoPointers_Stack.java ├── 2131. Longest Palindrome by Concatenating Two Letter Words ├── LongestPalindromeByConcatenatingTwoLetterWords_Counting.java └── LongestPalindromeByConcatenatingTwoLetterWords_HashTable.java ├── 2133. Check if Every Row and Column Contains All Numbers ├── CheckIfEveryRowAndColumnContainsAllNumbers.java └── CheckIfEveryRowAndColumnContainsAllNumbers_HashTable.java ├── 2136. Earliest Possible Day of Full Bloom └── EarliestPossibleDayOfFullBloom.java ├── 2169. Count Operations to Obtain Zero └── CountOperationsToObtainZero.java ├── 217. Contains Duplicate ├── ContainsDuplicate_HashMap.java ├── ContainsDuplicate_HashSet.java └── ContainsDuplicate_Sorting.java ├── 2176. Count Equal and Divisible Pairs in an Array └── CountEqualAndDivisiblePairsInAnArray.java ├── 219. Contains Duplicate II ├── ContainsDuplicateII_HashMap.java └── ContainsDuplicateII_SlidingWindow.java ├── 220. Contains Duplicate III ├── ContainsDuplicateIII_SlidingWindow_HashMap_BucketSort.java ├── ContainsDuplicateIII_SlidingWindow_TreeSet_OrderedSet.java └── ContainsDuplicateIII_Sorting.java ├── 222. Count Complete Tree Nodes └── CountCompleteTreeNodes.java ├── 2220. Minimum Bit Flips to Convert Number └── MinimumBitFlipsToConvertNumber.java ├── 223. Rectangle Area └── RectangleArea.java ├── 2240. Number of Ways to Buy Pens and Pencils └── NumberOfWaysToBuyPensAndPencils.java ├── 2244. Minimum Rounds to Complete All Tasks └── MinimumRoundsToCompleteAllTasks.java ├── 225. Implement Stack using Queues └── ImplementStackUsingQueues.java ├── 226. Invert Binary Tree ├── InvertBinaryTree_BFS.java ├── InvertBinaryTree_DFS_Iterative.java └── InvertBinaryTree_DFS_Recursive.java ├── 2279. Maximum Bags With Full Capacity of Rocks └── MaximumBagsWithFullCapacityOfRocks.java ├── 228. Summary Ranges └── SummaryRanges.java ├── 229. Majority Element II ├── MajorityElementII_BoyerMooreVotingAlgorithm.java ├── MajorityElementII_HashTable_Counting.java └── MajorityElementII_Sorting.java ├── 2315. Count Asterisks └── CountAsterisks.java ├── 232. Implement Queue using Stacks └── ImplementQueueUsingStacks.java ├── 2351. First Letter to Appear Twice ├── FirstLetterToAppearTwice_Counting.java └── FirstLetterToAppearTwice_HashTable.java ├── 2352. Equal Row and Column Pairs └── EqualRowAndColumnPairs.java ├── 2359. Find Closest Node to Given Two Nodes └── FindClosestNodeToGivenTwoNodes_DFS.java ├── 238. Product of Array Except Self └── ProductOfArrayExceptSelf.java ├── 2389. Longest Subsequence With Limited Sum └── LongestSubsequenceWithLimitedSum.java ├── 2395. Find Subarrays With Equal Sum └── FindSubarraysWithEqualSum.java ├── 2399. Check Distances Between Same Letters ├── CheckDistancesBetweenSameLetters.java └── CheckDistancesBetweenSameLetters_HashTable.java ├── 24. Swap Nodes in Pairs ├── SwapNodesInPairs.java └── SwapNodesInPairs_Recursion.java ├── 2413. Smallest Even Multiple └── SmallestEvenMultiple.java ├── 2437. Number of Valid Clock Times └── NumberOfValidClockTimes.java ├── 2438. Range Product Queries of Powers └── RangeProductQueriesOfPowers.java ├── 2451. Odd String Difference ├── OddStringDifference.java └── OddStringDifference_HashTable.java ├── 2452. Words Within Two Edits of Dictionary └── WordsWithinTwoEditsOfDictionary.java ├── 2453. Destroy Sequential Targets └── DestroySequentialTargets_HashTable.java ├── 2454. Next Greater Element IV └── NextGreaterElementIV_MonotonicStack.java ├── 257. Binary Tree Paths ├── BinaryTreePaths_DFS_Iterative_Backtracking.java └── BinaryTreePaths_DFS_Recursive_Backtracking.java ├── 26. Remove Duplicates from Sorted Array └── RemoveDuplicatesFromSortedArray.java ├── 263. Ugly Number └── UglyNumber.java ├── 264. Ugly Number II ├── UglyNumberII_DynamicProgramming.java └── UglyNumberII_PriorityQueue.java ├── 27. Remove Element └── RemoveElement.java ├── 274. H-Index ├── HIndex_CountingSort.java └── HIndex_Sorting.java ├── 275. H-Index II └── HIndexII.java ├── 283. Move Zeroes └── MoveZeroes.java ├── 29. Divide Two Integers └── DivideTwoIntegers.java ├── 290. Word Pattern └── WordPattern.java ├── 295. Find Median from Data Stream └── MedianFinder_PriorityQueue.java ├── 3. Longest Substring Without Repeating Characters ├── LongestSubstringWithoutRepeatingCharacters.java └── LongestSubstringWithoutRepeatingCharacters_HashTable.java ├── 334. Increasing Triplet Subsequence └── IncreasingTripletSubsequence.java ├── 344. Reverse String └── ReverseString_TwoPointers.java ├── 345. Reverse Vowels of a String └── ReverseVowelsOfAString_TwoPointers.java ├── 36. Valid Sudoku ├── ValidSudoku.java └── ValidSudoku_HashTable.java ├── 368. Largest Divisible Subset └── LargestDivisibleSubset.java ├── 37. Sudoku Solver └── SudokuSolver.java ├── 371. Sum of Two Integers └── SumOfTwoIntegers.java ├── 374. Guess Number Higher or Lower └── GuessNumberHigherOrLower_BinarySearch.java ├── 38. Count and Say ├── CountAndSay_Iterative.java └── CountAndSay_Recursive.java ├── 383. Ransom Note ├── RansomNote_Counting.java └── RansomNote_HashTable.java ├── 393. UTF-8 Validation ├── UTF8Validation.java └── UTF8Validation_BitManipulation.java ├── 404. Sum of Left Leaves ├── SumOfLeftLeaves_BFS.java ├── SumOfLeftLeaves_DFS_Iterative.java └── SumOfLeftLeaves_DFS_Recursive.java ├── 412. Fizz Buzz └── FizzBuzz.java ├── 414. Third Maximum Number ├── ThirdMaximumNumber.java ├── ThirdMaximumNumber_PriorityQueue_HashSet.java └── ThirdMaximumNumber_Sorting.java ├── 429. N-ary Tree Level Order Traversal └── NAryTreeLevelOrderTraversal.java ├── 437. Path Sum III ├── PathSumIII_DFS_Iterative.java └── PathSumIII_DFS_Recursive.java ├── 438. Find All Anagrams in a String └── FindAllAnagramsInAString.java ├── 448. Find All Numbers Disappeared in an Array ├── FindAllNumbersDisappearedInAnArray.java └── FindAllNumbersDisappearedInAnArray_HashTable.java ├── 45. Jump Game II ├── JumpGameII_DynamicProgramming_Memoization.java ├── JumpGameII_DynamicProgramming_Tabulation.java └── JumpGameII_Greedy.java ├── 46. Permutations ├── Permutations_Backtracking_Recursion.java ├── Permutations_Iteration.java └── Permutations_Recursion.java ├── 485. Maximum Consecutive Ones └── MaxConsecutiveOnes.java ├── 49. Group Anagrams └── GroupAnagrams.java ├── 492. Construct the Rectangle └── ConstructTheRectangle.java ├── 496. Next Greater Element I └── NextGreaterElementI_HashTable_MonotonicStack.java ├── 5. Longest Palindromic Substring ├── LongestPalindromicSubstring_DynamicProgramming.java ├── LongestPalindromicSubstring_TwoPointers1.java └── LongestPalindromicSubstring_TwoPointers2.java ├── 503. Next Greater Element II └── NextGreaterElementII.java ├── 509. Fibonacci Number ├── FibonacciNumber_Iterative.java └── FibonacciNumber_Recursive.java ├── 520. Detect Capital └── DetectCapital.java ├── 523. Continuous Subarray Sum └── ContinuousSubarraySum.java ├── 541. Reverse String II ├── ReverseStringII_StringBuilder.java └── ReverseStringII_TwoPointers.java ├── 55. Jump Game ├── JumpGame_DynamicProgramming.java └── JumpGame_Greedy.java ├── 556. Next Greater Element III └── NextGreaterElementIII.java ├── 557. Reverse Words in a String III ├── ReverseWordsInAStringIII_StringBuilder.java └── ReverseWordsInAStringIII_TwoPointers.java ├── 559. Maximum Depth of N-ary Tree ├── MaximumDepthOfNAryTree_BFS.java ├── MaximumDepthOfNAryTree_DFS_Iterative.java └── MaximumDepthOfNAryTree_DFS_Recursive.java ├── 560. Subarray Sum Equals K └── SubarraySumEqualsK.java ├── 561. Array Partition ├── ArrayPartition_CountingSort_Greedy.java └── ArrayPartition_Sorting_Greedy.java ├── 567. Permutation in String └── PermutationInString.java ├── 57. Insert Interval └── InsertInterval.java ├── 593. Valid Square └── ValidSquare.java ├── 6. Zigzag Conversion └── ZigzagConversion.java ├── 609. Find Duplicate File in System └── FindDuplicateFileInSystem_HashMap.java ├── 645. Set Mismatch ├── SetMismatch_BitManipulation.java ├── SetMismatch_HashTable.java └── SetMismatch_Sorting.java ├── 653. Two Sum IV - Input is a BST ├── TwoSumIV_InputIsABST_BFS_WithHashTable.java ├── TwoSumIV_InputIsABST_BFS_WithoutHashTable.java ├── TwoSumIV_InputIsABST_DFS_Iterative.java ├── TwoSumIV_InputIsABST_DFS_Iterative_TwoPointers.java ├── TwoSumIV_InputIsABST_DFS_Recursive.java └── TwoSumIV_InputIsABST_DFS_Recursive_TwoPointers.java ├── 70. Climbing Stairs ├── ClimbingStairs_Iterative.java └── ClimbingStairs_Recursive.java ├── 707. Design Linked List ├── DoublyLinkedList.java └── SinglyLinkedList.java ├── 713. Subarray Product Less Than K └── SubarrayProductLessThanK.java ├── 73. Set Matrix Zeroes ├── SetMatrixZeroes_Array.java ├── SetMatrixZeroes_HashTable.java └── SetMatrixZeroes_InPlace.java ├── 744. Find Smallest Letter Greater Than Target ├── FindSmallestLetterGreaterThanTarget.java └── FindSmallestLetterGreaterThanTarget_BinarySearch.java ├── 746. Min Cost Climbing Stairs ├── MinCostClimbingStairs_Iterative.java └── MinCostClimbingStairs_Recursive.java ├── 766. Toeplitz Matrix ├── ToeplitzMatrix.java ├── ToeplitzMatrix_OneColumnAtATime.java └── ToeplitzMatrix_OneRowAtATime.java ├── 783. Minimum Distance Between BST Nodes ├── MinimumDistanceBetweenBSTNodes_BFS.java ├── MinimumDistanceBetweenBSTNodes_DFS_Iterative.java └── MinimumDistanceBetweenBSTNodes_DFS_Recursive.java ├── 79. Word Search └── WordSearch.java ├── 797. All Paths From Source to Target ├── AllPathsFromSourceToTarget_BFS.java ├── AllPathsFromSourceToTarget_DFS_Iterative.java ├── AllPathsFromSourceToTarget_DFS_Recursive.java └── AllPathsFromSourceToTarget_DFS_Recursive_Backtracking.java ├── 80. Remove Duplicates from Sorted Array II └── RemoveDuplicatesFromSortedArrayII.java ├── 812. Largest Triangle Area └── LargestTriangleArea.java ├── 835. Image Overlap ├── ImageOverlap_BitManipulation.java └── ImageOverlap_HashTable.java ├── 836. Rectangle Overlap └── RectangleOverlap.java ├── 876. Middle of the Linked List └── MiddleOfTheLinkedList.java ├── 88. Merge Sorted Array ├── MergeSortedArray_Sorting.java └── MergeSortedArray_TwoPointers.java ├── 904. Fruit Into Baskets └── FruitIntoBaskets.java ├── 905. Sort Array By Parity └── SortArrayByParity.java ├── 92. Reverse Linked List II └── ReverseLinkedListII.java ├── 922. Sort Array By Parity II └── SortArrayByParityII.java ├── 923. 3Sum With Multiplicity ├── ThreeSumWithMultiplicity_Counting.java ├── ThreeSumWithMultiplicity_HashTable.java └── ThreeSumWithMultiplicity_Sorting_TwoPointers.java ├── 929. Unique Email Addresses └── UniqueEmailAddresses_HashSet.java ├── 94. Binary Tree Inorder Traversal ├── BinaryTreeInorderTraversal_Iterative.java └── BinaryTreeInorderTraversal_Recursive.java ├── 941. Valid Mountain Array └── ValidMountainArray_TwoPointers.java ├── 944. Delete Columns to Make Sorted └── DeleteColumnsToMakeSorted.java ├── 948. Bag of Tokens └── BagOfTokens.java ├── 953. Verifying an Alien Dictionary └── VerifyingAnAlienDictionary.java ├── 967. Numbers With Same Consecutive Differences ├── NumbersWithSameConsecutiveDifferences_BFS.java └── NumbersWithSameConsecutiveDifferences_Backtracking.java ├── 974. Subarray Sums Divisible by K ├── SubarraySumsDivisibleByK_Counting.java └── SubarraySumsDivisibleByK_HashTable.java ├── 976. Largest Perimeter Triangle └── LargestPerimeterTriangle.java ├── 977. Squares of a Sorted Array ├── SquaresOfASortedArray_Sorting.java └── SquaresOfASortedArray_TwoPointers.java ├── 98. Validate Binary Search Tree ├── ValidateBinarySearchTree_DFS_Iterative.java └── ValidateBinarySearchTree_DFS_Recursive.java ├── 985. Sum of Even Numbers After Queries └── SumOfEvenNumbersAfterQueries.java ├── 988. Smallest String Starting From Leaf ├── SmallestStringStartingFromLeaf_DFS_Iterative.java └── SmallestStringStartingFromLeaf_DFS_Recursive.java └── 989. Add to Array-Form of Integer └── AddToArrayFormOfInteger.java /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheehwatang/leetcode-java/6e596c65f719eeb0b05c72381faad24d2f35e239/.github/PULL_REQUEST_TEMPLATE.md -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore all markdown files. 2 | *.md 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright © 2023 Chee Hwa Tang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /solutions/1037. Valid Boomerang/ValidBoomerang.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(1), 4 | // as it is only an arithmetic calculation. 5 | // 6 | // Space Complexity : O(1), 7 | // as no additional space is used. 8 | 9 | public class ValidBoomerang { 10 | 11 | // Approach: 12 | // The three points forms a boomerang when the points form different slopes. 13 | // The points are linear if they have the same slopes. 14 | // Thus, 15 | // Slope_AB = (yB - yA) / (xB - xA) == (p[1][1] - p[0][1]) / (p[1][0] - p[0][0]) 16 | // Slope_BC = (yC - yB) / (xC - xB) == (p[2][1] - p[1][1]) / (p[2][0] - p[1][0]) 17 | // Boomerang when Slope_AB != Slope_BC. 18 | // Rather than calculating the fractions, which could be problematic with floating points, 19 | // rearrange the equation by multiplying the equation by its denominators. 20 | // (Slope_AB != Slope_BC) == ((yB - yA) * (xC - xB) != (yC - yB) * (xB - xA)). 21 | // 22 | // Note: Another method is to calculate the area of the triangle to check if the area is > 0, 23 | // with area = Math.abs((xA * (yB - yC)) + (xB * (yC - yA)) + (xC * (yA - yB)) / 2. 24 | 25 | public boolean isBoomerang(int[][] points) { 26 | // If the index of the array is confusing, we can use additional memory to 27 | // assign the coordinates to variables before calculating the slopes. 28 | // For Example: xA = points[0][0], xB = points[1][0], etc. 29 | return (points[1][1] - points[0][1]) * (points[2][0] - points[1][0]) 30 | != (points[2][1] - points[1][1]) * (points[1][0] - points[0][0]); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /solutions/104. Maximum Depth of Binary Tree/MaximumDepthOfBinaryTree_DFS_Recursive.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | /** 4 | * Definition for a binary tree node. 5 | * public class TreeNode { 6 | * int val; 7 | * TreeNode left; 8 | * TreeNode right; 9 | * TreeNode() {} 10 | * TreeNode(int val) { this.val = val; } 11 | * TreeNode(int val, TreeNode left, TreeNode right) { 12 | * this.val = val; 13 | * this.left = left; 14 | * this.right = right; 15 | * } 16 | * } 17 | */ 18 | // Note: Remember to set up a TreeNode class as the same folder. 19 | 20 | // Time Complexity : O(n), 21 | // where 'n' is the number of nodes in the tree. 22 | // We traverse every node in the binary tree to find the maximum depth of the tree. 23 | // 24 | // Space Complexity : O(m), 25 | // where 'm' is the depth of the tree. 26 | // The maximum size of the recursive call stack is the depth of the tree. 27 | 28 | public class MaximumDepthOfBinaryTree_DFS_Recursive { 29 | 30 | // Approach: 31 | // Using depth-first search to find the depth of every node. 32 | // Then, compare and find the maximum depth. 33 | // Here, the depth-first search is implemented recursively. 34 | 35 | public int maxDepth(TreeNode root) { 36 | // If the tree is empty, there is zero depth. 37 | if (root == null) return 0; 38 | 39 | // Traverse the left and right nodes. 40 | // The level of the 'root' is one level greater than the level of the left or the right node, 41 | // whichever is greater. 42 | return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /solutions/1051. Height Checker/HeightChecker_CountingSort.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'heights'. 5 | // We traverse the array 'heights' twice, once for the counting sort, 6 | // and once to compare with the counting array. 7 | // 8 | // Space Complexity : O(1), 9 | // as the counting array used has a fixed size of 101, independent on the size of the input array 'heights'. 10 | // Note: The counting array is set up based on the constraints stated in the problem. 11 | 12 | public class HeightChecker_CountingSort { 13 | 14 | // Approach: 15 | // First, we perform a counting sort on the 'heights' array, using an integer array of size 101. 16 | // This is possible because the constraint in the problem stated the range of height is from 1 to 100. 17 | // The size 101 is used because the integer array is zero-indexed. 18 | // 19 | // Then, we traverse the 'heights' array to compare with the heights in the counting sort array, 20 | // in ascending order, and count the number of heights that are different. 21 | 22 | public int heightChecker(int[] heights) { 23 | // Set up the counting array. 24 | int[] counting = new int[101]; 25 | // Perform counting sort, where the index of the 'counting' array is the height. 26 | for (int height : heights) counting[height]++; 27 | 28 | int count = 0; 29 | // The minimum height starts at 1. 30 | int sortedHeight = 1; 31 | // For each height, check if it is the same height as the sorted height. 32 | // If it is different, then add to the 'count'. 33 | for (int height : heights) { 34 | while (counting[sortedHeight] == 0) sortedHeight++; 35 | 36 | if (sortedHeight != height) count++; 37 | // Remove the checked height from the 'counting' array. 38 | counting[sortedHeight]--; 39 | } 40 | return count; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /solutions/1051. Height Checker/HeightChecker_Sorting.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | // Time Complexity : O(n logn), 6 | // where 'n' is the length of 'heights'. 7 | // The cloning the 'heights' array, and the traversal of 'heights' array has O(n) time complexity. 8 | // The sorting of the cloned array has a time complexity of O(n logn), 9 | // according to the Dual-Pivot Quicksort method implemented. 10 | // 11 | // Space Complexity : O(n), 12 | // where 'n' is the length of 'heights'. 13 | // We clone the 'heights' array of length 'n'. 14 | 15 | public class HeightChecker_Sorting { 16 | 17 | // Approach: 18 | // We clone the 'heights' array and sort it to get the 'expected' array. 19 | // Then, we compare the 'expected' and 'heights' array to count the number of heights that are different. 20 | 21 | public int heightChecker(int[] heights) { 22 | // Clone and sort the array to get the 'expected' array. 23 | int[] expected = heights.clone(); 24 | Arrays.sort(expected); 25 | 26 | int count = 0; 27 | // Traverse both 'expected' and 'heights' arrays to compare and count the number of heights that are different. 28 | for (int i = 0; i < heights.length; i++) { 29 | if (heights[i] != expected[i]) count++; 30 | } 31 | return count; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /solutions/1089. Duplicate Zeros/DuplicateZeros.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n^2), 4 | // where 'n' is the length of 'arr', 5 | // as the worst case being every element in 'arr' is zero, thus requires shifting the array for every element. 6 | // 7 | // Space Complexity : O(1), 8 | // as not new arrays are created. 9 | 10 | public class DuplicateZeros { 11 | 12 | // Approach: 13 | // Using the System.arraycopy() function to shift the elements in the array. 14 | 15 | public void duplicateZeros(int[] arr) { 16 | int n = arr.length; 17 | for (int i = 0; i < n; i++) { 18 | // Move to the next element if the integer is not zero. 19 | if (arr[i] != 0) continue; 20 | 21 | // The inputs for System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length). 22 | // Note that this is in-place as well, if the 'src' and 'dest' is the same. 23 | System.arraycopy(arr, i, arr, i + 1, n - 1 - i); 24 | 25 | // Take note to shift to pointer forward once as the next element is updated to zero. 26 | i++; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /solutions/1089. Duplicate Zeros/DuplicateZeros_TwoPointers.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n^2), 4 | // where 'n' is the length of 'arr', 5 | // as the worst case being every element in 'arr' is zero, thus requires shifting the array for every element. 6 | // 7 | // Space Complexity : O(1), 8 | // as not new arrays are created. 9 | 10 | public class DuplicateZeros_TwoPointers { 11 | 12 | // Approach: 13 | // Using an additional pointer to shift the elements to the right when found at zero. 14 | 15 | public void duplicateZeros(int[] arr) { 16 | int n = arr.length; 17 | for (int i = 0; i < n; i++) { 18 | // Move to the next element if the integer is not zero. 19 | if (arr[i] != 0) continue; 20 | 21 | // Shift the elements to the right, including the zero found. 22 | for (int j = n - 1; j > i ; j--) 23 | arr[j] = arr[j - 1]; 24 | 25 | // Take note to shift to pointer forward once as the next element is updated to zero. 26 | i++; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /solutions/1103. Distribute Candies to People/DistributeCandiesToPeople.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(sqrt(n)), 4 | // where 'n' is 'candies'. 5 | // For each person, the number of candies given increases by one. 6 | // Thus, the total number distributed candies is "n * (n + 1) / 2", resulting in time complexity of O(sqrt(n)). 7 | // 8 | // Space Complexity : O(m), 9 | // where 'm' is 'num_people'. 10 | // The result array has the length of 'num_people'. 11 | 12 | public class DistributeCandiesToPeople { 13 | 14 | // Approach: 15 | // Use two variables, 16 | // 1. 'person' to track the index of the person, and 17 | // 2. 'candy' to track the number of candies that should be given. 18 | // Then rotate the index while slowly reduce the total number of candies, while increasing the candy count. 19 | // Record the result in an int[]. 20 | 21 | public int[] distributeCandies(int candies, int num_people) { 22 | // Integer array to record the distribution of candies. 23 | int[] result = new int[num_people]; 24 | 25 | int person = 0; 26 | int candy = 1; 27 | 28 | // While we still have candies, add the candy count to the int[], and reduce the candies. 29 | // Each iteration increase the candy and people by 1. 30 | while (candies > 0) { 31 | // If candies is more than candy, return candy. 32 | // However, if the remaining candies is less than candy, distribute the remaining candies. 33 | result[person] += Math.min(candies, candy); 34 | candies -= candy++; 35 | // With the remainder operator %, the person will restart at index 0 once we reach the 'num_people'. 36 | person = (person + 1) % num_people; 37 | } 38 | return result; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /solutions/1137. N-th Tribonacci Number/NthTribonacciNumber_Iterative.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the input 'n'. 5 | // We traverse from 3 to 'n' to calculate the n-th tribonacci number. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input. 9 | 10 | public class NthTribonacciNumber_Iterative { 11 | 12 | // Approach: 13 | // We use the iterative method, using the variable 'first', 'second' and 'third' to keep track. 14 | 15 | public int tribonacci(int n) { 16 | if (n == 0 || n == 1) return n; 17 | if (n == 2) return 1; 18 | 19 | // As we need both 'n - 1', 'n - 2' and 'n - 3' to start, record 'first', 'second' and 'third', respectively. 20 | // For each iteration until n, sum all three numbers and replace the numbers. 21 | int first = 1; 22 | int second = 1; 23 | int third = 0; 24 | int result = 0; 25 | for (int i = 3; i <= n; i++) { 26 | result = first + second + third; 27 | third = second; 28 | second = first; 29 | first = result; 30 | } 31 | return result; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /solutions/1137. N-th Tribonacci Number/NthTribonacciNumber_Recursive.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the input 'n'. 5 | // The recursive call stack has a maximum height of 'n'. 6 | // 7 | // Space Complexity : O(n), 8 | // where 'n' is the input 'n'. 9 | // We use a memo of size 'n' to store the tribonacci numbers. 10 | // Additionally, the recursive call stack has a maximum height of 'n'. 11 | 12 | public class NthTribonacciNumber_Recursive { 13 | 14 | // Approach: 15 | // We use the recursive method, using the 'memo' keep track of the calculated number to lower the time complexity. 16 | 17 | public int tribonacci(int n) { 18 | 19 | // Use an integer array as 'memo' to record the results that was calculated. 20 | // This is so to not repeat the same calculation over the recursive calls. 21 | int[] memo = new int[n + 1]; 22 | return tribonacci(n, memo); 23 | } 24 | 25 | private int tribonacci(int n, int[] memo) { 26 | if (n == 0 || n == 1) return n; 27 | if (n == 2) return 1; 28 | 29 | // Record the first three element in the Fibonacci sequence. 30 | memo[1] = 1; 31 | memo[2] = 1; 32 | 33 | // If the ways for n is not recorded in the 'memo' yet, then calculate and record the result into the memo. 34 | if (memo[n] == 0) { 35 | memo[n] = tribonacci(n - 1, memo) + tribonacci(n - 2, memo) + tribonacci(n - 3, memo); 36 | } 37 | return memo[n]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /solutions/114. Flatten Binary Tree to Linked List/FlattenBinaryTreeToLinkedList_Recursive.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | /** 4 | * Definition for a binary tree node. 5 | * public class TreeNode { 6 | * int val; 7 | * TreeNode left; 8 | * TreeNode right; 9 | * TreeNode() {} 10 | * TreeNode(int val) { this.val = val; } 11 | * TreeNode(int val, TreeNode left, TreeNode right) { 12 | * this.val = val; 13 | * this.left = left; 14 | * this.right = right; 15 | * } 16 | * } 17 | */ 18 | // Note: Remember to set up a TreeNode class as the same folder. 19 | 20 | // Time Complexity : O(n), 21 | // where 'n' is the number of nodes in the tree. 22 | // We traverse the nodes from right to left to flatten the tree to a linked list. 23 | // 24 | // Space Complexity : O(1), 25 | // as we are only changing the left and right pointers in each node to flatten the tree. 26 | 27 | public class FlattenBinaryTreeToLinkedList_Recursive { 28 | 29 | // As we are using flatten() as recursive method, we need to store the 'previous' node outside of the method. 30 | TreeNode previous = null; 31 | 32 | public void flatten(TreeNode root) { 33 | if (root == null) return; 34 | 35 | // As we are flattening the binary tree in the preorder arrangement, we flatten the right child node first. 36 | flatten(root.right); 37 | flatten(root.left); 38 | // As we flatten, we set the left child node to null and the right to the previous node checked. 39 | // This ensures we flatten from the rightmost leaf node to the leftmost leaf node. 40 | root.left = null; 41 | root.right = previous; 42 | previous = root; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /solutions/1154. Day of the Year/DayOfTheYear.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n + m), 4 | // where 'n' is the length of string 'date', and 'm' is the month. 5 | // We split the string which has a linear time complexity to the length of the string. 6 | // Then, we traverse the 'dayOfMonth' array for the number of months to get the day sum of the previous months. 7 | // 8 | // Space Complexity : O(n + 12), 9 | // where 'n' is the length of string 'date'. 10 | // The String.split() method results in creation of strings with total length of 'date'. 11 | // The 'dayOfMonth' array has length of 12. 12 | 13 | public class DayOfTheYear { 14 | 15 | // Approach: 16 | // Use an array of day in the months. 17 | // For each year, check for leap year and adjust the day in February accordingly. 18 | // Then, iterate from 0 to the previous month to sum the days in the previous month. 19 | // For that month, we sum the day of the month. 20 | 21 | public int dayOfYear(String date) { 22 | // Split the date String to the year, month and day. 23 | String[] str = date.split("-"); 24 | 25 | // Array for the day of the month. 26 | int[] dayOfMonth = new int[]{31,28,31,30,31,30,31,31,30,31,30,31}; 27 | 28 | // If the year is a leap year, increase the day in February (index 1) by 1. 29 | if (isLeapYear(Integer.parseInt(str[0]))) dayOfMonth[1] = 29; 30 | 31 | // Sum all the days in the previous months. 32 | int day = 0; 33 | for (int i = 0; i < Integer.parseInt(str[1]) - 1; i++) { 34 | day += dayOfMonth[i]; 35 | } 36 | // Add the day to the total sum and return. 37 | return day + Integer.parseInt(str[2]); 38 | } 39 | 40 | // Method to check if the year is a leap year in the Gregorian calendar. 41 | private boolean isLeapYear(int year) { 42 | if (year % 400 == 0) return true; 43 | return year % 100 != 0 && year % 4 == 0; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /solutions/12. Integer to Roman/IntegerToRoman_HashTable.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(1), 4 | // as the time to iterate through the dictionary and the while loop inside results is a constant average time, 5 | // no matter the input 'num'. 6 | // 7 | // Space Complexity : O(1), 8 | // as the dictionary take up constant space, 9 | // while the string result has an average space not dependent on the size of the input 'num'. 10 | 11 | public class IntegerToRoman_HashTable { 12 | 13 | // Approach: 14 | // This method uses two arrays with the corresponding integer-roman acting as dictionary, 15 | // arranged in descending order. 16 | // As we subtract the largest possible number, we append the corresponding roman numeral to the StringBuilder. 17 | // StringBuilder is preferable to string concatenation 18 | // as StringBuilder is faster and more efficient in memory usage. 19 | 20 | public String intToRoman(int num) { 21 | // Below are the list of the unique roman numerals to check. 22 | int[] value = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; 23 | String[] roman = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}; 24 | 25 | StringBuilder romanNumeral = new StringBuilder(); 26 | // Traverse both 'value' and 'roman' array to slowly subtract 'num' until 'num' reaches 0. 27 | for (int i = 0; i < value.length && num > 0; i++) { 28 | // Continue to subtract the 'value[i]' from 'num' and append the 'roman[i]' to 'romanNumeral'. 29 | while (num >= value[i]) { 30 | romanNumeral.append(roman[i]); 31 | num -= value[i]; 32 | } 33 | } 34 | // Convert the StringBuilder to string before returning it. 35 | return romanNumeral.toString(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /solutions/1207. Unique Number of Occurrences/UniqueNumberOfOccurrences_HashTable.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashMap; 4 | import java.util.HashSet; 5 | import java.util.Map; 6 | import java.util.Set; 7 | 8 | // Time Complexity : O(n), 9 | // where 'n' is the length of 'arr'. 10 | // We traverse 'arr' once to count the frequency of each number. 11 | // Then, we check every frequency in Map to determine if the frequencies are unique. 12 | // 13 | // Space Complexity : O(n), 14 | // where 'n' is the length of 'arr'. 15 | // We use HashMap to record the frequency of the numbers in 'arr', which has a maximum size of 'n'. 16 | 17 | public class UniqueNumberOfOccurrences_HashTable { 18 | 19 | // Approach: 20 | // We first use a HashMap to count the frequency of each unique numbers in 'arr'. 21 | // Note that we can alternatively use a counting array since we know the constraint of "-1000 <= arr[i] <= 1000". 22 | // Once counted, we can use a HashSet to determine if the frequencies are unique. 23 | 24 | public boolean uniqueOccurrences(int[] arr) { 25 | // Use a HashMap to count the frequency of the numbers in 'arr'. 26 | Map map = new HashMap<>(); 27 | for (int number : arr) { 28 | map.put(number, map.getOrDefault(number, 0) + 1); 29 | } 30 | 31 | // Then, we use a HashSet to check if the frequencies in the HashMap are unique. 32 | Set set = new HashSet<>(); 33 | for (int frequency : map.values()) { 34 | // If the frequency is already added to the HashSet, return false. 35 | // Note that Set.add() returns true if successfully added, and false if value not added. 36 | if (!set.add(frequency)) return false; 37 | } 38 | // If all the frequencies are successfully added to the HashSet, return true. 39 | return true; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /solutions/1295. Find Numbers with Even Number of Digits/FindNumbersWithEvenNumberOfDigits.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(m^n), 4 | // where 'm' is the maximum number of digits for the elements of 'nums', and 'n' is the length of 'nums'. 5 | // This is because of the counting of the digits for every element in 'nums'. 6 | // 7 | // Space Complexity : O(1), 8 | // As only fixed variables are used. 9 | 10 | public class FindNumbersWithEvenNumberOfDigits { 11 | 12 | // Approach: 13 | // Calculate the number of digits for every elements in 'nums', 14 | // using division by 10 and a 'digit' variable to keep track. 15 | 16 | public int findNumbers(int[] nums) { 17 | int count = 0; 18 | int digit; 19 | for (int integer : nums) { 20 | digit = 0; 21 | // Calculate the number of digits. 22 | while (integer != 0) { 23 | digit++; 24 | integer /= 10; 25 | } 26 | // Increase the count if it is even number of digits. 27 | if (digit % 2 == 0) count++; 28 | } 29 | return count; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /solutions/1299. Replace Elements with Greatest Element on Right Side/ReplaceElementsWithGreatestElementOnRightSide.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'arr'. 5 | // 6 | // Space Complexity : O(1), 7 | // as not auxiliary space is used. 8 | 9 | public class ReplaceElementsWithGreatestElementOnRightSide { 10 | 11 | // Approach: 12 | // From the end to the start of the array, replace integer that is smaller than the current max, 13 | // until we found an integer with greater value. 14 | // Then update the max with the new maximum integer and continue. 15 | 16 | public int[] replaceElements(int[] arr) { 17 | int max = -1; 18 | for (int i = arr.length - 1; i >= 0; i--) { 19 | // "arr[i] = max" allows us to update arr[i] to max, 20 | // while the first input in Math.max() already records arr[i] before the update. 21 | // Otherwise, we would need a temporary variable to store the previous max before modifying the array. 22 | max = Math.max(arr[i], arr[i] = max); 23 | } 24 | return arr; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /solutions/1318. Minimum Flips to Make a OR b Equal to c/MinimumFlipsToMakeAORBEqualToC.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the maximum bitlength of 'a', 'b' and 'c'. 5 | // We traverse each bit for all three inputs, until we finish traversing the integer with the longest bitlength. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input. 9 | 10 | public class MinimumFlipsToMakeAORBEqualToC { 11 | 12 | // Approach: 13 | // Traverse each bit for all three numbers, each time shifting one bit to the right (bitwise right shift '>>'), 14 | // or dividing the number by 2. 15 | // For each iteration, we check the rightmost bit ('num' & 1) or ('num' % 2). 16 | // If 'c' has 1 bit, then add 1 flip if both 'a' and 'b' has 0 bits. 17 | // If 'c' has 0 bit, then add the bits for both 'a' and 'b', as any 1 bit would need to be flipped. 18 | // 19 | // Continue the iterations until all the numbers reaches 0. 20 | 21 | public int minFlips(int a, int b, int c) { 22 | int flips = 0; 23 | 24 | // While any of the numbers still has bit not checked, 25 | while (a > 0 || b > 0 || c > 0) { 26 | // get the bits for 'a', 'b' and 'c'. 27 | int abBits = (a & 1) + (b & 1); 28 | int cBit = c & 1; 29 | // If 'c' has 1 bit, and both 'a' and 'b' has 0 bits, then add 1 flip. 30 | if (cBit == 1 && abBits == 0) { 31 | flips += 1; 32 | } 33 | // If 'c' has 0 bit, then add the 'abBits'. 34 | else if (cBit == 0) { 35 | flips += abBits; 36 | } 37 | // Shift all numbers to right by 1 bit. 38 | a = a >> 1; 39 | b = b >> 1; 40 | c = c >> 1; 41 | } 42 | return flips; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /solutions/1323. Maximum 69 Number/Maximum69Number_String.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the number of digits in 'num'. 5 | // We convert 'num' to a string, convert the string to a char array, convert the char array back to string, 6 | // and parse the string to the result integer, all has linear time complexity to the number of digits in 'num'. 7 | // 8 | // Space Complexity : O(n), 9 | // where 'n' is the number of digits in 'num'. 10 | // The conversion of 'num' to string, string to char array, char array back to string, 11 | // all of which has a same size as the digits in 'num'. 12 | 13 | public class Maximum69Number_String { 14 | 15 | // Approach: 16 | // For any number, changing the first digit 6 to 9 from left to right yields the maximum number. 17 | // This is also known as to be Greedy as we only need to find the first digit 6. 18 | // As such, we can convert the integer 'num' to a char array, 19 | // and traverse from left to right to change the first digit 6 that we encounter to digit 9. 20 | 21 | public int maximum69Number (int num) { 22 | // Convert the integer 'num' to String, then to char[] for easy conversion of char '6' to char '9'. 23 | char[] chars = String.valueOf(num).toCharArray(); 24 | for (int i = 0; i < chars.length; i++) { 25 | // Once found and converted the 6 to 9, we can exit the loop and return the result. 26 | if (chars[i] == '6') { 27 | chars[i] = '9'; 28 | break; 29 | } 30 | } 31 | // Convert the char[] back to String and back to integer. 32 | return Integer.parseInt(String.valueOf(chars)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /solutions/1342. Numbers of Steps to Reduce a Number to Zero/NumberOfStepsToReduceANumberToZero_BitManipulation.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(logn), 4 | // where 'n' is 'num'. 5 | // Since we are dividing the number by 2 when it is even, we can approximate the time complexity as O(logn), 6 | // considering it similar to binary search. 7 | // 8 | // Space Complexity : O(1), 9 | // as the auxiliary space used is independent of the input. 10 | 11 | public class NumberOfStepsToReduceANumberToZero_BitManipulation { 12 | 13 | // Approach: 14 | // & is AND Operation (1 AND 1 is 1, 1 AND 0 is 0, 0 AND 0 is 0) 15 | // num & 1 == 1 meaning odd, == 0 meaning even. 16 | // Example: 17 | // n = 15 or 1111. n & 0001 = 0001 18 | // n = 8 or 1000. n & 0001 = 0000. 19 | // 20 | // ^ is XOR Operation (1 OR 1 is 0, 1 OR 0 is 1, 0 OR 0 is 0) 21 | // num ^ 1 is num - 1 if num is odd, or num + 1 if num is even. 22 | // We only use num ^ 1 when num is odd. 23 | // Example: 24 | // n = 15 or 1111. n ^ 0001 = 1110 (14) 25 | // n = 8 or 1000. n ^ 0001 = 1001 (9) 26 | // 27 | // >> is SHIFT RIGHT Operation, the number is the number of bits moved (moving the whole binary one bit right). 28 | // num >> 1 is num / 2 if num is even. If num is odd, then is (num - 1) / 2. 29 | // Example: 30 | // n = 15 or 1111. n >> 1 = 0111 (7) 31 | // n = 8 or 1000. n >> 1 = 0100 (4) 32 | 33 | public int numberOfSteps(int num) { 34 | int count = 0; 35 | 36 | while (num > 0) { 37 | // If 'num' is odd (num & 1 == true), then we subtract 1 (num ^ 1). 38 | // Else, we divide by 2 (num >> 1). 39 | num = (num & 1) == 1 ? num ^ 1 : num >> 1; 40 | count++; 41 | } 42 | return count; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /solutions/1342. Numbers of Steps to Reduce a Number to Zero/NumberOfStepsToReduceANumberToZero_Math.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(logn), 4 | // where 'n' is 'num'. 5 | // Since we are dividing the number by 2 when it is even, we can approximate the time complexity as O(logn), 6 | // considering it similar to binary search. 7 | // 8 | // Space Complexity : O(1), 9 | // as the auxiliary space used is independent of the input. 10 | 11 | public class NumberOfStepsToReduceANumberToZero_Math { 12 | 13 | // Approach: 14 | // The intuitive approach, to subtract by 1 when odd or divide by 2 when even. 15 | 16 | public int numberOfSteps(int num) { 17 | int count = 0; 18 | while (num > 0) { 19 | num = num % 2 == 0 ? num / 2 : num - 1; 20 | count++; 21 | } 22 | return count; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /solutions/1346. Check If N and Its Double Exist/CheckIfNAndItsDoubleExist_HashTable.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | // Time Complexity : O(n), 7 | // where 'n' is the length of 'arr', as we traverse through 'arr' to check for its double or half. 8 | // 9 | // Space Complexity : O(n), 10 | // where 'n' is the length of 'arr', as worst case with us storing every element from 'arr' into the HashSet. 11 | 12 | public class CheckIfNAndItsDoubleExist_HashTable { 13 | 14 | // Approach: 15 | // Using HashSet to record the elements in 'arr' while checking if its double or half is already in the HashSet. 16 | // The reason for checking both double and half is because 'arr' is not sorted, 17 | // thus 'n' and its double can be in any order in 'arr'. 18 | 19 | public boolean checkIfExist(int[] arr) { 20 | Set set = new HashSet<>(); 21 | 22 | // Do note that we are only traversing 'arr' once, both checking for the double, and adding the element into 'set'. 23 | // If we first add all the elements into the HashSet, then only traverse 'arr' again to check for the double, 24 | // there will be an edge case with the integer 0, as its double is still 0. 25 | for (int integer : arr) { 26 | // Make sure to check if the integer is even, before checking its half, 27 | // as both even and odd integer can result in the same half (e.g. 6 / 2 == 3, 7 / 2 == 3). 28 | if (integer % 2 == 0 && set.contains(integer / 2)) return true; 29 | // Check for the double. 30 | if (set.contains(integer * 2)) return true; 31 | 32 | set.add(integer); 33 | } 34 | // If none found, return false. 35 | return false; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /solutions/1346. Check If N and Its Double Exist/CheckIfNAndItsDoubleExist_Sorting_BinarySearch.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | // Time Complexity : O(n^2), 6 | // where 'n' is the length of 'arr'. 7 | // Arrays.sort() function uses Dual-Pivot Quicksort with average performance of O(n logn), but with worst case of O(n^2). 8 | // Arrays.binarySearch() function has a performance of O(logn), 9 | // however as we traverse each element in 'arr' to perform binary search, the performance of the search is O(n logn). 10 | // As such, we take the worst time complexity of Arrays.sort(). 11 | // Do note that both Arrays.sort() and Arrays.binarySearch() functions are developed and optimized, 12 | // thus using them could improve performance as compared to other methods. 13 | // 14 | // Space Complexity : O(1), 15 | // as no additional space is used. 16 | 17 | public class CheckIfNAndItsDoubleExist_Sorting_BinarySearch { 18 | 19 | // Approach: 20 | // Use sorting and binary search to find the double of the elements in 'arr'. 21 | 22 | public boolean checkIfExist(int[] arr) { 23 | 24 | // As binary search requires sorted array, we first need to sort 'arr'. 25 | Arrays.sort(arr); 26 | 27 | for (int i = 0; i < arr.length; i++) { 28 | // Arrays.binarySearch return the index of the double found, and -1 if not found. 29 | int index = Arrays.binarySearch(arr, arr[i] * 2); 30 | 31 | // If the index is non-negative, then we have found the element's double. 32 | // However, we need to check if index != i. 33 | // This is because of the edge case of 0, which the double of 0 is still 0. 34 | // Thus, we need to make sure that we do not accidentally return true when we found the same 0. 35 | if (index >= 0 && index != i) return true; 36 | } 37 | return false; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /solutions/1346. Check If N and Its Double Exist/CheckIfNAndItsDoubleExist_TwoPointers.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n^2), 4 | // where 'n' is the length of 'arr', as we use nested loops to traverse through 'arr'. 5 | // 6 | // Space Complexity : O(1), 7 | // as no additional space is used. 8 | 9 | public class CheckIfNAndItsDoubleExist_TwoPointers { 10 | 11 | // Approach: 12 | // Using two pointers and the brute force approach to check every element pair. 13 | 14 | public boolean checkIfExist(int[] arr) { 15 | for (int i = 0; i < arr.length; i++) { 16 | for (int j = i + 1; j < arr.length; j++) { 17 | // We need to check for both directions as the pair can be in any order in 'arr'. 18 | if (arr[i] == arr[j] * 2 || arr[i] * 2 == arr[j]) 19 | return true; 20 | } 21 | } 22 | return false; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /solutions/1351. Count Negative Numbers in a Sorted Matrix/CountNegativeNumbersInASortedMatrix.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(m * n), 4 | // where 'm' is the number of rows in 'grid', and 'n' is the number of columns in 'grid'. 5 | // We traverse the matrix once, 'n' number of position in 'm' number of rows to count the negative numbers. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input size. 9 | 10 | public class CountNegativeNumbersInASortedMatrix { 11 | 12 | // Approach: 13 | // Intuitive approach to traverse the matrix once with 2 for-loops to count the negative numbers. 14 | 15 | public int countNegatives(int[][] grid) { 16 | int count = 0; 17 | // For each row in 'grid', 18 | for (int[] row : grid) { 19 | // we check each element in the row and count the negative numbers. 20 | for (int j = 0; j < grid[0].length; j++) { 21 | if (row[j] < 0) count++; 22 | } 23 | } 24 | return count; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /solutions/1351. Count Negative Numbers in a Sorted Matrix/CountNegativeNumbersInASortedMatrix_BinarySearch.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(m logn), 4 | // where 'm' is the number of rows in 'grid', and 'n' is the number of columns in 'grid'. 5 | // We traverse each row 'm' of the matrix , 6 | // and perform binary search to find the position of the leftmost negative number, 7 | // with binary search having O(logn) time complexity. 8 | // 9 | // Space Complexity : O(1), 10 | // as the auxiliary space used is independent of the input size. 11 | 12 | public class CountNegativeNumbersInASortedMatrix_BinarySearch { 13 | 14 | // Approach: 15 | // Improving on the intuitive approach, we can perform binary search for each row 16 | // to find the leftmost negative number. 17 | // With the leftmost negative number, we can get the negative numbers of the row with "n - index". 18 | 19 | public int countNegatives(int[][] grid) { 20 | int columns = grid[0].length; 21 | 22 | int count = 0; 23 | // For each row in 'grid', 24 | for (int[] row : grid) { 25 | int left = 0, right = columns; 26 | // Perform binary search, with each iteration checking if row[mid] is negative number. 27 | while (left < right) { 28 | int mid = (right - left) / 2 + left; 29 | // If row[mid] is negative, check the right side by shifting 'right' to 'mid' + 1. 30 | if (row[mid] < 0) 31 | right = mid; 32 | // If row[mid] is not negative, check the left side by shifting 'left' to 'mid'. 33 | else 34 | left = mid + 1; 35 | } 36 | // The number of negative numbers of the row is 'columns - index', 37 | // in this case index can be 'left' or 'right'. 38 | count += (columns - left); 39 | } 40 | return count; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /solutions/136. Single Number/SingleNumber.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'nums'. 5 | // We traverse 'nums' once to find the single number. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input. 9 | 10 | public class SingleNumber { 11 | 12 | // Approach: 13 | // As the constraints are linear time complexity and constant space complexity, 14 | // it can only be achieved with bit manipulation. 15 | // Firstly, we need to understand the bitwise XOR operator '^'. 16 | // The XOR of any two numbers gives the difference of bit, 17 | // for example: 1010 ^ 1111 = 0101. 18 | // If we perform XOR of two identical number, then the result would be 0. 19 | // For example, 1111 ^ 1111 = 0. 20 | // 21 | // Within the 'nums' array, we are guaranteed to have a single distinct number without duplicates. 22 | // As such, all the other duplicates negates each other when performing XOR operation. 23 | // Thus, we can determine the single number by performing XOR for all the numbers in 'nums. 24 | // For example, 1111 ^ 1010 ^ 1111 = 1010, with 1111 negating each other in the XOR operation. 25 | 26 | public int singleNumber(int[] nums) { 27 | // For each number, perform the XOR operation and return the result. 28 | int result = 0; 29 | for (int number : nums) result ^= number; 30 | return result; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /solutions/136. Single Number/SingleNumber_StreamReduce.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | // Time Complexity : O(n), 6 | // where 'n' is the length of 'nums'. 7 | // We traverse 'nums' once to find the single number. 8 | // 9 | // Space Complexity : O(1), 10 | // as the auxiliary space used is independent of the input. 11 | 12 | public class SingleNumber_StreamReduce { 13 | 14 | // Approach: 15 | // As the constraints are linear time complexity and constant space complexity, 16 | // it can only be achieved with bit manipulation. 17 | // Firstly, we need to understand the bitwise XOR operator '^'. 18 | // The XOR of any two numbers gives the difference of bit, 19 | // for example: 1010 ^ 1111 = 0101. 20 | // If we perform XOR of two identical number, then the result would be 0. 21 | // For example, 1111 ^ 1111 = 0. 22 | // 23 | // Within the 'nums' array, we are guaranteed to have a single distinct number without duplicates. 24 | // As such, all the other duplicates negates each other when performing XOR operation. 25 | // Thus, we can determine the single number by performing XOR for all the numbers in 'nums. 26 | // For example, 1111 ^ 1010 ^ 1111 = 1010, with 1111 negating each other in the XOR operation. 27 | 28 | public int singleNumber(int[] nums) { 29 | // For each number, perform the XOR operation and return the result. 30 | return Arrays.stream(nums).reduce(0, (accumulator, number) -> accumulator ^ number); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /solutions/1446. Consecutive Characters/ConsecutiveCharacters.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of string 's'. 5 | // We traverse the string 's' to determine the max consecutive characters. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input. 9 | 10 | public class ConsecutiveCharacters { 11 | 12 | // Approach: 13 | // We traverse the string 's', counting by comparing the current character with the previous character, 14 | // increase the count if the same, 15 | // or reset the count to 1 if the characters are different. 16 | // For each character, we compare the max with the current count 17 | // to get the maximum length of consecutive characters. 18 | 19 | public int maxPower(String s) { 20 | int max = 1, count = 1; 21 | // Traverse the string 's', starting at index 1, 22 | // since the first character always yields count of 1. 23 | for (int i = 1; i < s.length(); i++) { 24 | // If the current character is the same as the previous character, 25 | // increase 'count' by 1, and update the 'max' value. 26 | if (s.charAt(i) == s.charAt(i - 1)) { 27 | count++; 28 | max = Math.max(max, count); 29 | } 30 | // If the characters are different, reset the 'count' to 1. 31 | else { 32 | count = 1; 33 | } 34 | } 35 | // Once we traverse the string, the 'max' is the number of characters in the longest consecutive characters. 36 | return max; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /solutions/1470. Shuffle the Array/ShuffleTheArray.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the size of 'nums'. 5 | // We traverse the array 'nums' once to get the elements to put into the new array. 6 | // 7 | // Space Complexity : O(n), 8 | // where 'n' is the size of 'nums'. 9 | // We created a new array for the result with the size of 'nums'. 10 | 11 | public class ShuffleTheArray { 12 | 13 | // Approach: 14 | // Traverse the array while taking the integer from the 'i' and 'n + i' position to 15 | // put into the new position in the new array, at index '2 * i' and '2 * i + 1' respectively. 16 | 17 | public int[] shuffle(int[] nums, int n) { 18 | // Result array of size 2 * n. 19 | int[] result = new int[2 * n]; 20 | 21 | // For each element, 22 | for (int i = 0; i < n; i++) { 23 | // put nums[i] into the '2 * i' position, 24 | result[2 * i] = nums[i]; 25 | // and put nums[n + i] into the '2 * i + 1' position. 26 | result[2 * i + 1] = nums[n + i]; 27 | } 28 | 29 | // Return the result array with elements in the shuffled position. 30 | return result; 31 | } 32 | } -------------------------------------------------------------------------------- /solutions/1480. Running Sum of 1D Array/RunningSumOf1DArray.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'nums'. 5 | // We traverse the 'nums' array once to get the running sum. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of 'nums'. 9 | 10 | public class RunningSumOf1DArray { 11 | 12 | // Approach: 13 | // Starting at index 1, 14 | // continue to add the previous number while replacing the number in 'nums' array in-place. 15 | 16 | public int[] runningSum(int[] nums) { 17 | // In-place update of the sum of current number nums[i] with the previous number nums[i-1]. 18 | for (int i = 1; i < nums.length; i++) { 19 | nums[i] += nums[i-1]; 20 | } 21 | return nums; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solutions/1486. XOR Operation in an Array/XOROperationInAnArray.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the input 'n'. 5 | // We traverse from 0 to 'n' to get the XOR for each number. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input. 9 | 10 | public class XOROperationInAnArray { 11 | 12 | // Approach: 13 | // With the intuitive approach of iterating from 0 to 'n', 14 | // and XOR '^' the result for each number "start + 2 * i". 15 | 16 | public int xorOperation(int n, int start) { 17 | int result = 0; 18 | for (int i = 0; i < n; i++) { 19 | result ^= (start + 2 * i); 20 | } 21 | return result; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solutions/151. Reverse Words in a String/ReverseWordsInAString_Collections.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | // Time Complexity : O(n), 8 | // where 'n' is the length of string 's'. 9 | // The string split() method, the Collections.reverse() method, and String.join() method 10 | // has a time complexity of O(n). 11 | // 12 | // Space Complexity : O(n), 13 | // where 'n' is the length of string 's'. 14 | // The splitting of string 's' into array of 'words', and the final result string 15 | // requires memory that grows linearly with the size of the input string 's'. 16 | 17 | public class ReverseWordsInAString_Collections { 18 | 19 | // Approach: 20 | // Use the String functions to trim the leading and trailing spaces, then split into words and store in a list. 21 | // With Collections package, reverse the word order in the list. 22 | // Use the String.join with " " as the delimiter to produce the reversedWords. 23 | 24 | public static String reverseWords(String s) { 25 | // .trim() removes leading and trailing spaces. 26 | // "\\s+" is regex for spaces (one or more). 27 | List words = Arrays.asList(s.trim().split("\\s+")); 28 | 29 | // Reverse the strings in the 'words' list. 30 | Collections.reverse(words); 31 | 32 | // Join the words with a single space between the words. 33 | return String.join(" ", words); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /solutions/151. Reverse Words in a String/ReverseWordsInAString_StringBuilder.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of string 's'. 5 | // The string split() method and the StringBuilder.toString() method has a time complexity of O(n), 6 | // while appending all words with the stringBuilder.append() has a total time complexity of O(n). 7 | // 8 | // Space Complexity : O(n), 9 | // where 'n' is the length of string 's'. 10 | // The splitting of string 's' into array of 'words', the StringBuilder and the final result string 11 | // requires memory that grows linearly with the size of the input string 's'. 12 | 13 | public class ReverseWordsInAString_StringBuilder { 14 | 15 | // Approach: 16 | // Use the String functions to trim the leading and trailing spaces, then split into words and store in an array. 17 | // Append the words in the reverse order from the array, with spaces " " in between. 18 | 19 | public String reverseWords(String s) { 20 | // .trim() removes leading and trailing spaces. 21 | // "\\s+" is regex for spaces (one or more). 22 | String[] words = s.trim().split("\\s+"); 23 | 24 | // Use StringBuilder to reduce time and space complexity, 25 | // as String concatenation is O(n). 26 | StringBuilder stringBuilder = new StringBuilder(words[words.length - 1]); 27 | for (int i = words.length - 2; i >= 0; i--) { 28 | stringBuilder.append(" ").append(words[i]); 29 | } 30 | 31 | return stringBuilder.toString(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /solutions/152. Maximum Product Subarray/MaximumProductSubarray_DynamicProgramming.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'nums'. 5 | // We traverse the whole array once to get the maximum product. 6 | // 7 | // Space Complexity : O(n), 8 | // where 'n' is the length of 'nums'. 9 | // We use an array with two rows and length of 'n' to keep track of the positive and negative product. 10 | 11 | public class MaximumProductSubarray_DynamicProgramming { 12 | 13 | // Approach: 14 | // Using a 2D array to store the product with the previous element, both maximum and minimum, 15 | // to account for multiplication of negative integer to previous negative product. 16 | 17 | public int maxProduct(int[] nums) { 18 | int[][] table = new int[nums.length + 1][2]; 19 | // For maximum product. 20 | table[0][0] = nums[0]; 21 | // For minimum product, to keep track of the most negative number. 22 | table[0][1] = nums[0]; 23 | int max = nums[0]; 24 | for (int i = 1; i < nums.length; i++) { 25 | int currentNumber = nums[i]; 26 | table[i][0] = Math.max(currentNumber, Math.max(currentNumber * table[i - 1][0], currentNumber * table[i - 1][1])); 27 | table[i][1] = Math.min(currentNumber, Math.min(currentNumber * table[i - 1][0], currentNumber * table[i - 1][1])); 28 | max = Math.max(max, table[i][0]); 29 | } 30 | return max; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /solutions/1523. Count Odd Numbers in an Interval Range/CountOddNumbersInAnIntervalRange.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(1), 4 | // as we just perform arithmetic. 5 | // 6 | // Space Complexity : O(1), 7 | // as the auxiliary space used is independent of the size of the input. 8 | 9 | public class CountOddNumbersInAnIntervalRange { 10 | 11 | // Approach: 12 | // If the range contains even number of integers, then the number of odd integers is half of the range. 13 | // For example, low = 3, high = 6, the range is 4, with only 2 odd integers in the range. 14 | // If the range contains odd number of integers, then the number of odd integers is dependent 15 | // if the low and high integer is odd or even. 16 | // If the low and high integer is odd, then the number of odd integers is half of the range + 1. 17 | // For example, low = 3, high = 7, the range is 5, with 3 odd integers in the range [3, 5, 7]. 18 | // If the low and high integer is even, then the number of odd integers is half of the range. 19 | // For example, low = 2, high = 6, the range is 5, with 2 odd integers in the range [3, 5]. 20 | 21 | public int countOdds(int low, int high) { 22 | // Get the range of the number. 23 | int range = high - low + 1; 24 | // If the range is odd and the low and high number is odd, then the number of odd integers 25 | // is half of range + 1. 26 | if (isOdd(range) && isOdd(low)) return range / 2 + 1; 27 | // All other scenarios, the number of odd integers is half of range. 28 | return range / 2; 29 | } 30 | 31 | // Helper method to determine if the number is odd. 32 | private boolean isOdd(int number) { 33 | return number % 2 == 1; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /solutions/1534. Count Good Triplets/CountGoodTriplets.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n^3), 4 | // where 'n' is the length of 'arr'. 5 | // We use 3 nested for-loops to check every combination where i < j < k, and count good triplets. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input. 9 | 10 | public class CountGoodTriplets { 11 | 12 | // Approach: 13 | // With the 'arr' having a maximum length of 100, we can use the intuitive brute force approach 14 | // to iterate through every possible combinations where i < j < k, and count good triplets. 15 | 16 | public int countGoodTriplets(int[] arr, int a, int b, int c) { 17 | int n = arr.length; 18 | 19 | int count = 0; 20 | // First for-loop, for index 'i'. 21 | for (int i = 0; i < n; i++) { 22 | // Second for-loop for index 'j'. 23 | for (int j = i + 1; j < n; j++) { 24 | // An early check for "|arr[i] - arr[j]|", skip if the value is greater than 'a'. 25 | if (Math.abs(arr[i] - arr[j]) > a) continue; 26 | 27 | // Thrid for-loop for index 'k'. 28 | for (int k = j + 1; k < n; k++) { 29 | // If either are greater than 'b' or 'c' respectively, skip. 30 | if (Math.abs(arr[j] - arr[k]) > b || Math.abs(arr[i] - arr[k]) > c) continue; 31 | 32 | // Increase the count by 1 if all 3 conditions are met. 33 | count++; 34 | } 35 | } 36 | } 37 | return count; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /solutions/1578. Minimum Time to Make Rope Colorful/MinimumTimeToMakeRopeColorful_DynamicProgramming.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of string 'colors'. 5 | // We traverse the string 'colors' once to find the adjacent balloons with the same color. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the size of input string 'colors' or int array 'neededTime'. 9 | 10 | public class MinimumTimeToMakeRopeColorful_DynamicProgramming { 11 | 12 | // Approach: 13 | // Check for any similar color with the previous balloon. 14 | // If it is the same color, then we always remove the balloon requiring the least time (Greedy Approach). 15 | // Here, the balloon with the most time needed is kept, and we are using 'neededTime' array to record, 16 | // instead of a separate variable. 17 | 18 | public int minCost(String colors, int[] neededTime) { 19 | int minTime = 0; 20 | 21 | // Traverse the string 'colors' to check for any consecutive balloons of identical color. 22 | for (int index = 1; index < colors.length(); index++) { 23 | // If found, then we record the least time needed to remove either balloon, 24 | // and update the current balloon with the most time needed. 25 | if (colors.charAt(index) == colors.charAt(index - 1)) { 26 | minTime += Math.min(neededTime[index], neededTime[index - 1]); 27 | neededTime[index] = Math.max(neededTime[index], neededTime[index - 1]); 28 | } 29 | } 30 | return minTime; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /solutions/1578. Minimum Time to Make Rope Colorful/MinimumTimeToMakeRopeColorful_Greedy.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of string 'colors'. 5 | // We traverse the string 'colors' once to find the adjacent balloons with the same color. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the size of input string 'colors' or int array 'neededTime'. 9 | 10 | public class MinimumTimeToMakeRopeColorful_Greedy { 11 | 12 | // Approach: 13 | // Check for any similar color with the previous balloon. 14 | // If it is the same color, then we always remove the balloon requiring the least time (Greedy Approach). 15 | // Using a variable to keep track of the most time needed between the two consecutive balloons of the same color. 16 | 17 | public int minCost(String colors, int[] neededTime) { 18 | int minTime = 0; 19 | int previousTime = neededTime[0]; 20 | 21 | // Traverse the 'colors' String to check for any consecutive balloons of identical color. 22 | for (int index = 1; index < colors.length(); index++) { 23 | 24 | // If found, then we record the least time needed to remove either balloon, 25 | // and record the most time needed into the 'previousTime' variable. 26 | if (colors.charAt(index) == colors.charAt(index - 1)) { 27 | minTime += Math.min(previousTime, neededTime[index]); 28 | previousTime = Math.max(previousTime, neededTime[index]); 29 | } 30 | // If not found, then keep updating the variable with the current time needed. 31 | else previousTime = neededTime[index]; 32 | } 33 | return minTime; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /solutions/1603. Design Parking System/ParkingSystem.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | /** 4 | * Your ParkingSystem object will be instantiated and called as such: 5 | * ParkingSystem obj = new ParkingSystem(big, medium, small); 6 | * boolean param_1 = obj.addCar(carType); 7 | */ 8 | 9 | // Time Complexity : O(1). 10 | // The addCar method has a constant time complexity. 11 | // 12 | // Space Complexity : O(1), 13 | // as the auxiliary space used is independent of the input size. 14 | 15 | public class ParkingSystem { 16 | 17 | // Approach: 18 | // Create a counting array 'lots' to keep track of the available lot for big, medium and small cars. 19 | // Each time the car is added, return true if the lot for the carType is greater than 0, 20 | // and reduce the count by 1 for that carType. 21 | 22 | // The counting array 'lots' is declared as a field in this 'ParkingSystem' class. 23 | int[] lots; 24 | public ParkingSystem(int big, int medium, int small) { 25 | // Instantiate the 'lots' array with big, medium and small. 26 | lots = new int[]{big, medium, small}; 27 | } 28 | 29 | // Return true if the carType in 'lots' is greater than 0, 30 | // and reduce the count by 1. 31 | public boolean addCar(int carType) { 32 | return lots[carType - 1]-- > 0; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /solutions/1662. Check If Two String Arrays are Equivalent/CheckIfTwoStringArraysAreEquivalent_Pointers.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(m), 4 | // where 'm' is the product of the length of 'word1' or 'word2' and the length of the words in 'word1' or 'word2', 5 | // as we are traversing through every character in every word in 'word1' and 'word2'. 6 | // 7 | // Space Complexity : O(1), 8 | // as we are only using pointers. 9 | 10 | public class CheckIfTwoStringArraysAreEquivalent_Pointers { 11 | 12 | // Approach: 13 | // Using 4 pointers, 2 for the outer elements in 'word1' and 'word2', and 2 for the inner characters. 14 | 15 | public boolean arrayStringsAreEqual(String[] word1, String[] word2) { 16 | int word1Outer = 0; 17 | int word1Inner = 0; 18 | int word2Outer = 0; 19 | int word2Inner = 0; 20 | while (word1Outer < word1.length || word2Outer < word2.length) { 21 | // If only one pointer reached the end of the array, meaning they form different string. 22 | if (word1Outer == word1.length || word2Outer == word2.length) return false; 23 | 24 | // Check if they have exactly the same characters. 25 | if (word1[word1Outer].charAt(word1Inner) != word2[word2Outer].charAt(word2Inner)) return false; 26 | 27 | // For both 'word1' and 'word2', shift the outer pointer to next 28 | // when the inner pointer reached the end of the element. 29 | if (word1Inner < word1[word1Outer].length() - 1) { 30 | word1Inner++; 31 | } else { 32 | word1Inner = 0; 33 | word1Outer++; 34 | } 35 | if (word2Inner < word2[word2Outer].length() - 1) { 36 | word2Inner++; 37 | } else { 38 | word2Inner = 0; 39 | word2Outer++; 40 | } 41 | } 42 | // If all the checks are successful, meaning both 'word1' and 'word2' forms the same string. 43 | return true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /solutions/1662. Check If Two String Arrays are Equivalent/CheckIfTwoStringArraysAreEquivalent_String.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'word1' or 'word2'. 5 | // Using StringBuilder, we are appending each word to the StringBuilder. 6 | // If we are using normal String concatenation, then the time complexity would be O(n^2). 7 | // 8 | // Space Complexity : O(m), 9 | // where 'm' is the product of the length of 'word1' or 'word2' and the length of the words in 'word1' or 'word2', 10 | // as we are not creating new String for each append. 11 | // If we are using normal String concatenation, then the time complexity would be O(m^2), 12 | // since we are creating new String for each concatenation. 13 | 14 | public class CheckIfTwoStringArraysAreEquivalent_String { 15 | 16 | // Approach: 17 | // Concatenated the elements for both 'word1' and 'word2' to check if they form the same string. 18 | // Here, we use StringBuilder to lower the time complexity from O(n^2) to O(n). 19 | 20 | public boolean arrayStringsAreEqual(String[] word1, String[] word2) { 21 | StringBuilder string1 = new StringBuilder(); 22 | StringBuilder string2 = new StringBuilder(); 23 | for (String str : word1) string1.append(str); 24 | for (String str : word2) string2.append(str); 25 | return string1.toString().equals(string2.toString()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /solutions/167. Two Sum II - Input Array is Sorted/TwoSumII_InputArrayIsSorted_BinarySearch.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n logn), 4 | // where 'n' is the length of 'numbers'. 5 | // For each of the integer in 'numbers', we perform binary search on the integers to the left 6 | // to find the integer to sum to 'target'. 7 | // Binary search has time complexity of O(logn). 8 | // For the worst-case to perform binary search for each number O(n), the final time complexity is O(n logn). 9 | // 10 | // Space Complexity : O(1), 11 | // as the auxiliary space used for the pointers is independent on the length of 'numbers'. 12 | 13 | public class TwoSumII_InputArrayIsSorted_BinarySearch { 14 | 15 | // Approach: 16 | // Use binary search for the difference between 'target' and 'i-th' number, given that the 'numbers' is sorted. 17 | 18 | public int[] twoSum(int[] numbers, int target) { 19 | // For each of the number, we perform binary search to find the second number that sum to 'target'. 20 | for (int i = 0; i < numbers.length; i++) { 21 | int difference = target - numbers[i]; 22 | // Find the 'difference' in the 'numbers' array using binary search. 23 | int left = i + 1; 24 | int right = numbers.length - 1; 25 | while (left <= right) { 26 | int mid = (left + right) / 2; 27 | if (numbers[mid] == difference) 28 | // Return the result indices when found. 29 | // Remember to return the indices added by one as stated in the problem. 30 | return new int[]{i + 1, mid + 1}; 31 | else if (numbers[mid] > difference) 32 | right = mid - 1; 33 | else 34 | left = mid + 1; 35 | } 36 | } 37 | // As a valid result is guaranteed in the test cases, 38 | // returning an empty array is mainly to prevent compile-time error. 39 | return new int[2]; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /solutions/1672. Richest Customer Wealth/RichestCustomerWealth.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n * m), 4 | // where 'n' is the length of 'accounts', and 'm' is the length of accounts[0]. 5 | // For each customer in 'accounts' (n), we traverse all the bank balance (m), resulting in O(n * m). 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent on the input size. 9 | 10 | public class RichestCustomerWealth { 11 | 12 | // Approach: 13 | // Get the sum for each account by iterating through the account, and get the max wealth for each customer. 14 | 15 | public int maximumWealth(int[][] accounts) { 16 | 17 | int maxWealth = 0; 18 | // For each customer, get the sum of the account value and compare to 'maxWealth'. 19 | for (int[] customer: accounts) { 20 | int sum = 0; 21 | //For each bank, add to the sum. 22 | for (int balance: customer) sum += balance; 23 | // Update the maxWealth with the higher wealth. 24 | maxWealth = Math.max(sum, maxWealth); 25 | } 26 | return maxWealth; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /solutions/1679. Max Number of K-Sum Pairs/MaxNumberOfKSumPairs_HashTable.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | // Time Complexity : O(n), 7 | // where 'n' is the length of 'nums'. 8 | // We traverse 'nums' array once to find the match. 9 | // 10 | // Space Complexity : O(n), 11 | // where 'n' is the length of 'nums'. 12 | // The HashMap has a maximum size of 'n', where all numbers are unique and no match is found. 13 | 14 | public class MaxNumberOfKSumPairs_HashTable { 15 | 16 | // Approach: 17 | // Using a HashMap to keep track of frequency of the numbers in 'nums'. 18 | // Reduce the count or remove the entry (value == 1) if we found the match. 19 | // If not, then we record the number into the HashMap. 20 | 21 | public int maxOperations(int[] nums, int k) { 22 | int count = 0; 23 | Map map = new HashMap<>(); 24 | 25 | // For each number in 'nums', 26 | for (int number : nums) { 27 | // 'difference' is the second number that pairs with 'number' to sum to 'k'. 28 | int difference = k - number; 29 | 30 | // Skip the number if it is greater than k. 31 | if (difference <= 0) continue; 32 | 33 | // If there is the 'difference' in the HashMap, meaning the number came up previously. 34 | // Increase the count, and reduce the frequency or remove the entry. 35 | if (map.containsKey(difference)) { 36 | count++; 37 | if (map.get(difference) == 1) 38 | map.remove(difference); 39 | else 40 | map.put(difference, map.get(difference) - 1); 41 | } 42 | // If no match found, increase the frequency or add the entry into the HashMap. 43 | else 44 | map.put(number, map.getOrDefault(number, 0) + 1); 45 | } 46 | return count; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /solutions/1680. Concatenation of Consecutive Binary Numbers/ConcatenationOfConsecutiveBinaryNumbers_Math.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n logn), 4 | // where 'n' is the input 'n'. 5 | // We traverse from 1 to 'n', and we use division to find the bit length of each number, with O(log n) time complexity, 6 | // resulting in the final O(n logn) time complexity. 7 | // 8 | // Space Complexity : O(1), 9 | // as the auxiliary space used is independent on the input 'n'. 10 | 11 | public class ConcatenationOfConsecutiveBinaryNumbers_Math { 12 | 13 | // Approach: 14 | // We concatenate by shifting position of result with division and multiplication, then add the number. 15 | // As there are a lot of repetitions in shifting of positions, it is much less efficient than using bit manipulation. 16 | 17 | public int concatenatedBinary(int n) { 18 | final long modulo = (long) (1e9 + 7); 19 | long result = 0; 20 | for (int i = 1; i <= n; i++) { 21 | // For each i, we shift left the position of result with * 2, 22 | // while shifting right the position of i with / 2. 23 | int temp = i; 24 | while (temp > 0) { 25 | temp /= 2; 26 | result *= 2; 27 | } 28 | // Add the i to the result and get the remainder of modulo. 29 | result = (result + i) % modulo; 30 | } 31 | return (int) result; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /solutions/169. Majority Element/MajorityElement_HashTable_Counting.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | // Time Complexity : O(n), 7 | // where 'n' is the length of 'nums'. 8 | // We traverse 'nums' array once to count the frequency of the numbers. 9 | // 10 | // Space Complexity : O(n), 11 | // where 'n' is the length of 'nums'. 12 | // We use HashMap with a maximum size of 'n / 2', thus growing linearly with the input 'nums'. 13 | 14 | public class MajorityElement_HashTable_Counting { 15 | 16 | // Approach: 17 | // Using a HashMap to count the frequency of the numbers in 'nums'. 18 | // If any number has frequency greater than 'n / 2', then that number is the majority number. 19 | 20 | public int majorityElement(int[] nums) { 21 | Map map = new HashMap(); 22 | int result = 0; 23 | // Traverse 'nums' and count the frequency of the numbers. 24 | for (int number : nums) { 25 | int currentCount = map.getOrDefault(number, 0) + 1; 26 | 27 | if (currentCount > nums.length / 2) { 28 | // Optional to return the result here. 29 | // We are using a 'result' variable to prevent compile-time error with the 30 | // return statement after exiting the for-loop. 31 | result = number; 32 | break; 33 | } 34 | map.put(number, currentCount); 35 | } 36 | return result; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /solutions/169. Majority Element/MajorityElement_Sorting.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | // Time Complexity : O(n logn), 6 | // where 'n' is the length of 'nums'. 7 | // We use Arrays.sort() method which implements Dual-Pivot Quicksort with O(n logn) time complexity. 8 | // 9 | // Space Complexity : O(1), 10 | // as the auxiliary space used is independent of the input. 11 | 12 | public class MajorityElement_Sorting { 13 | 14 | // Approach: 15 | // For the majority, we are certain that a number has frequency at least 'n / 2'. 16 | // As such, we can sort 'nums'. 17 | // Whichever number that is in the middle of the sorted array is the majority number. 18 | 19 | public int majorityElement(int[] nums) { 20 | Arrays.sort(nums); 21 | return nums[nums.length / 2]; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solutions/1704. Determine if String Halves Are Alike/DetermineIfStringHalvesAreAlike.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 's'. 5 | // We traverse the string 's' once to count the vowels in the two halves. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input string. 9 | 10 | public class DetermineIfStringHalvesAreAlike { 11 | 12 | // Approach: 13 | // We traverse the two halves to count the number of vowels. 14 | // Return true if the vowel counts are equal. 15 | 16 | public boolean halvesAreAlike(String s) { 17 | int n = s.length(); 18 | 19 | int count1 = 0; 20 | int count2 = 0; 21 | // We only need to traverse half of the String 's', 22 | // since we can get the character of the second half with "i + n / 2". 23 | for (int i = 0; i < n / 2; i++) { 24 | // Add to the count if we found a vowel for each respective halves. 25 | if (isVowel(s.charAt(i))) count1++; 26 | if (isVowel(s.charAt(i + n / 2))) count2++; 27 | } 28 | // If the counts for both halves are equal, return true. 29 | return count1 == count2; 30 | } 31 | 32 | // Helper method to determine if the character is vowel. 33 | // This helps with readability. 34 | private boolean isVowel(char character) { 35 | final String VOWELS = "aeiouAEIOU"; 36 | // If the index is >= 0, then 'character' is a vowel. 37 | // If the index is -1, then 'character' is not a vowel. 38 | return VOWELS.indexOf(character) != -1; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /solutions/1732. Find the Highest Altitude/FindTheHighestAltitude.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'gain'. 5 | // We traverse the 'gain' array once to find the prefix sum of the array, and determine the maximum altitude. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input array. 9 | 10 | public class FindTheHighestAltitude { 11 | 12 | // Approach: 13 | // We perform prefix sum on 'gain' array, 14 | // and using a 'max' variable to compare each value and determine the maximum altitude. 15 | // Alternatively, we can use an additional variable to record 16 | // the current value while adding each value in 'gain'. 17 | 18 | public int largestAltitude(int[] gain) { 19 | // As it is possible for gain[0] to be negative, we need to get the maximum of the first value to 0. 20 | int max = Math.max(0, gain[0]); 21 | // Then, we perform the prefix sum, by starting at index 1, 22 | // and adding the values from gain[i - 1] to gain[i]. 23 | // After each addition, we compare to get the maximum altitude. 24 | for (int i = 1; i < gain.length; i++) { 25 | gain[i] += gain[i - 1]; 26 | max = Math.max(max, gain[i]); 27 | } 28 | return max; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /solutions/1832. Check if the Sentence Is Pangram/CheckIfTheSentenceIsPangram.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(26 * n), 4 | // where 'n' is the length of the string 'sentence'. 5 | // For each alphabet, we use String.indexOf() method to check if the alphabet is in 'sentence'. 6 | // String.indexOf() has time complexity of O(n). 7 | // 8 | // Space Complexity : O(1), 9 | // as the auxiliary space used is independent of the input size. 10 | 11 | public class CheckIfTheSentenceIsPangram { 12 | 13 | // Approach: 14 | // For each of the 26 alphabets, check if it is found in the 'sentence'. 15 | 16 | public boolean checkIfPangram(String sentence) { 17 | 18 | // A quick check. If the String length is less than 26 characters, we know it is not a pangram, 19 | // given there are no spaces in the 'sentence'. 20 | if (sentence.length() < 26) return false; 21 | 22 | // Traversing the alphabet from 'a' to 'z', check if any is in 'sentence'. 23 | // If the index is less than 0, return false. 24 | for (char alphabet = 'a'; alphabet <= 'z'; alphabet++) { 25 | if (sentence.indexOf(alphabet) < 0) { 26 | return false; 27 | } 28 | } 29 | // If after checking all 26 alphabets and not false is returned, return true. 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /solutions/1832. Check if the Sentence Is Pangram/CheckIfTheSentenceIsPangram_BitManipulation.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of the string 'sentence'. 5 | // We traverse the string 'sentence' to add the characters to the counting array. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent on the input size. 9 | 10 | public class CheckIfTheSentenceIsPangram_BitManipulation { 11 | 12 | // Approach: 13 | // With the string can only have a maximum of 26 unique characters, 14 | // we can use an integer to record if any character is present using bit manipulation. 15 | // Using the bitwise OR "|" operator, along with the bitwise left shift "<<" operator, 16 | // we could use an integer to record if the character is present, with 1 bit as indicator. 17 | // Once all recorded, we compare if the result is equal to the number "(1 << 26) - 1", 18 | // to check if all the alphabets are present in 'sentence'. 19 | 20 | public boolean checkIfPangram(String sentence) { 21 | // A quick check. If the String length is less than 26 characters, we know it is not a pangram, 22 | // given there are no spaces in the 'sentence'. 23 | if (sentence.length() < 26) return false; 24 | 25 | int seen = 0; 26 | for (int i = 0; i < sentence.length(); i++) { 27 | // Using the bitwise OR "|" operator to store that the alphabet is present. 28 | seen = seen | (1 << sentence.charAt(i) - 'a'); 29 | } 30 | return seen == (1 << 26) - 1; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /solutions/1832. Check if the Sentence Is Pangram/CheckIfTheSentenceIsPangram_Counting.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of the string 'sentence'. 5 | // We traverse the string 'sentence' to add the characters to the counting array. 6 | // 7 | // Space Complexity : O(1), 8 | // as the counting array has a fixed maximum size of 26. 9 | 10 | public class CheckIfTheSentenceIsPangram_Counting { 11 | 12 | // Approach: 13 | // Use a Counting array (of size 26) to keep track of the alphabet frequency that appeared in 'sentence'. 14 | // If any of the frequency in the counting array is 0, return false. 15 | // This works as there no spaces, other symbols and only consist of lowercase letters. Other approach needed otherwise. 16 | 17 | public boolean checkIfPangram(String sentence) { 18 | // A quick check. If the String length is less than 26 characters, we know it is not a pangram, 19 | // given there are no spaces in the 'sentence'. 20 | if (sentence.length() < 26) return false; 21 | 22 | int[] alphabets = new int[26]; 23 | // Record the frequency of each character in the counting array. 24 | for (int i = 0; i < sentence.length(); i++) { 25 | alphabets[sentence.charAt(i) - 'a']++; 26 | } 27 | 28 | // Traverse 'alphabets' to check if any frequency is 0. 29 | for (int frequency : alphabets) { 30 | // If any character is not recorded, then 'sentence' is not pangram. 31 | if (frequency == 0) return false; 32 | } 33 | return true; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /solutions/1832. Check if the Sentence Is Pangram/CheckIfTheSentenceIsPangram_HashSet.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | // Time Complexity : O(n), 7 | // where 'n' is the length of the string 'sentence'. 8 | // We traverse the string 'sentence' to add the characters to the HashSet. 9 | // 10 | // Space Complexity : O(1), 11 | // as the HashSet has a fixed maximum size of 26. 12 | 13 | public class CheckIfTheSentenceIsPangram_HashSet { 14 | 15 | // Approach: 16 | // Use a HashSet to keep track of the alphabets that appeared in 'sentence'. 17 | // If the set has size of 26, it means all the alphabets are in 'sentence'. 18 | // This works as there no spaces, other symbols and only consist of lowercase letters. Other approach needed otherwise. 19 | 20 | public boolean checkIfPangram(String sentence) { 21 | // A quick check. If the String length is less than 26 characters, we know it is not a pangram, 22 | // given there are no spaces in the 'sentence'. 23 | if (sentence.length() < 26) return false; 24 | 25 | // Record each character in HashSet. 26 | Set set = new HashSet<>(); 27 | for (int i = 0; i < sentence.length(); i++) { 28 | set.add(sentence.charAt(i)); 29 | } 30 | // If the HashSet has size of 26, then the 'sentence' is a pangram. 31 | return set.size() == 26; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /solutions/1833. Maximum Ice Cream Bars/MaximumIceCreamBars.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | // Time Complexity : O(n logn), 6 | // where 'n' is the number of ice cream bars (size of 'costs'). 7 | // As we sort the array, the Arrays.sort() method uses the Dual-Pivot Quicksort, 8 | // which has an average performance of O(n logn). 9 | // 10 | // Space Complexity : O(1), 11 | // as we only use variables that are independent of the size of the input. 12 | 13 | public class MaximumIceCreamBars { 14 | 15 | // Approach: 16 | // Since we can buy the ice cream bars in any order, we would always buy the cheapest ice cream bars first. 17 | // As such, we would first sort the 'costs' in ascending order. 18 | // Then we reduce the 'coins' for each ice cream bar until unable to buy another one. 19 | // This is also known as Greedy Algorithm as we always buy the cheapest ice cream bar first. 20 | 21 | public int maxIceCream(int[] costs, int coins) { 22 | // By default, Arrays.sort() sorts the array in ascending order. 23 | Arrays.sort(costs); 24 | 25 | int numberOfIceCream = 0; 26 | // For each ice cream bar, from the cheapest to the most expensive, 27 | for (int cost : costs) { 28 | // If we do not have enough 'coins', stop buying and break from the loop. 29 | if (coins < cost) break; 30 | // Else, buy the ice cream bar. 31 | coins -= cost; 32 | numberOfIceCream++; 33 | } 34 | 35 | return numberOfIceCream; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /solutions/1869. Longer Contiguous Segments of Ones than Zeros/LongerContiguousSegmentsOfOnesThanZeros.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 's'. 5 | // We traverse the string 's' once to count the consecutive substring. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input string. 9 | 10 | public class LongerContiguousSegmentsOfOnesThanZeros { 11 | 12 | // Approach: 13 | // We traverse the string 's' to compare the current character with the previous character, 14 | // and use two variables to record the longest length of consecutive '0' and '1' respectively. 15 | // If the two characters are the same, increase the count. 16 | // Else, reset the count to 1. 17 | // For each character, we check whether it is '0' or '1', and update the max respectively. 18 | 19 | public boolean checkZeroOnes(String s) { 20 | int max0 = 0, max1 = 0, count = 1; 21 | // Traverse the string 's', 22 | for (int i = 0; i < s.length(); i++) { 23 | // and increase 'count' by 1 if the current character is the same as the previous character. 24 | if (i > 0 && s.charAt(i) == s.charAt(i - 1)) 25 | count++; 26 | // If the two characters are different, reset 'count' to 1. 27 | else 28 | count = 1; 29 | 30 | // If the character is '0', update 'max0'. 31 | if (s.charAt(i) == '0') max0 = Math.max(max0, count); 32 | // If the character is '1', update 'max1'. 33 | else max1 = Math.max(max1, count); 34 | } 35 | // Return true if 'max1' is greater than 'max0'. 36 | return max1 > max0; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /solutions/1920. Build Array from Permutation/BuildArrayFromPermutation.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'nums'. 5 | // We traverse 'nums' once to record the permutation array. 6 | // 7 | // Space Complexity : O(n), 8 | // where 'n' is the length of 'nums'. 9 | // We use a result array with the same length as 'nums'. 10 | 11 | public class BuildArrayFromPermutation { 12 | 13 | // Approach: 14 | // As the problem statement, we use a new integer array with the same length as 'nums' 15 | // and traverse 'nums' to map to result[i] with nums[nums[i]]. 16 | 17 | public int[] buildArray(int[] nums) { 18 | int n = nums.length; 19 | 20 | // New empty array of same length as 'nums'. 21 | int[] result = new int[n]; 22 | // For each position in the result, map with nums[nums[i]]. 23 | for (int i = 0; i < n; i++) result[i] = nums[nums[i]]; 24 | 25 | return result; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /solutions/1979. Find Greatest Common Divisor of Array/FindGreatestCommonDivisorOfArray.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'nums'. 5 | // We traverse 'nums' once to find the minimum and the maximum number. 6 | // 7 | // Space Complexity : O(1), 8 | // as the recursive call stack is not quantifiable from the input, thus we can assume that the memory used is constant. 9 | // The recursive method can be implemented iteratively. 10 | 11 | public class FindGreatestCommonDivisorOfArray { 12 | 13 | // Approach: 14 | // Using Euclid's Algorithm from math for the strings' Greatest Common Divisor (GCD). 15 | // Euclid's algorithm has 2 main theorem: 16 | // 1. Subtracting the smaller number from the larger number does not change the GCD. 17 | // (e.g. 6 - 4 = 2, the GCD remains as 2). 18 | // 2. If the smaller number exactly divides the larger number, the smallest number is the GCD. 19 | // (e.g. 8 % 4 = 0, so 4 is the GCD) 20 | 21 | public int findGCD(int[] nums) { 22 | 23 | // With the smallest number and largest number for Integer is Integer.MIN_VALUE and Integer.MAX_VALUE respectively, 24 | // any number smaller than the MAX_VALUE is the new minimum, and vice versa for the maximum. 25 | int min = Integer.MAX_VALUE; 26 | int max = Integer.MIN_VALUE; 27 | 28 | // Traverse 'nums' to get the minimum and maximum values. 29 | for (int number : nums) { 30 | if (number < min) min = number; 31 | if (number > max) max = number; 32 | } 33 | 34 | // Euclid's algorithm. 35 | return gcd(max, min); 36 | } 37 | 38 | // Recursive method to find the Greatest Common Divisor of 2 integers. 39 | private int gcd(int num1, int num2) { 40 | if (num2 == 0) return num1; 41 | return gcd(num2, num1 % num2); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /solutions/1995. Count Special Quadruplets/CountSpecialQuadruplets.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n^4), 4 | // where 'n' is the length of 'nums'. 5 | // We traverse 'nums' with 4 nested for-loops to count the special quadruplets. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input size. 9 | 10 | public class CountSpecialQuadruplets { 11 | 12 | // Approach: 13 | // As the length of 'nums' is only 50, we can use Brute Force approach 14 | // by nesting 4 for-loops to check every possible combination for i < j < k < l, 15 | // whether it fulfills nums[i] + nums[j] + nums[k] == nums[l]. 16 | // This results in time complexity of O(n^4). 17 | 18 | public int countQuadruplets(int[] nums) { 19 | int count = 0; 20 | // Using nested for-loops to check every combination, 21 | // and count if nums[i] + nums[j] + nums[k] == nums[l]. 22 | for (int l = nums.length - 1; l >= 3; l--) 23 | for (int k = l - 1; k >= 2; k--) 24 | for (int j = k - 1; j >= 1; j--) 25 | for (int i = j - 1; i >= 0; i--) 26 | if (nums[i] + nums[j] + nums[k] == nums[l]) count++; 27 | return count; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /solutions/2006. Count Number of Pairs With Absolute Difference K/CountNumberOfPairsWithAbsoluteDifferenceK.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n^2), 4 | // where 'n' is the length of 'nums'. 5 | // We traverse 'nums' in a nested for-loop to count the pair with 'k' differences. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input. 9 | 10 | public class CountNumberOfPairsWithAbsoluteDifferenceK { 11 | 12 | // Approach: 13 | // Intuitive and brute force approach to check every combination and count the ones with 'k' difference. 14 | 15 | public int countKDifference(int[] nums, int k) { 16 | int count = 0; 17 | for (int i = 0; i < nums.length - 1; i++) { 18 | for (int j = i + 1; j < nums.length; j++) { 19 | if (Math.abs(nums[i] - nums[j]) == k) count++; 20 | } 21 | } 22 | return count; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /solutions/2006. Count Number of Pairs With Absolute Difference K/CountNumberOfPairsWithAbsoluteDifferenceK_Counting.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n + k), 4 | // where 'n' is the length of 'nums', and 'k' is 'k'. 5 | // We traverse 'nums' to count the numbers in 'nums', and we traverse maximum 'k' length to get the count. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input. 9 | 10 | public class CountNumberOfPairsWithAbsoluteDifferenceK_Counting { 11 | 12 | // Approach: 13 | // Using a counting array to record the frequency of occurrence for all the numbers in 'nums'. 14 | // Since we know the number ranges from 1 to 100, we can build array of that size to keep track. 15 | 16 | public int countKDifference(int[] nums, int k) { 17 | 18 | // Counting array of size 101, since it is 0-indexed. 19 | int[] countingArray = new int[100 + 1]; 20 | 21 | // Record the frequency for all the numbers. 22 | for (int number : nums) countingArray[number]++; 23 | 24 | // The number of combinations is the multiples of both frequency. 25 | // e.g. [1,1,2,2,2] can have 2 * 3 = 6 combinations for k = 1. 26 | // Since we are traversing from 1 to 100, we will only add to the count if both i and i+k is > 0 frequency. 27 | // With that, we do not need to compare with i-k. 28 | int count = 0; 29 | for (int i = 1; i < countingArray.length - k; i++) { 30 | count += countingArray[i] * countingArray[i + k]; 31 | } 32 | return count; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /solutions/2028. Find Missing Observations/FindMissingObservations.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(m + n), 4 | // where 'm' is the length of 'rolls', and 'n' is 'n'. 5 | // We traverse 'rolls' to get the sum, and traverse the result array of size 'n' to populate the missing observations. 6 | // 7 | // Space Complexity : O(n), 8 | // where 'n' is the input variable 'n'. 9 | // The result has a size of 'n'. 10 | 11 | public class FindMissingObservations { 12 | 13 | // Approach: 14 | // Arithmetically determine the sum of the 'n' rolls by first getting the sum of the 'm' rolls. 15 | // Then determine the average roll for the 'n' rolls and its remainders to assign the correct rolls. 16 | // If sum = 10, n = 4, the average roll is 10 / 4 == 2, with remainder of 2. Thus, we know to assign [3,3,2,2] 17 | 18 | public int[] missingRolls(int[] rolls, int mean, int n) { 19 | // Determine the sum of 'n' rolls. 20 | int sumM = 0; 21 | for (int roll : rolls) sumM += roll; 22 | int sumN = mean * (rolls.length + n) - sumM; 23 | 24 | // If the sum for 'n' rolls is: 25 | // - less than all 'n' rolls of 1, or 26 | // - greater than all 'n' rolls of 6, 27 | // then we know it is impossible to get the target with 'n' rolls. 28 | if (sumN < n || sumN > 6 * n) return new int[0]; 29 | 30 | // Determine the 'floor' number, and the 'remainder' for the number of rolls to add 1 to the 'floor'. 31 | int floor = sumN / n; 32 | int remainder = sumN % n; 33 | int[] result = new int[n]; 34 | for (int i = 0; i < n; i++) { 35 | result[i] = remainder-- > 0 ? floor + 1 : floor; 36 | } 37 | return result; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /solutions/205. Isomorphic Strings/IsomorphicStrings.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | // Time Complexity : O(n), 7 | // where 'n' is the length of string 's' and string 't'. 8 | // We iterate through every character in both input strings to check if they are isomorphic. 9 | // 10 | // Space Complexity : O(n), 11 | // where 'n' is the length of string 's' and string 't'. 12 | // The worst-case scenario is when each character is unique, 13 | // resulting in the space used by the HashMap to be the length of string 's' and 't'. 14 | 15 | public class IsomorphicStrings { 16 | 17 | // Approach: 18 | // Use two HashMap to map the character pairs for strings 's' and 't' in both directions, 19 | // to ensure the characters are correctly mapped to one another. 20 | // 21 | // For example, if only using one HashMap, string 's' = "cat", string 't' = "dad", 22 | // both 'c' and 't' in "cat" is mapped to 'd', which is wrong. 23 | // Thus, we need another map for string 't' to check otherwise. 24 | 25 | public boolean isIsomorphic(String s, String t) { 26 | Map mapS = new HashMap<>(); 27 | Map mapT = new HashMap<>(); 28 | 29 | for(int i = 0; i < s.length(); i++) { 30 | char charS = s.charAt(i); 31 | char charT = t.charAt(i); 32 | // Map to the HashMaps if both characters are not mapped. 33 | if (!mapS.containsKey(charS) && !mapT.containsKey(charT)) { 34 | mapS.put(charS, charT); 35 | mapT.put(charT, charS); 36 | } 37 | // If the characters are mapped incorrectly, then the strings are not isomorphic. 38 | else if (!mapS.containsKey(charS) || !mapT.containsKey(charT) || !mapS.get(charS).equals(charT)) { 39 | return false; 40 | } 41 | } 42 | // If we successfully traverse both strings, then the strings are isomorphic. 43 | return true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /solutions/206. Reverse Linked List/ReverseLinkedList_Iterative.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | /** 4 | * Definition for singly-linked list. 5 | * public class ListNode { 6 | * int val; 7 | * ListNode next; 8 | * ListNode() {} 9 | * ListNode(int val) { this.val = val; } 10 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 11 | * } 12 | */ 13 | // Note: Remember to set up a ListNode class as the same folder as the reverseList() function. 14 | 15 | // Time Complexity : O(n), 16 | // where 'n' is the length of the linked list. 17 | // We traverse the linked list once while flipping the direction of the linked list. 18 | // 19 | // Space Complexity : O(1), 20 | // as the auxiliary space used is independent on the length of the linked list. 21 | 22 | public class ReverseLinkedList_Iterative { 23 | 24 | // Approach: 25 | // Traverse the linked list, while using a temporary variable 'next' to flip the direction of the two nodes. 26 | 27 | public ListNode reverseList(ListNode head) { 28 | ListNode newHead = null; 29 | while (head != null) { 30 | ListNode nextNode = head.next; 31 | head.next = newHead; 32 | newHead = head; 33 | head = nextNode; 34 | } 35 | return newHead; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /solutions/206. Reverse Linked List/ReverseLinkedList_Recursive.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | /** 4 | * Definition for singly-linked list. 5 | * public class ListNode { 6 | * int val; 7 | * ListNode next; 8 | * ListNode() {} 9 | * ListNode(int val) { this.val = val; } 10 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 11 | * } 12 | */ 13 | // Note: Remember to set up a ListNode class as the same folder as the reverseList() function. 14 | 15 | // Time Complexity : O(n), 16 | // where 'n' is the length of the linked list. 17 | // We traverse the linked list once with recursion to flip the direction of the linked list. 18 | // 19 | // Space Complexity : O(n), 20 | // where 'n' is the length of the linked list. 21 | // The recursive method call stack is the length of the linked list. 22 | 23 | public class ReverseLinkedList_Recursive { 24 | 25 | // Approach: 26 | // Using a recursive method to traverse the linked list 27 | // while using a temporary variable 'next' to flip the direction of the two nodes. 28 | 29 | // Main method. 30 | public ListNode reverseList(ListNode head) { 31 | return reverseList(head, null); 32 | } 33 | 34 | // Recursive method. 35 | private ListNode reverseList(ListNode head, ListNode newHead) { 36 | if (head == null) return newHead; 37 | 38 | // Flip the direction of the two nodes. 39 | ListNode next = head.next; 40 | head.next = newHead; 41 | newHead = head; 42 | 43 | // Continue to call the recursive method with the next two nodes. 44 | return reverseList(next, newHead); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /solutions/2095. Delete the Middle Node of a Linked List/DeleteTheMiddleNodeOfALinkedList.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | /** 4 | * Definition for singly-linked list. 5 | * public class ListNode { 6 | * int val; 7 | * ListNode next; 8 | * ListNode() {} 9 | * ListNode(int val) { this.val = val; } 10 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 11 | * } 12 | */ 13 | 14 | // Time Complexity : O(n), 15 | // where 'n' is the number of nodes in the Linked List. 16 | // We traverse the whole Linked List once. 17 | // In actual case, it would be O(n/2) as we are moving the 'fast' pointers two nodes at a time, but simplify as O(n). 18 | // 19 | // Space Complexity : O(1), 20 | // as we are only using fixed variable that do not grow with the length of the Linked List. 21 | 22 | public class DeleteTheMiddleNodeOfALinkedList { 23 | 24 | // Approach: 25 | // Using Two Pointers to traverse the Singly Linked List to find the middle node: 26 | // - 'fast' pointer move two nodes at a time, 27 | // - 'slow' pointer move one node at a time. 28 | 29 | public ListNode deleteMiddle(ListNode head) { 30 | // If the Linked List has only one node, the node is deleted, thus return null. 31 | if (head.next == null) return null; 32 | 33 | ListNode fast = head; 34 | ListNode slow = head; 35 | // An additional 'parent' pointer to keep track of the parent node of 'slow'. 36 | // Since this is a Singly Linked List, there is no way to return to the previous node. 37 | // We need the previous node to delete a node from the Singly Linked List. 38 | ListNode parent = slow; 39 | while (fast != null && fast.next != null) { 40 | fast = fast.next.next; 41 | parent = slow; 42 | slow = slow.next; 43 | } 44 | // Remove the middle node from the Singly Linked List. 45 | parent.next = slow.next; 46 | 47 | return head; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /solutions/2129. Capitalize the Title/CapitalizeTheTitle.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'title'. 5 | // When we split the 'title' into the words array, as well as the joining of words with delimiter, 6 | // and modifying the letters with toUpperCase() and toLowerCase() methods, 7 | // we are iterating each and every char in the string. 8 | // 9 | // Space Complexity : O(n), 10 | // where 'n' is the length of 'title'. 11 | // We create new strings when we split the 'title' into the words array, 12 | // as well as joining the modified words into a new capitalized string. 13 | 14 | public class CapitalizeTheTitle { 15 | 16 | // Approach: 17 | // Split the 'title' into words array and modify each word based on the criteria stated in the problem. 18 | // Then, we use the String.join() method with the space " " delimiter to from the capitalized title. 19 | // Since the problem clearly stated that there words are separated by a space, we can use space " " as delimiter. 20 | 21 | public String capitalizeTitle(String title) { 22 | // Split the 'title' using a space " " as delimiter. 23 | String[] words = title.split(" "); 24 | 25 | // For each word, if the length is two or less, change to lowercase. 26 | // Else, uppercase the first letter and lowercase the remaining characters. 27 | for (int i = 0; i < words.length; i++) { 28 | words[i] = words[i].length() <= 2 ? 29 | words[i].toLowerCase() : 30 | words[i].substring(0, 1).toUpperCase() + words[i].substring(1).toLowerCase(); 31 | } 32 | // Join the capitalized words using space " " delimiter. 33 | return String.join(" ", words); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /solutions/2133. Check if Every Row and Column Contains All Numbers/CheckIfEveryRowAndColumnContainsAllNumbers_HashTable.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | // Time Complexity : O(n^2), 7 | // where 'n' is the length and width of the 'matrix', as we iterate through every position in the matrix. 8 | // 9 | // Space Complexity : O(n^2), 10 | // where 'n' is the length and width of the 'matrix'. 11 | // We use a new HashSets which grows linearly with 'n', for all 'n' rows and columns. 12 | 13 | public class CheckIfEveryRowAndColumnContainsAllNumbers_HashTable { 14 | 15 | // Approach: 16 | // Using a new HashSet for each row and column to check if any duplicates found in that row or column. 17 | 18 | public boolean checkValid(int[][] matrix) { 19 | int n = matrix.length; 20 | // Both the 'i' and 'j' variables are used as both row and column position, 21 | // depending on whether we are using checking the row or the column. 22 | for (int i = 0; i < n; i++) { 23 | Set row = new HashSet<>(); 24 | Set column = new HashSet<>(); 25 | for (int j = 0; j < n; j++) { 26 | // When iterating through row 'i', the 'j' represents the column position in the row. 27 | // When iterating through column 'i', the 'j' represents the row position in the column. 28 | if (!row.add(matrix[i][j]) || !column.add(matrix[j][i])) return false; 29 | } 30 | } 31 | // If we successfully checked every number in 'matrix', meaning the matrix is valid. 32 | return true; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /solutions/2169. Count Operations to Obtain Zero/CountOperationsToObtainZero.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is either 'num1' or 'num2', depending on which is greater. 5 | // The operations range from O(1), when both numbers are the same, to O(n), when one of the number is 1. 6 | // As it is hard to determine the time complexity based on the input, 7 | // we can take the worst-case scenario when one of the number is 1. 8 | // 9 | // Space Complexity : O(1), 10 | // as the auxiliary space used is independent of the inputs. 11 | 12 | public class CountOperationsToObtainZero { 13 | 14 | // Approach: 15 | // Using a while-loop and execute the stated conditions: 16 | // 1. when num1 >= num2, subtract num2 from num1, or 17 | // 2. when num2 > num1, subtract num1 from num2. 18 | // 19 | // Use a 'count' variable to record the count, and exit the loop when either number reaches 0. 20 | 21 | public int countOperations(int num1, int num2) { 22 | int count = 0; 23 | // While both 'num1' and 'num2' are greater than 0, 24 | while (num1 > 0 && num2 > 0) { 25 | // subtract 'num2' from 'num1' if "num1 >= num2", or 26 | if (num1 >= num2) num1 -= num2; 27 | // subtract 'num1' from 'num2' if "num1 < num2", or 28 | else num2 -= num1; 29 | // Increase count by 1 for each operation performed. 30 | count++; 31 | } 32 | return count; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /solutions/217. Contains Duplicate/ContainsDuplicate_HashMap.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | // Time Complexity : O(n), 7 | // where 'n' is the length of 'nums'. 8 | // We traverse the 'nums' array to add the integer to the HashMap. 9 | // 10 | // Space Complexity : O(n), 11 | // where 'n' is the length of 'nums'. 12 | // In the worst-case when no duplicate is found, the HashMap has a size of 'n'. 13 | 14 | public class ContainsDuplicate_HashMap { 15 | 16 | // Approach: 17 | // Using HashMap, store the integers in 'nums'. Return true if the same integer is already in the HashMap. 18 | 19 | public boolean containsDuplicate(int[] nums) { 20 | // Set up the HashMap. 21 | Map hashMap = new HashMap<>(); 22 | 23 | // For each integer in 'nums', 24 | for (int integer : nums) { 25 | // if HashMap contains the key, duplicate integer is found and return true. 26 | if (hashMap.containsKey(integer)) return true; 27 | // Add the integer into the HashMap. 28 | hashMap.put(integer, 1); 29 | } 30 | // If all integers added successfully, that means all integers are distinct. 31 | return false; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /solutions/217. Contains Duplicate/ContainsDuplicate_HashSet.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | // Time Complexity : O(n), 7 | // where 'n' is the length of 'nums'. 8 | // We traverse the 'nums' array to add the integer to the HashSet. 9 | // 10 | // Space Complexity : O(n), 11 | // where 'n' is the length of 'nums'. 12 | // In the worst-case when no duplicate is found, the HashSet has a size of 'n'. 13 | 14 | public class ContainsDuplicate_HashSet { 15 | 16 | // Approach: 17 | // Using HashSet, store the integers in 'nums'. Return true if the same integer is already in the HashSet. 18 | // Since Set unable to store repeated integers, the add function will return true if added successfully, 19 | // Return false if fail to add into the HashSet. 20 | // Note: HashSet uses less memory than HashMap. 21 | 22 | public boolean containsDuplicate(int[] nums) { 23 | // Set up the HashSet. 24 | Set hashSet = new HashSet<>(); 25 | 26 | // For each integer in 'nums'. 27 | for (int integer : nums) { 28 | // If fail to add, return true, since it means that there are duplicate integers. 29 | if (!hashSet.add(integer)) return true; 30 | } 31 | // If all integers added successfully, that means all integers are distinct. 32 | return false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /solutions/217. Contains Duplicate/ContainsDuplicate_Sorting.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | // Time Complexity : O(n logn), 6 | // where 'n' is the length of 'nums'. 7 | // The sorting function in Arrays class has a time complexity of O(n logn). 8 | // The traversal of the 'nums' array has linear time complexity. 9 | // 10 | // Space Complexity : O(n), 11 | // where 'n' is the length of 'nums'. 12 | // The sorted array has the same length of 'n' as the input 'nums' array. 13 | 14 | public class ContainsDuplicate_Sorting { 15 | 16 | // Approach: 17 | // Sort the 'nums' array so that the duplicate integers (if any) are next to each other. 18 | // Then, we traverse the sorted array to check if any adjacent integers are the same. 19 | // Note: With the sorting algorithm having time complexity of O(n logn), it is slower than HashMap and HashSet. 20 | 21 | public boolean containsDuplicate(int[] nums) { 22 | // Sort the array. 23 | Arrays.sort(nums); 24 | 25 | // For each integer in 'nums', compare if it is the same as the next integer. 26 | for (int i = 0; i < nums.length - 1; i++) { 27 | if (nums[i] == nums[i+1]) return true; 28 | } 29 | // If all integers added successfully, meaning all are distinct integers. 30 | return false; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /solutions/2176. Count Equal and Divisible Pairs in an Array/CountEqualAndDivisiblePairsInAnArray.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n^2), 4 | // where 'n' is the length of 'nums'. 5 | // We traverse 'nums' with two nested for-loops. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the inputs. 9 | 10 | public class CountEqualAndDivisiblePairsInAnArray { 11 | 12 | // Approach: 13 | // The intuitive and the brute force approach is to traverse 'nums' with two nested for-loops, 14 | // checking each combination and count if the requirements are met: 15 | // 1. nums[i] == nums[j], 16 | // 2. i * j is divisible by k. 17 | 18 | public int countPairs(int[] nums, int k) { 19 | int n = nums.length; 20 | 21 | int count = 0; 22 | for (int i = 0; i < n; i++) { 23 | for (int j = i+1; j < n; j++) { 24 | // Check if i and j meet the condition. 25 | if (nums[i] == nums[j] && (i * j) % k == 0) count++; 26 | } 27 | } 28 | return count; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /solutions/219. Contains Duplicate II/ContainsDuplicateII_HashMap.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | // Time Complexity : O(n), 7 | // where 'n' is the length of 'nums'. 8 | // We traverse the 'nums' array, with the worst-case having to traverse the whole array, 9 | // which has a linear time complexity. 10 | // 11 | // Space Complexity : O(n), 12 | // where 'n' is the length of 'nums'. 13 | // The worst case is when all the integers in 'nums' are unique, 14 | // thus resulting in the HashMap having the same size as the input 'nums'. 15 | 16 | public class ContainsDuplicateII_HashMap { 17 | 18 | // Approach: 19 | // We use a HashMap to keep track of the last seen index of the integer. 20 | // Since we only concern about the i - j <= k, any prior j indices is not needed. 21 | 22 | public boolean containsNearbyDuplicate(int[] nums, int k) { 23 | // If k is 0, then i and j cannot be distinct. 24 | if (k == 0) return false; 25 | 26 | // Set up the HashMap, with key = integer in 'nums' and value = index. 27 | Map map = new HashMap<>(); 28 | 29 | // Traverse the 'nums'. 30 | for (int i = 0; i < nums.length; i++) { 31 | int integer = nums[i]; 32 | // If contains key and i - j <= k, return true. 33 | if (map.containsKey(integer) && i - map.get(integer) <= k) { 34 | return true; 35 | } 36 | // Either put a new pair, or update index of existing integer in the HashMap. 37 | map.put(integer, i); 38 | } 39 | // If successfully traverse the whole array, meaning we fail to find any integers fulfilling the conditions. 40 | return false; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /solutions/219. Contains Duplicate II/ContainsDuplicateII_SlidingWindow.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | // Time Complexity : O(n), 7 | // where 'n' is the length of 'nums'. 8 | // We traverse the 'nums' array, with the worst-case having to traverse the whole array, 9 | // which has a linear time complexity. 10 | // 11 | // Space Complexity : O(k), 12 | // where 'k' is the input value 'k'. 13 | // At any one time, the HashSet has a maximum size of 'k', and the integers outside the sliding window is removed. 14 | 15 | public class ContainsDuplicateII_SlidingWindow { 16 | 17 | // Approach: 18 | // We use the sliding window technique. 19 | // Traversing from left to right, we use a HashSet to store the integers that we saw. 20 | // If the same integer is seen again, we have found the duplicate. 21 | // Then, we update the window again to be within 'k' index from 'index'. 22 | 23 | public boolean containsNearbyDuplicate(int[] nums, int k) { 24 | // If k is 0, then i and j cannot be distinct. 25 | if (k == 0) return false; 26 | 27 | // Set up the HashSet. 28 | Set slidingWindow = new HashSet<>(); 29 | 30 | // Start sliding the slidingWindow to the right. 31 | for (int index = 0; index < nums.length; index++) { 32 | // Return true when found duplicates in the slidingWindow. 33 | if (slidingWindow.contains(nums[index])) 34 | return true; 35 | 36 | // Update the state of the window, but removing the leftmost integer and add the new integer. 37 | if (index >= k) 38 | slidingWindow.remove(nums[index - k]); 39 | 40 | slidingWindow.add(nums[index]); 41 | } 42 | // If successfully traverse the whole array, meaning we fail to find any integers fulfilling the conditions. 43 | return false; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /solutions/2220. Minimum Bit Flips to Convert Number/MinimumBitFlipsToConvertNumber.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the maximum bitlength for both 'start' and 'goal'. 5 | // The Integer.bitCount() method has linear time complexity. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input. 9 | 10 | public class MinimumBitFlipsToConvertNumber { 11 | 12 | // Approach: 13 | // In order to make 'start' to be 'goal', we would flip the bits that are different. 14 | // Using the bitwise XOR operator "^", we can get the bit differences between 'start' and 'goal'. 15 | // Then, we can either implement bit traversal, or use the Integer.bitCount() method 16 | // to count the number of bits that are different. 17 | 18 | public int minBitFlips(int start, int goal) { 19 | // 'start' ^ 'goal' to get the differences, 20 | // then use Integer.bitCount to count the number of bits that are different. 21 | return Integer.bitCount(start ^ goal); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solutions/2240. Number of Ways to Buy Pens and Pencils/NumberOfWaysToBuyPensAndPencils.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the number of pen possible to buy. 5 | // After finding out the number of pen possible to buy, we iterate through the pen numbers to find the count for pencils. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the size of the input. 9 | 10 | public class NumberOfWaysToBuyPensAndPencils { 11 | 12 | // Approach: 13 | // First determine how many pen it is possible to buy. 14 | // Then for each number of pen, check how many pencil can be bought with the remaining amount of money. 15 | 16 | public long waysToBuyPensPencils(int total, int cost1, int cost2) { 17 | long count = 0; 18 | 19 | // Determine the number of pen possible. 20 | int pen = total / cost1; 21 | 22 | // For each number of pen bought, determine how much pencil can be bought with the money left. 23 | for (int i = 0; i <= pen; i++) { 24 | int remaining = total - (cost1 * i); 25 | int pencil = remaining / cost2; 26 | // The + 1 is to account for the case with 0 pencils. 27 | count += pencil + 1; 28 | } 29 | return count; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /solutions/226. Invert Binary Tree/InvertBinaryTree_DFS_Recursive.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | /** 4 | * Definition for a binary tree node. 5 | * public class TreeNode { 6 | * int val; 7 | * TreeNode left; 8 | * TreeNode right; 9 | * TreeNode() {} 10 | * TreeNode(int val) { this.val = val; } 11 | * TreeNode(int val, TreeNode left, TreeNode right) { 12 | * this.val = val; 13 | * this.left = left; 14 | * this.right = right; 15 | * } 16 | * } 17 | */ 18 | // Note: Remember to set up a TreeNode class as the same folder. 19 | 20 | // Time Complexity : O(n), 21 | // where 'n' is the number of nodes in the tree. 22 | // We traverse every node in the binary tree to invert each branch. 23 | // 24 | // Space Complexity : O(m), 25 | // where 'm' is the depth of the tree. 26 | // The maximum size of the recursive stack is the depth of the tree. 27 | 28 | public class InvertBinaryTree_DFS_Recursive { 29 | 30 | // Approach: 31 | // Using depth-first search to traverse and visit every node in the binary tree. 32 | // For each node, we invert the two branches by swapping the left and right child node. 33 | // Here, the depth-first search is implemented recursively. 34 | 35 | public TreeNode invertTree(TreeNode root) { 36 | // Continue to the next node if the current node is null. 37 | if (root == null) return null; 38 | 39 | // Swap the left and right child node using a temporary variable. 40 | TreeNode leftChild = invertTree(root.left); 41 | root.left = invertTree(root.right); 42 | root.right = leftChild; 43 | 44 | // Return the current node once the child is swapped. 45 | return root; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /solutions/228. Summary Ranges/SummaryRanges.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | // Time Complexity : O(n), 7 | // where 'n' is the length of 'nums'. 8 | // We traverse 'nums' to check each number for their range. 9 | // 10 | // Space Complexity : O(n), 11 | // where 'n' is the length of 'nums'. 12 | // The maximum size of the result list is 'n', which each element being unique and not in any range. 13 | 14 | public class SummaryRanges { 15 | 16 | // Approach: 17 | // We traverse 'nums', recording the 'start' number for each range. 18 | // While the current element is within range with the next element, 19 | // shift the index to the next until we found the end of the current range. 20 | // If the current number is the same as 'start', add the number as String to the result. 21 | // Else, add the Stringify range to the result, for example "1->2". 22 | 23 | public List summaryRanges(int[] nums) { 24 | int n = nums.length; 25 | 26 | List result = new ArrayList<>(); 27 | 28 | // Traverse 'nums'. 29 | for (int i = 0; i < n; i++) { 30 | int start = nums[i]; 31 | // While the current element is within range with the next element, 32 | // shift the index until we found the end of the range. 33 | while (i + 1 < n && nums[i] + 1 == nums[i + 1]) 34 | i++; 35 | 36 | // If the current number is the same as 'start', add the number as String to the result. 37 | if (start == nums[i]) 38 | result.add(String.valueOf(start)); 39 | // Else, add the Stringify range to the result, for example "1->2". 40 | else 41 | result.add(String.join("->", String.valueOf(start), String.valueOf(nums[i]))); 42 | } 43 | return result; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /solutions/229. Majority Element II/MajorityElementII_HashTable_Counting.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | // Time Complexity : O(n), 9 | // where 'n' is the length of 'nums'. 10 | // We traverse 'nums' once to count the frequency of the numbers. 11 | // Then, we check the recorded number if the frequency is greater than 'n / 3'. 12 | // 13 | // Space Complexity : O(n), 14 | // where 'n' is the length of 'nums'. 15 | // The HashMap has a maximum size of '2n / 3', which is linear with the input 'nums'. 16 | 17 | public class MajorityElementII_HashTable_Counting { 18 | 19 | // Approach: 20 | // We count the frequency of the numbers in 'nums' using a HashMap. 21 | // Then, we check each distinct number recorded if the frequency is greater than 'n / 3'. 22 | 23 | public List majorityElement(int[] nums) { 24 | int n = nums.length; 25 | 26 | Map map = new HashMap<>(); 27 | // Count the frequency of each number in 'nums'. 28 | for (int number : nums) 29 | map.put(number, map.getOrDefault(number, 0) + 1); 30 | 31 | List result = new ArrayList<>(); 32 | // From the HashMap, find the majority number if frequency greater than 'n / 3'. 33 | for (int key : map.keySet()) 34 | if (map.get(key) > (n / 3)) result.add(key); 35 | 36 | return result; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /solutions/229. Majority Element II/MajorityElementII_Sorting.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | // Time Complexity : O(n logn), 8 | // where 'n' is the length of 'nums'. 9 | // We use Arrays.sort() method which implements Dual-Pivot Quicksort with O(n logn) time complexity. 10 | // Then, we traverse 'nums' to count and find the numbers with frequency greater than 'n / 3'. 11 | // 12 | // Space Complexity : O(1), 13 | // as the auxiliary space used is independent of the input 'nums'. 14 | 15 | public class MajorityElementII_Sorting { 16 | 17 | // Approach: 18 | // With sorting the 'nums' array, we can get the numbers in ascending order. 19 | // As such, we can count each distinct number to check if the frequency is greater than 'n / 3'. 20 | 21 | public List majorityElement(int[] nums) { 22 | int n = nums.length; 23 | 24 | Arrays.sort(nums); 25 | 26 | List result = new ArrayList<>(); 27 | int previous = nums[0]; 28 | int count = 1; 29 | // For each number, count the frequency. 30 | for (int i = 1; i < n; i++) { 31 | // If the current number is the same as previous, increase the count by 1. 32 | if (nums[i] == previous) { 33 | count++; 34 | } 35 | // If the current number is different, check if the previous number count is the majority. 36 | // Then, change the counting number to the current number. 37 | else { 38 | if (count > n / 3) result.add(previous); 39 | count = 1; 40 | previous = nums[i]; 41 | } 42 | } 43 | // Check if the last element is the majority. 44 | if (count > n / 3) result.add(previous); 45 | 46 | return result; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /solutions/2315. Count Asterisks/CountAsterisks.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of string 's'. 5 | // We traverse the string 's' to check and count the asterisks. 6 | // 7 | // Space Complexity : O(n), 8 | // where 'n' is the length of string 's'. 9 | // We convert the string 's' into char array with the same size. 10 | // Note: We can achieve constant time O(1) by using index when checking for vertical bar and asterisks. 11 | 12 | public class CountAsterisks { 13 | 14 | // Approach: 15 | // Using a boolean variable to flag whether to count the asterisks. 16 | // The boolean variable 'isCounting' is first set to true as we start from outside the vertical bar pair. 17 | // When encounter vertical bar, we toggle 'isCounting', and only count the asterisks '*' when 'isCounting' is true. 18 | 19 | public int countAsterisks(String s) { 20 | int count = 0; 21 | boolean isCounting = true; 22 | 23 | for (char character : s.toCharArray()) { 24 | // Count the asterisks only when isCounting == true. Flip isCounting when encounter the '|' symbol. 25 | if (isCounting && character == '*') 26 | count++; 27 | else if (character == '|') 28 | isCounting = !isCounting; 29 | } 30 | return count; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /solutions/2351. First Letter to Appear Twice/FirstLetterToAppearTwice_Counting.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length string 's'. 5 | // We traverse the whole string to not find duplicate letters in the worst-case. 6 | // 7 | // Space Complexity : O(1), 8 | // as we are using a fixed boolean array independent of the size of the input string 's'. 9 | 10 | public class FirstLetterToAppearTwice_Counting { 11 | 12 | // Approach: 13 | // Using HashTable to record character's first occurrence. 14 | // If the subsequent letter appears when it is already in the HashTable, 15 | // we have found the first char that appear twice. 16 | 17 | public char repeatedCharacter(String s) { 18 | // Can use either int[] with default as 0, or boolean[] with default as false, also with loser memory usage. 19 | boolean[] count = new boolean[26]; 20 | for (int i = 0; i < s.length(); i++) { 21 | char current = s.charAt(i); 22 | if (count[current - 'a']) 23 | return current; 24 | else 25 | count[current - 'a'] = true; 26 | } 27 | // As we returned the result in the during the check, this is mainly to prevent compile-time error. 28 | // Otherwise, it can be used to show that no characters appears twice in the string. 29 | return '!'; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /solutions/2351. First Letter to Appear Twice/FirstLetterToAppearTwice_HashTable.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | // Time Complexity : O(n), 7 | // where 'n' is the length string 's'. 8 | // We traverse the whole string to not find duplicate letters in the worst-case. 9 | // 10 | // Space Complexity : O(n), 11 | // where 'n' is the length string 's'. 12 | // We traverse the whole string to not find duplicate letters in the worst-case, 13 | // storing 'n' number of characters in the HashSet. 14 | 15 | public class FirstLetterToAppearTwice_HashTable { 16 | 17 | // Approach: 18 | // Using HashTable to record character's first occurrence. 19 | // If the subsequent letter appears when it is already in the HashTable, 20 | // we have found the first char that appear twice. 21 | 22 | public char repeatedCharacter(String s) { 23 | Set set = new HashSet<>(); 24 | for (int i = 0; i < s.length(); i++) { 25 | char current = s.charAt(i); 26 | if (set.contains(current)) 27 | return current; 28 | else 29 | set.add(current); 30 | } 31 | // As we returned the result in the during the check, this is mainly to prevent compile-time error. 32 | // Otherwise, it can be used to show that no characters appears twice in the string. 33 | return '!'; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /solutions/2395. Find Subarrays With Equal Sum/FindSubarraysWithEqualSum.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | // Time Complexity : O(n), 7 | // where 'n' is the length of 'nums', as we traverse 'nums' to check every subarray of length 2. 8 | // 9 | // Space Complexity : O(n), 10 | // where 'n' is the length of 'nums', as we store the subarray sum in 'nums' in the HashSet. 11 | 12 | public class FindSubarraysWithEqualSum { 13 | 14 | // Approach: 15 | // Using Hash Set to record the sum that is found. Return true when found the same sum in the Hash Set. 16 | 17 | public boolean findSubarrays(int[] nums) { 18 | Set set = new HashSet<>(); 19 | for (int i = 1; i < nums.length; i++) 20 | // The set.add() function returns boolean whether added or not. 21 | // If the subarray sum is already in the HashSet, then we have found the subarray of equal sum. 22 | if (!set.add(nums[i] + nums[i - 1])) return true; 23 | 24 | return false; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /solutions/2399. Check Distances Between Same Letters/CheckDistancesBetweenSameLetters.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of the string 's', because we traverse the string 's' once. 5 | // 6 | // Space Complexity : O(1), 7 | // as we are modifying the 'distance' array in-place. 8 | 9 | public class CheckDistancesBetweenSameLetters { 10 | 11 | // Approach: 12 | // For each first occurrence, check if the letter after distance[i] is the same. 13 | // Do note to make sure the index is within the length to prevent IndexOutOfBound error. 14 | 15 | public boolean checkDistances(String s, int[] distance) { 16 | int n = s.length(); 17 | for (int i = 0, spaces; i < n; i++) { 18 | // Get the spaces between the two occurrences in the 'distance' array. 19 | spaces = distance[s.charAt(i) - 'a']; 20 | // For each letter that we checked, we change the distance[i] to -1. 21 | // If the letter is out of range or different, return false. 22 | if (spaces >= 0) { 23 | if (i + spaces + 1 >= n || s.charAt(i) != s.charAt(i + spaces + 1)) return false; 24 | distance[s.charAt(i) - 'a'] = -1; 25 | } 26 | } 27 | // If every letter is checked, return true. 28 | return true; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /solutions/2399. Check Distances Between Same Letters/CheckDistancesBetweenSameLetters_HashTable.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | // Time Complexity : O(n), 7 | // where 'n' is the length of the string 's', because we traverse the string 's' once. 8 | // 9 | // Space Complexity : O(n), 10 | // where 'n' is the length of the string 's'. 11 | // The algorithm is basically "n / 2" as there are only two occurrences for each letter, to record in the HashMap. 12 | 13 | public class CheckDistancesBetweenSameLetters_HashTable { 14 | 15 | // Approach: 16 | // Using Hash Table to store the index of the first occurrence of a letter. 17 | // At the second occurrence, check if the spaces between is the same as in distance[i]. 18 | // Due to the fact that distance[i] representing the letters between, but not index difference, 19 | // we need to reduce the index difference by 1 to compare to distance[i], 20 | // or compare index difference with distance[i] + 1. 21 | 22 | public boolean checkDistances(String s, int[] distance) { 23 | Map map = new HashMap<>(); 24 | char current; 25 | for (int i = 0; i < s.length(); i++) { 26 | current = s.charAt(i); 27 | // Store the index for the first occurrence. 28 | if (!map.containsKey(current)) 29 | map.put(current, i); 30 | else 31 | // At the second occurrence, check if the distance is the same, return false otherwise. 32 | if (distance[current - 'a'] + 1 != i - map.get(current)) 33 | return false; 34 | } 35 | // If every letter is checked, return true. 36 | return true; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /solutions/24. Swap Nodes in Pairs/SwapNodesInPairs_Recursion.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | /** 4 | * Definition for singly-linked list. 5 | * public class ListNode { 6 | * int val; 7 | * ListNode next; 8 | * ListNode() {} 9 | * ListNode(int val) { this.val = val; } 10 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 11 | * } 12 | */ 13 | // Note: Remember to set up a ListNode class as the same folder as the swapPairs() function. 14 | 15 | // Time Complexity : O(n), 16 | // where 'n' is the number of nodes in the linked list. 17 | // With recursion, the recursive call stack has a height that grows linearly 18 | // with the input linked list. 19 | // 20 | // Space Complexity : O(n), 21 | // where 'n' is the number of nodes in the linked list. 22 | // While the auxiliary space used is independent on the length of the linked list, 23 | // the recursive call stack results in O(n). 24 | 25 | public class SwapNodesInPairs_Recursion { 26 | 27 | // Approach: 28 | // Using recursion, swap the ListNodes in the pair and return the new first ListNode of the pair, 29 | // and link the second node (head.next) to the next pair by calling the swapPairs() function 30 | // with the first node of the next pair (head.next.next). 31 | 32 | public ListNode swapPairs(ListNode head) { 33 | // If there is no pair, return head. 34 | if (head == null || head.next == null) return head; 35 | 36 | // Swap the ListNodes in the pair. 37 | ListNode newHead = head.next; 38 | // Link the second node ('head' ListNode) to the next pair, 39 | // by recursively calling the swapPairs() function with the head of the next pair. 40 | head.next = swapPairs(head.next.next); 41 | newHead.next = head; 42 | 43 | // Return the first node of the pair. 44 | return newHead; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /solutions/2413. Smallest Even Multiple/SmallestEvenMultiple.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(1), 4 | // as the number of operations performed is independent of the input 'n'. 5 | // 6 | // Space Complexity : O(1), 7 | // as the auxiliary space used is independent of the input 'n'. 8 | 9 | public class SmallestEvenMultiple { 10 | 11 | // Approach: 12 | // If the n is even, then the smallest even multiple is n, else it is n * 2. 13 | 14 | public int smallestEvenMultiple(int n) { 15 | return n % 2 == 0 ? n : n * 2; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /solutions/26. Remove Duplicates from Sorted Array/RemoveDuplicatesFromSortedArray.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'nums'. 5 | // We traverse through 'nums' once to check every element. 6 | // 7 | // Space Complexity : O(1), 8 | // as we only use fixed variables that does not grow with 'n'. 9 | 10 | public class RemoveDuplicatesFromSortedArray { 11 | 12 | // Approach: 13 | // With the removal of duplicates, we can use two pointers, 14 | // - a 'tail' to represent the final array with the duplicates removed, and 15 | // - a 'head' to iterate through 'nums'. 16 | // A duplicate is found when nums[head] == nums[head - 1]. 17 | // Thus, we can move the pointer 'tail' forward when nums[head] != nums[head - 1], and stay otherwise. 18 | 19 | public int removeDuplicates(int[] nums) { 20 | // As the first element is not a duplicate, we start 'tail' at 1 and 'head' at 1. 21 | // Else, we need to move 'tail' forward first before replacing the element, and the result is 'tail' + 1. 22 | int tail = 1; 23 | for (int head = 1; head < nums.length; head++) 24 | // As the question is basically asking the length of the final array, 25 | // we only need to count the number unique integers. 26 | // However, for the spirit of the question, we are updating the array in-place up until 'k' unique elements. 27 | if (nums[head] != nums[head - 1]) 28 | nums[tail++] = nums[head]; 29 | 30 | return tail; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /solutions/263. Ugly Number/UglyNumber.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(logn), 4 | // as we are dividing 'n' by either 2, 3 or 5 until reaching 1, 5 | // the time complexity scales with the log2 of 'n' in the worst case. 6 | // 7 | // Space Complexity : O(1), 8 | // as no additional space is used. 9 | 10 | public class UglyNumber { 11 | 12 | // Approach: 13 | // Continue to divide 'n' with either 2, 3 or 5 until unable to fully divide anymore. 14 | // If the result is 1, then 'n' is an ugly number. 15 | // If it is another prime number other than 2, 3 or 5, then it is not an ugly number. 16 | 17 | public boolean isUgly(int n) { 18 | // Edge case of 'n' == 0 and return true. 19 | if (n == 0) return true; 20 | 21 | // We continue to divide 'n' with number 2, 3, 4 and 5 until 'n' cannot be completely divided. 22 | for (int i = 5; i >= 2; i--) { 23 | while (n % i == 0) n /= i; 24 | } 25 | 26 | // As 'n' can be negative, we take the absolute value of the result. 27 | return Math.abs(n) == 1; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /solutions/27. Remove Element/RemoveElement.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'nums', as we traverse 'nums' once. 5 | // 6 | // Space Complexity : O(1), 7 | // as we only modified 'nums' in-place, not creating additional array. 8 | 9 | public class RemoveElement { 10 | 11 | // Approach: 12 | // Using two pointers, 'i' is to traverse 'nums' and 13 | // 'k' is the pointer indicating the position of the modified array. 14 | // Since the test only check for the elements up to 'k' position, thus not required to modify the remaining elements. 15 | 16 | public int removeElement(int[] nums, int val) { 17 | int k = 0; 18 | for (int i = 0; i < nums.length; i++) { 19 | // If the element is different from 'val', then we can put it at the latest position in the modified array, 20 | // at position 'k'. 21 | if (nums[i] != val) { 22 | nums[k] = nums[i]; 23 | k++; 24 | } 25 | } 26 | return k; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /solutions/274. H-Index/HIndex_Sorting.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | // Time Complexity : O(n logn), 6 | // where 'n' is the length of 'citations'. 7 | // The Arrays.sort() method implements Dual-Pivot Quicksort, which has a O(n logn) time complexity. 8 | // Additionally, we traverse 'citations' once to get the H-Index. 9 | // 10 | // Space Complexity : O(1), 11 | // as the auxiliary space used is independent of the input size. 12 | 13 | public class HIndex_Sorting { 14 | 15 | // Approach: 16 | // The problem is asking us to find the maximum paper count with citation values greater than the paper count. 17 | // As such, we need to find the intersection between the paper count and the citations, 18 | // traversing the citation from least to greatest, and the paper count from greatest ot least. 19 | // 20 | // This is achieved by first sorting 'citations' array. 21 | // Checking each citation in ascending order while decreasing the paper count, 22 | // the H-Index is when the paper count is less than or equal to citation, 23 | // with the remaining citations to be at least the number of paper. 24 | 25 | public int hIndex(int[] citations) { 26 | // Sort the citations in ascending order. 27 | Arrays.sort(citations); 28 | 29 | // 'count' is the number of paper. 30 | int count = citations.length; 31 | // Traversing from the least to the greatest number of citations, 32 | for (int citation : citations) { 33 | // and check if the number of paper is less than the current citation. 34 | // If it is, then the 'count' is the H-Index. 35 | // Note that the 'citations' is in ascending order, 36 | // thus the remaining citations are at least 'count'. 37 | if (count <= citation) { 38 | return count; 39 | } 40 | // Reduce the 'count' for each citation checked. 41 | count--; 42 | } 43 | return count; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /solutions/283. Move Zeroes/MoveZeroes.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'nums'. 5 | // We traverse through 'nums' to check every element. 6 | // 7 | // Space Complexity : O(1), 8 | // as we only use fixed variables that does not grow with 'n'. 9 | 10 | public class MoveZeroes { 11 | 12 | // Approach: 13 | // Using Two Pointers to traverse through 'nums': 14 | // - 'head' pointer check for non-zero integer, and 15 | // - 'tail' pointer is the latest index to put the non-zero integer. 16 | // Once all the non-zero numbers are put into their respective positions, 17 | // we replace the remaining positions in the array with 0. 18 | 19 | public void moveZeroes(int[] nums) { 20 | 21 | // Both 'tail' and 'head' pointer starts at index 0. 22 | int tail = 0; 23 | 24 | for (int head = 0; head < nums.length; head++) 25 | // If the integer is non-zero, we put it in the final position. 26 | if (nums[head] != 0) nums[tail++] = nums[head]; 27 | 28 | // Once done, we replace the remaining positions with 0. 29 | for (; tail < nums.length; tail++) 30 | nums[tail] = 0; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /solutions/3. Longest Substring Without Repeating Characters/LongestSubstringWithoutRepeatingCharacters.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 's'. 5 | // We use two pointers as sliding window to traverse the string 's' once. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input. 9 | 10 | public class LongestSubstringWithoutRepeatingCharacters { 11 | 12 | // Approach: 13 | // Using sliding window technique with two pointers 'front' and 'back', 14 | // and an array to store the latest index of the character found. 15 | 16 | public int lengthOfLongestSubstring(String s) { 17 | 18 | // The standard ASCII characters range from 0 to 127. 19 | int[] characterIndex = new int[128]; 20 | int max = 0; 21 | for (int front = 0, back = 0; front < s.length(); front++) { 22 | char character = s.charAt(front); 23 | // Get the latest 'back' index 24 | // if there is a character index (non-zero) that was recorded in the 'characterIndex' array. 25 | back = Math.max(back, characterIndex[character]); 26 | 27 | // Update 'max' for the longer substring without repeating characters. 28 | max = Math.max(max, front - back + 1); 29 | 30 | // The index is recorded as "front + 1" is because it will be the start of the substring, 31 | // when the 'back' index above is updated. 32 | characterIndex[character] = front + 1; 33 | } 34 | return max; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /solutions/344. Reverse String/ReverseString_TwoPointers.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of the char array 's'. 5 | // We traverse half of the array once to swap the characters, which scales linearly with the length of the char array 's'. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent on the length of the char array 's'. 9 | 10 | public class ReverseString_TwoPointers { 11 | 12 | // Approach: 13 | // Use two pointers, one from the left, the other from the right, and swap the characters. 14 | 15 | public void reverseString(char[] s) { 16 | // We only need to traverse until halfway, since we are swapping the left and right. 17 | // Traversing the whole length will result in the original array, since we swap twice. 18 | for (int index = 0; index < s.length / 2; index++) { 19 | int left = index; 20 | int right = s.length - index - 1; 21 | // Optional to check if both characters are the same. 22 | // Or we can just swap the left and right characters without checking. 23 | if (s[left] != s[right]) { 24 | char temp = s[left]; 25 | s[left] = s[right]; 26 | s[right] = temp; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /solutions/371. Sum of Two Integers/SumOfTwoIntegers.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the longest bits of the number 'a' or 'b'. 5 | // The worst-case is when the while-loop occurs for numbers such as 11111 + 1, 6 | // which loops for 5 times until the result 100000. 7 | // 8 | // Space Complexity : O(1), 9 | // as the auxiliary space used is independent of the input. 10 | 11 | public class SumOfTwoIntegers { 12 | 13 | // Approach: 14 | // Using bit manipulation, with the bitwise AND '&' to get the carries (1 + 1 = 0 carries 1), 15 | // and with bitwise XOR '^' to get the 1s that remains in that position. 16 | // For example, 1 + 1 = 10, with 1 & 1 = 1, and 1 ^ 1 = 0. 17 | // We then use bitwise left shift for the carries, 1 << 1 = 10. 18 | // Repeat the process with 10 & 0 = 0, 10 ^ 0 = 10. 19 | // With that, we have found to sum of 1 + 1 to be 2 (or binary 10). 20 | 21 | public int getSum(int a, int b) { 22 | // If either is zero, return the non-zero number. 23 | if (a == 0) return b; 24 | if (b == 0) return a; 25 | 26 | // While there are still carries remain. 27 | // For this, we use 'b' to hold the carries. 28 | while (b != 0) { 29 | int carries = a & b; 30 | a = a ^ b; 31 | // Left shift the carries by one bit. 32 | b = carries << 1; 33 | } 34 | return a; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /solutions/374. Guess Number Higher or Lower/GuessNumberHigherOrLower_BinarySearch.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | /** 4 | * Forward declaration of guess API. 5 | * @param num your guess 6 | * @return -1 if num is higher than the picked number 7 | * 1 if num is lower than the picked number 8 | * otherwise return 0 9 | * int guess(int num); 10 | */ 11 | 12 | // Time Complexity : O(logn), 13 | // where 'n' is the range of number to search for the pick. 14 | // In a binary search function, worst case is only log (base 2) of 'n' as we are only checking the midpoints. 15 | // 16 | // Space Complexity : O(1), 17 | // as not additional space is used other than the fixed variables. 18 | 19 | public class GuessNumberHigherOrLower_BinarySearch extends GuessGame { 20 | 21 | // Approach: 22 | // Using binary search to reduce time complexity as compared to linear search. 23 | // This is possible as we are search for the range of 1 to 'n', with the numbers in sorted orders. 24 | 25 | public int guessNumber(int n) { 26 | int low = 1; 27 | int high = n; 28 | int mid; 29 | while (low <= high) { 30 | // Do take note on integer overflow as 'n' <= 2^31 - 1, 31 | // thus the midpoint, 'mid' is calculated with "low + (high - low) / 2" rather than "(low + high) / 2". 32 | mid = low + (high - low) / 2; 33 | // Return 'mid' when found 'pick'. 34 | if (guess(mid) == 0) return mid; 35 | // Shrink the search space accordingly when 'pick' is greater or lesser. 36 | else if (guess(mid) == -1) high = mid - 1; 37 | else if (guess(mid) == 1) low = mid + 1; 38 | } 39 | // Return negative integer is not found. 40 | // Even though it is impossible to not find 'pick' in this question, 41 | // but it is a good practice to indicate that the search is not successful. 42 | return -1; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /solutions/412. Fizz Buzz/FizzBuzz.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | // Time Complexity : O(n), 7 | // where 'n' is the input integer 'n'. 8 | // We iterate from 1 to 'n' to check each and every number. 9 | // 10 | // Space Complexity : O(n), 11 | // where 'n' is the input integer 'n'. 12 | // As we put the elements into the List, the size of the List grows linearly with the input integer 'n'. 13 | 14 | public class FizzBuzz { 15 | 16 | // Approach: 17 | // For each number from 1 to 'n', check if the number is equal to 18 | // 15 (for "FizzBuzz"), 5 (for "Buzz") and 3 (for "Fizz"). 19 | // 20 | // Do note that the ordering of the if-else statement is important, and check for 15 first, 21 | // as it is divisible by both 3 and 5. 22 | 23 | public List fizzBuzz(int n) { 24 | 25 | // Using an arrayList, we can automatically achieve 1-indexed list with list.add(), 26 | // as it will add to the end of the list. 27 | List list = new ArrayList<>(n); 28 | for (int i = 1; i <= n; i++) { 29 | // Make sure to check for 15 first before checking for 3 and 5. 30 | if (i % 15 == 0) { 31 | list.add("FizzBuzz"); 32 | } else if (i % 3 == 0) { 33 | list.add("Fizz"); 34 | } else if (i % 5 == 0) { 35 | list.add("Buzz"); 36 | } else { 37 | list.add(String.valueOf(i)); 38 | } 39 | } 40 | return list; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /solutions/414. Third Maximum Number/ThirdMaximumNumber_PriorityQueue_HashSet.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashSet; 4 | import java.util.PriorityQueue; 5 | import java.util.Set; 6 | 7 | // Time Complexity : O(n logn), 8 | // where 'n' is the length of 'nums'. 9 | // For each number in 'nums', we offer to the priority queue with O(logn) time complexity, 10 | // thus resulting in O(n logn) time complexity. 11 | // 12 | // Space Complexity : O(n), 13 | // where 'n' is the length of 'nums'. 14 | // We use a Priority Queue and HashSet to store the numbers in 'nums', 15 | // with the maximum size the same as the size of 'nums'. 16 | 17 | public class ThirdMaximumNumber_PriorityQueue_HashSet { 18 | 19 | // Approach: 20 | // We use Priority Queue, with comparator set to a max heap, allows us to offer the number to the max heap, 21 | // then we return the first element if the heap size is less than 3, or return the third element. 22 | // In order to address the possibilities of duplicated numbers, 23 | // we use HashSet the keep track of the distinct numbers in 'nums'. 24 | // We skip the number if the number is already found in the HashSet. 25 | 26 | public int thirdMax(int[] nums) { 27 | // Set up the Priority Queue as a max heap. 28 | PriorityQueue pq = new PriorityQueue<>((a, b) -> Integer.compare(b, a)); 29 | Set set = new HashSet<>(); 30 | 31 | // For each number, 32 | for (int number : nums) { 33 | // Offer to the priority queue if it is not in the HashSet. 34 | if (set.add(number)) 35 | pq.offer(number); 36 | } 37 | 38 | // If there are less than 3 distinct numbers, return the first number in the max heap. 39 | if (set.size() < 3) 40 | return pq.peek(); 41 | 42 | // Return the third maximum number otherwise. 43 | pq.poll(); 44 | pq.poll(); 45 | return pq.peek(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /solutions/448. Find All Numbers Disappeared in an Array/FindAllNumbersDisappearedInAnArray_HashTable.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashSet; 5 | import java.util.List; 6 | import java.util.Set; 7 | 8 | // Time Complexity : O(n), 9 | // where 'n' is the length of 'nums'. 10 | // We traverse the 'nums' array twice, once to add the numbers to the HashSet, 11 | // and once to find numbers that are missing. 12 | // 13 | // Space Complexity : O(n), 14 | // where 'n' is the length of 'nums'. 15 | // The result list has length of 'n', and the HashSet has a maximum size of 'n'. 16 | 17 | public class FindAllNumbersDisappearedInAnArray_HashTable { 18 | 19 | // Approach: 20 | // We use a HashSet to record the distinct numbers found in 'nums'. 21 | // First traverse 'nums' array to add the numbers to the HashSet. 22 | // Then, we check each number from 1 to 'n' to find the numbers that are missing and add to the result list. 23 | 24 | public List findDisappearedNumbers(int[] nums) { 25 | Set set = new HashSet<>(); 26 | 27 | // Add the numbers to the HashSet. 28 | for (int number : nums) set.add(number); 29 | 30 | List result = new ArrayList<>(); 31 | // For each number from 1 to 'n', check if the number is in the HashSet. 32 | // If the number is not found, add to the result list. 33 | for (int i = 1; i <= nums.length; i++) { 34 | if (!set.contains(i)) result.add(i); 35 | } 36 | return result; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /solutions/45. Jump Game II/JumpGameII_DynamicProgramming_Tabulation.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | // Time Complexity : O(n^2), 6 | // where 'n' is the length of 'nums'. 7 | // For each position, we check every possible jumping positions to get the minimum steps. 8 | // As such, the worst-case is when every position can reach every other positions after it. 9 | // 10 | // Space Complexity : O(n), 11 | // where 'n' is the length of 'nums'. 12 | // We used an array to tabulate the minimum jumps to get from index 0 to index 'n - 1'. 13 | 14 | public class JumpGameII_DynamicProgramming_Tabulation { 15 | 16 | // Approach: 17 | // Using the dynamic programming and the tabulation technique, 18 | // we can use a table to propagate the minimum number of jump that we need to take, starting from position 0. 19 | // With the index 0 in the array being zero jumps, 20 | // all the positions that we can jump to will have minimum of 1 jump. 21 | // Update the table accordingly with the least number of jumps required to arrive. 22 | 23 | public int jump(int[] nums) { 24 | int n = nums.length; 25 | 26 | // Set the table array with all the values being Integer.MAX_VALUE, 27 | // as we are getting the minimum number of jumps for each check. 28 | int[] table = new int[n]; 29 | Arrays.fill(table, Integer.MAX_VALUE); 30 | // Set the first position as zero jumps, as we have not made any jumps. 31 | table[0] = 0; 32 | 33 | // Propagate the number of jumps to arrive at each position up, start with position 0 of zero jumps. 34 | for (int i = 0; i < n; i++) { 35 | // For each position, we update the minimum number of jumps to jump to all the reachable positions. 36 | for (int j = i; j < n && j <= i + nums[i]; j++) 37 | table[j] = Math.min(table[j], table[i] + 1); 38 | } 39 | // The last position of the table has the minimum number of jumps required to jump from index 0. 40 | return table[n - 1]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /solutions/45. Jump Game II/JumpGameII_Greedy.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'nums'. 5 | // We traverse the array 'nums' once to find the minimum steps to reach position 'n - 1'. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent on the size of 'nums'. 9 | 10 | public class JumpGameII_Greedy { 11 | 12 | // Approach: 13 | // For any position, where the range of the current jump is from 'start' to 'end', 14 | // the farthest point to make the jump from the current position is 'end'. 15 | // Then, we check all the point from 'start' to 'end' to determine the next farthest point 'farthest' to jump. 16 | // We then make the jump and check the next farthest points from 'end' to 'farthest', 17 | // each time recording the number of times we jumped. 18 | // We continue the process until we check all the positions in 'nums'. 19 | 20 | public int jump(int[] nums) { 21 | // 'currentEnd' keeps track of the last position to make the jump. 22 | // 'currentFarthest' keeps track of the farthest position that we can jump to. 23 | int result = 0, currentEnd = 0, currentFarthest = 0; 24 | 25 | // Traverse the whole array, except for the last position in 'nums' as that is the destination. 26 | for (int i = 0; i < nums.length - 1; i++) { 27 | // Record the furthest position we can jump to. 28 | currentFarthest = Math.max(currentFarthest, i + nums[i]); 29 | // If we have arrived at the last position to make the jump, 30 | if (i == currentEnd) { 31 | // we jump, increasing the count by 1, 32 | result++; 33 | // and we set the next last position to jump as 'currentFarthest'. 34 | currentEnd = currentFarthest; 35 | } 36 | } 37 | return result; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /solutions/485. Maximum Consecutive Ones/MaxConsecutiveOnes.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'nums'. 5 | // We traverse 'nums' once to count the maximum consecutive ones. 6 | // 7 | // Space Complexity: O(1), 8 | // as the auxiliary space used is independent on the size of the input 'nums'. 9 | 10 | public class MaxConsecutiveOnes { 11 | 12 | // Approach: 13 | // Using a 'count' variable to keep track of the current count of consecutive ones, 14 | // and a 'max' to keep track of the maximum number of consecutive ones found. 15 | 16 | public int findMaxConsecutiveOnes(int[] nums) { 17 | // Using 'max' to keep track of maximum consecutive ones, and 'count' to keep track each consecutive ones. 18 | int max = 0; 19 | int count = 0; 20 | for (int number: nums) { 21 | // Increase count by one, and compare count to max. 22 | if (number == 1) { 23 | count++; 24 | max = Math.max(count, max); 25 | } 26 | // Reset count when 0 occurs. 27 | else count = 0; 28 | } 29 | return max; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /solutions/49. Group Anagrams/GroupAnagrams.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.*; 4 | 5 | // Time Complexity : O(n * m logm), 6 | // where 'n' is the length of 'strs', and 'm' is the average length of each string. 7 | // For each of the elements in 'strs', 8 | // we convert the string to char array, and convert char array back to string, each with O(m) time complexity, 9 | // and the sorting of the char array results in O(m logm) time complexity. 10 | // As such, the time complexity is O(n * m logm). 11 | // 12 | // Space Complexity : O(n), 13 | // where 'n' is the length of 'strs'. 14 | // The HashMap has a maximum length of 'n', in the case where each strings in 'strs' is a unique anagram. 15 | 16 | public class GroupAnagrams { 17 | 18 | // Approach: 19 | // Using Sorting to first sort the letters in the word in alphabetical order, 20 | // then store the sorted word in the Hash Table, with the values containing a list to store the word. 21 | // This is because for the same group of anagrams, they all have the same sorted string. 22 | 23 | public List> groupAnagrams(String[] strs) { 24 | // Key is the sorted string, value is the list of words that forms the sorted string. 25 | Map> map = new HashMap<>(); 26 | for (String string : strs) { 27 | // To sort a string, convert the string to char array, then sort the array before forming the sorted string. 28 | char[] chars = string.toCharArray(); 29 | Arrays.sort(chars); 30 | String sorted = String.valueOf(chars); 31 | 32 | // Create a new entry if a new group of anagram found. 33 | if (!map.containsKey(sorted)) map.put(sorted, new ArrayList<>()); 34 | map.get(sorted).add(string); 35 | } 36 | return new ArrayList<>(map.values()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /solutions/492. Construct the Rectangle/ConstructTheRectangle.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(sqrt(n)), 4 | // where 'n' is the area, with the worst case is that the area is a prime number, thus only a width of 1 is possible. 5 | // 6 | // Space Complexity : O(1), 7 | // as only fixed variable is used. 8 | 9 | public class ConstructTheRectangle { 10 | 11 | // Approach: 12 | // As we know the greatest width possible is the square-root of 'area'. 13 | // However, as the result only accepts int, not double, 14 | // we can use the remainder operator % to find the greatest 'width' that fully divides 'area'. 15 | // The first possible 'width' is the width with the least difference to 'length'. 16 | 17 | public int[] constructRectangle(int area) { 18 | // Reminder: Result == [L, W] 19 | 20 | // Starts 'width' as the square-root of 'area' as we need to satisfy 'width' <= 'length'. 21 | int width = (int) Math.sqrt(area); 22 | 23 | // Continue to reduce 'width' (at the same time extends 'length'), 24 | // until we found a 'width' that fully divides 'area'. 25 | while (area % width != 0) width--; 26 | 27 | return new int[]{area / width, width}; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /solutions/509. Fibonacci Number/FibonacciNumber_Iterative.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // as we iterate from 1 to 'n' to find the fibonacci number 'n'. 5 | // 6 | // Space Complexity : O(n), 7 | // as we use the table of size 'n' to record the result of fib(1) to fib(n). 8 | // If we use only two variable to record fib(i - 1) and fib(i - 2), then it will be O(1). 9 | 10 | public class FibonacciNumber_Iterative { 11 | 12 | // Approach: 13 | // Using dynamic programming, through iteration and tabulation. 14 | // 15 | // Note that it is possible to use only two variables to keep track of (i - 1) and (i - 2), 16 | // but this is a good practice for the tabulation method in dynamic programming. 17 | 18 | public int fib(int n) { 19 | 20 | // Return the fibonacci number for n == 0 and n == 1, since we know the result already. 21 | if (n == 0 || n == 1) return n; 22 | 23 | // When using tabulation, seed the table with the base cases for n == 0 and n == 1. 24 | // Since the array is zero-indexed, we make sure to have the table of size "n + 1" 25 | // as we need to access index 'n'. 26 | int[] table = new int[n + 1]; 27 | table[0] = 0; 28 | table[1] = 1; 29 | 30 | // Iterate through the table and update its values until 'n'. 31 | for (int i = 2; i <= n; i++) { 32 | table[i] = table[i - 1] + table[i - 2]; 33 | } 34 | 35 | // table[n] is the result. 36 | return table[n]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /solutions/509. Fibonacci Number/FibonacciNumber_Recursive.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // as the recursive call stack is at a maximum of size 'n', when fib(i - 1) is called until reaching the base case. 5 | // 6 | // Space Complexity : O(n), 7 | // as we use the memo of size 'n' to record the result of fib(1) to fib(n). 8 | 9 | public class FibonacciNumber_Recursive { 10 | 11 | // Approach: 12 | // Using dynamic programming through the recursive and memoization method, 13 | // with the 'memo' to keep track of the calculated number to lower the time complexity. 14 | 15 | // Wrapper method to set up and initiate the recursive call. 16 | public int fib(int n) { 17 | // Use an integer array as 'memo' to record the results that was calculated. 18 | // This is so to not repeat the same calculation over the recursive calls. 19 | int[] memo = new int[n + 1]; 20 | return fib(n, memo); 21 | } 22 | 23 | // Recursive method. 24 | private int fib(int n, int[] memo) { 25 | // If 'n' is already in the memo, return memo[n]. 26 | if (memo[n] > 0) return memo[n]; 27 | 28 | // We know the fibonacci number for n == 0 and n == 1, so record it into the memo. 29 | if (n == 0) return memo[0] = 0; 30 | if (n == 1) return memo[1] = 1; 31 | 32 | // If the current 'n' is not in the memo, then we call the recursive method to calculate and record memo[n], 33 | // and return the result. 34 | return memo[n] = fib(n - 1, memo) + fib(n - 2, memo); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /solutions/520. Detect Capital/DetectCapital.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'word'. 5 | // For each of the methods used, toUpperCase() and toLowerCase(), 6 | // we create new strings before comparing the strings if they are equal. 7 | // Additionally, the string concatenation also creates a new string. 8 | // 9 | // Space Complexity : O(n), 10 | // where 'n' is the length of 'word'. 11 | // Both methods, toUpperCase() and toLowerCase(), create new strings. 12 | 13 | public class DetectCapital { 14 | 15 | // Approach: 16 | // The naive approach is to check if: 17 | // 1. The full uppercase of the 'word' is equal. 18 | // 2. The full lowercase of the 'word' is equal. 19 | // 3. The uppercase of first letter, and lowercase of the remaining letters are equal. 20 | 21 | public boolean detectCapitalUse(String word) { 22 | 23 | // Check the first and second conditions. 24 | if (word.equals(word.toUpperCase()) || word.equals(word.toLowerCase())) 25 | return true; 26 | 27 | // Check the third condition. 28 | return word.equals(word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /solutions/541. Reverse String II/ReverseStringII_StringBuilder.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n^2), 4 | // where 'n' is the length of string 's'. 5 | // As we traverse string 's' to append or insert the characters into the StringBuilder, would be O(n). 6 | // However, insertion into StringBuilder has a time complexity of O(n), 7 | // since we have to shift the characters to the right. 8 | // As such, the worst case is when we insert all the letters at the index 0, 9 | // resulting in O(n) for each character inserted O(n), which is O(n^2). 10 | // 11 | // Space Complexity : O(n), 12 | // where 'n' is the length of string 's'. 13 | // The StringBuilder and the final result string scales linearly with the length of string 's'. 14 | 15 | public class ReverseStringII_StringBuilder { 16 | 17 | // Approach: 18 | // Using a StringBuilder, 19 | // 1. Append the characters if not reversed, or 20 | // 2. Insert the characters at the start of index if we want reversed, where index % k == 0, and (index / k) % 2 == 0. 21 | 22 | public String reverseStr(String s, int k) { 23 | StringBuilder reversedString = new StringBuilder(); 24 | 25 | for (int index = 0; index < s.length(); index++) { 26 | // 'kMultiples' is to check if index is at first k (need to reverse) or second k (no need to reverse). 27 | int kMultiples = index / k; 28 | 29 | // To reverse, insert the characters at kMultiples * k. 30 | if (kMultiples % 2 == 0) reversedString.insert(kMultiples * k, s.charAt(index)); 31 | // If no need to reverse, then just append. 32 | else reversedString.append(s.charAt(index)); 33 | } 34 | return reversedString.toString(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /solutions/541. Reverse String II/ReverseStringII_TwoPointers.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of string 's'. 5 | // As we are using two pointers to reverse the substrings, the worst-case is when we reverse the whole string, 6 | // which scales linearly with the length of string 's'. 7 | // Additionally, the conversion of the string 's' to char array has linear time complexity O(n) as well. 8 | // 9 | // Space Complexity : O(n), 10 | // where 'n' is the length of string 's'. 11 | // The conversion of string 's' to char array, and from char array back to the result string, 12 | // both have a space complexity of O(n). 13 | 14 | public class ReverseStringII_TwoPointers { 15 | 16 | // Approach: 17 | // Basically using two pointers, but we are using index as start, and index + k as end. 18 | // We convert the String 's' to a char array, then reverse the characters in the array within each k % 2 == 0. 19 | 20 | public String reverseStr(String s, int k) { 21 | 22 | // Convert s into char array. 23 | char[] chars = s.toCharArray(); 24 | 25 | // In each iteration, we increase the index by 2 * k. 26 | for (int index = 0; index < chars.length; index += 2 * k) { 27 | // In each loop we will reverse only up to index + k. 28 | // If we reach the end of the array, then reverse the rest. 29 | int end = Math.min(index + k, chars.length) - 1; 30 | reverse(chars, index, end); 31 | } 32 | return new String(chars); 33 | } 34 | 35 | // A private method to reverse the char in the array using the 'start' and 'end' pointer. 36 | private void reverse(char[] chars, int start, int end) { 37 | while (start < end) { 38 | char temp = chars[start]; 39 | chars[start++] = chars[end]; 40 | chars[end--] = temp; 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /solutions/55. Jump Game/JumpGame_DynamicProgramming.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n^2), 4 | // where 'n' is the length of 'nums'. 5 | // Worst case is when we need to traverse 'table' for each position in 'nums'. 6 | // 7 | // Space Complexity : O(n), 8 | // where 'n' is the length of 'nums'. 9 | // We use a truth table of size 'n' to record the index of the position that we jump to from index 0. 10 | 11 | public class JumpGame_DynamicProgramming { 12 | 13 | // Approach: 14 | // Using the dynamic programming and the tabulation technique, 15 | // we can use a truth table to propagate the positions that we can jump to, starting from position 0. 16 | // With the index 0 in the boolean array being true, 17 | // all the positions that we can jump to are positions 'i' to "i + nums[i]". 18 | // Update the truth table accordingly if table[i] is true. 19 | 20 | public boolean canJump(int[] nums) { 21 | 22 | int n = nums.length; 23 | boolean[] table = new boolean[n]; 24 | // Set the first position as true, since we start jumping from here. 25 | table[0] = true; 26 | for (int i = 0; i < n; i++) { 27 | // If the table[i] is false, meaning we cannot jump to position 'i' from the first index. 28 | // So, we skip to the next position to check if that position can reach from the first index. 29 | if (!table[i]) continue; 30 | // If we can reach 'i' from the first index, we update the table[position] reachable from position 'i'. 31 | for (int j = 1; (j <= nums[i]) && (i + j < n); j++) { 32 | table[i + j] = true; 33 | } 34 | } 35 | // If the last index is true, then we can jump from the first index to the last index. 36 | return table[n - 1]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /solutions/55. Jump Game/JumpGame_Greedy.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'nums'. 5 | // We traverse the array 'nums' once. 6 | // 7 | // Space Complexity : O(1), 8 | // Only fixed variables that do not grow is used. 9 | 10 | public class JumpGame_Greedy { 11 | 12 | // Approach: 13 | // From the very last position in 'nums', "n - 1", 14 | // we traverse 'nums' from back to front to check if the next position can jump to the last position. 15 | // Continue to update the last position until we traverse 'nums'. 16 | // If we have successfully arrived at position 0, return true. 17 | 18 | public boolean canJump(int[] nums) { 19 | 20 | int lastPosition = nums.length - 1; 21 | 22 | for (int i = lastPosition - 1; i >= 0; i--) { 23 | // If the 'lastPosition' can arrive from position 'i', then 'i' update 'i' as the new 'lastPosition'. 24 | if (i + nums[i] >= lastPosition) lastPosition = i; 25 | } 26 | // We can jump from the first index to the last index if the 'lastPosition' is at position 0. 27 | return lastPosition == 0; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /solutions/557. Reverse Words in a String III/ReverseWordsInAStringIII_StringBuilder.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of String 's'. 5 | // The split() method for String has a linear time complexity. 6 | // For each word, we convert to a StringBuilder object, perform reverse() method on the StringBuilder, 7 | // and convert the StringBuilder back to String object, each has linear time complexity to the word. 8 | // Assuming that the input String 's' containing mostly of words, the linear time complexity of the words 9 | // translate to a linear time complexity for the whole reverseWords() method. 10 | // To be specific, it would approximate to O(5*n), but we simplify to O(n). 11 | // 12 | // Space Complexity : O(n), 13 | // where 'n' is the length of String 's'. 14 | // The split() method to get the array of words, the conversion of word to StringBuilder and convert back to String, 15 | // together with joining the words back to a String, all contributes to a linear space complexity. 16 | // To be specific, it would approximate to O(4*n), but we simplify to O(n). 17 | 18 | public class ReverseWordsInAStringIII_StringBuilder { 19 | 20 | // Approach: 21 | // Split the string into String array 'words'. 22 | // Then use a StringBuilder to reverse each words within the 'words' array. 23 | // Note: This approach uses more time and memory than the two pointers, due to the use of StringBuilder. 24 | 25 | public String reverseWords(String s) { 26 | // Split the String 's' using regex " ". 27 | String[] words = s.split(" "); 28 | 29 | // Reverse each word in the 'words' array. 30 | for (int i = 0; i < words.length; i++) { 31 | words[i] = new StringBuilder(words[i]).reverse().toString(); 32 | } 33 | 34 | // Build a new String using the " " delimiter and return result. 35 | return String.join(" ", words); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /solutions/561. Array Partition/ArrayPartition_Sorting_Greedy.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | // Time Complexity : O(n logn), 6 | // where 'n' is the length of 'nums'. 7 | // The Arrays.sort() function implements the Dual-Pivot Quicksort, which has O(n logn) time complexity. 8 | // We traverse the 'nums' array once to sum the even-indexed numbers, which results in O(n) time complexity. 9 | // Thus, the time complexity of the function is O(n logn) due to the sorting function. 10 | // 11 | // Space Complexity : O(1), 12 | // as the auxiliary spaced used is independent of the input size. 13 | 14 | public class ArrayPartition_Sorting_Greedy { 15 | 16 | // Approach: 17 | // From the problem, we know that the best approach is to pair the numbers with the least difference, 18 | // and sum the lower number of the pair. 19 | // This is the greedy approach, as we only consider the lower number of the pair, 20 | // regardless on the value, as we know this would lead to the maximum sum. 21 | // 22 | // With that understanding, we can sort the numbers in ascending order. 23 | // Then, we only sum the even-indexed number, which is the lower number of the pair. 24 | 25 | public int arrayPairSum(int[] nums) { 26 | // Sort the 'nums' array. 27 | Arrays.sort(nums); 28 | 29 | int sum = 0; 30 | // Sum the even-indexed number. 31 | for (int i = 0; i < nums.length; i += 2) { 32 | sum += nums[i]; 33 | } 34 | return sum; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /solutions/645. Set Mismatch/SetMismatch_HashTable.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | // Time Complexity : O(n), 7 | // where 'n' is the length of 'nums'. 8 | // We traverse the 'nums' array and the imaginary correct array once to find the duplicate and the missing number. 9 | // In actual, it is O(2n), which simplified to O(n). 10 | // 11 | // Space Complexity : O(n), 12 | // where 'n' is the length of 'nums'. 13 | // We use a HashSet which grows linearly with the length of the input 'nums'. 14 | 15 | public class SetMismatch_HashTable { 16 | 17 | // Approach: 18 | // Using HashSet to check which number is duplicate and which is missing. 19 | // This is because we know for a fact that the integers in 'nums' is from 1 to n. 20 | 21 | public int[] findErrorNums(int[] nums) { 22 | // Optional to use result = new int[], with result[0] == duplicate, and result[1] == missing. 23 | // Here, we use separate variable for readability. 24 | int duplicate = 0; 25 | int missing = 0; 26 | Set set = new HashSet<>(); 27 | for (int integer : nums) { 28 | // If the integer is already in the HashSet, then it is the duplicate. 29 | // Note that "!set.add(integer)" will still add the integer to the set, 30 | // just that it will return true of successful, and false otherwise. 31 | if (!set.add(integer)) duplicate = integer; 32 | } 33 | 34 | // From the imaginary correct array of 1 to n, we check which integer is missing from the set. 35 | for (int i = 1; i <= nums.length; i++) { 36 | if (!set.contains(i)) { 37 | missing = i; 38 | break; 39 | } 40 | } 41 | return new int[]{duplicate, missing}; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /solutions/70. Climbing Stairs/ClimbingStairs_Iterative.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // as we iterate from 1 to 'n' to find the number of ways to climb stairs. 5 | // 6 | // Space Complexity : O(n), 7 | // as we use the table of size 'n' to record the result of stairs from 1 to 'n'. 8 | // If we use only two variable to record ways(i - 1) and ways(i - 2), then it will be O(1). 9 | 10 | public class ClimbingStairs_Iterative { 11 | 12 | // Approach: 13 | // This problem is the same as the Fibonacci number sequence, 14 | // where the number of ways is the sum of the ways for 'n - 1' and 'n - 2'. 15 | // When we are on step i, we can only be at i + 1 or i + 2 for one iteration. 16 | // Conversely, when we are at step n, we can only have taken the route from i - 1 or i - 2. 17 | // The same applies to the route to arrive at i - 1 and i - 2 respectively. 18 | // Thus, ways(n) = ways(n - 1) + ways(n - 2). 19 | // Here, we use the iterative and tabulation method, using an array to keep track. 20 | // 21 | // Note that it is possible to use only two variables to keep track of ways(i - 1) and ways(i - 2), 22 | // but this is a good practice for the tabulation method in dynamic programming. 23 | 24 | public int climbStairs(int n) { 25 | 26 | // Return the ways for n == 1 and n == 2, since we know the result already. 27 | if (n == 1 || n == 2) return n; 28 | 29 | // When using tabulation, seed the table with the base cases for n == 1 and n == 2. 30 | // Since the array in Java is zero-indexed, we make sure to have the table of size "n + 1" 31 | // as we need to access index 'n'. 32 | int[] table = new int[n + 1]; 33 | table[1] = 1; 34 | table[2] = 2; 35 | // Iterate through the table and update its values until 'n'. 36 | for (int i = 3; i <= n; i++) { 37 | table[i] = table[i - 1] + table[i - 2]; 38 | } 39 | 40 | // table[n] is the result. 41 | return table[n]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /solutions/70. Climbing Stairs/ClimbingStairs_Recursive.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // as the recursive call stack is at a maximum of size 'n', when climbStairs(i - 1) is called until reaching the base case. 5 | // 6 | // Space Complexity : O(n), 7 | // as we use the memo of size 'n' to record the result of stairs from 1 to 'n'. 8 | 9 | public class ClimbingStairs_Recursive { 10 | 11 | // Approach: 12 | // This problem is the same as the Fibonacci number sequence, 13 | // where the number of ways is the sum of the ways for 'n - 1' and 'n - 2'. 14 | // When we are on step i, we can only be at i + 1 or i + 2 for one iteration. 15 | // Conversely, when we are at step n, we can only have taken the route from i - 1 or i - 2. 16 | // The same applies to the route to arrive at i - 1 and i - 2 respectively. 17 | // Thus, ways(n) = ways(n - 1) + ways(n - 2). 18 | // Here, we use the recursive method, 19 | // using the 'memo' keep track of the calculated number to lower the time complexity. 20 | 21 | // Wrapper method. 22 | public int climbStairs(int n) { 23 | 24 | // Use an integer array as 'memo' to record the results that was calculated. 25 | // This is so to not repeat the same calculation over the recursive calls. 26 | int[] memo = new int[n + 1]; 27 | return climbStairs(n, memo); 28 | } 29 | 30 | // Recursive method. 31 | private int climbStairs(int n, int[] memo) { 32 | 33 | // If 'n' is already in the memo, return memo[n]. 34 | if (memo[n] > 0) return memo[n]; 35 | 36 | // We know the ways for n == 1 and n == 2, so record it into the memo. 37 | if (n == 1) memo[1] = 1; 38 | if (n == 2) memo[2] = 2; 39 | 40 | // If the current 'n' is not in the memo, then we call the recursive method to calculate and record memo[n], 41 | // and return the result. 42 | return memo[n] = climbStairs(n - 1, memo) + climbStairs(n - 2, memo); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /solutions/744. Find Smallest Letter Greater Than Target/FindSmallestLetterGreaterThanTarget.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'letters'. 5 | // We traverse 'letters' once to find the first letter that is lexicographically greater than 'target'. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent of the input size. 9 | 10 | public class FindSmallestLetterGreaterThanTarget { 11 | 12 | // Approach: 13 | // As 'letters' is sorted in non-descending order, 14 | // we can traverse 'letters' to find the first letter that is lexicographically greater 'target'. 15 | // If none is found, return the first letter. 16 | 17 | public char nextGreatestLetter(char[] letters, char target) { 18 | for (char letter : letters) { 19 | // If the letter is greater than target, return letter. 20 | if (letter - target > 0) return letter; 21 | } 22 | return letters[0]; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /solutions/744. Find Smallest Letter Greater Than Target/FindSmallestLetterGreaterThanTarget_BinarySearch.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(logn), 4 | // where 'n' is the length of 'letters'. 5 | // We perform binary search to find the first letter that is lexicographically greater than 'target'. 6 | // Binary search has O(logn) time complexity. 7 | // 8 | // Space Complexity : O(1), 9 | // as the auxiliary space used is independent of the input size. 10 | 11 | public class FindSmallestLetterGreaterThanTarget_BinarySearch { 12 | 13 | // Approach: 14 | // As 'letters' is sorted in non-descending order, 15 | // we can perform binary search to find the letter that is the least greater than 'target'. 16 | // If the element is not found, with 'low' and 'high' reaches letters.length, return the first element. 17 | 18 | public char nextGreatestLetter(char[] letters, char target) { 19 | int low = 0, high = letters.length; 20 | while (low < high) { 21 | // The implementation below prevents integer overflow. 22 | int mid = (high - low) / 2 + low; 23 | // Shift the 'high' pointer to the right if the letter is lexicographically greater than 'target'. 24 | if (letters[mid] - target > 0) { 25 | high = mid; 26 | } 27 | // Shift the 'low' pointer to the left otherwise. 28 | else { 29 | low = mid + 1; 30 | } 31 | } 32 | // If the pointer is outside the array, return the first element. 33 | // Else, return the letter greater than 'target' with the least difference. 34 | return low == letters.length ? letters[0] : letters[low]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /solutions/746. Min Cost Climbing Stairs/MinCostClimbingStairs_Iterative.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // as we iterate from 1 to 'n' to find the minimum cost to climb the stairs to the top. 5 | // 6 | // Space Complexity : O(1), 7 | // as we use the 'cost' array to record the minimum cost at each step in-place, 8 | // thus, we did not use any additional space for the tabulation. 9 | 10 | public class MinCostClimbingStairs_Iterative { 11 | 12 | // Approach: 13 | // Same as the Fibonacci number sequence, where the number of ways is the sum of the ways for 'n - 1' and 'n - 2'. 14 | // When we are on step i, we can only be at i + 1 or i + 2 for one iteration. 15 | // Conversely, when we are at step n, we can only have taken the route from i - 1 or i - 2. 16 | // The same applies to the route to arrive at i - 1 and i - 2 respectively. 17 | // Between the two choice, we would take the minimum total cost. 18 | // Thus, cost(n) = Math.min(cost(n - 1) + cost(n - 2)). 19 | // Here, we use the iterative method, using the variable 'oneBefore' and 'twoBefore' to keep track. 20 | 21 | public int minCostClimbingStairs(int[] cost) { 22 | 23 | int n = cost.length; 24 | // Get the minimum cost between the previous 2 steps, from n = 2 onwards. 25 | // This ensures each new cost is the minimum possible cost to take at i-th index. 26 | for (int i = 2; i < n; i++) { 27 | cost[i] += Math.min(cost[i - 1], cost[i - 2]); 28 | } 29 | // Return the lower total cost between 'n - 1' and 'n - 2'. 30 | return Math.min(cost[n - 1], cost[n - 2]); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /solutions/746. Min Cost Climbing Stairs/MinCostClimbingStairs_Recursive.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // as the recursive call stack is at a maximum of size 'n', 5 | // when minCostClimbingStairs(i - 1) is called until reaching the base case. 6 | // 7 | // Space Complexity : O(n), 8 | // as we use the memo of size 'n' to record the result of stairs from 1 to 'n'. 9 | 10 | public class MinCostClimbingStairs_Recursive { 11 | 12 | // Approach: 13 | // Same as the Fibonacci number sequence, where the number of ways is the sum of the ways for 'n - 1' and 'n - 2'. 14 | // When we are on step i, we can only be at i + 1 or i + 2 for one iteration. 15 | // Conversely, when we are at step n, we can only have taken the route from i - 1 or i - 2. 16 | // The same applies to the route to arrive at i - 1 and i - 2 respectively. 17 | // Between the two choice, we would take the minimum total cost. 18 | // Thus, cost(n) = Math.min(cost(n - 1) + cost(n - 2)). 19 | // Here, we use the recursive and memoization method, 20 | // using the 'memo' keep track of the calculated number to lower the time complexity. 21 | 22 | public int minCostClimbingStairs(int[] cost) { 23 | 24 | // Use an integer array as 'memo' to record the total cost to arrive at 'n'. 25 | // This is so to not repeat the same calculation over the recursive calls. 26 | int[] memo = new int[cost.length + 1]; 27 | return minCostClimbingStairs(cost, cost.length, memo); 28 | } 29 | 30 | private int minCostClimbingStairs(int[] cost, int n, int[] memo) { 31 | 32 | // As memo record the total cost to arrive at step 'n', 33 | // we get the minimum cost between the previous 2 steps, together with the minimum cost needed to get it. 34 | if (n > 1 && memo[n] == 0) { 35 | memo[n] = Math.min(minCostClimbingStairs(cost, n - 1, memo) + cost[n - 1], 36 | minCostClimbingStairs(cost, n - 2, memo) + cost[n - 2]); 37 | } 38 | return memo[n]; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /solutions/766. Toeplitz Matrix/ToeplitzMatrix.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n * m), 4 | // where 'n' is the number of rows, and 'm' is the number of columns in the matrix. 5 | // We traverse the matrix once to check if the matrix is Toeplitz. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent on the size of the input 'matrix'. 9 | 10 | public class ToeplitzMatrix { 11 | 12 | // Approach: 13 | // Traverse through the array to check the next element matrix[i + 1][j + 1] if it is different. 14 | // If all is the same, then return true. 15 | 16 | public boolean isToeplitzMatrix(int[][] matrix) { 17 | int m = matrix.length; 18 | int n = matrix[0].length; 19 | 20 | for (int i = 0; i < m; i++) { 21 | for (int j = 0; j < n; j++) { 22 | // Note: Check if i + 1 and j + 1 is within the matrix, to ensure there is no IndexOutOfBound error. 23 | if (i + 1 < m && j + 1 < n && matrix[i][j] != matrix[i + 1][j + 1]) { 24 | return false; 25 | } 26 | } 27 | } 28 | // If successfully traverse the whole array, return true. 29 | return true; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /solutions/783. Minimum Distance Between BST Nodes/MinimumDistanceBetweenBSTNodes_DFS_Recursive.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | /** 4 | * Definition for a binary tree node. 5 | * public class TreeNode { 6 | * int val; 7 | * TreeNode left; 8 | * TreeNode right; 9 | * TreeNode() {} 10 | * TreeNode(int val) { this.val = val; } 11 | * TreeNode(int val, TreeNode left, TreeNode right) { 12 | * this.val = val; 13 | * this.left = left; 14 | * this.right = right; 15 | * } 16 | * } 17 | */ 18 | // Note: Remember to set up a TreeNode class as the same folder. 19 | 20 | // Time Complexity : O(n), 21 | // where 'n' is the number of nodes in the tree. 22 | // We traverse the binary tree in-order, comparing each value with the previous value to get the minimum difference. 23 | // 24 | // Space Complexity : O(1), 25 | // as the auxiliary space used for the variables are constant. 26 | 27 | public class MinimumDistanceBetweenBSTNodes_DFS_Recursive { 28 | 29 | // Approach: 30 | // Using recursion to perform in-order traversal, comparing the value of the nodes to the previous node. 31 | // For in-order traversal, to nodes are visited in the following order: 32 | // 1. Left node. 33 | // 2. Root node to get the difference with the previous node. 34 | // 3. Right node. 35 | 36 | int result = Integer.MAX_VALUE, previous = -1; 37 | 38 | public int minDiffInBST(TreeNode root) { 39 | // Visit the left node. 40 | if (root.left != null) minDiffInBST(root.left); 41 | 42 | // Get the value difference of the two nodes, and get the minimum difference. 43 | if (previous != -1) result = Math.min(result, root.val - previous); 44 | previous = root.val; 45 | 46 | // Visit the right node. 47 | if (root.right != null) minDiffInBST(root.right); 48 | 49 | // Return the minimum difference between any two nodes once all the nodes are traversed. 50 | return result; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /solutions/80. Remove Duplicates from Sorted Array II/RemoveDuplicatesFromSortedArrayII.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'nums'. 5 | // We traverse through 'nums' once to check every element. 6 | // 7 | // Space Complexity : O(1), 8 | // as we only use fixed variables that does not grow with 'n'. 9 | 10 | public class RemoveDuplicatesFromSortedArrayII { 11 | 12 | // Approach: 13 | // With the removal of duplicates, we can use two pointers, 14 | // - a 'tail' to represent the final array with the duplicates removed, and 15 | // - a 'head' to iterate through 'nums'. 16 | // A duplicate is found when nums[head] == nums[tail], 17 | // where nums[tail] is the latest number added in-place in the array. 18 | // We also use a counter to keep track if how many of a number is added in the array. 19 | 20 | public int removeDuplicates(int[] nums) { 21 | // 'tail' indicating the index in 'nums'. 22 | int tail = 0; 23 | // 'count' to keep track of the frequency of the number added. 24 | int count = 1; 25 | 26 | // Using a 'head' pointer to traverse through 'nums'. 27 | for (int head = 1; head < nums.length; head++) { 28 | // If we already have 2 of the same number added in the array, 29 | // we skip (meaning we remove the second duplicate). 30 | if (nums[tail] == nums[head] && count == 2) continue; 31 | 32 | // If the count is 1 and nums[tail] == nums[head], increase the count. 33 | if (nums[tail] == nums[head]) count++; 34 | // If nums[tail] != nums[head], reset the count to 1. 35 | else count = 1; 36 | 37 | // In both cases, we add nums[head] to the next position. 38 | nums[++tail] = nums[head]; 39 | } 40 | // As the array is 0-indexed, we return the index + 1 value for the length of the new array. 41 | return tail + 1; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /solutions/812. Largest Triangle Area/LargestTriangleArea.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n^3), 4 | // where 'n' is the length of 'points'. 5 | // We traverse 'points' in 3 for-loops to check every combination. 6 | // 7 | // Space Complexity : O(1), 8 | // as the auxiliary space used is independent on the size of the input 'points'. 9 | 10 | public class LargestTriangleArea { 11 | 12 | // Approach: 13 | // The equation to calculate the triangle area of any 3 points: 14 | // 1. (1/2) * (x1*y2 + x2*y3 + x3*y1 - x1*y3 - x2*y1 - x3*y2), or simplified to 15 | // 2. (1/2) * (x1*(y2-y3) + x2*(y3-y1) + x3*(y1-y2)) 16 | // We traverse the 'points' in 3 for-loops to check every combination. 17 | 18 | public double largestTriangleArea(int[][] points) { 19 | 20 | double maxArea = 0d; 21 | // Check each combination of 3 points. 22 | for (int i = 0; i < points.length; i++) { 23 | for (int j = i + 1; j < points.length; j++) { 24 | for (int k = j + 1; k < points.length; k++) { 25 | 26 | // Using the formula mentioned above to calculate the area. 27 | double area = Math.abs(points[i][0] * (points[j][1] - points[k][1]) + 28 | points[j][0] * (points[k][1] - points[i][1]) + 29 | points[k][0] * (points[i][1] - points[j][1])) * 0.5; 30 | maxArea = Math.max(maxArea, area); 31 | } 32 | } 33 | } 34 | return maxArea; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /solutions/836. Rectangle Overlap/RectangleOverlap.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(1), 4 | // as no iteration is performed, only simple arithmetic calculations. 5 | // 6 | // Space Complexity : O(1), 7 | // as only fixed variables are created. 8 | 9 | public class RectangleOverlap { 10 | 11 | // Approach: 12 | // For the overlap, we find the coordinates which is explained below. 13 | // Using x-coordinates as example: 14 | // Rectangle A: | | * Indicates the max for x1 and min for x2. 15 | // ax1* ax2 16 | // Rectangle B: | | 17 | // bx1 bx2* 18 | // The overlap on the left is Math.max(ax1, bx1), while the right is Math.min(ax2, bx2). 19 | // The same applies for the y-coordinates. 20 | // If there are no overlap, then (Math.min(ax2, bx2) <= Math.max(ax1, bx1)) == (bx2 <= ax1). 21 | // Rectangle A: | | * Indicates the max for x1 and min for x2. 22 | // ax1* ax2 23 | // Rectangle B: | | 24 | // bx1 bx2* 25 | 26 | public boolean isRectangleOverlap(int[] rec1, int[] rec2) { 27 | // Reminder: rec[0] == x1, rec[1] == y1, rec[2] == x2, rec[3] == y2. 28 | 29 | // If there are any overlap, the top right corner coordinates of the overlap 30 | // will be the minimum of the top right of both A and B. 31 | int top = Math.min(rec1[3], rec2[3]); 32 | int right = Math.min(rec1[2], rec2[2]); 33 | 34 | // Likewise for the bottom left corner is the maximum of the bottom left of both A and B. 35 | int bottom = Math.max(rec1[1], rec2[1]); 36 | int left = Math.max(rec1[0], rec2[0]); 37 | 38 | // There are overlap only if top > bottom and right > left. 39 | return top > bottom && right > left; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /solutions/876. Middle of the Linked List/MiddleOfTheLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | /** 4 | * Definition for singly-linked list. 5 | * public class ListNode { 6 | * int val; 7 | * ListNode next; 8 | * ListNode() {} 9 | * ListNode(int val) { this.val = val; } 10 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 11 | * } 12 | */ 13 | 14 | // Time Complexity : O(n), 15 | // where 'n' is the number of nodes in the Linked List. 16 | // We traverse the whole Linked List once. 17 | // In actual case, it would be O(n/2) as we are moving the 'fast' pointers two nodes at a time, but simplify as O(n). 18 | // 19 | // Space Complexity : O(1), 20 | // as we are only using fixed variable that do not grow with the length of the Linked List. 21 | 22 | public class MiddleOfTheLinkedList { 23 | 24 | // Approach: 25 | // Using Two Pointers to traverse the Singly Linked List to find the middle node: 26 | // - 'fast' pointer move two nodes at a time, 27 | // - 'slow' pointer move one node at a time. 28 | 29 | public ListNode middleNode(ListNode head) { 30 | 31 | // Traverse 'fast' two node at a time, and 'slow' one node at a time, 32 | // until the 'fast' pointer reaches the end of the list. 33 | ListNode fast = head; 34 | ListNode slow = head; 35 | while (fast != null && fast.next != null) { 36 | fast = fast.next.next; 37 | slow = slow.next; 38 | } 39 | // Once 'fast' reaches the end of the list, the 'slow' pointer is at the middle node. 40 | return slow; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /solutions/88. Merge Sorted Array/MergeSortedArray_Sorting.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | // Time Complexity : O((m + n)^2), 6 | // where 'm' is the length of 'nums1' with elements and 'n' is the length of 'nums2'. 7 | // This is because of the Arrays.sort() function uses the Dual-Pivot Quicksort, 8 | // which on average has a time complexity of O(t logt), but has the worst case quadratic function of O(t^2). 9 | // 10 | // Space Complexity : O(1), 11 | // as no new arrays are created. 12 | 13 | public class MergeSortedArray_Sorting { 14 | 15 | // Approach: 16 | // Copy all the elements from 'nums2' to the remaining positions in 'num1', then sort 'nums1' 17 | // using the in-built sort function. 18 | 19 | public void merge(int[] nums1, int m, int[] nums2, int n) { 20 | // The inputs for System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length). 21 | // Note that this is in-place. 22 | System.arraycopy(nums2, 0, nums1, m, n); 23 | 24 | Arrays.sort(nums1); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /solutions/88. Merge Sorted Array/MergeSortedArray_TwoPointers.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(m + n), 4 | // where 'm' is the length of 'nums1' with elements and 'n' is the length of 'nums2'. 5 | // 6 | // Space Complexity : O(1), 7 | // as no new arrays are created. 8 | 9 | public class MergeSortedArray_TwoPointers { 10 | 11 | // Approach: 12 | // Using two pointers to compare the elements in 'nums1' and 'nums2' to check which is greater, from right to left. 13 | // Move the greater number to the rightmost position in 'nums1' from right to left. 14 | 15 | public void merge(int[] nums1, int m, int[] nums2, int n) { 16 | // Keep track of the index in the final merged sorted array. 17 | int lastUnsortedIndex = m + n - 1; 18 | // Keep track of the index in 'nums1'. 19 | int pointer1 = m - 1; 20 | // Keep track of the index in 'nums2'. 21 | int pointer2 = n - 1; 22 | 23 | while (pointer2 >= 0) { 24 | // If the element in 'nums1' is greater, then copy into the merged array. 25 | if (pointer1 >= 0 && nums1[pointer1] >= nums2[pointer2]) 26 | nums1[lastUnsortedIndex--] = nums1[pointer1--]; 27 | // If fully traversed 'nums1', or when the element in 'nums2' is greater, then copy into the merged array. 28 | else 29 | nums1[lastUnsortedIndex--] = nums2[pointer2--]; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /solutions/905. Sort Array By Parity/SortArrayByParity.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the size of 'nums'. 5 | // We use two pointers to traverse the array 'nums'. 6 | // 7 | // Space Complexity : O(1), 8 | // as we use variables that are independent of the size of 'nums'. 9 | 10 | public class SortArrayByParity { 11 | 12 | // Approach: 13 | // Since we are sorting the even number to the front and the odd number to the back of the array 'nums', 14 | // we use a pointer 'end' to traverse the array to find any even number, 15 | // and a pointer 'start' to indicate the partition for the even number to be placed. 16 | // Each time we place an even number at position 'start', we move the pointer forward. 17 | 18 | public int[] sortArrayByParity(int[] nums) { 19 | 20 | // Both 'start' and 'end' pointers start at index 0. 21 | for (int start = 0, end = 0; end < nums.length; end++) { 22 | // If the 'end' pointer found an even number, swap the number in-place to the position 'start', 23 | // and move the 'start' pointer forward. 24 | if (nums[end] % 2 == 0) { 25 | int temp = nums[start]; 26 | nums[start++] = nums[end]; 27 | nums[end] = temp; 28 | } 29 | } 30 | // Return the same 'nums' array. 31 | return nums; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /solutions/922. Sort Array By Parity II/SortArrayByParityII.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'nums'. 5 | // We use two pointers to traverse the 'nums' array once. 6 | // 7 | // Space Complexity : O(1), 8 | // as we only use variables that are independent on the size of the input. 9 | // We are swapping the elements in-place, so the result array does not take up additional space. 10 | 11 | public class SortArrayByParityII { 12 | 13 | // Approach: 14 | // Using two pointers, 'even' and 'odd', 15 | // to keep track of the position of the number that is not even, and not odd respectively. 16 | // If both pointers found numbers that do not fulfill the requirement, swap the two numbers. 17 | // Continue for the whole array. 18 | 19 | public int[] sortArrayByParityII(int[] nums) { 20 | int n = nums.length; 21 | // The 'even' pointer starts at the first even position, which is 0, 22 | // and the 'odd' pointer starts at the first odd position, which is 1. 23 | int even = 0, odd = 1; 24 | 25 | // Continue to traverse 'nums' until the end of the array. 26 | while (even < n && odd < n) { 27 | // If the 'even' pointer position is an even number, 28 | // continue until found an odd number or reached the end of the array. 29 | while (even < n && nums[even] % 2 == 0) even += 2; 30 | 31 | // If the 'odd' pointer position is an odd number, 32 | // continue until found an even number or reached the end of the array. 33 | while (odd < n && nums[odd] % 2 != 0) odd += 2; 34 | 35 | // Swap the two numbers in-place if the pointers are within the bound of the array. 36 | if (even < n && odd < n) { 37 | int temp = nums[even]; 38 | nums[even] = nums[odd]; 39 | nums[odd] = temp; 40 | } 41 | } 42 | return nums; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /solutions/923. 3Sum With Multiplicity/ThreeSumWithMultiplicity_HashTable.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | // Time Complexity : O(n^2), 7 | // where 'n' is the length of 'arr'. 8 | // We traverse 'arr' in a nested for-loop, checking each triplet for each 'arr[i]'. 9 | // 10 | // Space Complexity : O(n^2), 11 | // where 'n' is the length of 'arr'. 12 | // For each 'arr[i]', there are 'n' number of possible differences to store in the HashTable. 13 | 14 | public class ThreeSumWithMultiplicity_HashTable { 15 | 16 | // Approach: 17 | // Using a HashTable to record "target - arr[k]" of the equation, then traverse both 'i' and 'j' to check if equal. 18 | // Note that we rearranged the equation as arr[i] + arr[j] == target - arr[k]. 19 | // Each loop recording the frequency of "target - arr[k]", add the frequency if equal. 20 | 21 | public int threeSumMulti(int[] arr, int target) { 22 | int n = arr.length; 23 | // Store the first value of 'arr[k]' which is arr[n - 1], starting from right to left each iteration. 24 | Map map = new HashMap<>(); 25 | map.put(target - arr[n - 1], 1); 26 | long count = 0; 27 | for (int j = n - 2; j >= 0; j--) { 28 | // Add the frequency of "target - arr[k]" to the count if found. 29 | for (int i = j - 1; i >= 0; i--) { 30 | count += map.getOrDefault(arr[i] + arr[j], 0); 31 | } 32 | // Once done with all the 'j' for this loop, increase the frequency for "target - arr[j]". 33 | int difference = target - arr[j]; 34 | map.put(difference, map.getOrDefault(difference, 0) + 1); 35 | } 36 | return (int) (count % (1e9 + 7)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /solutions/941. Valid Mountain Array/ValidMountainArray_TwoPointers.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'arr', as we only traverse the array once with both pointers. 5 | // 6 | // Space Complexity : O(1), 7 | // as no additional space is used. 8 | 9 | public class ValidMountainArray_TwoPointers { 10 | 11 | // Approach: 12 | // Using two pointers to traverse 'arr' from both ends, 13 | // much like having two climbers climbing the mountain from each side of the mountain. 14 | // If the two climbers meet, and either climbers are not at the starting points, 15 | // then 'arr' is a valid mountain array. 16 | 17 | public boolean validMountainArray(int[] arr) { 18 | int n = arr.length, left = 0, right = n - 1; 19 | 20 | // Continue to move 'left' as the next integer is greater, from left to right. 21 | while (left < n - 1 && arr[left] < arr[left + 1]) 22 | left++; 23 | 24 | // Continue to move 'right' as the next integer is greater, from right to left. 25 | while (right > 0 && arr[right] < arr[right - 1]) 26 | right--; 27 | 28 | // If the two pointers meet, and either are not at the starting points, then 'arr' is a valid mountain array. 29 | return left == right && right < n - 1 && left > 0; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /solutions/944. Delete Columns to Make Sorted/DeleteColumnsToMakeSorted.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(m * n), 4 | // where 'm' is the length of each string in 'strs' (strs[0].length()), 5 | // and 'n' is the number of strings in 'strs'. 6 | // We iterate through every letter in every string to check if the letters in the column is in non-descending order. 7 | // 8 | // Space Complexity : O(1), 9 | // as we only variable that is independent of the size of the input. 10 | 11 | public class DeleteColumnsToMakeSorted { 12 | 13 | // Approach: 14 | // Iterate through the strings in 'strs' column-wise, 15 | // check if the current letter is lexicographically smaller than the previous letter in the column. 16 | // If smaller, increase the count by 1, and move on to the next column. 17 | 18 | public int minDeletionSize(String[] strs) { 19 | int columnsToDelete = 0; 20 | 21 | // Iterate the 'strs' column-wise. 22 | for (int column = 0; column < strs[0].length(); column++) { 23 | // Start the row at 1, as there is no previous string to compare to. 24 | for (int row = 1; row < strs.length; row++) { 25 | // If the current letter lexicographically smaller than the previous letter in the column, 26 | // increase the 'columnsToDelete' by one and move on to the next column. 27 | if (strs[row].charAt(column) < strs[row - 1].charAt(column)) { 28 | columnsToDelete++; 29 | break; 30 | } 31 | } 32 | } 33 | return columnsToDelete; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /solutions/976. Largest Perimeter Triangle/LargestPerimeterTriangle.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | // Time Complexity : O(n logn), 6 | // where 'n' is the length of 'nums'. 7 | // We use Arrays.sort() to sort 'nums', which implements the Dual-Pivot Quicksort with O(n logn) time complexity. 8 | // Then, we traverse the 'nums' array once to find the largest perimeter triangle. 9 | // 10 | // Space Complexity : O(1), 11 | // as the auxiliary space used is independent on the size of the input. 12 | 13 | public class LargestPerimeterTriangle { 14 | 15 | // Approach: 16 | // Sort the array. 17 | // A triangle is only possible if the longer edge is smaller than the sum of the 2 other edges. 18 | // With the top 3 lengths, there can only be in 2 scenarios: 19 | // 1. Not able to form a triangle, meaning all the lengths that are shorter than the 2 points cannot form a triangle. 20 | // 2. Can form a triangle, meaning any lengths shorter will be a smaller triangle. 21 | // As such, we can traverse from longest to shortest lengths, considering only the top 3 lengths. 22 | // From the longest lengths, if we found 3 lengths that can form a triangle, we can be sure that it is the largest. 23 | 24 | public int largestPerimeter(int[] nums) { 25 | 26 | Arrays.sort(nums); 27 | // Since we sorted the array in ascending order, traverse from n - 1 in decreasing order. 28 | for (int i = nums.length - 1; i >= 2; i--) { 29 | // If the 3 lengths can form a triangle, then we have the largest perimeter. 30 | // If not, then move on to the next 3 lengths. 31 | if (nums[i] < nums[i - 1] + nums[i - 2]) { 32 | return nums[i] + nums[i - 1] + nums[i - 2]; 33 | } 34 | } 35 | return 0; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /solutions/977. Squares of a Sorted Array/SquaresOfASortedArray_Sorting.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | // Time Complexity : O(n^2), 6 | // where 'n' is the length of 'nums'. 7 | // In the documentation, the sort() function of the Arrays class uses Dual-Pivot Quicksort, 8 | // which offers a O(n logn) performance on average, but the worst case of the quicksort is quadratic O(n^2). 9 | // 10 | // Space Complexity : O(n), 11 | // where 'n' is the length of 'nums'. 12 | // Although the Dual-Pivot Quicksort does not use auxiliary space, it uses stack in its recursive calls. 13 | 14 | public class SquaresOfASortedArray_Sorting { 15 | 16 | // Approach: 17 | // Square all the integers in 'nums' in-place, then use the sort() function in the Arrays class to sort. 18 | 19 | public int[] sortedSquares(int[] nums) { 20 | // Here we use nums[i] * nums[i], but optional to use "(int) Math.pow(nums[i], 2)". 21 | for (int i = 0; i < nums.length; i++) 22 | nums[i] = nums[i] * nums[i]; 23 | Arrays.sort(nums); 24 | return nums; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /solutions/977. Squares of a Sorted Array/SquaresOfASortedArray_TwoPointers.java: -------------------------------------------------------------------------------- 1 | package com.cheehwatang.leetcode; 2 | 3 | // Time Complexity : O(n), 4 | // where 'n' is the length of 'nums'. 5 | // As we only traverse 'nums' once. 6 | // 7 | // Space Complexity : O(n), 8 | // where 'n' is the length of 'nums', as we use an additional array to store the result. 9 | 10 | public class SquaresOfASortedArray_TwoPointers { 11 | 12 | // Approach: 13 | // Using two pointers to check the most negative (leftmost) and the most positive (rightmost) integers. 14 | // Whichever integer in its absolute value is greater, store its square in the rightmost position of the result. 15 | // For Example, nums = [-7,-4,0,5,8], 16 | // The absolute value of the leftmost -7 and rightmost 8, with 8 squared being greater, 17 | // thus store in the result [0,0,0,0,64]. 18 | // Then compare leftmost -7 and rightmost 5, with -7 squared being greater, 19 | // resulting in [0,0,0,49,64], and so on. 20 | 21 | public int[] sortedSquares(int[] nums) { 22 | int n = nums.length; 23 | int[] result = new int[n]; 24 | int left = 0; 25 | int right = n - 1; 26 | for (int i = n - 1; i >= 0; i--) { 27 | // If Math.abs(nums[left]) is greater, 28 | // store its square in result[i] and move the pointer to the next integer. 29 | if (Math.abs(nums[left]) >= Math.abs(nums[right])) { 30 | // Here we use nums[i] * nums[i], but optional to use "(int) Math.pow(nums[i], 2)". 31 | result[i] = nums[left] * nums[left]; 32 | left++; 33 | } 34 | // If Math.abs(nums[right]) is greater, 35 | // store its square in result[i] and move the pointer to the next integer. 36 | else { 37 | result[i] = nums[right] * nums[right]; 38 | right--; 39 | } 40 | } 41 | return result; 42 | } 43 | } 44 | --------------------------------------------------------------------------------