diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..c432b382 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +CheckerClass.template +TaskClass.template +TestCaseClass.template +TopCoderTaskClass.template +TopCoderTestCaseClass.template +build/ +chelper.properties +gradle/ +gradlew +gradlew.bat +leetcode.iml +leetcode.ipr +leetcode.iws +out/ +problems/src.iml +.idea +.gradle/ +.DS_Store diff --git a/README.md b/README.md index 72f59c18..50b25b37 100644 --- a/README.md +++ b/README.md @@ -1,146 +1,515 @@ # Leetcode solutions in Java -My accepted leetcode solutions to some of the common interview problems. +My accepted leetcode solutions to some of the common interview problems. +Also, some solutions have youtube video link. + +[Youtube channel](https://www.youtube.com/@codernaut) + + +#### [Array](src/main/java/array) + +- [Pascals Traiangle II](src/main/java/array/PascalsTriangle.java) (Easy) +- [Product Of Array Except Self](src/main/java/array/ProductOfArrayExceptSelf.java) (Medium) +- [Rotate Matrix](src/main/java/array/RotateMatrix.java) (Medium) +- [Set Matrix Zeroes](src/main/java/array/SetMatrixZeroes.java) (Medium) +- [Third Maximum Number](src/main/java/array/ThirdMaximumNumber.java) (Easy) +- [Two Sum](src/main/java/array/TwoSum.java) (Easy) +- [TwoSum II](src/main/java/array/TwoSumII.java) (Easy) +- [Can Place Flowers](src/main/java/array/CanPlaceFlowers.java) (Easy) +- [Merge Intervals](src/main/java/array/MergeIntervals.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [First Missing Positive](src/main/java/array/FirstMissingPositive.java) (Hard) +- [Fruit Into Baskets](src/main/java/array/FruitIntoBaskets.java) (Medium) +- [MaxProduct Of Three Numbers](src/main/java/array/MaxProductOfThreeNumbers.java) (Easy) +- [Missing Number](src/main/java/array/MissingNumber.java) (Easy) +- [Merge Sorted Array](src/main/java/array/MergeSortedArray.java) (Easy) +- [Rotate Array](src/main/java/array/RotateArray.java) (Easy) +- [Sort Colors](src/main/java/array/SortColors.java) (Medium) +- [Battleships in a Board](src/main/java/array/BattleshipsInABoard.java) (Medium) +- [Find the Celebrity](src/main/java/array/FindTheCelebrity.java) (Medium) +- [Meeting Rooms](src/main/java/array/MeetingRooms.java) (Easy) +- [Longest Continuous Increasing Subsequence](src/main/java/array/LongestIncreasingSubsequence.java) (Easy) +- [Sparse Matrix Multiplication](src/main/java/array/SparseMatrixMultiplication.java) (Medium) +- [Read N Characters Given Read4](src/main/java/array/ReadNCharacters.java) (Easy) +- [Maximum Swap](src/main/java/array/MaximumSwap.java) (Medium) +- [H-Index](src/main/java/array/HIndex.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Insert Interval](src/main/java/array/InsertInterval.java) (Hard) +- [Increasing Triplet Subsequence](src/main/java/array/IncreasingTripletSubsequence.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [K Empty Slots](src/main/java/array/KEmptySlots.java) (Hard) +- [Subarray Sum Equals K](src/main/java/array/SubarraySumEqualsK.java) (Medium) +- [Pour Water](src/main/java/array/PourWater.java) (Medium) +- [Relative Ranks](src/main/java/array/RelativeRanks.java) (Easy) +- [Next Greater Element I](src/main/java/array/NextGreaterElementI.java) (Easy) +- [Largest Number At Least Twice of Others](src/main/java/array/LargestNumberAtLeastTwice.java) (Easy) +- [Minimum Moves to Equal Array Elements II](src/main/java/array/MinimumMovesToEqualArray.java) (Median) +- [Image Smoother](src/main/java/array/ImageSmoother.java) (Easy) +- [Minimum Index Sum of Two Lists](src/main/java/array/MinimumIndexSumOfTwoLists.java) (Easy) +- [Card Flipping Game](src/main/java/array/CardFilipGame.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Employee Free Time](src/main/java/array/EmployeeFreeTime.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Best Meeting Point](src/main/java/array/BestMeetingPoint.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [My Calendar III](src/main/java/array/MyCalendarThree.java) (Hard) +- [Champagne Tower](src/main/java/array/ChampagneTower.java) (Medium) +- [Valid Tic-Tac-Toe State](src/main/java/array/ValidTicTacToeState.java) (Medium) +- [Number of Subarrays with Bounded Maximum](src/main/java/array/SubArraysWithBoundedMaximum.java) (Medium) +- [Surface Area of 3D Shapes](src/main/java/array/SurfaceAreaOfThreeDShapes.java) (Easy) +- [Max Consecutive Ones](src/main/java/array/MaxConsecutiveOnes.java) (Easy) +- [Max Consecutive Ones II](src/main/java/array/MaxConsecutiveOnesII.java) (Medium) +- [Add to Array-Form of Integer](src/main/java/array/AddToArrayFormOfInteger.java) (Easy) +- [Find Pivot Index](src/main/java/array/FindPivotIndex.java) (Easy) +- [Largest Time for Given Digits](src/main/java/array/LargestTimeForGivenDigits.java) (Easy) +- [Minimum Time Difference](src/main/java/array/MinimumTimeDifference.java) (Medium) +- [Reveal Cards In Increasing Order](src/main/java/array/RevealCardsInIncreasingOrder.java) (Medium) +- [Sort Array By Parity II](src/main/java/array/SortArrayByParityII.java) (Easy) +- [Matrix Cells in Distance Order](src/main/java/array/MatrixCellsinDistanceOrder.java) (Easy) +- [Maximum Sum of Two Non-Overlapping Subarrays](src/main/java/array/MaximumSumofTwoNonOverlappingSubarrays.java) (Medium) +- [Longest Line of Consecutive One in Matrix](src/main/java/array/LongestLineofConsecutiveOneinMatrix.java) (Medium) +- [Array Partition I](src/main/java/array/ArrayPartitionI.java) (Easy) +- [Relative Sort Array](src/main/java/array/RelativeSortArray.java) (Easy) +- [Meeting Scheduler](src/main/java/array/MeetingScheduler.java) (Medium) +- [Minimum Swaps to Group All 1's Together](src/main/java/array/MinimumSwapsToGroupAll1Together.java) (Medium) +- [Array Nesting](src/main/java/array/ArrayNesting.java) (Medium) + +#### [Backtracking](src/main/java/backtracking) + +- [Combinations](src/main/java/backtracking/Combinations.java) (Medium) +- [Combinations Sum](src/main/java/backtracking/CombinationSum.java) (Medium) +- [Combinations Sum II](src/main/java/backtracking/CombinationSumII.java) (Medium) +- [Letter Phone Number](src/main/java/backtracking/LetterPhoneNumber.java) (Medium) +- [Paliandrome Partitioning](src/main/java/backtracking/PalindromePartitioning.java) (Medium) +- [Permutations](src/main/java/backtracking/Permutations.java) (Medium) +- [Permutations II](src/main/java/backtracking/PermutationsII.java) (Medium) +- [SubSets](src/main/java/backtracking/Subsets.java) (Medium) +- [SubSet II](src/main/java/backtracking/SubsetsII.java) (Medium) +- [Word Search](src/main/java/backtracking/WordSearch.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Word Search II](src/main/java/backtracking/WordSearchII.java) (Hard) +- [Generate Parentheses](src/main/java/backtracking/GenerateParentheses.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Remove Invalid Parentheses](src/main/java/backtracking/RemoveInvalidParentheses.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Regular Expression Matching](src/main/java/backtracking/RegularExpressionMatching.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Expression Add Operators](src/main/java/backtracking/ExpressionAddOperators.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Wildcard Matching](src/main/java/backtracking/WildcardMatching.java) (Hard) +- [Letter Case Permutation](src/main/java/backtracking/LetterCasePermutation.java) (Easy) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Zuma Game](src/main/java/backtracking/ZumaGame.java) (Hard) +- [Matchsticks to Square](src/main/java/backtracking/MatchsticksToSquare.java) (Medium) + +#### [Binary Search](src/main/java/binary_search) + +- [Minimum Sorted Rotated Array](src/main/java/binary_search/MinSortedRotatedArray.java) (Medium) +- [Search in a Rotated Sorted Array](src/main/java/binary_search/SearchRotatedSortedArray.java) (Medium) +- [Search for a Range](src/main/java/binary_search/SearchForARange.java) (Medium) +- [Sqrt(x)](src/main/java/binary_search/SqrtX.java) (Easy) +- [Search Insert Position](src/main/java/binary_search/SearchInsertPosition.java) (Easy) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Median of Two Sorted Arrays](src/main/java/binary_search/MedianOfTwoSortedArrays.java) (Hard) +- [Pow(x, n)](src/main/java/binary_search/PowXN.java) (Medium) +- [Find Peak Element](src/main/java/binary_search/FindPeakElement.java) (Medium) +- [Target Sum](src/main/java/binary_search/TargetSum.java) (Medium) +- [H-Index II](src/main/java/binary_search/HIndexII.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Swim in Rising Water](src/main/java/binary_search/SwimInRisingWater.java) (Hard) +- [Time Based Key-Value Store](src/main/java/binary_search/TimeBasedKeyValuePair.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Minimum Window Subsequence](src/main/java/binary_search/MinimumWindowSubsequence.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Koko Eating Bananas](src/main/java/binary_search/KokoEatingBananas.java) (Hard) +- [Single Element in a Sorted Array](src/main/java/binary_search/SingleElementInASortedArray.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Minimize the Maximum Adjacent Element Difference](src/main/java/binary_search/MinimizeTheMaximumAdjacentElementDifference.java) (Hard) + - [Youtube video explanation](https://www.youtube.com/watch?v=2fCtjA_eitU) + +#### [Bit Manipulation](src/main/java/bit_manipulation) + +- [Gray Code](src/main/java/bit_manipulation/GrayCode.java) (Medium) +- [Hamming Distance](src/main/java/bit_manipulation/HammingDistance.java) (Easy) +- [Total Hamming Distance](src/main/java/bit_manipulation/TotalHammingDistance.java) (Medium) +- [Divide Two Integers](src/main/java/bit_manipulation/DivideTwoIntegers.java) (Medium) +- [Binary Number with Alternating Bits](src/main/java/bit_manipulation/BinaryNumberWithAlternatingBits.java) (Easy) +- [Binary Watch](src/main/java/bit_manipulation/BinaryWatch.java) (Easy) + +#### [Breadth First Search](src/main/java/breadth_first_search) + +- [Binaray Tree Level Order Traversal](src/main/java/breadth_first_search/BinarayTreeLevelOrderTraversal.java) (Medium) +- [Word Ladder](src/main/java/breadth_first_search/WordLadder.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Word Ladder II](src/main/java/breadth_first_search/WordLadderII.java) (Hard) +- [Walls and Gates](src/main/java/breadth_first_search/WallsAndGates.java) (Medium) +- [Open the lock](src/main/java/breadth_first_search/OpenTheLock.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Cut Off Trees for Golf Event](src/main/java/breadth_first_search/CutOffTreesForGolfEvent.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Race Car](src/main/java/breadth_first_search/RaceCar.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Bus Routes](src/main/java/breadth_first_search/BusRoutes.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Sliding Puzzle](src/main/java/breadth_first_search/SlidingPuzzle.java) (Hard) +- [Matrix](src/main/java/breadth_first_search/Matrix.java) (Medium) +- [Rotting Oranges](src/main/java/breadth_first_search/RottingOranges.java) (Medium) + +#### [Depth First Search](src/main/java/depth_first_search) + +- [Minesweeper](src/main/java/depth_first_search/Minesweeper.java) (Medium) +- [Movie Recommend](src/main/java/depth_first_search/MovieRecommend.java) (Medium) +- [Number Of Islands](src/main/java/depth_first_search/NumberOfIslands.java) (Medium) +- [Course Schedule](src/main/java/depth_first_search/CourseSchedule.java) (Medium) +- [Course Schedule II](src/main/java/depth_first_search/CourseScheduleII.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Alien Dictionary](src/main/java/depth_first_search/AlienDictionary.java) (Hard) +- [Graph Valid Tree](src/main/java/depth_first_search/GraphValidTree.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Longest Consecutive Sequence](src/main/java/depth_first_search/LongestConsecutiveSequence.java) (Hard) +- [Accounts Merge](src/main/java/depth_first_search/AccountsMerge.java) (Medium) +- [CloneGraph](src/main/java/depth_first_search/CloneGraph.java) (Medium) +- [Island Perimeter](src/main/java/depth_first_search/IslandPerimeter.java) (Easy) +- [Number of Distinct Islands](src/main/java/depth_first_search/NumberOfDistinctIslands.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Number of Distinct Islands II](src/main/java/depth_first_search/NumberOfDistinctIslandsII.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Smallest Rectangle Enclosing Black Pixels](src/main/java/depth_first_search/SmallestRectangleEnclosingBlackPixels.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Bricks Falling When Hit](src/main/java/depth_first_search/BricksFallingWhenHit.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Robot Room Cleaner](src/main/java/depth_first_search/RobotRoomCleaner.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Cracking the Safe](src/main/java/depth_first_search/CrackingTheSafe.java) (Hard) +- [All Paths From Source to Target](src/main/java/depth_first_search/AllPathsFromSourceToTarget.java) (Medium) +- [Max Area of Island](src/main/java/depth_first_search/MaxAreaOfIsland.java) (Medium) +- [Satisfiability of Equality Equations](src/main/java/depth_first_search/SatisfiabilityOfEquations.java) (Medium) +- [Number of Enclaves](src/main/java/depth_first_search/NumberOfEnclaves.java) (Medium) +- [As Far from Land as Possible](src/main/java/depth_first_search/AsFarfromLandAsPossible.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Minimize Malware Spread](src/main/java/depth_first_search/MinimizeMalwareSpread.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Parallel Courses](src/main/java/depth_first_search/ParallelCourses.java) (Hard) +- [Connecting Cities With Minimum Cost](src/main/java/depth_first_search/ConnectingCitiesWithMinimumCost.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Critical Connections in a Network](src/main/java/depth_first_search/CriticalConnection.java) (Hard) + +#### [Design](src/main/java/design) + +- [Copy List With Random Pointer](src/main/java/design/CopyListWithRandomPointer.java) (Medium) +- [Encode and Decode Tiny URL](src/main/java/design/EncodeAndDecodeTinyURL.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [LFU Cache](src/main/java/design/LFUCache.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [LRU Cache](src/main/java/design/LRUCache.java) (Hard) +- [Insert Delete Get Random](src/main/java/design/RandomizedSet.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Serialize Deserialize Binary Tree](src/main/java/design/SerializeDeserializeBinaryTree.java) (Hard) +- [Design Twitter](src/main/java/design/Twitter.java) (Medium) +- [Tic-Tac-Toe](src/main/java/design/TicTacToe.java) (Medium) +- [Implement Trie (Prefix Tree)](src/main/java/design/Trie.java) (Medium) +- [Binary Search Tree Iterator](src/main/java/design/BSTIterator.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Design Search Autocomplete System](src/main/java/design/AutocompleteSystem.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Design Excel Sum Formula](src/main/java/design/Excel.java) (Hard) +- [Flatten Nested List Iterator](src/main/java/design/NestedIterator.java) (Medium) +- [Add and Search Word - Data structure design](src/main/java/design/WordDictionary.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Prefix and Suffix Search](src/main/java/design/WordFilter.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Insert Delete GetRandom O(1) - Duplicates allowed](src/main/java/design/RandomizedCollection.java) (Hard) + +#### [Divide and Conquer](src/main/java/divide_and_conquer) + +- [Kth Largest Element In a Array](src/main/java/divide_and_conquer/KthLargestElementInAnArray.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Reverse Pairs](src/main/java/divide_and_conquer/ReversePairs.java) (Hard) +- [Search in a 2D Matrix](src/main/java/divide_and_conquer/SearchA2DMatrix.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [24 Game](src/main/java/divide_and_conquer/TwentyFourGame.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Reverse Pairs II](src/main/java/divide_and_conquer/ReversePairsII.java) (Hard) +- [My Calendar II](src/main/java/divide_and_conquer/MyCalendarII.java) (Medium) + +#### [Dynamic Programming](src/main/java/dynamic_programming) + +- [Best Time To Buy and Sell Stocks](src/main/java/dynamic_programming/BestTimeToBuyAndSellStocks.java) (Easy) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Best Time to Buy and Sell Stock III](src/main/java/dynamic_programming/BestTimeToBuyAndSellStockIII.java) (Hard) +- [Best Time to Buy and Sell Stock with Transaction Fee](src/main/java/dynamic_programming/BestTimeToBuyAndSellStocksWithFee.java) (Medium) +- [Climbing Stairs](src/main/java/dynamic_programming/ClimbingStairs.java) (Easy) +- [Coin Change](src/main/java/dynamic_programming/CoinChange.java) (Medium) +- [Coin Change 2](src/main/java/dynamic_programming/CoinChange2.java) (Medium) +- [Decode Ways](src/main/java/dynamic_programming/DecodeWays.java) (Medium) +- [House Robber](src/main/java/dynamic_programming/HouseRobber.java) (Easy) +- [House Robber II](src/main/java/dynamic_programming/HouseRobberII.java) (Medium) +- [Longest Increasing Subsequence](src/main/java/dynamic_programming/LongestIncreasingSubsequence.java) (Medium) +- [Longest Paliandromic Substring](src/main/java/dynamic_programming/LongestPaliandromicSubstring.java) (Medium) +- [Longest Palindromic Subsequence](src/main/java/dynamic_programming/LongestPalindromicSubsequence.java) (Medium) +- [Maximum Product Subarray](src/main/java/dynamic_programming/MaximumProductSubarray.java) (Medium) +- [Min Cost Climbing Stairs](src/main/java/dynamic_programming/MinCostClimbingStairs.java) (Easy) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Palindrome Partitioning II](src/main/java/dynamic_programming/PalindromePartitioningII.java) (Hard) +- [UniqueBinary Search Trees](src/main/java/dynamic_programming/UniqueBinarySearchTrees.java) (Medium) +- [Unique Binary Search Trees II](src/main/java/dynamic_programming/UniqueBinarySearchTreesII.java) (Medium) +- [WordBreak](src/main/java/dynamic_programming/WordBreak.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [WordBreak II](src/main/java/dynamic_programming/WordBreakII.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Concatenated Words](src/main/java/dynamic_programming/ConcatenatedWords.java) (Hard) +- [Can I Win](src/main/java/dynamic_programming/CanIWin.java) (Medium) +- [Maximum Subarray](src/main/java/dynamic_programming/MaximumSubarray.java) (Easy) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Dungeon Game](src/main/java/dynamic_programming/DungeonGame.java) (Hard) +- [2 Keys Keyboard](src/main/java/dynamic_programming/TwoKeysKeyboard.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Maximum Sum of 3 Non-Overlapping Subarrays](src/main/java/dynamic_programming/MaxSum3SubArray.java) (Hard) +- [Maximal Square](src/main/java/dynamic_programming/MaximalSquare.java) (Medium) +- [Continuous Subarray Sum](src/main/java/dynamic_programming/ContinuousSubarraySum.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Decode Ways II](src/main/java/dynamic_programming/DecodeWaysII.java) (Hard) +- [Palindromic Substrings](src/main/java/dynamic_programming/PalindromicSubstrings.java) (Medium) +- [Number of Longest Increasing Subsequence](src/main/java/dynamic_programming/NumberOfLIS.java) (Medium) +- [Combination Sum IV](src/main/java/dynamic_programming/CombinationSumIV.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Paint House II](src/main/java/dynamic_programming/PaintHouseII.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Split Array Largest Sum](src/main/java/dynamic_programming/SplitArrayLargestSum.java) (Hard) +- [Number Of Corner Rectangles](src/main/java/dynamic_programming/CornerRectangles.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Burst Balloons](src/main/java/dynamic_programming/BurstBalloons.java) (Hard) +- [Largest Plus Sign](src/main/java/dynamic_programming/LargestPlusSign.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Palindrome Pairs](src/main/java/dynamic_programming/PalindromePairs.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Cherry Pickup](src/main/java/dynamic_programming/CherryPickup.java) (Hard) +- [Knight Probability in Chessboard](src/main/java/dynamic_programming/KnightProbabilityInChessboard.java) (Medium) +- [Largest Sum of Averages](src/main/java/dynamic_programming/LargestSumOfAverages.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Minimum Number of Refueling Stops](src/main/java/dynamic_programming/MinimumNumberOfRefuelingStops.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Cat and Mouse](src/main/java/dynamic_programming/CatAndMouse.java) (Hard) +- [Stone Game](src/main/java/dynamic_programming/StoneGame.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Odd Even Jump](src/main/java/dynamic_programming/OddEvenJump.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Profitable Schemes](src/main/java/dynamic_programming/ProfitableSchemes.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Maximum Vacation Days](src/main/java/dynamic_programming/MaximumVacationDays.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Russian Doll Envelopes](src/main/java/dynamic_programming/RussianDollEnvelopes.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Student Attendance Record II](src/main/java/dynamic_programming/StudentAttendanceRecordII.java) (Hard) +- [Out of Boundary Paths](src/main/java/dynamic_programming/OutOfBoundaryPaths.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Remove Boxes](src/main/java/dynamic_programming/RemoveBoxes.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Stickers to Spell Word](src/main/java/dynamic_programming/StickersToSpellWord.java) (Hard) +- [Ones and Zeroes](src/main/java/dynamic_programming/OnesAndZeroes.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Encode String with Shortest Length](src/main/java/dynamic_programming/EncodeStringWithShortestLength.java) (Hard) +- [Length of Longest Fibonacci Subsequence](src/main/java/dynamic_programming/LengthofLongestFibonacciSubsequence.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Make Array Strictly Increasing](src/main/java/dynamic_programming/MakeArrayStrictlyIncreasing.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Minimum Number of Taps to Open to Water a Garden](src/main/java/dynamic_programming/MinimumNumberOfTaps.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Delete Columns to Make Sorted III](src/main/java/dynamic_programming/DeleteColumnsToMakeSortedIII.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Handshakes That Don't Cross](src/main/java/dynamic_programming/HandshakesThatDontCross.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Minimum Difficulty of a Job Schedule](src/main/java/dynamic_programming/MinimumDifficultyOfAJobSchedule.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Jump Game V](src/main/java/dynamic_programming/JumpGameV.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Freedom Trail](src/main/java/dynamic_programming/FreedomTrail.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Strange Printer](src/main/java/dynamic_programming/StrangePrinter.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Minimum Cost to Merge Stones](src/main/java/dynamic_programming/MinimumCostToMergeStones.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Interleaving String](src/main/java/dynamic_programming/InterleavingString.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Count Vowels Permutation](src/main/java/dynamic_programming/CountVowelsPermutation.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Non-negative Integers without Consecutive Ones](src/main/java/dynamic_programming/NonNegativeIntegersWithoutConsecutiveOnes.java) (Hard) +- [Bomb Enemy](src/main/java/dynamic_programming/BombEnemy.java) (Medium) +- [Number of Dice Rolls With Target Sum](src/main/java/dynamic_programming/NumberOfDiceRollsWithTargetSum.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Distinct Subsequences](src/main/java/dynamic_programming/DistinctSubsequences.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Distinct Subsequences II](src/main/java/dynamic_programming/DistinctSubsequencesII.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Minimum Distance to Type a Word Using Two Fingers](src/main/java/dynamic_programming/MinimumDistanceToTypeAWordUsingTwoFingers.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Valid Palindrome III](src/main/java/dynamic_programming/ValidPalindromeIII.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Palindrome Partitioning III](src/main/java/dynamic_programming/PalindromePartitioningIII.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Tiling a Rectangle with the Fewest Squares](src/main/java/dynamic_programming/TilingARectangle.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Longest Chunked Palindrome Decomposition](src/main/java/dynamic_programming/LongestChunkedPalindromeDecomposition.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Stone Game III](src/main/java/dynamic_programming/StoneGameIII.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Number of Ways to Stay in the Same Place After Some Steps](src/main/java/dynamic_programming/NumberOfWaysToStayInTheSamePlace.java) (Hard) +- [Toss Strange Coins](src/main/java/dynamic_programming/TossStrangeCoins.java) (Medium) +- [Knight Dialer](src/main/java/dynamic_programming/KnightDialer.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Palindrome Removal](src/main/java/dynamic_programming/PalindromeRemoval.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Restore The Array](src/main/java/dynamic_programming/RestoreTheArray.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Cherry Pickup II](src/main/java/dynamic_programming/CherryPickupII.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Constrained Subsequence Sum](src/main/java/dynamic_programming/ConstrainedSubsequenceSum.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Largest Multiple of Three](src/main/java/dynamic_programming/LargestMultipleOfThree.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Largest Multiple of Three](src/main/java/dynamic_programming/MaximumProfitInJobScheduling.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Number of Music Playlists](src/main/java/dynamic_programming/NumberOfMusicPlaylists.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Paint House III](src/main/java/dynamic_programming/PaintHouseIII.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Shortest Path Visiting All Nodes](src/main/java/dynamic_programming/ShortestPathVisitingAllNodes.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Smallest Sufficient Team](src/main/java/dynamic_programming/SmallestSufficientTeam.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Stone Game IV](src/main/java/dynamic_programming/StoneGameIV.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Tallest Billboard](src/main/java/dynamic_programming/TallestBillboard.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Count Different Palindromic Subsequences](src/main/java/dynamic_programming/CountDifferentPalindromicSubsequences.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Number of Paths with Max Score](src/main/java/dynamic_programming/NumberOfPathsWithMaxScore.java) (Hard) + + +#### [Greedy](src/main/java/greedy) + +- [Jump Game](src/main/java/greedy/JumpGame.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Jump Game II](src/main/java/greedy/JumpGameII.java) (Hard) +- [Course Schedule III](src/main/java/greedy/CourseScheduleIII.java) (Medium) +- [GasStation](src/main/java/greedy/GasStation.java) (Medium) +- [Non-Overlapping Intervals](src/main/java/greedy/NonOverlappingIntervals.java) (Medium) +- [Minimum Number of Arrows to Burst Balloons](src/main/java/greedy/BurstBalloons.java) (Medium) +- [Queue Reconstruction By Height](src/main/java/greedy/QueueReconstructionByHeight.java) (Medium) +- [Task Scheduler](src/main/java/greedy/TaskScheduler.java) (Medium) +- [Maximum Length of Pair Chain](src/main/java/greedy/MaximumLengthOfPairChain.java) (Medium) +- [Lemonade Change](src/main/java/greedy/LemonadeChange.java) (Easy) +- [Score After Flipping Matrix](src/main/java/greedy/ScoreAfterFlippingMatrix.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [IPO](src/main/java/greedy/IPO.java) (Hard) +- [String Without AAA or BBB](src/main/java/greedy/StringWithout3A3B.java) (Medium) +- [Boats to Save People](src/main/java/greedy/BoatsToSavePeople.java) (Medium) +- [Broken Calculator](src/main/java/greedy/BrokenCalculator.java) (Medium) +- [Two City Scheduling](src/main/java/greedy/TwoCityScheduling.java) (Easy) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Minimum Time to Build Blocks](src/main/java/greedy/MinimumTimeToBuildBlocks.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Reducing Dishes](src/main/java/greedy/ReducingDishes.java) (Hard) + +#### [Hashing](src/main/java/hashing) + +- [Anagrams](src/main/java/hashing/Anagrams.java) (Medium) +- [Group Anagrams](src/main/java/hashing/GroupAnagrams.java) (Medium) +- [Kdiff Pairs In a Array](src/main/java/hashing/KdiffPairsInanArray.java) (Easy) +- [Sort Character by Frequency](src/main/java/hashing/SortCharByFrequency.java) (Medium) +- [Two Sum](src/main/java/hashing/TwoSum.java) (Easy) +- [Valid Anagram](src/main/java/hashing/ValidAnagram.java) (Easy) +- [Maximum Size Subarray Sum Equals k](src/main/java/hashing/MaximumSizeSubarraySumEqualsk.java) (Medium) +- [Contiguous Array](src/main/java/hashing/ContiguousArray.java) (Medium) +- [Brick Wall](src/main/java/hashing/BrickWall.java) (Medium) +- [Partition Labels](src/main/java/hashing/PartitionLabels.java) (Medium) +- [Custom Sort String](src/main/java/hashing/CustomSortString.java) (Medium) +- [Short Encoding of Words](src/main/java/hashing/ShortEncodingOfWords.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Substring with Concatenation of All Words](src/main/java/hashing/SubstringConcatenationOfWords.java) (Hard) +- [Distribute Candies](src/main/java/hashing/DistributeCandies.java) (Easy) +- [Groups of Special-Equivalent Strings](src/main/java/hashing/GroupsOfSpecialEquivalentStrings.java) (Easy) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Number of Atoms](src/main/java/hashing/NumberOfAtoms.java) (Hard) +- [Analyze User Website Visit Pattern](src/main/java/hashing/AnalyzeUserWebsiteVisitPattern.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [String Transforms Into Another String](src/main/java/hashing/StringTransformsIntoAnotherString.java) (Hard) + +#### [Heap](src/main/java/heap) + +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Sliding Window Maximum](src/main/java/heap/SlidingWindowMaximum.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [The Skyline Problem](src/main/java/heap/TheSkylineProblem.java) (Hard) +- [Meeting Rooms II](src/main/java/heap/MeetingRoomsII.java) (Medium) +- [Top K Frequent Words](src/main/java/heap/TopKFrequentWords.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Candy](src/main/java/heap/Candy.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Smallest Rotation with Highest Score](src/main/java/heap/SmallestRotationWithHighestScore.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Maximum Frequency Stack](src/main/java/heap/FreqStack.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Reachable Nodes In Subdivided Graph](src/main/java/heap/ReachableNodesInSubdividedGraph.java) (Hard) +- [K Closest Points to Origin](src/main/java/heap/KClosestPointsToOrigin.java) (Medium) +- [Distant Barcodes](src/main/java/heap/DistantBarcodes.java) (Medium) + +#### [Linked List](src/main/java/linked_list) + +- [Intersection of two Linked-Lists](src/main/java/linked_list/IntersectionOfTwoLists.java) (Easy) +- [Linked List Cycle](src/main/java/linked_list/LinkedListCycle.java) (Easy) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Merge K Sorted Lists](src/main/java/linked_list/MergeKSortedLists.java) (Hard) +- [Merge Two Sorted List](src/main/java/linked_list/MergeTwoSortedList.java) (Easy) +- [Paliandrome List](src/main/java/linked_list/PaliandromeList.java) (Easy) +- [Reverse Linked List](src/main/java/linked_list/ReverseLinkedList.java) (Easy) +- [Delete Node in a Linked List](src/main/java/linked_list/DeleteNode.java) (Easy) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Reverse Nodes in k-Group](src/main/java/linked_list/ReverseNodesKGroup.java) (Hard) +- [Swap Nodes in Pairs](src/main/java/linked_list/SwapNodesInPairs.java) (Medium) +- [Middle of Linked List](src/main/java/linked_list/MiddleOfLinkedList.java) (Easy) +- [Split Linked List in Parts](src/main/java/linked_list/SplitLinkedListInParts.java) (Medium) +- [Next Greater Node In Linked List](src/main/java/linked_list/NextGreaterNodeInLinkedList.java) (Medium) + +#### [Math](src/main/java/math) + +- [Add Two Numbers](src/main/java/math/AddTwoNumbers.java) (Medium) +- [Count Primes](src/main/java/math/CountPrimes.java) (Easy) +- [Rotate Function](src/main/java/math/RotateFunction.java) (Medium) +- [Water and Jug Problem](src/main/java/math/WaterAndJugProblem.java) (Medium) +- [Add Digits](src/main/java/math/AddDigits.java) (Easy) +- [Excel Sheet Column Title](src/main/java/math/ExcelSheetColumnTitle.java) (Easy) +- [Roman to Integer](src/main/java/math/RomanToInteger.java) (Easy) +- [Bulb Switcher II](src/main/java/math/BulbSwitcherII.java) (Medium) +- [Global and Local Inversions](src/main/java/math/GlobalAndLocalInversions.java) (Medium) +- [Solve the Equation](src/main/java/math/SolveTheEquation.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Couples Holding Hands](src/main/java/math/CouplesHoldingHands.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Reaching Points](src/main/java/math/ReachingPoints.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Nth Magical Number](src/main/java/math/NthMagicalNumber.java) (Hard) +- [Squirrel Simulation](src/main/java/math/SquirrelSimulation.java) (Medium) +- [Projection Area of 3D Shapes](src/main/java/math/ProjectionAreaOf3DShapes.java) (Easy) +- [Decoded String at Index](src/main/java/math/DecodedStringAtIndex.java) (Medium) +- [Base 7](src/main/java/math/Base7.java) (Easy) +- [Smallest Range I](src/main/java/math/SmallestRangeI.java) (Easy) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Largest Component Size by Common Factor](src/main/java/math/LargestComponentSizebyCommonFactor.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Super Washing Machines](src/main/java/math/SuperWashingMachines.java) (Hard) +- [Rectangle Overlap](src/main/java/math/RectangleOverlap.java) (Easy) +- [Nth Digit](src/main/java/math/NthDigit.java) (Easy) + +#### [Reservoir Sampling](src/main/java/reservoir_sampling) + +- [Random Pick Index](src/main/java/reservoir_sampling/RandomPickIndex.java) (Medium) + +#### [Stack](src/main/java/stack) + +- [Min Stack](src/main/java/stack/MinStack.java) (Easy) +- [Valid Parentheses](src/main/java/stack/ValidParentheses.java) (Easy) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Largest Rectangle In Histogram](src/main/java/stack/LargestRectangleInHistogram.java) (Hard) +- [Implement Queue using Stacks](src/main/java/stack/MyQueue.java) (Easy) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Maximal Rectangle](src/main/java/stack/MaximalRectangle.java) (Hard) +- [Exclusive Time of Functions](src/main/java/stack/ExclusiveTimeOfFunctions.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Basic Calculator](src/main/java/stack/BasicCalculator.java) (Hard) +- [Decode String](src/main/java/stack/DecodeString.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Longest Valid Parentheses](src/main/java/stack/LongestValidParentheses.java) (Hard) + + +#### [String](src/main/java/string) + +- [First Unique Character In a String](src/main/java/string/FirstUniqueCharacterInAString.java) (Easy) +- [Repeated Substring Pattern](src/main/java/string/RepeatedSubstringPattern.java) (Easy) +- [Reverse Words In a String](src/main/java/string/ReverseWordsInAString.java) (Medium) +- [ReverseWords II](src/main/java/string/ReverseWordsII.java) (Medium) +- [String to Integer](src/main/java/string/StringToInteger.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Text Justification](src/main/java/string/TextJustification.java) (Hard) +- [ZigZag Conversion](src/main/java/string/ZigZagConversion.java) (Medium) +- [Implement StrStr](src/main/java/string/ImplementStrStr.java) (Easy) +- [Excel Sheet Column Number](src/main/java/string/ExcelSheetColumnNumber.java) (Easy) +- [Compare Version Numbers](src/main/java/string/CompareVersionNumbers.java) (Easy) +- [Valid Palindrome](src/main/java/string/ValidPalindrome.java) (Easy) +- [Simplify Path](src/main/java/string/SimplifyPath.java) (Medium) +- [Permutation in String](src/main/java/string/PermutationInString.java) (Medium) +- [Add Binary](src/main/java/string/AddBinary.java) (Easy) +- [Valid Palindrome II](src/main/java/string/ValidPalindromeII.java) (Easy) +- [One Edit Distance](src/main/java/string/OneEditDistance.java) (Medium) +- [Count and Say](src/main/java/string/CountAndSay.java) (Easy) +- [Multiply Strings](src/main/java/string/MultiplyStrings.java) (Medium) +- [Longest Word in Dictionary through Deleting](src/main/java/string/LongestWordInDictonary.java) (Medium) +- [Isomorphic Strings](src/main/java/string/IsomorphicStrings.java) (Easy) +- [String Compression](src/main/java/string/StringCompression.java) (Easy) +- [Longest Common Prefix](src/main/java/string/LongestCommonPrefix.java) (Easy) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Find the Closest Palindrome](src/main/java/string/FindTheClosestPalindrome.java) (Hard) +- [Monotone Increasing Digits](src/main/java/string/MonotoneIncreasingDigits.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Shortest Palindrome](src/main/java/string/ShortestPalindrome.java) (Hard) +- [Valid Word Abbreviation](src/main/java/string/ValidWordAbbreviation.java) (Easy) +- [Longest Palindrome](src/main/java/string/LongestPalindrome.java) (Easy) +- [Replace Words](src/main/java/string/ReplaceWords.java) (Medium) +- [Rotate String](src/main/java/string/RotateString.java) (Easy) +- [Keyboard Row](src/main/java/string/KeyboardRow.java) (Easy) +- [Student Attendance Record I](src/main/java/string/StudentAttendanceRecordI.java) (Easy) +- [Split Concatenated Strings](src/main/java/string/SplitConcatenatedStrings.java) (Medium) +- [Valid Word Square](src/main/java/string/ValidWordSquare.java) (Easy) +- [Reconstruct Original Digits from English](src/main/java/string/ReconstructOriginalDigitsFromEnglish.java) (Medium) +- [Push Dominoes](src/main/java/string/PushDominoes.java) (Medium) +- [Validate IP Address](src/main/java/string/ValidateIPAddress.java) (Medium) +- [Reverse String II](src/main/java/string/ReverseStringII.java) (Easy) +- [Find Words That Can Be Formed by Characters](src/main/java/string/FindWordsThatCanBeFormedbyCharacters.java) (Easy) +- [Minimum Add to Make Parentheses Valid](src/main/java/string/MinimumAddtoMakeParenthesesValid.java) (Medium) + +#### [Tree](src/main/java/tree) + +- [Binaray Tree Right Side View](src/main/java/tree/BinarayTreeRightSideView.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Binary Tree Maximum Path Sum](src/main/java/tree/BinaryTreeMaximumPathSum.java) (Hard) +- [Boundary of Binary Tree](src/main/java/tree/BoundaryOfBinaryTree.java) (Medium) +- [Convert sorted array to BST](src/main/java/tree/ConvertSortedArrayToBST.java) (Medium) +- [Lowest Common Ancestor of a Binary Tree](src/main/java/tree/LCA.java) (Medium) +- [Lowest Common Ancestor of a BST](src/main/java/tree/LowestCommonAncestorBST.java) (Easy) +- [Most Frequent Subtree Sum](src/main/java/tree/MostFrequentSubtreeSum.java) (Medium) +- [Path Sum III](src/main/java/tree/PathSumIII.java) (Easy) +- [Convert Postorder and Inorder traversal to Binary Tree](src/main/java/tree/PostorderToBT.java) (Medium) +- [Convert Preorder and Inorder traversal to Binary Tree](src/main/java/tree/PreorderToBT.java) (Medium) +- [Sorted Array to BST](src/main/java/tree/SortedArrayToBST.java) (Medium) +- [Valid Binary Search Tree](src/main/java/tree/ValidBinarySearchTree.java) (Medium) +- [Largest BST Subtree](src/main/java/tree/LargestBSTSubtree.java) (Medium) +- [Closest Binary Search Tree Value](src/main/java/tree/ClosestBinarySearchTreeValue.java) (Easy) +- [Inorder Successor in BST](src/main/java/tree/InorderSuccessorInBST.java) (Medium) +- [Construct String From Binary Tree](src/main/java/tree/ConstructStringFromBinaryTree.java) (Easy) +- [Flatten Binary Tree to Linked List](src/main/java/tree/FlattenBinaryTree.java) (Medium) +- [Populating Next Right Pointers in Each Node](src/main/java/tree/NextRightPointer.java) (Medium) +- [Populating Next Right Pointers in Each Node II](src/main/java/tree/NextRightPointerII.java) (Medium) +- [Subtree of Another Tree](src/main/java/tree/SubtreeOfAnotherTree.java) (Easy) +- [Binary Tree Zigzag Level Order Traversal](src/main/java/tree/ZigZagTraversal.java) (Medium) +- [Binary Tree Inorder Traversal](src/main/java/tree/BinaryTreeInorderTraversal.java) (Medium) +- [Symmetric Tree](src/main/java/tree/SymmetricTree.java) (Easy) +- [Maximum Binary Tree](src/main/java/tree/MaximumBinaryTree.java) (Medium) +- [Find Bottom Left Tree Value](src/main/java/tree/FindBottomLeftTreeValue.java) (Medium) +- [Diameter of Binary Tree](src/main/java/tree/DiameterOfBinaryTree.java) (Easy) +- [Binary Tree Paths](src/main/java/tree/BinaryTreePaths.java) (Easy) +- [Sum of Left Leaves](src/main/java/tree/SumofLeftLeaves.java) (Easy) +- [Two Sum IV - Input is a BST](src/main/java/tree/TwoSumIV.java) (Easy) +- [Average of Levels in Binary Tree](src/main/java/tree/AverageOfLevelsInBinaryTree.java) (Easy) +- [Convert Binary Search Tree to Sorted Doubly Linked List](src/main/java/tree/BSTtoDoublyLinkedList.java) (Easy) +- [Same Tree](src/main/java/tree/SameTree.java) (Easy) +- [Binary Tree Longest Consecutive SequencefindMinDifference II](src/main/java/tree/BinaryTreeLongestConsecutiveSequenceII.java) (Medium) +- [Minimum Absolute Difference in BST](src/main/java/tree/MinimumAbsoluteDifferenceInBST.java) (Medium) +- [Equal Tree Partition](src/main/java/tree/EqualTreePartition.java) (Medium) +- [Split BST](src/main/java/tree/SplitBST.java) (Medium) +- [Closest Leaf in a Binary Tree](src/main/java/tree/ClosestLeafInABinaryTree.java) (Medium) +- [Maximum Width of Binary Tree](src/main/java/tree/MaximumWidthOfBinaryTree.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Recover Binary Search Tree](src/main/java/tree/RecoverBinarySearchTree.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Binary Tree Postorder Traversal](src/main/java/tree/BinaryTreePostorderTraversal.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Serialize and Deserialize N-ary Tree](src/main/java/tree/SerializeAndDeserializeNAryTree.java) (Hard) +- [Convert BST to Greater Tree](src/main/java/tree/ConvertBSTToGreaterTree.java) (Easy) +- [All Nodes Distance K in Binary Tree](src/main/java/tree/AllNodesDistanceKInBinaryTree.java) (Medium) +- [All Possible Full Binary Trees](src/main/java/tree/AllPossibleFullBinaryTrees.java) (Medium) +- [Flip Equivalent Binary Trees](src/main/java/tree/FlipEquivalentBinaryTrees.java) (Medium) +- [Construct Binary Tree from String](src/main/java/tree/ConstructBinaryTreefromString.java) (Medium) +- [Find Largest Value in Each Tree Row](src/main/java/tree/FindLargestValueInEachTreeRow.java) (Medium) +- [Find Bottom Left Tree Value](src/main/java/tree/FindBottomLeftTreeValue.java) (Medium) +- [Maximum Level Sum of a Binary Tree](src/main/java/tree/MaximumLevelSumofABinaryTree.java) (Medium) +- [Leaf-Similar Trees](src/main/java/tree/LeafSimilarTrees.java) (Easy) +- [Binary Tree Tilt](src/main/java/tree/BinaryTreeTilt.java) (Easy) + +#### [Two Pointers](src/main/java/two_pointers) + +- [Four Sum](src/main/java/two_pointers/FourSum.java) (Medium) +- [Longest Substring Witout Repeats](src/main/java/two_pointers/LongestSubstringWitoutRepeats.java) (Medium) +- [Three Sum](src/main/java/two_pointers/ThreeSum.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Trapping Rain Water](src/main/java/two_pointers/TrappingRainWater.java) (Hard) +- [3Sum Closest](src/main/java/two_pointers/ThreeSumClosest.java) (Medium) +- [Move Zeroes](src/main/java/two_pointers/MoveZeroes.java) (Easy) +- [Remove Duplicates](src/main/java/two_pointers/RemoveDuplicates.java) (Easy) +- [Remove Duplicates II](src/main/java/two_pointers/RemoveDuplicatesII.java) (Medium) +- [Minimum Size Subarray Sum](src/main/java/two_pointers/MinimumSizeSubarraySum.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Minimum Window Substring](src/main/java/two_pointers/MinimumWindowSubstring.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Smallest Range](src/main/java/two_pointers/SmallestRange.java) (Hard) +- [Subarray Product Less Than K](src/main/java/two_pointers/SubarrayProductLessThanK.java) (Medium) +- [Number of Matching Subsequences](src/main/java/two_pointers/NumberOfMatchingSubsequences.java) (Medium) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Subarrays with K Different Integers](src/main/java/two_pointers/SubarraysWithKDifferentIntegers.java) (Hard) +- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) [Last Substring in Lexicographical Order](src/main/java/two_pointers/LastSubstringInLexicographicalOrder.java) (Hard) -#### [Array](problems/src/array) - -- [Pascals Traiangle II](problems/src/array/PascalsTriangle.java) (Easy) -- [Product Of Array Except Self](problems/src/array/ProductOfArrayExceptSelf.java) (Medium) -- [Rotate Matrix](problems/src/array/RotateMatrix.java) (Medium) -- [Set Matrix Zeroes](problems/src/array/SetMatrixZeroes.java) (Medium) -- [Third Maximum Number](problems/src/array/ThirdMaximumNumber.java) (Easy) -- [TwoSum II](problems/src/array/TwoSumII.java) (Easy) - -#### [Backtracking](problems/src/backtracking) - -- [Combinations](problems/src/backtracking/Combinations.java) (Medium) -- [Combinations Sum](problems/src/backtracking/CombinationSum.java) (Medium) -- [Combinations Sum II](problems/src/backtracking/CombinationSumII.java) (Medium) -- [Letter Phone Number](problems/src/backtracking/LetterPhoneNumber.java) (Medium) -- [Paliandrome Partitioning](problems/src/backtracking/PalindromePartitioning.java) (Medium) -- [Permutations](problems/src/backtracking/Permutations.java) (Medium) -- [Permutations II](problems/src/backtracking/PermutationsII.java) (Medium) -- [SubSets](problems/src/backtracking/Subsets.java) (Medium) -- [SubSet II](problems/src/backtracking/SubsetsII.java) (Medium) -- [WordSearch](problems/src/backtracking/WordSearch.java) (Medium) - -#### [Binary Search](problems/src/binary_search) - -- [Minimum Sorted Rotated Array](problems/src/binary_search/MinSortedRotatedArray.java) (Medium) -- [Search in a Rotated Sorted Array](problems/src/binary_search/SearchRotatedSortedArray.java) (Medium) - -#### [Bit Manipulation](problems/src/bit_manipulation) - -- [Gray Code](problems/src/bit_manipulation/GrayCode.java) (Medium) - -#### [Breadth First Search](problems/src/breadth_first_search) - -- [Binaray Tree Level Order Traversal](problems/src/breadth_first_search/BinarayTreeLevelOrderTraversal.java) (Medium) -- [Word Ladder](problems/src/breadth_first_search/WordLadder.java) (Medium) -- [Word Ladder II](problems/src/breadth_first_search/WordLadderII.java) (Hard) - -#### [Depth First Search](problems/src/depth_first_search) - -- [Minesweeper](problems/src/depth_first_search/Minesweeper.java) (Medium) -- [Movie Recommend](problems/src/depth_first_search/MovieRecommend.java) (Medium) -- [Number Of Islands](problems/src/depth_first_search/NumberOfIslands.java) (Medium) - -#### [Design](problems/src/design) - -- [Copy List With Random Pointer](problems/src/design/CopyListWithRandomPointer.java) (Medium) -- [Encode and Decode Tiny URL](problems/src/design/EncodeAndDecodeTinyURL.java) (Medium) -- [LFU Cache](problems/src/design/LFUCache.java) (Hard) -- [LRU Cache](problems/src/design/LRUCache.java) (Hard) -- [Insert Delete Get Random](problems/src/design/RandomizedSet.java) (Medium) -- [Serialize Deserialize Binary Tree](problems/src/design/SerializeDeserializeBinaryTree.java) (Hard) -- [Design Twitter](problems/src/design/Twitter.java) (Medium) - -#### [Devide and Conquer](problems/src/divide_and_conquer) - -- [Kth Largest Element In a Array](problems/src/divide_and_conquer/KthLargestElementInAnArray.java) (Medium) -- [Search in a 2D Matrix](problems/src/divide_and_conquer/SearchA2DMatrix.java) (Medium) - -#### [Dynamic Programming](problems/src/dynamic_programming) - -- [Best Time To Buy and Sell Stocks](problems/src/dynamic_programming/BestTimeToBuyAndSellStocks.java) (Easy) -- [Climbing Stairs](problems/src/dynamic_programming/ClimbingStairs.java) (Easy) -- [Coin Change 2](problems/src/dynamic_programming/CoinChange2.java) (Medium) -- [Decode Ways](problems/src/dynamic_programming/DecodeWays.java) (Medium) -- [House Robber](problems/src/dynamic_programming/HouseRobber.java) (Easy) -- [Longest Increasing Subsequence](problems/src/dynamic_programming/LongestIncreasingSubsequence.java) (Medium) -- [Longest Paliandromic Substring](problems/src/dynamic_programming/LongestPaliandromicSubstring.java) (Medium) -- [Longest Palindromic Subsequence](problems/src/dynamic_programming/LongestPalindromicSubsequence.java) (Medium) -- [Maximum Product Subarray](problems/src/dynamic_programming/MaximumProductSubarray.java) (Medium) -- [Palindrome Partitioning II](problems/src/dynamic_programming/PalindromePartitioningII.java) (Hard) -- [UniqueBinary Search Trees](problems/src/dynamic_programming/UniqueBinarySearchTrees.java) (Medium) -- [Unique Binary Search Trees II](problems/src/dynamic_programming/UniqueBinarySearchTreesII.java) (Medium) -- [WordBreak](problems/src/dynamic_programming/WordBreak.java) (Medium) -- [WordBreak II](problems/src/dynamic_programming/WordBreakII.java) (Hard) - -#### [Greedy](problems/src/greedy) - -- [Jump Game](problems/src/greedy/JumpGame.java) (Medium) -- [Jump Game II](problems/src/greedy/JumpGameII.java) (Medium) - -#### [Hashing](problems/src/hashing) - -- [Anagrams](problems/src/hashing/Anagrams.java) (Medium) -- [Group Anagrams](problems/src/hashing/GroupAnagrams.java) (Medium) -- [Kdiff Pairs In a Array](problems/src/hashing/KdiffPairsInanArray.java) (Easy) -- [Sort Character by Frequency](problems/src/hashing/SortCharByFrequency.java) (Medium) -- [Two Sum](problems/src/hashing/TwoSum.java) (Easy) -- [Valid Anagram](problems/src/hashing/ValidAnagram.java) (Easy) - -#### [Heap](problems/src/heap) - -- [Sliding Window Maximum](problems/src/heap/SlidingWindowMaximum.java) (Hard) - -#### [Linked List](problems/src/linked_list) - -- [Intersection of two Linked-Lists](problems/src/linked_list/IntersectionOfTwoLists.java) (Easy) -- [Linked List Cycle](problems/src/linked_list/LinkedListCycle.java) (Easy) -- [Merge K Sorted Lists](problems/src/linked_list/MergeKSortedLists.java) (Hard) -- [Merge Two Sorted List](problems/src/linked_list/MergeTwoSortedList.java) (Easy) -- [Paliandrome List](problems/src/linked_list/PaliandromeList.java) (Easy) -- [Reverse Linked List](problems/src/linked_list/ReverseLinkedList.java) (Easy) - -#### [Math](problems/src/math) - -- [Add Two Numbers](problems/src/math/AddTwoNumbers.java) (Medium) -- [Count Primes](problems/src/math/CountPrimes.java) (Easy) -- [Rotate Function](problems/src/math/RotateFunction.java) (Medium) - -#### [Stack](problems/src/stack) - -- [Min Stack](problems/src/stack/MinStack.java) (Easy) -- [Valid Parentheses](problems/src/stack/ValidParentheses.java) (Easy)) - -#### [String](problems/src/string) - -- [First Unique Character In a String](problems/src/string/FirstUniqueCharacterInAString.java) (Easy) -- [Repeated Substring Pattern](problems/src/string/RepeatedSubstringPattern.java) (Easy) -- [ReverseWords II](problems/src/string/ReverseWordsII.java) (Medium) -- [String to Integer](problems/src/string/StringToInteger.java) (Medium) -- [Text Justification](problems/src/string/TextJustification.java) (Hard) - -#### [Tree](problems/src/tree) - -- [Binaray Tree Right Side View](problems/src/tree/BinarayTreeRightSideView.java) (Medium) -- [Binary Tree Maximum Path Sum](problems/src/tree/BinaryTreeMaximumPathSum.java) (Hard) -- [Boundary of Binary Tree](problems/src/tree/BoundaryOfBinaryTree.java) (Medium) -- [Convert sorted array to BST](problems/src/tree/ConvertSortedArrayToBST.java) (Medium) -- [Lowest Common Ancestor of a Binary Tree](problems/src/tree/LCA.java) (Medium) -- [Lowest Common Ancestor of a BST](problems/src/tree/LowestCommonAncestorBST.java) (Easy) -- [Most Frequent Subtree Sum](problems/src/tree/MostFrequentSubtreeSum.java) (Medium) -- [Path Sum III](problems/src/tree/PathSumIII.java) (Easy) -- [Convert Postorder and Inorder traversal to Binary Tree](problems/src/tree/PostorderToBT.java) (Medium) -- [Convert Preorder and Inorder traversal to Binary Tree](problems/src/tree/PreorderToBT.java) (Medium) -- [Sorted Array to BST](problems/src/tree/SortedArrayToBST.java) (Medium) -- [Valid Binary Search Tree](problems/src/tree/ValidBinarySearchTree.java) (Medium) - -#### [Two Pointers](problems/src/two_pointers) - -- [Four Sum](problems/src/two_pointers/FourSum.java) (Medium) -- [Longest Substring Witout Repeats](problems/src/two_pointers/LongestSubstringWitoutRepeats.java) (Medium) -- [Three Sum](problems/src/two_pointers/ThreeSum.java) (Medium) -- [Trapping Rain Water](problems/src/two_pointers/TrappingRainWater.java) (Hard) diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..9f9314b2 --- /dev/null +++ b/build.gradle @@ -0,0 +1,31 @@ +plugins { + id 'java' + id 'com.diffplug.spotless' version '7.0.0.BETA4' +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(23) // Replace with your desired version + } +} + +spotless { + java { + // Use the default import order configuration + importOrder('java', 'javax', 'com.acme', '', '#com.acme', '#') + + // Remove unused imports + removeUnusedImports() + + // Apply formatting to annotations + formatAnnotations() + } +} + +tasks.withType(JavaCompile).configureEach { + options.release = 23 // Match the desired version +} + +repositories { + mavenCentral() +} diff --git a/problems/src/array/PascalsTriangle.java b/problems/src/array/PascalsTriangle.java deleted file mode 100644 index c1b00861..00000000 --- a/problems/src/array/PascalsTriangle.java +++ /dev/null @@ -1,54 +0,0 @@ -package array; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Created by gouthamvidyapradhan on 25/03/2017. - * - * Given an index k, return the kth row of the Pascal's triangle. - - For example, given k = 3, - Return [1,3,3,1]. - - Note: - Could you optimize your algorithm to use only O(k) extra space? - */ -public class PascalsTriangle -{ - public static void main(String[] args) throws Exception - { - System.out.println(new PascalsTriangle().getRow(3)); - } - - public List getRow(int rowIndex) - { - int k = rowIndex; - if(k == 0) - return Arrays.asList(1); - else if(k == 1) - return Arrays.asList(1, 1); - else if (k == 2) - return Arrays.asList(1, 2, 1); - List result = new ArrayList<>(); - result.add(2); - k = k - 2; - int p, c; - while(k-- > 0) - { - p = 1; - int i = 0; - for(int l = result.size(); i < l; i ++) - { - c = result.get(i); - result.set(i, p + c); - p = c; - } - result.add(p + 1); - } - result.add(0, 1); - result.add(1); - return result; - } -} diff --git a/problems/src/array/ProductOfArrayExceptSelf.java b/problems/src/array/ProductOfArrayExceptSelf.java deleted file mode 100644 index fc380515..00000000 --- a/problems/src/array/ProductOfArrayExceptSelf.java +++ /dev/null @@ -1,42 +0,0 @@ -package array; - -/** - Created by gouthamvidyapradhan on 04/05/2017. - - Given an array of n integers where n > 1, nums, return an array output such that output[i] is equal to the product of all the elements of nums except nums[i]. - - Solve it without division and in O(n). - - For example, given [1,2,3,4], return [24,12,8,6]. - - Follow up: - Could you solve it with constant space complexity? (Note: The output array does not count as extra space for the purpose of space complexity analysis.) - */ - -public class ProductOfArrayExceptSelf -{ - public static void main(String[] args) - { - int[] nums = {1,2,3,4}; - int[] result = new ProductOfArrayExceptSelf().productExceptSelf(nums); - for (int r : result) - System.out.print(r + " "); - } - - public int[] productExceptSelf(int[] nums) - { - int[] result = new int[nums.length]; - for(int i = 0, temp = 1, l = nums.length; i < l; i++) - { - result[i] = temp; - temp *= nums[i]; - } - for(int i = nums.length - 1, temp = 1; i >= 0; i--) - { - result[i] = result[i] * temp; - temp *= nums[i]; - } - return result; - } - -} diff --git a/problems/src/array/RotateMatrix.java b/problems/src/array/RotateMatrix.java deleted file mode 100644 index aff6e5c8..00000000 --- a/problems/src/array/RotateMatrix.java +++ /dev/null @@ -1,50 +0,0 @@ -package array; - -/** - * Created by gouthamvidyapradhan on 21/03/2017. - * You are given an n x n 2D matrix representing an image. - - Rotate the image by 90 degrees (clockwise). - - Follow up: - Could you do this in-place? - */ -public class RotateMatrix -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[][] A = {{1,2,3}, {4,5,6}, {7,8,9}}; - new RotateMatrix().rotate(A); - for (int i = 0; i < A.length; i ++) - { - for(int j = 0; j < A[0].length; j ++) - { - System.out.println(A[i][j]); - } - } - } - - public void rotate(int[][] matrix) - { - int lc = 0, tr = 0, rc = matrix[0].length - 1, br = matrix.length - 1; - while(tr < br) - { - for(int i = lc, j = tr, k = rc, l = br; i < rc && j < br && k > lc && l > tr; i ++, j ++, k--, l--) - { - int temp1 = matrix[j][rc]; - matrix[j][rc] = matrix[tr][i]; - int temp2 = matrix[br][k]; - matrix[br][k] = temp1; - temp1 = matrix[l][lc]; - matrix[l][lc] = temp2; - matrix[tr][i] = temp1; - } - lc ++; tr ++; rc --; br --; - } - } -} diff --git a/problems/src/array/SetMatrixZeroes.java b/problems/src/array/SetMatrixZeroes.java deleted file mode 100644 index c520bd69..00000000 --- a/problems/src/array/SetMatrixZeroes.java +++ /dev/null @@ -1,66 +0,0 @@ -package array; - -import java.util.HashSet; -import java.util.Set; - -/** - * Created by pradhang on 3/28/2017. - * Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place. - - click to show follow up. - - Follow up: - Did you use extra space? - A straight forward solution using O(mn) space is probably a bad idea. - A simple improvement uses O(m + n) space, but still not the best solution. - Could you devise a constant space solution? - */ -public class SetMatrixZeroes -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[][] matrix = {{0, 8, 7}, {9, 0, 8}, {9, 9, 0}}; - - new SetMatrixZeroes().setZeroes(matrix); - } - - public void setZeroes(int[][] matrix) - { - Set row = new HashSet<>(); - Set col = new HashSet<>(); - int m = matrix.length; - int n = matrix[0].length; - for(int i = 0; i < m; i ++) - { - for(int j = 0; j < n; j ++) - { - if(matrix[i][j] == 0) - { - row.add(i); - col.add(j); - } - } - } - - for(int r : row) - { - for(int j = 0; j < n; j++) - { - matrix[r][j] = 0; - } - } - - for(int c : col) - { - for(int i = 0; i < m; i++) - { - matrix[i][c] = 0; - } - } - } -} diff --git a/problems/src/array/ThirdMaximumNumber.java b/problems/src/array/ThirdMaximumNumber.java deleted file mode 100644 index 6438ad20..00000000 --- a/problems/src/array/ThirdMaximumNumber.java +++ /dev/null @@ -1,64 +0,0 @@ -package array; - -/** - * Created by gouthamvidyapradhan on 25/03/2017. - Given a non-empty array of integers, return the third maximum number in this array. If it does not exist, return the maximum number. The time complexity must be in O(n). - - Example 1: - Input: [3, 2, 1] - - Output: 1 - - Explanation: The third maximum is 1. - Example 2: - Input: [1, 2] - - Output: 2 - - Explanation: The third maximum does not exist, so the maximum (2) is returned instead. - Example 3: - Input: [2, 2, 3, 1] - - Output: 1 - - Explanation: Note that the third maximum here means the third maximum distinct number. - Both numbers with value 2 are both considered as second maximum. - */ -public class ThirdMaximumNumber -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] a = {1, 2}; - System.out.println(new ThirdMaximumNumber().thirdMax(a)); - } - - public int thirdMax(int[] nums) - { - long[] max = {Long.MIN_VALUE, Long.MIN_VALUE, Long.MIN_VALUE}; - int count = 0; - for (int num : nums) { - for (int j = 0; j < 3; j++) { - if (max[j] > num) continue; - else if (max[j] == num) break; - int k = j; - long temp1, temp2; - temp1 = num; - count++; - while (k < 3) { - temp2 = max[k]; - max[k] = temp1; - temp1 = temp2; - k++; - } - break; - } - } - System.out.println(Integer.MIN_VALUE); - return (count >= 3)? (int)max[2] : (int)max[0]; - } -} diff --git a/problems/src/array/TwoSumII.java b/problems/src/array/TwoSumII.java deleted file mode 100644 index c69928b9..00000000 --- a/problems/src/array/TwoSumII.java +++ /dev/null @@ -1,50 +0,0 @@ -package array; - -/** - * Created by gouthamvidyapradhan on 18/03/2017. - Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number. - - The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based. - - You may assume that each input would have exactly one solution and you may not use the same element twice. - - Input: numbers={2, 7, 11, 15}, target=9 - Output: index1=1, index2=2 - */ -public class TwoSumII -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] nums = {2, 7, 11, 15}; - int[] result = new TwoSumII().twoSum(nums, 23); - for (int i : result) - System.out.println(i); - } - - public int[] twoSum(int[] numbers, int target) - { - int i = 0, j = numbers.length - 1; - while(i < j) - { - int x = (numbers[i] + numbers[j]); - if(x == target) - { - int[] result = new int[2]; - result[0] = i + 1; - result[1] = j + 1; - return result; - } - else if(x < target) - i++; - else j--; - } - return new int[2]; - } - - -} diff --git a/problems/src/backtracking/CombinationSum.java b/problems/src/backtracking/CombinationSum.java deleted file mode 100644 index f426adec..00000000 --- a/problems/src/backtracking/CombinationSum.java +++ /dev/null @@ -1,63 +0,0 @@ -package backtracking; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by pradhang on 3/14/2017. - Given a set of candidate numbers (C) (without duplicates) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. - - The same repeated number may be chosen from C unlimited number of times. - - Note: - All numbers (including target) will be positive integers. - The solution set must not contain duplicate combinations. - For example, given candidate set [2, 3, 6, 7] and target 7, - A solution set is: - [ - [7], - [2, 2, 3] - ] - */ -public class CombinationSum -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] candidates = {2,3,6,7}; - - List> result = new CombinationSum().combinationSum(candidates, 7); - } - - public List> combinationSum(int[] candidates, int target) - { - List> result = new ArrayList<>(); - List subList = new ArrayList<>(); - doNext(0, result, 0, candidates, target, subList); - return result; - } - - private void doNext(int i, List> result, int count, int[] candidates, int target, List subArr) - { - if(target == 0) - { - List subList = new ArrayList<>(); - for(int k = 0; k < count; k ++) - subList.add(subArr.get(k)); - result.add(subList); - } - else if(target > 0) - { - for(int j = i, l = candidates.length; j < l; j ++) - { - subArr.add(candidates[j]); - doNext(j, result, count + 1, candidates, target - candidates[j], subArr); - subArr.remove(subArr.size() - 1); - } - } - } -} diff --git a/problems/src/backtracking/CombinationSumII.java b/problems/src/backtracking/CombinationSumII.java deleted file mode 100644 index 091c2d45..00000000 --- a/problems/src/backtracking/CombinationSumII.java +++ /dev/null @@ -1,64 +0,0 @@ -package backtracking; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Created by gouthamvidyapradhan on 14/03/2017. - Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. - - Each number in C may only be used once in the combination. - - Note: - All numbers (including target) will be positive integers. - The solution set must not contain duplicate combinations. - For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8, - A solution set is: - [ - [1, 7], - [1, 2, 5], - [2, 6], - [1, 1, 6] - ] - */ - -public class CombinationSumII -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] candidates = {1, 1, 2, 2}; - List> result = new CombinationSumII().combinationSum2(candidates, 4); - } - - public List> combinationSum2(int[] candidates, int target) - { - Arrays.sort(candidates); - List> result = new ArrayList<>(); - combination(0, target, candidates, new ArrayList<>(), result); - return result; - } - - private void combination(int i, int target, int[] candidates, List row, List> result) - { - if(target == 0) - { - result.add(new ArrayList<>(row)); - } - else if(target > 0) - { - for(int j = i, l = candidates.length; j < l; j ++) - { - if(j > i && candidates[j] == candidates[j - 1]) continue; - row.add(candidates[j]); - combination(j + 1, target - candidates[j], candidates, row, result); - row.remove(row.size() - 1); - } - } - } -} diff --git a/problems/src/backtracking/Combinations.java b/problems/src/backtracking/Combinations.java deleted file mode 100644 index 5d11932d..00000000 --- a/problems/src/backtracking/Combinations.java +++ /dev/null @@ -1,57 +0,0 @@ -package backtracking; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by pradhang on 3/8/2017. - Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. - - For example, - If n = 4 and k = 2, a solution is: - - [ - [2,4], - [3,4], - [2,3], - [1,2], - [1,3], - [1,4], - ] - */ -public class Combinations -{ - - public static void main(String[] args) throws Exception - { - List> result = new Combinations().combine(3, 3); - } - - public List> combine(int n, int k) - { - int[] subArr = new int[k]; - List> result = new ArrayList<>(); - getNext(0, 0, n, k, subArr, result); - return result; - } - - private void getNext(int i, int count, - int n, int k, int[] subArr, List> result) - { - if(k == 0) - { - List subList = new ArrayList<>(); - for(int a : subArr) - subList.add(a); - result.add(subList); - } - else - { - for(int j = i + 1; j <= n; j++) - { - subArr[count] = j; - getNext(j, count + 1, n, k - 1, subArr, result); - } - } - } -} diff --git a/problems/src/backtracking/LetterPhoneNumber.java b/problems/src/backtracking/LetterPhoneNumber.java deleted file mode 100644 index 1712396c..00000000 --- a/problems/src/backtracking/LetterPhoneNumber.java +++ /dev/null @@ -1,59 +0,0 @@ -package backtracking; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by gouthamvidyapradhan on 09/03/2017. - Given a digit string, return all possible letter combinations that the number could represent. - - A mapping of digit to letters (just like on the telephone buttons) is given below. - 1 2(abc) 3(def) - 4(ghi) 5(jkl) 6(mno) - 7(pqrs) 8(tuv) 9(wxyz) - - - Input:Digit string "23" - Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. - Note: - Although the above answer is in lexicographical order, your answer could be in any order you want. - */ -public class LetterPhoneNumber -{ - private String[] NUMBER_ALPHA = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; - - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - List result = new LetterPhoneNumber().letterCombinations("23"); - result.forEach(System.out::println); - } - - private List letterCombinations(String digits) - { - if(digits == null || digits.isEmpty() || digits.contains("1") || digits.contains("0")) return new ArrayList<>(); - List prev = new ArrayList<>(); - prev.add(""); - for(int i = digits.length() - 1; i >= 0; i --) - { - String str = NUMBER_ALPHA[Integer.parseInt(String.valueOf(digits.charAt(i)))]; - List newList = new ArrayList<>(); - for(int j = 0, l = str.length(); j < l; j ++) - { - for(String s : prev) - { - s = str.charAt(j) + s; - newList.add(s); - } - } - prev = newList; - } - return prev; - } - - -} diff --git a/problems/src/backtracking/PalindromePartitioning.java b/problems/src/backtracking/PalindromePartitioning.java deleted file mode 100644 index 008aa5c7..00000000 --- a/problems/src/backtracking/PalindromePartitioning.java +++ /dev/null @@ -1,72 +0,0 @@ -package backtracking; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by pradhang on 3/15/2017. - Given a string s, partition s such that every substring of the partition is a palindrome. - - Return all possible palindrome partitioning of s. - - For example, given s = "aab", - Return - - [ - ["aa","b"], - ["a","a","b"] - ] - */ -public class PalindromePartitioning -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - List> result = new PalindromePartitioning().partition("aaaaaaaaaaaaaaaaaa"); - } - - public List> partition(String s) - { - List> result = new ArrayList<>(); - doNext(0, new ArrayList<>(), s, result); - return result; - } - - private void doNext(int i, List row, String s, List> result) - { - if(i == s.length()) - { - List list = new ArrayList<>(row); - result.add(list); - } - else - { - for(int j = i, l = s.length(); j < l; j++) - { - String sbStr = s.substring(i, j + 1); - if(isPalindrome(sbStr)) - { - row.add(sbStr); - doNext(j + 1, row, s, result); - row.remove(row.size() - 1); - } - } - } - } - - private boolean isPalindrome(String s) - { - int i = 0, j = s.length() - 1; - while(i <= j) - { - if(s.charAt(i) != s.charAt(j)) - return false; - i++; j--; - } - return true; - } -} diff --git a/problems/src/backtracking/Permutations.java b/problems/src/backtracking/Permutations.java deleted file mode 100644 index c74674d2..00000000 --- a/problems/src/backtracking/Permutations.java +++ /dev/null @@ -1,64 +0,0 @@ -package backtracking; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by gouthamvidyapradhan on 15/03/2017. - Given a collection of distinct numbers, return all possible permutations. - - For example, - [1,2,3] have the following permutations: - [ - [1,2,3], - [1,3,2], - [2,1,3], - [2,3,1], - [3,1,2], - [3,2,1] - ] - */ -public class Permutations -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] nums = {1, 2, 3}; - List> result = new Permutations().permute(nums); - } - - public List> permute(int[] nums) - { - List> result = new ArrayList<>(); - nextPermutation(0, nums, result); - return result; - } - - private void nextPermutation(int i, int[] nums, List> result) - { - if(i == nums.length - 1) - { - List list = new ArrayList<>(); - for(int n : nums) - list.add(n); - result.add(list); - } - else - { - for(int j = i, l = nums.length; j < l; j++) - { - int temp = nums[j]; - nums[j] = nums[i]; - nums[i] = temp; - nextPermutation(i + 1, nums, result); - temp = nums[j]; - nums[j] = nums[i]; - nums[i] = temp; - } - } - } -} diff --git a/problems/src/backtracking/PermutationsII.java b/problems/src/backtracking/PermutationsII.java deleted file mode 100644 index 80829241..00000000 --- a/problems/src/backtracking/PermutationsII.java +++ /dev/null @@ -1,61 +0,0 @@ -package backtracking; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Created by gouthamvidyapradhan on 12/04/2017. - Given a collection of numbers that might contain duplicates, return all possible unique permutations. - - For example, - [1,1,2] have the following unique permutations: - [ - [1,1,2], - [1,2,1], - [2,1,1] - ] - - */ -public class PermutationsII -{ - public static void main(String[] args) - { - int[] A = {1, 2, 2}; - System.out.println(new PermutationsII().permuteUnique(A)); - } - - public List> permuteUnique(int[] nums) - { - List> result = new ArrayList<>(); - Arrays.sort(nums); - nextPermutation(0, nums, result); - return result; - } - - private void nextPermutation(int i, int[] nums, List> result) - { - if(i == nums.length - 1) - { - List list = new ArrayList<>(); - for(int n : nums) - list.add(n); - result.add(list); - } - else - { - for(int j = i, l = nums.length; j < l; j++) - { - if(j > i && nums[j] == nums[i]) continue; - swap(nums, i, j); - nextPermutation(i + 1, Arrays.copyOf(nums, nums.length), result); - } - } - } - - private void swap(int[] a, int i , int j){ - int tmp = a[i]; - a[i] = a[j]; - a[j] = tmp; - } -} diff --git a/problems/src/backtracking/Subsets.java b/problems/src/backtracking/Subsets.java deleted file mode 100644 index bbfef2a4..00000000 --- a/problems/src/backtracking/Subsets.java +++ /dev/null @@ -1,56 +0,0 @@ -package backtracking; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by gouthamvidyapradhan on 14/03/2017. - Given a set of distinct integers, nums, return all possible subsets. - - Note: The solution set must not contain duplicate subsets. - - For example, - If nums = [1,2,3], a solution is: - - [ - [3], - [1], - [2], - [1,2,3], - [1,3], - [2,3], - [1,2], - [] - ] - - */ -public class Subsets -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] n = {1, 2, 3}; - List> result = new Subsets().subsets(n); - } - - public List> subsets(int[] nums) - { - List> result = new ArrayList<>(); - result.add(new ArrayList<>()); //empty subset - for(int i = 0, l = nums.length; i < l; i ++) - { - for(int j = 0, resLen = result.size(); j < resLen; j++) - { - List newList = new ArrayList<>(result.get(j)); - newList.add(nums[i]); - result.add(newList); - } - } - return result; - } - -} diff --git a/problems/src/backtracking/SubsetsII.java b/problems/src/backtracking/SubsetsII.java deleted file mode 100644 index bfd93ecd..00000000 --- a/problems/src/backtracking/SubsetsII.java +++ /dev/null @@ -1,62 +0,0 @@ -package backtracking; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Created by gouthamvidyapradhan on 14/03/2017. - Given a collection of integers that might contain duplicates, nums, return all possible subsets. - - Note: The solution set must not contain duplicate subsets. - - For example, - If nums = [1,2,2], a solution is: - - [ - [2], - [1], - [1,2,2], - [2,2], - [1,2], - [] - ] - */ -public class SubsetsII -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] n = {1, 2, 3}; - List> result = new SubsetsII().subsetsWithDup(n); - } - - public List> subsetsWithDup(int[] nums) - { - List> result = new ArrayList<>(); - result.add(new ArrayList<>()); //empty subset - int start = 0, newStart = 0; - Arrays.sort(nums); - for(int i = 0, l = nums.length; i < l; i ++) - { - newStart = result.size(); - if(i == 0 || nums[i] != nums[i - 1]) - { - start = 0; - } - for(int j = start, resLen = result.size(); j < resLen; j++) - { - List newList = new ArrayList<>(result.get(j)); - newList.add(nums[i]); - result.add(newList); - } - start = newStart; - } - return result; - } - -} diff --git a/problems/src/backtracking/WordSearch.java b/problems/src/backtracking/WordSearch.java deleted file mode 100644 index 3e4b409a..00000000 --- a/problems/src/backtracking/WordSearch.java +++ /dev/null @@ -1,86 +0,0 @@ -package backtracking; - -/** - * Created by PRADHANG on 4/13/2017. - Given a 2D board and a word, find if the word exists in the grid. - - The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once. - - For example, - Given board = - - [ - ['A','B','C','E'], - ['S','F','C','S'], - ['A','D','E','E'] - ] - word = "ABCCED", -> returns true, - word = "SEE", -> returns true, - word = "ABCB", -> returns false. - */ -public class WordSearch -{ - private static final int[] R = {0,0,1,-1}; - private static final int[] C = {1,-1,0,0}; - private static boolean[][] visited; - private static int length = 0, N, M; - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - char[][] board = { - {'A'} - }; - System.out.println(new WordSearch().exist(board, "A")); - } - - public boolean exist(char[][] board, String word) - { - N = board.length; - M = board[0].length; - if(N * M < word.length()) return false; - visited = new boolean[N][M]; - length = word.length(); - for (int i = 0 ; i < N; i ++) - { - for (int j = 0 ; j < M; j ++) - { - if(board[i][j] == word.charAt(0)) - { - if(dfs(i, j, board, word, 1)) return true; - visited[i][j] = false; - } - } - } - return false; - } - - private boolean dfs(int r, int c, char[][] board, String word, int pos) - { - if(pos < length) - { - visited[r][c] = true; - for(int i = 0; i < 4; i ++) - { - int newR = r + R[i]; - int newC = c + C[i]; - if(newR >= 0 && newR < N && newC >= 0 && newC < M) - { - if(!visited[newR][newC]) - { - if(board[newR][newC] == word.charAt(pos)) - { - if(dfs(newR, newC, board, word, pos + 1)) return true; - visited[newR][newC] = false; - } - } - } - } - } - else return true; - return false; - } -} diff --git a/problems/src/binary_search/MinSortedRotatedArray.java b/problems/src/binary_search/MinSortedRotatedArray.java deleted file mode 100644 index 9ae7e843..00000000 --- a/problems/src/binary_search/MinSortedRotatedArray.java +++ /dev/null @@ -1,44 +0,0 @@ -package binary_search; - -/** - * Created by gouthamvidyapradhan on 10/04/2017. - Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. - - (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). - - Find the minimum element. - - You may assume no duplicate exists in the array. - */ -public class MinSortedRotatedArray -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] A = {5, 1, 2, 3, 4}; - System.out.println(new MinSortedRotatedArray().findMin(A)); - } - - public int findMin(int[] nums) - { - if(nums.length == 0) return 0; - else if(nums.length == 1) return nums[0]; - int low = 0, high = nums.length - 1; - while(low < high) - { - int mid = (low + high) / 2; - if(mid > 0 && nums[mid] < nums[mid - 1]) - return nums[mid]; - if(nums[low] > nums[mid]) - high = mid - 1; - else if(nums[high] < nums[mid]) - low = mid + 1; - else high = mid - 1; - } - return nums[low]; - } -} diff --git a/problems/src/binary_search/SearchRotatedSortedArray.java b/problems/src/binary_search/SearchRotatedSortedArray.java deleted file mode 100644 index e6b17e21..00000000 --- a/problems/src/binary_search/SearchRotatedSortedArray.java +++ /dev/null @@ -1,48 +0,0 @@ -package binary_search; - -/** - * Created by gouthamvidyapradhan on 10/04/2017. - Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. - - (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). - - You are given a target value to search. If found in the array return its index, otherwise return -1. - - You may assume no duplicate exists in the array. - - */ -public class SearchRotatedSortedArray -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] A = {5, 4, 3, 2, 1}; - System.out.println(new SearchRotatedSortedArray().search(A, 4)); - } - - public int search(int[] nums, int target) - { - if(nums.length == 0) return -1; - if(nums.length == 1) - { - return (nums[0] == target) ? 0 : -1; - } - int low = 0, high = nums.length - 1; - while(low < high) - { - int mid = (low + high) / 2; - if(nums[mid] == target) - return mid; - if((nums[mid] <= nums[low]) && (target > nums[mid] && target <= nums[high]) || - (nums[low] <= nums[mid] && (target < nums[low] || target > nums[mid]))) - low = mid + 1; - else high = mid - 1; - } - return (nums[low] == target) ? low : -1; - } - -} diff --git a/problems/src/bit_manipulation/GrayCode.java b/problems/src/bit_manipulation/GrayCode.java deleted file mode 100644 index 6c50336a..00000000 --- a/problems/src/bit_manipulation/GrayCode.java +++ /dev/null @@ -1,44 +0,0 @@ -package bit_manipulation; - -import java.util.*; - -/** - * Created by gouthamvidyapradhan on 16/03/2017. - The gray code is a binary numeral system where two successive values differ in only one bit. - - Given a non-negative integer n representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with 0. - - For example, given n = 2, return [0,1,3,2]. Its gray code sequence is: - - 00 - 0 - 01 - 1 - 11 - 3 - 10 - 2 - Note: - For a given n, a gray code sequence is not uniquely defined. - - For example, [0,2,3,1] is also a valid gray code sequence according to the above definition. - - For now, the judge is able to judge based on one instance of gray code sequence. Sorry about that. - */ -public class GrayCode -{ - - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - List result = new GrayCode().grayCode(3); - } - - public List grayCode(int n) - { - List result = new ArrayList<>(); - for(int i = 0; i <= ((1 << n) - 1); i ++) - result.add(i ^ (i >> 1)); - return result; - } -} diff --git a/problems/src/breadth_first_search/BinarayTreeLevelOrderTraversal.java b/problems/src/breadth_first_search/BinarayTreeLevelOrderTraversal.java deleted file mode 100644 index 5df4b49d..00000000 --- a/problems/src/breadth_first_search/BinarayTreeLevelOrderTraversal.java +++ /dev/null @@ -1,98 +0,0 @@ -package breadth_first_search; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.List; -import java.util.Queue; - -/** - * Created by gouthamvidyapradhan on 13/03/2017. - Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level). - - For example: - Given binary tree [3,9,20,null,null,15,7], - 3 - / \ - 9 20 - / \ - 15 7 - return its level order traversal as: - [ - [3], - [9,20], - [15,7] - ] - - */ -public class BinarayTreeLevelOrderTraversal -{ - public static class TreeNode - { - int val; - TreeNode left; - TreeNode right; - TreeNode(int x) { val = x; } - } - - private class LevelNode - { - TreeNode node; - int level; - LevelNode(TreeNode node, int level) - { - this.node = node; - this.level = level; - } - } - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - TreeNode root = new TreeNode(2); - root.left = new TreeNode(3); - root.right = new TreeNode(4); - root.right.right = new TreeNode(5); - root.right.left = new TreeNode(4); - root.right.left.right = new TreeNode(8); - root.right.left.left = new TreeNode(7); - root.right.left.left.right = new TreeNode(10); - root.right.left.left.left = new TreeNode(9); - - List> result = new BinarayTreeLevelOrderTraversal().levelOrder(root); - } - - public List> levelOrder(TreeNode root) - { - List> result = new ArrayList<>(); - if(root == null) return result; - Queue queue = new ArrayDeque<>(); - queue.offer(new LevelNode(root, 0)); - int currentLevel = 0; - List row = new ArrayList<>(); - while(!queue.isEmpty()) - { - LevelNode levelNode = queue.poll(); - if(levelNode.node != null) - { - if(levelNode.level != currentLevel) - { - result.add(row); - row = new ArrayList<>(); - currentLevel++; - } - row.add(levelNode.node.val); - TreeNode left = levelNode.node.left; - TreeNode right = levelNode.node.right; - LevelNode lNodeL = new LevelNode(left, levelNode.level + 1); - LevelNode lNodeR = new LevelNode(right, levelNode.level + 1); - queue.offer(lNodeL); - queue.offer(lNodeR); - } - } - result.add(row); - return result; - } -} diff --git a/problems/src/breadth_first_search/WordLadder.java b/problems/src/breadth_first_search/WordLadder.java deleted file mode 100644 index af7cefa1..00000000 --- a/problems/src/breadth_first_search/WordLadder.java +++ /dev/null @@ -1,95 +0,0 @@ -package breadth_first_search; - -import java.util.*; - -/** - * Created by gouthamvidyapradhan on 21/03/2017. - Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWord to endWord, such that: - - Only one letter can be changed at a time. - Each transformed word must exist in the word list. Note that beginWord is not a transformed word. - For example, - - Given: - beginWord = "hit" - endWord = "cog" - wordList = ["hot","dot","dog","lot","log","cog"] - As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog", - return its length 5. - - Note: - Return 0 if there is no such transformation sequence. - All words have the same length. - All words contain only lowercase alphabetic characters. - You may assume no duplicates in the word list. - You may assume beginWord and endWord are non-empty and are not the same. - */ -public class WordLadder -{ - - class State - { - String word; - int len; - State(String word, int len) - { - this.word = word; - this.len = len; - } - } - - private static Queue queue = new ArrayDeque<>(); - private static Set dictionary = new HashSet<>(); - private static final String CONST = "abcdefghijklmnopqrstuvwxyz"; - private static Set done = new HashSet<>(); - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - List list = new ArrayList<>(); - list.add("hot"); - list.add("dot"); - list.add("dog"); - list.add("lot"); - list.add("log"); - list.add("cog"); - System.out.println(new WordLadder().ladderLength("hit", "cog", list)); - } - - - public int ladderLength(String beginWord, String endWord, List wordList) - { - dictionary.addAll(wordList); - queue.offer(new State(beginWord, 0)); - done.add(beginWord); - while(!queue.isEmpty()) - { - State head = queue.poll(); - if(head.word.equals(endWord)) - return head.len + 1; - for(int i = 0, l = CONST.length(); i < l; i ++ ) - { - StringBuilder word = new StringBuilder(head.word); - for(int j = 0, ln = word.length(); j < ln; j ++ ) - { - char old = word.charAt(j); - word.replace(j, j + 1, String.valueOf(CONST.charAt(i))); - if(!done.contains(word.toString())) - { - if(dictionary.contains(word.toString())) - { - done.add(word.toString()); - queue.offer(new State(word.toString(), head.len + 1)); - } - } - word.replace(j, j + 1, String.valueOf(old)); - } - } - } - return 0; - } - -} diff --git a/problems/src/breadth_first_search/WordLadderII.java b/problems/src/breadth_first_search/WordLadderII.java deleted file mode 100644 index 8df6bb21..00000000 --- a/problems/src/breadth_first_search/WordLadderII.java +++ /dev/null @@ -1,144 +0,0 @@ -package breadth_first_search; - -import java.util.*; - -/** - * Created by gouthamvidyapradhan on 24/03/2017. - Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that: - - Only one letter can be changed at a time - Each transformed word must exist in the word list. Note that beginWord is not a transformed word. - For example, - - Given: - beginWord = "hit" - endWord = "cog" - wordList = ["hot","dot","dog","lot","log","cog"] - Return - [ - ["hit","hot","dot","dog","cog"], - ["hit","hot","lot","log","cog"] - ] - Note: - Return an empty list if there is no such transformation sequence. - All words have the same length. - All words contain only lowercase alphabetic characters. - You may assume no duplicates in the word list. - You may assume beginWord and endWord are non-empty and are not the same. - */ -public class WordLadderII -{ - - private static Queue queue = new ArrayDeque<>(); - private static Set dictionary = new HashSet<>(); - private static final String CONST = "abcdefghijklmnopqrstuvwxyz"; - private static Map> graph = new HashMap<>(); - private static Map minDistance = new HashMap<>(); - private static List> result = new ArrayList<>(); - - - - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - List dic = Arrays.asList("kid","tag","pup","ail","tun","woo","erg","luz","brr","gay","sip","kay","per","val","mes","ohs","now","boa","cet","pal","bar","die","war","hay","eco","pub","lob","rue","fry","lit","rex","jan","cot","bid","ali","pay","col","gum","ger","row","won","dan","rum","fad","tut","sag","yip","sui","ark","has","zip","fez","own","ump","dis","ads","max","jaw","out","btu","ana","gap","cry","led","abe","box","ore","pig","fie","toy","fat","cal","lie","noh","sew","ono","tam","flu","mgm","ply","awe","pry","tit","tie","yet","too","tax","jim","san","pan","map","ski","ova","wed","non","wac","nut","why","bye","lye","oct","old","fin","feb","chi","sap","owl","log","tod","dot","bow","fob","for","joe","ivy","fan","age","fax","hip","jib","mel","hus","sob","ifs","tab","ara","dab","jag","jar","arm","lot","tom","sax","tex","yum","pei","wen","wry","ire","irk","far","mew","wit","doe","gas","rte","ian","pot","ask","wag","hag","amy","nag","ron","soy","gin","don","tug","fay","vic","boo","nam","ave","buy","sop","but","orb","fen","paw","his","sub","bob","yea","oft","inn","rod","yam","pew","web","hod","hun","gyp","wei","wis","rob","gad","pie","mon","dog","bib","rub","ere","dig","era","cat","fox","bee","mod","day","apr","vie","nev","jam","pam","new","aye","ani","and","ibm","yap","can","pyx","tar","kin","fog","hum","pip","cup","dye","lyx","jog","nun","par","wan","fey","bus","oak","bad","ats","set","qom","vat","eat","pus","rev","axe","ion","six","ila","lao","mom","mas","pro","few","opt","poe","art","ash","oar","cap","lop","may","shy","rid","bat","sum","rim","fee","bmw","sky","maj","hue","thy","ava","rap","den","fla","auk","cox","ibo","hey","saw","vim","sec","ltd","you","its","tat","dew","eva","tog","ram","let","see","zit","maw","nix","ate","gig","rep","owe","ind","hog","eve","sam","zoo","any","dow","cod","bed","vet","ham","sis","hex","via","fir","nod","mao","aug","mum","hoe","bah","hal","keg","hew","zed","tow","gog","ass","dem","who","bet","gos","son","ear","spy","kit","boy","due","sen","oaf","mix","hep","fur","ada","bin","nil","mia","ewe","hit","fix","sad","rib","eye","hop","haw","wax","mid","tad","ken","wad","rye","pap","bog","gut","ito","woe","our","ado","sin","mad","ray","hon","roy","dip","hen","iva","lug","asp","hui","yak","bay","poi","yep","bun","try","lad","elm","nat","wyo","gym","dug","toe","dee","wig","sly","rip","geo","cog","pas","zen","odd","nan","lay","pod","fit","hem","joy","bum","rio","yon","dec","leg","put","sue","dim","pet","yaw","nub","bit","bur","sid","sun","oil","red","doc","moe","caw","eel","dix","cub","end","gem","off","yew","hug","pop","tub","sgt","lid","pun","ton","sol","din","yup","jab","pea","bug","gag","mil","jig","hub","low","did","tin","get","gte","sox","lei","mig","fig","lon","use","ban","flo","nov","jut","bag","mir","sty","lap","two","ins","con","ant","net","tux","ode","stu","mug","cad","nap","gun","fop","tot","sow","sal","sic","ted","wot","del","imp","cob","way","ann","tan","mci","job","wet","ism","err","him","all","pad","hah","hie","aim","ike","jed","ego","mac","baa","min","com","ill","was","cab","ago","ina","big","ilk","gal","tap","duh","ola","ran","lab","top","gob","hot","ora","tia","kip","han","met","hut","she","sac","fed","goo","tee","ell","not","act","gil","rut","ala","ape","rig","cid","god","duo","lin","aid","gel","awl","lag","elf","liz","ref","aha","fib","oho","tho","her","nor","ace","adz","fun","ned","coo","win","tao","coy","van","man","pit","guy","foe","hid","mai","sup","jay","hob","mow","jot","are","pol","arc","lax","aft","alb","len","air","pug","pox","vow","got","meg","zoe","amp","ale","bud","gee","pin","dun","pat","ten","mob"); - new WordLadderII().findLadders("cet", "ism", dic); - } - - public List> findLadders(String beginWord, String endWord, List wordList) - { - dictionary.addAll(wordList); - bfs(beginWord, endWord, wordList); - List path = new ArrayList<>(); - path.add(beginWord); - dfs(beginWord, endWord, path); - System.out.println(result); - return result; - } - - /** - * Bfs - * @param beginWord begin word - * @param endWord end word - * @param wordList wordlist - */ - private void bfs(String beginWord, String endWord, List wordList) - { - queue.offer(beginWord); - minDistance.put(beginWord, 0); - while(!queue.isEmpty()) - { - String currWord = queue.poll(); - StringBuilder childSb = new StringBuilder(currWord); - for(int j = 0, ln = childSb.length(); j < ln; j ++ ) - { - for(int i = 0, l = CONST.length(); i < l; i ++ ) - { - char old = childSb.charAt(j); - childSb.replace(j, j + 1, String.valueOf(CONST.charAt(i))); - String child = childSb.toString(); - if(dictionary.contains(child)) - { - if(minDistance.get(child) == null) - { - minDistance.put(child, minDistance.get(currWord) + 1); - addChild(currWord, child); - if(!child.equals(endWord)) - queue.offer(child); - } - else - { - if(minDistance.get(child) == (minDistance.get(currWord) + 1)) - addChild(currWord, child); - } - } - childSb.replace(j, j + 1, String.valueOf(old)); - } - } - } - } - /** - * Add child - * @param parent parent - * @param child child - */ - private void addChild(String parent, String child) - { - Set children = graph.get(parent); - if(children == null) - children = new HashSet<>(); - children.add(child); - graph.put(parent, children); - } - - /** - * Dfs to build path - * @param currWord node - * @param endWord endword - * @param path path - */ - private void dfs(String currWord, String endWord, List path) - { - if(currWord.equals(endWord)) - { - result.add(new ArrayList<>(path)); - } - else - { - Set children = graph.get(currWord); - if(children != null) - { - for(String c : children) - { - path.add(c); - dfs(c, endWord, path); - path.remove(path.size() - 1); - } - } - } - } -} diff --git a/problems/src/depth_first_search/Minesweeper.java b/problems/src/depth_first_search/Minesweeper.java deleted file mode 100644 index 1008ed08..00000000 --- a/problems/src/depth_first_search/Minesweeper.java +++ /dev/null @@ -1,116 +0,0 @@ -package depth_first_search; - -/** - * Created by pradhang on 3/28/2017. - You are given a 2D char matrix representing the game board. 'M' represents an unrevealed mine, 'E' represents an unrevealed empty square, 'B' represents a revealed blank square that has no adjacent (above, below, left, right, and all 4 diagonals) mines, digit ('1' to '8') represents how many mines are adjacent to this revealed square, and finally 'X' represents a revealed mine. - - Now given the next click position (row and column indices) among all the unrevealed squares ('M' or 'E'), return the board after revealing this position according to the following rules: - - If a mine ('M') is revealed, then the game is over - change it to 'X'. - If an empty square ('E') with no adjacent mines is revealed, then change it to revealed blank ('B') and all of its adjacent unrevealed squares should be revealed recursively. - If an empty square ('E') with at least one adjacent mine is revealed, then change it to a digit ('1' to '8') representing the number of adjacent mines. - Return the board when no more squares will be revealed. - Example 1: - Input: - - [['E', 'E', 'E', 'E', 'E'], - ['E', 'E', 'M', 'E', 'E'], - ['E', 'E', 'E', 'E', 'E'], - ['E', 'E', 'E', 'E', 'E']] - - Click : [3,0] - - Output: - - [['B', '1', 'E', '1', 'B'], - ['B', '1', 'M', '1', 'B'], - ['B', '1', '1', '1', 'B'], - ['B', 'B', 'B', 'B', 'B']] - - Example 2: - Input: - - [['B', '1', 'E', '1', 'B'], - ['B', '1', 'M', '1', 'B'], - ['B', '1', '1', '1', 'B'], - ['B', 'B', 'B', 'B', 'B']] - - Click : [1,2] - - Output: - - [['B', '1', 'E', '1', 'B'], - ['B', '1', 'X', '1', 'B'], - ['B', '1', '1', '1', 'B'], - ['B', 'B', 'B', 'B', 'B']] - - Note: - The range of the input matrix's height and width is [1,50]. - The click position will only be an unrevealed square ('M' or 'E'), which also means the input board contains at least one clickable square. - The input board won't be a stage when game is over (some mines have been revealed). - For simplicity, not mentioned rules should be ignored in this problem. For example, you don't need to reveal all the unrevealed mines when the game is over, consider any cases that you will win the game or flag any squares. - - */ -public class Minesweeper -{ - private static final int[] R = {1, 1, 1, 0, 0, -1, -1, -1}; - private static final int[] C = {-1, 0, 1, -1, 1, -1, 0, 1}; - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - char[][] board = {{'E','E','E','E','E'},{'E','E','M','E','E'},{'E','E','E','E','E'},{'E','E','E','E','E'}}; - int[] click = {3, 0}; - new Minesweeper().updateBoard(board, click); - for (int i = 0; i < board.length; i ++) - System.out.println(board[i]); - } - - public char[][] updateBoard(char[][] board, int[] click) - { - int r = click[0]; - int c = click[1]; - dfs(board, r, c); - return board; - } - - private void dfs(char[][] board, int r, int c) - { - if(board[r][c] == 'M') - { - board[r][c] = 'X'; - } - else - { - int mineCount = 0; - for(int i = 0; i < 8; i ++) - { - int newR = r + R[i]; - int newC = c + C[i]; - if(newR >=0 && newC >= 0 && newR < board.length && newC < board[0].length && - board[newR][newC] == 'M') //boundary check - mineCount++; - } - if(mineCount > 0) - board[r][c] = (char)(mineCount + '0'); - else - { - board[r][c] = 'B'; - for(int i = 0; i < 8; i ++) - { - int newR = r + R[i]; - int newC = c + C[i]; - if(newR >=0 && newC >= 0 && newR < board.length && newC < board[0].length && - board[newR][newC] == 'E') //boundary check - { - dfs(board, newR, newC); - } - } - } - } - } -} - diff --git a/problems/src/depth_first_search/MovieRecommend.java b/problems/src/depth_first_search/MovieRecommend.java deleted file mode 100644 index dff0c202..00000000 --- a/problems/src/depth_first_search/MovieRecommend.java +++ /dev/null @@ -1,74 +0,0 @@ -package depth_first_search; - -import java.util.*; - -/** - * Created by gouthamvidyapradhan on 25/02/2017. - * Accepted - */ -public class MovieRecommend -{ - Set visited = new HashSet<>(); - List list = new ArrayList<>(); - class Movie - { - private int movieId; - private float rating; - private ArrayList similarMovies; - public List getSimilarMovies() - { - return similarMovies; - } - } - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - - } - - public Set getMovieRecommendations (Movie movie, int N) - { - dfs(movie); - Set result = new HashSet<>(); - Comparator cmp = new Comparator() - { - @Override - public int compare(Movie o1, Movie o2) - { - return Float.compare(o2.rating, o1.rating); - } - }; - Collections.sort(list, cmp); - - if(list.size() < N) - { - result.addAll(list); - return result; - } - - for(int i = 0; i < N; i ++) - { - result.add(list.get(i)); - } - - return result; - } - - private void dfs(Movie m) - { - visited.add(m.movieId); // mark this visited - List movies = m.getSimilarMovies(); - for(Movie mo : movies) - { - if(!visited.contains(mo.movieId)) - { - list.add(mo); - dfs(mo); - } - } - } -} diff --git a/problems/src/depth_first_search/NumberOfIslands.java b/problems/src/depth_first_search/NumberOfIslands.java deleted file mode 100644 index a5ff9468..00000000 --- a/problems/src/depth_first_search/NumberOfIslands.java +++ /dev/null @@ -1,74 +0,0 @@ -package depth_first_search; - -/** - * Created by gouthamvidyapradhan on 09/03/2017. - Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. - - Example 1: - - 11110 - 11010 - 11000 - 00000 - Answer: 1 - - Example 2: - - 11000 - 11000 - 00100 - 00011 - Answer: 3 - */ -public class NumberOfIslands -{ - int[] R = {0, 0, 1, -1}; - int[] C = {1, -1, 0, 0}; - private static int M, N; - private static char temp[][]; - - public int numIslands(char[][] grid) - { - M = grid.length; - if(M == 0) return 0; - N = grid[0].length; - temp = new char[M][N]; - int count = 0; - - for(int i = 0; i < M; i ++) - { - System.arraycopy(grid[i], 0, temp[i], 0, N); - } - - for(int i = 0; i < M; i ++) - { - for(int j = 0; j < N; j++) - { - if(temp[i][j] == '1') - { - ++count; - dfs(i, j); - } - } - } - - return count; - } - - private void dfs(int r, int c) - { - temp[r][c] = '0'; - for(int i = 0; i < 4; i++) - { - int newR = r + R[i]; - int newC = c + C[i]; - if(newR >=0 && newC >= 0 && newR < M && newC < N) - { - if(temp[newR][newC] != '0') //not visited - { - dfs(newR, newC); - } - } - } - } -} diff --git a/problems/src/design/CopyListWithRandomPointer.java b/problems/src/design/CopyListWithRandomPointer.java deleted file mode 100644 index 90157e19..00000000 --- a/problems/src/design/CopyListWithRandomPointer.java +++ /dev/null @@ -1,80 +0,0 @@ -package design; - -/** - * Created by gouthamvidyapradhan on 11/03/2017. - A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. - - Return a deep copy of the list. - */ -public class CopyListWithRandomPointer -{ - - static class RandomListNode - { - int label; - RandomListNode next, random; - RandomListNode(int x) - { this.label = x; } - } - - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - RandomListNode one = new RandomListNode(1); - one.next = null; - one.random = one; - /*RandomListNode two = new RandomListNode(2); - RandomListNode three = new RandomListNode(3); - RandomListNode four = new RandomListNode(4); - RandomListNode five = new RandomListNode(5); - one.next = two; - two.next = three; - three.next = four; - four.next = five; - one.random = three; - two.random = five; - three.random = null; - four.random = two; - five.random = four;*/ - RandomListNode result = new CopyListWithRandomPointer().copyRandomList(one); - System.out.println(); - } - - private RandomListNode copyRandomList(RandomListNode head) - { - if(head == null) return null; - RandomListNode ite = head, next; - while(ite != null) - { - next = ite.next; - RandomListNode node = new RandomListNode(ite.label); - ite.next = node; - node.next = next; - ite = next; - } - - ite = head; - while(ite != null) - { - if(ite.random != null) - ite.next.random = ite.random.next; - ite = ite.next.next; - } - - ite = head; RandomListNode copyIte = ite.next, copyHead = ite.next; - while(copyIte.next != null) - { - ite.next = copyIte.next; - copyIte.next = ite.next.next; - copyIte = copyIte.next; - ite = ite.next; - } - ite.next = null; - - return copyHead; - } -} diff --git a/problems/src/design/EncodeAndDecodeTinyURL.java b/problems/src/design/EncodeAndDecodeTinyURL.java deleted file mode 100644 index fb9b8001..00000000 --- a/problems/src/design/EncodeAndDecodeTinyURL.java +++ /dev/null @@ -1,44 +0,0 @@ -package design; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by gouthamvidyapradhan on 11/04/2017. - TinyURL is a URL shortening service where you enter a URL such as https://leetcode.com/problems/design-tinyurl and it returns a short URL such as http://tinyurl.com/4e9iAk. - - Design the encode and decode methods for the TinyURL service. There is no restriction on how your encode/decode algorithm should work. You just need to ensure that a URL can be encoded to a tiny URL and the tiny URL can be decoded to the original URL. - - */ -public class EncodeAndDecodeTinyURL -{ - private List list = new ArrayList<>(); - private static final String URL = "http://tinyurl.com/"; - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - EncodeAndDecodeTinyURL encoder = new EncodeAndDecodeTinyURL(); - String shorterUrl = encoder.encode("https://leetcode.com/problems/design-tinyurl"); - System.out.println(encoder.decode(shorterUrl)); - } - - // Encodes a URL to a shortened URL. - public String encode(String longUrl) - { - list.add(longUrl); - return URL.concat(String.valueOf(list.size())); - } - - // Decodes a shortened URL to its original URL. - public String decode(String shortUrl) - { - String[] parts = shortUrl.split("http://tinyurl.com/"); - String code = parts[1]; - return list.get(Integer.parseInt(code) - 1); - } - -} diff --git a/problems/src/design/LFUCache.java b/problems/src/design/LFUCache.java deleted file mode 100644 index d8e6b0f6..00000000 --- a/problems/src/design/LFUCache.java +++ /dev/null @@ -1,254 +0,0 @@ -package design; - -import java.util.*; - -/** - * Created by gouthamvidyapradhan on 20/03/2017. - Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the following operations: get and put. - - get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. - put(key, value) - Set or insert the value if the key is not already present. When the cache reaches its capacity, it should invalidate the least frequently used item before inserting a new item. For the purpose of this problem, when there is a tie (i.e., two or more keys that have the same frequency), the least recently used key would be evicted. - - Follow up: - Could you do both operations in O(1) time complexity? - - Example: - - LFUCache cache = new LFUCache( 2 /* capacity */ /*) - - cache.put(1, 1); - cache.put(2, 2); - cache.get(1); // returns 1 - cache.put(3, 3); // evicts key 2 - cache.get(2); // returns -1 (not found) - cache.get(3); // returns 3. - cache.put(4, 4); // evicts key 1. - cache.get(1); // returns -1 (not found) - cache.get(3); // returns 3 - cache.get(4); // returns 4 - */ -public class LFUCache -{ - private class Node - { - int frequency; - Node prev; - Node next; - LinkedHashSet hashSet; - Node(int frequency, - LinkedHashSet hashSet) - { - this.frequency = frequency; - this.hashSet = hashSet; - prev = null; - next = null; - } - } - - - private int capacity; - private int currentSize; - private Map cache; - private Map fMap; //frequency - private Node head; - /** - * Main method - * @param args - */ - public static void main(String[] args) - { - LFUCache cache1 = new LFUCache(2); - cache1.put(1, 1); - cache1.put(2, 2); - System.out.println(cache1.get(1)); - cache1.put(3, 3); - System.out.println(cache1.get(2)); - //System.out.println(cache1.get(3)); - cache1.put(4, 4); - System.out.println(cache1.get(1)); - System.out.println(cache1.get(3)); - System.out.println(cache1.get(4)); - System.out.println(cache1.get(1)); - System.out.println(cache1.get(4)); - System.out.println(cache1.get(2)); - cache1.put(4, 4); - cache1.put(5, 4); - cache1.put(1, 9); - cache1.put(7, 1); - cache1.put(4, 2); - System.out.println(cache1.get(1)); - System.out.println(cache1.get(4)); - System.out.println(cache1.get(7)); - //System.out.println(cache1.get(3)); - //System.out.println(cache1.get(4)); - } - - public LFUCache(int capacity) - { - currentSize = 0; - this.capacity = capacity; - cache = new HashMap<>(); - fMap = new HashMap<>(); - } - - /** - * Remove node and delink - * @param node Node - */ - private void popNode(Node node) - { - if(node.prev != null && node.next != null) - { - node.prev.next = node.next; - node.next.prev = node.prev; - } - else if(node.prev == null) - { - node.next.prev = null; - node.next = null; - } - else - { - node.prev.next = null; - node.prev = null; - } - } - - /** - * Get value - * @param key key - * @return value - */ - public int get(int key) - { - if(!cache.containsKey(key)) return -1; - fMap.put(key, update(key)); - return cache.get(key); - } - - /** - * Update fMap - * @param key key - */ - private Node update(int key) - { - Node node = fMap.get(key); - node.hashSet.remove(key); - Node newNode; - if(node.next == null) - { - newNode = makeNewNode(key, node.frequency + 1); - node.next = newNode; - newNode.prev = node; - } - else if(node.next.frequency == node.frequency + 1) - { - node.next.hashSet.add(key); - newNode = node.next; - } - else - { - newNode = makeNewNode(key, node.frequency + 1); - node.next.prev = newNode; - newNode.next = node.next; - newNode.prev = node; - node.next = newNode; - } - if(node.equals(head)) - incrementHead(); - else if(node.hashSet.isEmpty()) - popNode(node); - return newNode; - } - /** - * Make new node - * @param key key - * @param frequency frequency - * @return Node - */ - private Node makeNewNode(int key, int frequency) - { - LinkedHashSet linkedHashSet = new LinkedHashSet<>(); - linkedHashSet.add(key); - return new Node(frequency, linkedHashSet); - } - - /** - * Add new head - * @param key key - * @param frequency frequency - */ - private Node addHead(int key, int frequency) - { - if(head == null) - head = makeNewNode(key, frequency); - else if(head.frequency > frequency) - { - Node node = makeNewNode(key, frequency); - node.next = head; - head.prev = node; - head = node; - } - else head.hashSet.add(key); - return head; - } - /** - * Increment head - */ - private void incrementHead() - { - if(head.hashSet.isEmpty()) - { - head = head.next; - if(head != null) - { - head.prev.next = null; - head.prev = null; - } - } - } - - /** - * Put key value pair - * @param key key - * @param value value - */ - public void put(int key, int value) - { - if(capacity != 0) - { - if(cache.containsKey(key)) - { - fMap.put(key, update(key)); //update existing - cache.put(key, value); - } - else - { - if(currentSize == capacity) - { - evict(); - cache.put(key, value); - fMap.put(key, addHead(key, 1)); - } - else - { - fMap.put(key, addHead(key, 1)); //add new head - cache.put(key, value); - currentSize++; - } - } - } - } - - /** - * Evict the node with least frequency - */ - private void evict() - { - int key = head.hashSet.iterator().next(); - head.hashSet.remove(key); - cache.remove(key); - fMap.remove(key); - incrementHead(); - } -} diff --git a/problems/src/design/LRUCache.java b/problems/src/design/LRUCache.java deleted file mode 100644 index 7838106a..00000000 --- a/problems/src/design/LRUCache.java +++ /dev/null @@ -1,161 +0,0 @@ -package design; - -import java.util.*; - -/** - * Created by gouthamvidyapradhan on 18/03/2017. - Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put. - - get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. - put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item. - - Follow up: - Could you do both operations in O(1) time complexity? - - Example: - - LRUCache cache = new LRUCache( 2 /* capacity */ /*); - - cache.put(1, 1); - cache.put(2, 2); - cache.get(1); // returns 1 - cache.put(3, 3); // evicts key 2 - cache.get(2); // returns -1 (not found) - cache.put(4, 4); // evicts key 1 - cache.get(1); // returns -1 (not found) - cache.get(3); // returns 3 - cache.get(4); // returns 4 - Show Company Tags - Show Tags - Show Similar Problems - - */ -public class LRUCache -{ - public static class DLinkList - { - int key, value; - DLinkList left; - DLinkList right; - DLinkList(int key, int value) - { - this.key = key; - this.value = value; - left = null; - right = null; - } - } - - private Map cache; - private DLinkList head, tail; - private int capacity, currentSize; - - /** - * Pop head node - * @return - */ - private DLinkList popHead() - { - if(!head.right.equals(tail)) - { - DLinkList node = head.right; - head.right = node.right; - node.right.left = head; - node.right = null; - node.left = null; - return node; - } - return null; - } - - /** - * Push to tail - * @param node - */ - private void offer(DLinkList node) - { - tail.left.right = node; - node.left = tail.left; - node.right = tail; - tail.left = node; - } - - /** - * Move node to tail - * @param node - */ - private void moveToTail(DLinkList node) - { - node.left.right = node.right; - node.right.left = node.left; - offer(node); - } - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - LRUCache cache = new LRUCache(2); - cache.put(1, 1); - cache.put(2, 2); - System.out.println(cache.get(1)); - cache.put(3,3); - System.out.println(cache.get(2)); - cache.put(4, 4); - System.out.println(cache.get(1)); - System.out.println(cache.get(3)); - System.out.println(cache.get(4)); - } - - public LRUCache(int capacity) - { - this.capacity = capacity; - this.currentSize = 0; - cache = new HashMap<>(); - head = new DLinkList(-1, -1); - tail = new DLinkList(-1, -1); - head.right = tail; - tail.left = head; - } - - public int get(int key) - { - if(cache.get(key) == null) return -1; - DLinkList node = cache.get(key); - moveToTail(node); - return node.value; - } - - public void put(int key, int value) - { - if(cache.containsKey(key)) - { - DLinkList node = cache.get(key); - node.value = value; - moveToTail(node); - } - else - { - if(capacity == currentSize) - { - DLinkList head = popHead(); - if(head != null) - { - cache.remove(head.key); - DLinkList node = new DLinkList(key, value); - offer(node); - cache.put(key, node); - } - } - else - { - DLinkList node = new DLinkList(key, value); - offer(node); - cache.put(key, node); - ++currentSize; - } - } - } -} diff --git a/problems/src/design/RandomizedSet.java b/problems/src/design/RandomizedSet.java deleted file mode 100644 index f675c9b9..00000000 --- a/problems/src/design/RandomizedSet.java +++ /dev/null @@ -1,117 +0,0 @@ -package design; - -import java.util.*; - -/** - * Created by gouthamvidyapradhan on 23/03/2017. - Design a data structure that supports all following operations in average O(1) time. - - insert(val): Inserts an item val to the set if not already present. - remove(val): Removes an item val from the set if present. - getRandom: Returns a random element from current set of elements. Each element must have the same probability of being returned. - Example: - - // Init an empty set. - RandomizedSet randomSet = new RandomizedSet(); - - // Inserts 1 to the set. Returns true as 1 was inserted successfully. - randomSet.insert(1); - - // Returns false as 2 does not exist in the set. - randomSet.remove(2); - - // Inserts 2 to the set, returns true. Set now contains [1,2]. - randomSet.insert(2); - - // getRandom should return either 1 or 2 randomly. - randomSet.getRandom(); - - // Removes 1 from the set, returns true. Set now contains [2]. - randomSet.remove(1); - - // 2 was already in the set, so return false. - randomSet.insert(2); - - // Since 2 is the only number in the set, getRandom always return 2. - randomSet.getRandom(); - */ -public class RandomizedSet -{ - private Map map; - private List list; - private Random random; - /** Initialize your data structure here. */ - public RandomizedSet() - { - map = new HashMap<>(); - list = new ArrayList<>(); - random = new Random(); - } - - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - RandomizedSet rSet = new RandomizedSet(); - System.out.println(rSet.getRandom()); - System.out.println(rSet.insert(1)); - System.out.println(rSet.insert(2)); - System.out.println(rSet.insert(2)); - System.out.println(rSet.insert(3)); - System.out.println(rSet.remove(2)); - System.out.println(rSet.insert(2)); - System.out.println(rSet.getRandom()); - System.out.println(rSet.insert(234)); - System.out.println(rSet.insert(23)); - System.out.println(rSet.insert(22)); - System.out.println(rSet.getRandom()); - System.out.println(rSet.remove(245)); - System.out.println(rSet.remove(234)); - System.out.println(rSet.getRandom()); - } - - /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */ - public boolean insert(int val) - { - if(!map.keySet().contains(val)) - { - int pos = list.size(); - map.put(val, pos); - list.add(val); - return true; - } - return false; - } - - /** Removes a value from the set. Returns true if the set contained the specified element. */ - public boolean remove(int val) - { - if(map.containsKey(val)) - { - int size = list.size(); - int posVal = map.get(val); - if(posVal < (size - 1)) - { - int last = list.get(size - 1); - map.put(last, posVal); - list.set(posVal, last); - } - map.remove(val); - list.remove(size - 1); - return true; - } - return false; - } - - /** Get a random element from the set. */ - public int getRandom() - { - /*if(list.size() == 0) return 0; - else if (list.size() == 1) return list.get(0);*/ - return list.get(random.nextInt(list.size() - 1)); - } - -} diff --git a/problems/src/design/SerializeDeserializeBinaryTree.java b/problems/src/design/SerializeDeserializeBinaryTree.java deleted file mode 100644 index c3251026..00000000 --- a/problems/src/design/SerializeDeserializeBinaryTree.java +++ /dev/null @@ -1,112 +0,0 @@ -package design; - -import java.util.*; - -/** - * Created by gouthamvidyapradhan on 11/03/2017. - Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment. - - Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure. - - For example, you may serialize the following tree - - 1 - / \ - 2 3 - / \ - 4 5 - as "[1,2,3,null,null,4,5]", just the same as how LeetCode OJ serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself. - Note: Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms should be stateless. - - */ -public class SerializeDeserializeBinaryTree -{ - public static class TreeNode - { - int val; - TreeNode left; - TreeNode right; - TreeNode(int x) { val = x; } - } - - private static final String NULL = "X"; - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - TreeNode root = new TreeNode(1); - TreeNode two = new TreeNode(2); - TreeNode three = new TreeNode(3); - TreeNode four = new TreeNode(4); - TreeNode five = new TreeNode(5); - TreeNode six = new TreeNode(6); - TreeNode seven = new TreeNode(7); - TreeNode eight = new TreeNode(8); - TreeNode nine = new TreeNode(9); - TreeNode ten = new TreeNode(10); - root.left = null; - root.right = two; - two.left = three; - three.left = four; - four.right = five; - five.right = six; - six.left = seven; - seven.left = eight; - eight.right = nine; - nine.right = ten; - String serializedStr = new SerializeDeserializeBinaryTree().serialize(root); - - TreeNode result = new SerializeDeserializeBinaryTree().deserialize(serializedStr); - } - - // Encodes a tree to a single string. - public String serialize(TreeNode root) - { - if(root == null) return null; - List list = new ArrayList<>(); - encode(root, list); - StringBuilder sb = new StringBuilder(); - sb.append(list.get(0)); - for(int i = 1, l = list.size(); i < l; i++) - { - sb.append(",").append(list.get(i)); - } - return sb.toString(); - } - - private void encode(TreeNode root, List list) - { - if(root == null) list.add(NULL); - else - { - list.add(String.valueOf(root.val)); - encode(root.left, list); - encode(root.right, list); - } - } - - // Decodes your encoded data to tree. - public TreeNode deserialize(String data) - { - if(data == null || data.isEmpty()) return null; - StringTokenizer st = new StringTokenizer(data, ","); - Queue queue = new ArrayDeque<>(); - while(st.hasMoreTokens()) - queue.offer(st.nextToken()); - return decode(queue); - } - - private TreeNode decode(Queue queue) - { - String node = queue.poll(); - if(node.equals(NULL)) - return null; - TreeNode root = new TreeNode(Integer.parseInt(node)); - root.left = decode(queue); - root.right = decode(queue); - return root; - } -} diff --git a/problems/src/design/Twitter.java b/problems/src/design/Twitter.java deleted file mode 100644 index d56c3bc2..00000000 --- a/problems/src/design/Twitter.java +++ /dev/null @@ -1,204 +0,0 @@ -package design; - -import java.util.*; - -/** - * Created by gouthamvidyapradhan on 18/03/2017. - Design a simplified version of Twitter where users can post tweets, follow/unfollow another user and is able to see the 10 most recent tweets in the user's news feed. Your design should support the following methods: - - postTweet(userId, tweetId): Compose a new tweet. - getNewsFeed(userId): Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. - follow(followerId, followeeId): Follower follows a followee. - unfollow(followerId, followeeId): Follower unfollows a followee. - Example: - - Twitter twitter = new Twitter(); - - // User 1 posts a new tweet (id = 5). - twitter.postTweet(1, 5); - - // User 1's news feed should return a list with 1 tweet id -> [5]. - twitter.getNewsFeed(1); - - // User 1 follows user 2. - twitter.follow(1, 2); - - // User 2 posts a new tweet (id = 6). - twitter.postTweet(2, 6); - - // User 1's news feed should return a list with 2 tweet ids -> [6, 5]. - // Tweet id 6 should precede tweet id 5 because it is posted after tweet id 5. - twitter.getNewsFeed(1); - - // User 1 unfollows user 2. - twitter.unfollow(1, 2); - - // User 1's news feed should return a list with 1 tweet id -> [5], - // since user 1 is no longer following user 2. - twitter.getNewsFeed(1); - */ -public class Twitter -{ - class User - { - int id; - Set follow = new HashSet<>(); - Queue tweets = new ArrayDeque<>(); - User(int id) - { - this.id = id; - } - public void follow(int id) - { - follow.add(id); - } - public void addTweet(Tweet t) - { - if(tweets.size() == 10) - { - tweets.poll(); - } - tweets.offer(t); - } - public void unFollow(int id) - { - follow.remove(id); - } - - public Set getFollow() { - return follow; - } - - public Queue getTweets() { - return tweets; - } - } - - class Tweet - { - int id; - long time; - Tweet(int id, long time) - { - this.id = id; - this.time = time; - } - } - - private Map userMap; - private Map tweetMap; - private static long tweetCount = 0L; - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - Twitter twitter = new Twitter(); - twitter.postTweet(1, 5); - twitter.follow(1, 1); - System.out.println(twitter.getNewsFeed(1)); - /*twitter.follow(2, 1); - System.out.println(twitter.getNewsFeed(2)); - //twitter.unfollow(2, 1); - twitter.postTweet(2, 3); - System.out.println(twitter.getNewsFeed(1)); - System.out.println(twitter.getNewsFeed(2)); - twitter.follow(1, 2); - System.out.println(twitter.getNewsFeed(1)); - twitter.unfollow(2, 1); - System.out.println(twitter.getNewsFeed(2)); - System.out.println(twitter.getNewsFeed(1)); - //twitter.getNewsFeed(2); - */ - } - - /** Initialize your data structure here. */ - public Twitter() - { - userMap = new HashMap<>(); - tweetMap = new HashMap<>(); - } - - /** Compose a new tweet. */ - public void postTweet(int userId, int tweetId) - { - User user = userMap.get(userId); - if(user == null) - { - user = new User(userId); - userMap.put(userId, user); - } - user.addTweet(new Tweet(tweetId, tweetCount++)); - } - - /** Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. */ - public List getNewsFeed(int userId) - { - User user = userMap.get(userId); - List result = new ArrayList<>(); - if(user == null) return result; - Set follwers = user.getFollow(); - if(follwers != null) - { - List tweets = new ArrayList<>(); - tweets.addAll(user.getTweets()); - for(Integer i : follwers) - { - User f = userMap.get(i); - if(f != null) - { - tweets.addAll(f.getTweets()); - } - } - Comparator comparator = new Comparator() { - @Override - public int compare(Tweet o1, Tweet o2) { - return Long.compare(o2.time, o1.time); - } - }; - - Collections.sort(tweets, comparator); - - for(int i = 0; i < 10; i ++) - { - if(i >= tweets.size()) - break; - result.add(tweets.get(i).id); - } - } - return result; - } - - /** Follower follows a followee. If the operation is invalid, it should be a no-op. */ - public void follow(int followerId, int followeeId) - { - if(followerId == followeeId) return; - User user = userMap.get(followerId); - if(user == null) - user = new User(followerId); - userMap.put(followerId, user); - if(userMap.get(followeeId) != null) - { - user.follow(userMap.get(followeeId).id); - } - else - { - User newUser = new User(followeeId); - userMap.put(followeeId, newUser); - user.follow(userMap.get(followeeId).id); - } - } - - /** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */ - public void unfollow(int followerId, int followeeId) - { - User user = userMap.get(followerId); - if(user != null) - { - user.unFollow(followeeId); - } - } - -} diff --git a/problems/src/divide_and_conquer/KthLargestElementInAnArray.java b/problems/src/divide_and_conquer/KthLargestElementInAnArray.java deleted file mode 100644 index 7d2b44db..00000000 --- a/problems/src/divide_and_conquer/KthLargestElementInAnArray.java +++ /dev/null @@ -1,63 +0,0 @@ -package divide_and_conquer; - -/** - * Created by gouthamvidyapradhan on 09/03/2017. - Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element. - - For example, - Given [3,2,1,5,6,4] and k = 2, return 5. - - Note: - You may assume k is always valid, 1 ≤ k ≤ array's length. - */ -public class KthLargestElementInAnArray -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] nums = {3,2,1,5,6,4}; - - System.out.println(new KthLargestElementInAnArray().findKthLargest(nums, 6)); - } - - private int findKthLargest(int[] nums, int k) - { - return solve(nums, 0, nums.length - 1, k); - } - - private int solve(int[] nums, int pIndex, int end, int k) - { - int pivot = nums[end]; - int temp; - int start = pIndex; - for(int i = pIndex; i < end; i ++) - { - if(nums[i] <= pivot) - { - temp = nums[i]; - nums[i] = nums[pIndex]; - nums[pIndex] = temp; - pIndex += 1; - } - } - temp = nums[pIndex]; - nums[pIndex] = nums[end]; - nums[end] = temp; - - int pos = (end - pIndex) + 1; - if(pos == k) return nums[pIndex]; - else if(pos > k) - { - return solve(nums, pIndex + 1, end, k); - } - else - { - return solve(nums, start, pIndex - 1, k - pos); - } - } - -} diff --git a/problems/src/divide_and_conquer/SearchA2DMatrix.java b/problems/src/divide_and_conquer/SearchA2DMatrix.java deleted file mode 100644 index fb533803..00000000 --- a/problems/src/divide_and_conquer/SearchA2DMatrix.java +++ /dev/null @@ -1,59 +0,0 @@ -package divide_and_conquer; - -/** - * Created by gouthamvidyapradhan on 09/03/2017. - Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties: - - Integers in each row are sorted in ascending from left to right. - Integers in each column are sorted in ascending from top to bottom. - For example, - - Consider the following matrix: - - [ - [1, 4, 7, 11, 15], - [2, 5, 8, 12, 19], - [3, 6, 9, 16, 22], - [10, 13, 14, 17, 24], - [18, 21, 23, 26, 30] - ] - Given target = 5, return true. - - Given target = 20, return false. - */ -public class SearchA2DMatrix -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[][] matrix = - { - {1,3,5,7,9} , //1, 3, 5, 7, 9 - {2,4,6,8,10}, //2, 4, 6, 8, 10 - {11,13,15,17,19}, //11, 15, 17, 18, 19 - {12,14,16,18,20}, //13, 20, 21, 22, 23 - {21,22,23,24,25} //14, 25, 26, 27, 28 - }; - - System.out.println(new SearchA2DMatrix().searchMatrix(matrix, 11)); - } - - private boolean searchMatrix(int[][] matrix, int target) - { - if(matrix.length == 0) return false; - int M = matrix.length; - int N = matrix[0].length; - int r = 0, c = N - 1; - while(r < M && c >= 0) - { - if(matrix[r][c] == target) return true; - else if(target < matrix[r][c]) --c; - else if(target > matrix[r][c]) r++; - } - return false; - } -} diff --git a/problems/src/dynamic_programming/BestTimeToBuyAndSellStocks.java b/problems/src/dynamic_programming/BestTimeToBuyAndSellStocks.java deleted file mode 100644 index 1d312863..00000000 --- a/problems/src/dynamic_programming/BestTimeToBuyAndSellStocks.java +++ /dev/null @@ -1,49 +0,0 @@ -package dynamic_programming; - -/** - * Created by gouthamvidyapradhan on 17/03/2017. - Say you have an array for which the ith element is the price of a given stock on day i. - - If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit. - - Example 1: - Input: [7, 1, 5, 3, 6, 4] - Output: 5 - - max. difference = 6-1 = 5 (not 7-1 = 6, as selling price needs to be larger than buying price) - Example 2: - Input: [7, 6, 4, 3, 1] - Output: 0 - - In this case, no transaction is done, i.e. max profit = 0. - */ -public class BestTimeToBuyAndSellStocks -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] prices = {1, 1, 1, 1, 1}; - System.out.println(new BestTimeToBuyAndSellStocks().maxProfit(prices)); - } - - public int maxProfit(int[] prices) - { - if(prices.length == 0) return 0; - int[] max = new int[prices.length]; - max[prices.length - 1] = prices[prices.length - 1]; - for(int i = prices.length - 2; i >= 0; i --) - { - max[i] = Math.max(prices[i], max[i + 1]); - } - int result = Integer.MIN_VALUE; - for(int i = 0, l = max.length; i < l; i ++) - { - result = Math.max(result, max[i] - prices[i]); - } - return result; - } -} diff --git a/problems/src/dynamic_programming/ClimbingStairs.java b/problems/src/dynamic_programming/ClimbingStairs.java deleted file mode 100644 index d886fd3c..00000000 --- a/problems/src/dynamic_programming/ClimbingStairs.java +++ /dev/null @@ -1,34 +0,0 @@ -package dynamic_programming; - -/** - * Created by gouthamvidyapradhan on 01/04/2017. - You are climbing a stair case. It takes n steps to reach to the top. - - Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? - - Note: Given n will be a positive integer. - */ -public class ClimbingStairs -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - - } - - public int climbStairs(int n) - { - if(n == 0 || n == 1) return 1; - int[] A = new int[n + 1]; - A[n] = 1; - A[n - 1] = 1; - for(int i = n - 2; i >= 0; i --) - A[i] = A[i + 1] + A[i + 2]; - return A[0]; - } - -} diff --git a/problems/src/dynamic_programming/CoinChange2.java b/problems/src/dynamic_programming/CoinChange2.java deleted file mode 100644 index 275e02a5..00000000 --- a/problems/src/dynamic_programming/CoinChange2.java +++ /dev/null @@ -1,65 +0,0 @@ -package dynamic_programming; - -import java.util.Arrays; - -/** - * Created by gouthamvidyapradhan on 22/03/2017. - You are given coins of different denominations and a total amount of money. Write a function to compute the number of combinations that make up that amount. You may assume that you have infinite number of each kind of coin. - - Note: You can assume that - - 0 <= amount <= 5000 - 1 <= coin <= 5000 - the number of coins is less than 500 - the answer is guaranteed to fit into signed 32-bit integer - Example 1: - - Input: amount = 5, coins = [1, 2, 5] - Output: 4 - Explanation: there are four ways to make up the amount: - 5=5 - 5=2+2+1 - 5=2+1+1+1 - 5=1+1+1+1+1 - Example 2: - - Input: amount = 3, coins = [2] - Output: 0 - Explanation: the amount of 3 cannot be made up just with coins of 2. - Example 3: - - Input: amount = 10, coins = [10] - Output: 1 - */ -public class CoinChange2 -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] coins = {1,2,5}; - System.out.println(new CoinChange2().change(5, coins)); - } - - public int change(int amount, int[] coins) - { - int[][] dp = new int[coins.length][amount + 1]; - for(int i = 0, l = coins.length; i < l; i ++) - Arrays.fill(dp[i], -1); - return dp(dp, 0, coins, coins.length, amount); - } - - private int dp(int[][] dp, int i, int[] coins, int l, int n) - { - if(n == 0) return 1; - else if(i >= l) return 0; - if(n < 0) return 0; - if(dp[i][n] != -1) return dp[i][n]; - dp[i][n] = dp(dp, i + 1, coins, l, n) + dp(dp, i, coins, l, n - coins[i]); - return dp[i][n]; - } - -} diff --git a/problems/src/dynamic_programming/DecodeWays.java b/problems/src/dynamic_programming/DecodeWays.java deleted file mode 100644 index 95dffb39..00000000 --- a/problems/src/dynamic_programming/DecodeWays.java +++ /dev/null @@ -1,56 +0,0 @@ -package dynamic_programming; - -/** - * Created by gouthamvidyapradhan on 01/04/2017. - A message containing letters from A-Z is being encoded to numbers using the following mapping: - - 'A' -> 1 - 'B' -> 2 - ... - 'Z' -> 26 - Given an encoded message containing digits, determine the total number of ways to decode it. - - For example, - Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12). - - The number of ways decoding "12" is 2. - */ -public class DecodeWays -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - System.out.println(new DecodeWays().numDecodings("3120")); - } - - public int numDecodings(String s) - { - if(s == null || s.isEmpty()) return 0; - int[] dp = new int[s.length() + 2]; - dp[s.length()] = 1; - dp[s.length() + 1] = 1; - for(int i = s.length() - 1; i >= 0; i --) - { - for(int j = i + 1; j < i + 3; j ++) - { - if(j <= s.length()) - { - String subStr = s.substring(i, j); - if(!subStr.startsWith("0")) - { - int intVal = Integer.parseInt(subStr); - if(intVal <= 26) - { - dp[i] += dp[j]; - } - } - } - } - } - return dp[0]; - } -} diff --git a/problems/src/dynamic_programming/HouseRobber.java b/problems/src/dynamic_programming/HouseRobber.java deleted file mode 100644 index aa4ccfdd..00000000 --- a/problems/src/dynamic_programming/HouseRobber.java +++ /dev/null @@ -1,35 +0,0 @@ -package dynamic_programming; - -/** - * Created by pradhang on 4/3/2017. - You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night. - - Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police. - */ -public class HouseRobber -{ - private int[] max; - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - - } - - public int rob(int[] nums) - { - if(nums.length == 0) return 0; - max = new int[nums.length]; - if(nums.length == 1) return nums[0]; - max[nums.length - 1] = nums[nums.length - 1]; - max[nums.length - 2] = Math.max(nums[nums.length - 1], nums[nums.length - 2]); - for(int i = nums.length - 3; i >= 0; i --) - { - max[i] = Math.max(max[i + 1], nums[i] + max[i + 2]); - } - return max[0]; - } -} diff --git a/problems/src/dynamic_programming/LongestIncreasingSubsequence.java b/problems/src/dynamic_programming/LongestIncreasingSubsequence.java deleted file mode 100644 index 4a1bf4aa..00000000 --- a/problems/src/dynamic_programming/LongestIncreasingSubsequence.java +++ /dev/null @@ -1,46 +0,0 @@ -package dynamic_programming; - -/** - * Created by gouthamvidyapradhan on 02/04/2017. - Given an unsorted array of integers, find the length of longest increasing subsequence. - - For example, - Given [10, 9, 2, 5, 3, 7, 101, 18], - The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length. - - Your algorithm should run in O(n2) complexity. - - Follow up: Could you improve it to O(n log n) time complexity? - */ -public class LongestIncreasingSubsequence -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] nums = {9, 8, 7, 6}; - System.out.println(new LongestIncreasingSubsequence().lengthOfLIS(nums)); - } - - public int lengthOfLIS(int[] nums) - { - if(nums.length == 0) return 0; - int[] A = new int[nums.length]; - int max = Integer.MIN_VALUE; - for(int i = 0, l = nums.length; i < l; i ++) - { - int lis = 1; - for(int j = 0; j < i; j ++) - { - if(nums[i] > nums[j]) - lis = Math.max(lis, A[j] + 1); - } - A[i] = lis; - max = Math.max(max, A[i]); - } - return max; - } -} diff --git a/problems/src/dynamic_programming/LongestPaliandromicSubstring.java b/problems/src/dynamic_programming/LongestPaliandromicSubstring.java deleted file mode 100644 index 33b92216..00000000 --- a/problems/src/dynamic_programming/LongestPaliandromicSubstring.java +++ /dev/null @@ -1,71 +0,0 @@ -package dynamic_programming; - -/** - * Created by gouthamvidyapradhan on 24/02/2017. - Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000. - - Example: - - Input: "babad" - - Output: "bab" - - Note: "aba" is also a valid answer. - Example: - - Input: "cbbd" - - Output: "bb" - */ -public class LongestPaliandromicSubstring -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - System.out.println(new LongestPaliandromicSubstring().longestPalindrome("forgeeksskeegfor")); - } - - public String longestPalindrome(String s) - { - int l = s.length(); - int startIndex = 0; int maxLen = 1; - boolean[][] A = new boolean[l][l]; - for(int i = 0, j = 0; i < l; i++, j++) - A[i][j] = true; - - for(int i = 0, j = i + 1; j < l; i++, j++) - { - if(s.charAt(i) == s.charAt(j)) - { - A[i][j] = true; - startIndex = i; - maxLen = 2; - } - } - - for(int k = 3; k <= l; k++) - { - for(int i = 0, j = k - 1; j < l; i++, j++) - { - if(s.charAt(i) == s.charAt(j)) - { - A[i][j] = A[i + 1][j - 1]; - if(A[i][j]) - { - if(k > maxLen) - { - startIndex = i; - maxLen = k; - } - } - } - } - } - - return s.substring(startIndex, startIndex + maxLen); - } -} diff --git a/problems/src/dynamic_programming/LongestPalindromicSubsequence.java b/problems/src/dynamic_programming/LongestPalindromicSubsequence.java deleted file mode 100644 index d00f7890..00000000 --- a/problems/src/dynamic_programming/LongestPalindromicSubsequence.java +++ /dev/null @@ -1,40 +0,0 @@ -package dynamic_programming; - -/** - * Created by gouthamvidyapradhan on 27/03/2017. - Given an unsorted array of integers, find the length of longest increasing subsequence. - - For example, - Given [10, 9, 2, 5, 3, 7, 101, 18], - The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length. - - Your algorithm should run in O(n2) complexity. - - Follow up: Could you improve it to O(n log n) time complexity? - */ -public class LongestPalindromicSubsequence -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - System.out.println(new LongestPalindromicSubsequence().longestPalindromeSubseq("bbbab")); - } - - public int longestPalindromeSubseq(String s) - { - int[][] dp = new int[s.length() + 1][s.length() + 1]; - String sI = new StringBuilder(s).reverse().toString(); - for(int i = 1, l = s.length(); i <= l; i++) - for(int j = 1; j <= l; j++) - { - dp[i][j] = (s.charAt(i - 1) == sI.charAt(j - 1)) ? dp[i - 1][j - 1] + 1 : Math.max(dp[i - 1][j], dp[i][j - 1]); - } - - return dp[s.length()][s.length()]; - } - -} diff --git a/problems/src/dynamic_programming/MaximumProductSubarray.java b/problems/src/dynamic_programming/MaximumProductSubarray.java deleted file mode 100644 index 0ed05cdc..00000000 --- a/problems/src/dynamic_programming/MaximumProductSubarray.java +++ /dev/null @@ -1,38 +0,0 @@ -package dynamic_programming; - -/** - * Created by gouthamvidyapradhan on 02/04/2017. - Find the contiguous subarray within an array (containing at least one number) which has the largest product. - - For example, given the array [2,3,-2,4], - the contiguous subarray [2,3] has the largest product = 6. - */ -public class MaximumProductSubarray -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] A = {2,3,-2,4}; - System.out.println(new MaximumProductSubarray().maxProduct(A)); - } - - public int maxProduct(int[] nums) - { - if(nums.length == 1) return nums[0]; - int min = nums[0]; - int max = nums[0]; - int result = max; - for(int i = 1; i < nums.length; i ++) - { - int prevMin = min, prevMax = max; - min = Math.min(nums[i], Math.min(nums[i] * prevMin, nums[i] * prevMax)); - max = Math.max(nums[i], Math.max(nums[i] * prevMin, nums[i] * prevMax)); - result = Math.max(result, max); - } - return result; - } -} diff --git a/problems/src/dynamic_programming/PalindromePartitioningII.java b/problems/src/dynamic_programming/PalindromePartitioningII.java deleted file mode 100644 index 83705149..00000000 --- a/problems/src/dynamic_programming/PalindromePartitioningII.java +++ /dev/null @@ -1,58 +0,0 @@ -package dynamic_programming; - -import java.util.Arrays; - -/** - * Created by pradhang on 4/3/2017. - Given a string s, partition s such that every substring of the partition is a palindrome. - - Return the minimum cuts needed for a palindrome partitioning of s. - - For example, given s = "aab", - Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut. - */ -public class PalindromePartitioningII -{ - private int A[]; - private boolean[][] paliandrome; - /** - * Main method - * @param args - */ - public static void main(String[] args) - { - System.out.println(new PalindromePartitioningII().minCut("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); - } - - public int minCut(String s) - { - if(s == null || s.isEmpty()) return 0; - A = new int[s.length()]; - Arrays.fill(A, Integer.MAX_VALUE); - char[] charArr = s.toCharArray(); - paliandrome = new boolean[charArr.length][charArr.length]; - return doNext(charArr, 0) - 1; - } - - private int doNext(char[] s, int p) - { - if(p >= s.length) return 0; - if(A[p] < Integer.MAX_VALUE) return A[p]; - for(int i = p, l = s.length; i < l; i ++ ) - { - if(p + 1 <= i - 1) - { - paliandrome[p][i] = (paliandrome[p+1][i-1] && (s[p] == s[i])); - } - else - { - paliandrome[p][i] = (i == p) || (s[i] == s[p]); - } - if(paliandrome[p][i]) - { - A[p] = Math.min(doNext(s, i + 1) + 1, A[p]); - } - } - return A[p]; - } -} diff --git a/problems/src/dynamic_programming/UniqueBinarySearchTrees.java b/problems/src/dynamic_programming/UniqueBinarySearchTrees.java deleted file mode 100644 index 922e7296..00000000 --- a/problems/src/dynamic_programming/UniqueBinarySearchTrees.java +++ /dev/null @@ -1,45 +0,0 @@ -package dynamic_programming; - -/** - * Created by gouthamvidyapradhan on 31/03/2017. - Given n, how many structurally unique BST's (binary search trees) that store values 1...n? - - For example, - Given n = 3, there are a total of 5 unique BST's. - - 1 3 3 2 1 - \ / / / \ \ - 3 2 1 1 3 2 - / / \ \ - 2 1 2 3 - - */ -public class UniqueBinarySearchTrees -{ - int[] dp; - /** - * Main method - * @param args - */ - public static void main(String[] args) throws Exception - { - System.out.println(new UniqueBinarySearchTrees().numTrees(5)); - } - - public int numTrees(int n) - { - dp = new int[n + 1]; - dp[0] = 1; - return dp(n); - } - - private int dp(int n) - { - if(dp[n] != 0) return dp[n]; - for(int i = 1; i <= n; i ++) - { - dp[n] += dp(n - i) * dp(n - (n - i) - 1); - } - return dp[n]; - } -} diff --git a/problems/src/dynamic_programming/UniqueBinarySearchTreesII.java b/problems/src/dynamic_programming/UniqueBinarySearchTreesII.java deleted file mode 100644 index e55c19fa..00000000 --- a/problems/src/dynamic_programming/UniqueBinarySearchTreesII.java +++ /dev/null @@ -1,120 +0,0 @@ -package dynamic_programming; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by gouthamvidyapradhan on 31/03/2017. - Given an integer n, generate all structurally unique BST's (binary search trees) that store values 1...n. - - For example, - Given n = 3, your program should return all 5 unique BST's shown below. - - 1 3 3 2 1 - \ / / / \ \ - 3 2 1 1 3 2 - / / \ \ - 2 1 2 3 - - */ -public class UniqueBinarySearchTreesII -{ - public static class TreeNode - { - int val; - TreeNode left; - TreeNode right; - TreeNode(int x) { val = x; } - } - - private List[][] dp; - - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - List list = new UniqueBinarySearchTreesII().generateTrees(3); - } - - public List generateTrees(int n) - { - if(n == 0) return new ArrayList<>(); - dp = new List[n + 1][n + 1]; - dp[0][0] = new ArrayList<>(); - for(int i = 1, j = 1; i <= n; i ++, j ++) - { - dp[i][j] = new ArrayList<>(); - dp[i][j].add(new TreeNode(i)); - } - return dp(1, n, n); - } - - private List dp(int s, int e, int n) - { - if(e < s) return null; - if(dp[s][e] != null) return dp[s][e]; - List result = new ArrayList<>(); - for(int i = s; i <= e; i ++) - { - List left = dp(s, i - 1, n); - List right = dp(i + 1, e, n); - List temp = new ArrayList<>(); - if(left != null) - { - for(TreeNode node : left) - { - TreeNode root = new TreeNode(i); - root.left = node; - temp.add(root); - } - } - if(right != null) - { - if(!temp.isEmpty()) - { - for(TreeNode root : temp) - { - for(TreeNode node : right) - { - TreeNode newRoot = clone(root); - newRoot.right = node; - result.add(newRoot); - } - } - } - else - { - for(TreeNode node : right) - { - TreeNode root = new TreeNode(i); - root.right = node; - result.add(root); - } - } - } - else if(!temp.isEmpty()) - { - result.addAll(temp); - } - } - dp[s][e] = result; - return result; - } - - /** - * Clone treeNode - * @param root rootnode - * @return cloned root - */ - private TreeNode clone(TreeNode root) - { - if(root == null) return null; - TreeNode newNode = new TreeNode(root.val); - newNode.left = clone(root.left); - newNode.right = clone(root.right); - return newNode; - } -} diff --git a/problems/src/dynamic_programming/WordBreak.java b/problems/src/dynamic_programming/WordBreak.java deleted file mode 100644 index 70968715..00000000 --- a/problems/src/dynamic_programming/WordBreak.java +++ /dev/null @@ -1,64 +0,0 @@ -package dynamic_programming; - -import java.util.*; - -/** - * Created by gouthamvidyapradhan on 16/03/2017. - Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words. You may assume the dictionary does not contain duplicate words. - - For example, given - s = "leetcode", - dict = ["leet", "code"]. - - Return true because "leetcode" can be segmented as "leet code". - */ -public class WordBreak -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - List dic = new ArrayList<>(); - String[] arr = {"a","aa","aaa","aaaa","aaaaa","aaaaaa","aaaaaaa","aaaaaaaa","aaaaaaaaa","aaaaaaaaaa"}; - for (String s : arr) - dic.add(s); - System.out.println(new WordBreak().wordBreak("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", dic)); - } - - public boolean wordBreak(String s, List wordDict) - { - Set dictionary = new HashSet<>(); - dictionary.addAll(wordDict); - Map dic = new HashMap<>(); - for(int i = s.length() - 1; i >= 0; i --) - dp(i, s, dic, dictionary); - return dic.get(0); - } - - private boolean dp(int i, String s, Map dic, Set dictionary) - { - if(i == s.length()) return true; - else if(dic.containsKey(i)) return dic.get(i); - else - { - for(int j = i, l = s.length(); j < l; j++) - { - String subStr = s.substring(i, j + 1); - if(dictionary.contains(subStr)) - { - if(dp(j + 1, s, dic, dictionary)) - { - dic.put(i, true); - break; - } - } - } - } - if(!dic.containsKey(i)) - dic.put(i, false); - return dic.get(i); - } -} diff --git a/problems/src/dynamic_programming/WordBreakII.java b/problems/src/dynamic_programming/WordBreakII.java deleted file mode 100644 index 6c99493d..00000000 --- a/problems/src/dynamic_programming/WordBreakII.java +++ /dev/null @@ -1,70 +0,0 @@ -package dynamic_programming; - -import java.util.*; - -/** - * Created by gouthamvidyapradhan on 07/04/2017. - Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, add spaces in s to construct a sentence where each word is a valid dictionary word. You may assume the dictionary does not contain duplicate words. - - Return all such possible sentences. - - For example, given - s = "catsanddog", - dict = ["cat", "cats", "and", "sand", "dog"]. - - A solution is ["cats and dog", "cat sand dog"]. - */ -public class WordBreakII -{ - private Map> map; - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - List wordList = new ArrayList<>(); - wordList.add("cat"); - wordList.add("cats"); - wordList.add("and"); - wordList.add("sand"); - wordList.add("dog"); - System.out.println(new WordBreakII().wordBreak("catsanddog", wordList)); - } - - public List wordBreak(String s, List wordDict) - { - if(s == null) return new ArrayList<>(); - map = new HashMap<>(); - Set dictionary = new HashSet<>(); - dictionary.addAll(wordDict); - return dp(0, s, s.length(), dictionary); - } - - private List dp(int p, String s, int l, Set dictionary) - { - List result = new ArrayList<>(); - if(p >= s.length()) - { - result.add(""); - return result; - } - else if(map.containsKey(p)) - { - return map.get(p); - } - for(int i = p; i < l; i ++) - { - String subStr = s.substring(p, i + 1); - if(dictionary.contains(subStr)) - { - List subList = dp(i + 1, s, l, dictionary); - for(String se : subList) - result.add((subStr + " " + se).trim()); - } - } - map.put(p, result); - return result; - } -} diff --git a/problems/src/greedy/JumpGame.java b/problems/src/greedy/JumpGame.java deleted file mode 100644 index 91b43b0f..00000000 --- a/problems/src/greedy/JumpGame.java +++ /dev/null @@ -1,40 +0,0 @@ -package greedy; - -/** - * Created by gouthamvidyapradhan on 17/03/2017. - Given an array of non-negative integers, you are initially positioned at the first index of the array. - - Each element in the array represents your maximum jump length at that position. - - Determine if you are able to reach the last index. - - For example: - A = [2,3,1,1,4], return true. - - A = [3,2,1,0,4], return false. - */ -public class JumpGame -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] nums = {1,2,1,0,4}; - System.out.println(new JumpGame().canJump(nums)); - } - - public boolean canJump(int[] nums) - { - if(nums.length == 0) return false; - int min = nums.length - 1, max = nums.length - 1; - for(int i = nums.length - 2; i >= 0; i --) - { - if((nums[i] + i) >= min) - min = i; - } - return (min == 0); - } -} diff --git a/problems/src/greedy/JumpGameII.java b/problems/src/greedy/JumpGameII.java deleted file mode 100644 index 7e45e13d..00000000 --- a/problems/src/greedy/JumpGameII.java +++ /dev/null @@ -1,46 +0,0 @@ -package greedy; - -/** - * Created by gouthamvidyapradhan on 02/04/2017. - Given an array of non-negative integers, you are initially positioned at the first index of the array. - - Each element in the array represents your maximum jump length at that position. - - Your goal is to reach the last index in the minimum number of jumps. - - For example: - Given array A = [2,3,1,1,4] - - The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.) - - Note: - You can assume that you can always reach the last index. - */ -public class JumpGameII -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - - } - - public int jump(int[] nums) - { - int step = 0; - int e = 0, max = 0; - for(int i = 0; i < nums.length - 1; i++) - { - max = Math.max(max, i + nums[i]); - if(i == e) - { - step++; - e = max; - } - } - return step; - } -} diff --git a/problems/src/hashing/Anagrams.java b/problems/src/hashing/Anagrams.java deleted file mode 100644 index 10fc0bf1..00000000 --- a/problems/src/hashing/Anagrams.java +++ /dev/null @@ -1,92 +0,0 @@ -package hashing; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Created by gouthamvidyapradhan on 25/02/2017. - Given a string s and a non-empty string p, find all the start indices of p's anagrams in s. - - Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100. - - The order of output does not matter. - - Example 1: - - Input: - s: "cbaebabacd" p: "abc" - - Output: - [0, 6] - - Explanation: - The substring with start index = 0 is "cba", which is an anagram of "abc". - The substring with start index = 6 is "bac", which is an anagram of "abc". - Example 2: - - Input: - s: "abab" p: "ab" - - Output: - [0, 1, 2] - - Explanation: - The substring with start index = 0 is "ab", which is an anagram of "ab". - The substring with start index = 1 is "ba", which is an anagram of "ab". - The substring with start index = 2 is "ab", which is an anagram of "ab". - */ -public class Anagrams -{ - int[] TC = new int[256]; - int[] PC = new int[256]; - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - List result = new Anagrams().findAnagrams("abab", "ab"); - result.forEach(System.out::print); - } - - public List findAnagrams(String s, String p) - { - List result = new ArrayList<>(); - int pLen = p.length(); - if(pLen > s.length()) return result; - Arrays.fill(TC, 0); - Arrays.fill(PC, 0); - for(int i = 0; i < pLen; i ++) - { - TC[s.charAt(i)]++; - PC[p.charAt(i)]++; - } - - int i = pLen; - for(int l = s.length(); i < l; i ++) - { - if(compare()) - result.add(i - pLen); - - TC[s.charAt(i)]++; - TC[s.charAt(i - pLen)]--; - } - if(compare()) - result.add(i - pLen); - - return result; - } - - private boolean compare() - { - for(int i = 0; i < 256; i ++) - { - if(TC[i] != PC[i]) - return false; - } - return true; - } - -} diff --git a/problems/src/hashing/GroupAnagrams.java b/problems/src/hashing/GroupAnagrams.java deleted file mode 100644 index 4b62b9c3..00000000 --- a/problems/src/hashing/GroupAnagrams.java +++ /dev/null @@ -1,72 +0,0 @@ -package hashing; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; - -/** - * Created by gouthamvidyapradhan on 10/03/2017. - Given an array of strings, group anagrams together. - - For example, given: ["eat", "tea", "tan", "ate", "nat", "bat"], - Return: - - [ - ["ate", "eat","tea"], - ["nat","tan"], - ["bat"] - ] - Note: All inputs will be in lower-case. - */ -public class GroupAnagrams -{ - private int[] A = new int[256]; - private HashMap> hashMap = new HashMap<>(); - private List> result = new ArrayList<>(); - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - String[] strs = {"huh", "tit"}; - - List> result = new GroupAnagrams().groupAnagrams(strs); - for (List l : result) - { - for(String s : l) - System.out.println(s); - System.out.println("-----"); - } - } - - public List> groupAnagrams(String[] strs) - { - for(int i = 0, l = strs.length; i < l; i ++) - { - Arrays.fill(A, 0); - String s = strs[i]; - for(int j = 0, sl = s.length(); j < sl; j ++) - A[s.charAt(j)]++; - - StringBuilder sb = new StringBuilder(); - for(int k = 0; k < 256; k ++) - { - if(A[k] != 0) - sb.append(k).append("").append(A[k]); - } - List value = hashMap.get(sb.toString()); - if(value == null) - value = new ArrayList<>(); - value.add(s); - hashMap.put(sb.toString(), value); - } - - for(String s : hashMap.keySet()) - result.add(hashMap.get(s)); - - return result; - } -} diff --git a/problems/src/hashing/KdiffPairsInanArray.java b/problems/src/hashing/KdiffPairsInanArray.java deleted file mode 100644 index 5d1b330d..00000000 --- a/problems/src/hashing/KdiffPairsInanArray.java +++ /dev/null @@ -1,65 +0,0 @@ -package hashing; - -import java.util.*; - -/** - * Created by gouthamvidyapradhan on 28/03/2017. - Given an array of integers and an integer k, you need to find the number of unique k-diff pairs in the array. Here a k-diff pair is defined as an integer pair (i, j), where i and j are both numbers in the array and their absolute difference is k. - - Example 1: - Input: [3, 1, 4, 1, 5], k = 2 - Output: 2 - Explanation: There are two 2-diff pairs in the array, (1, 3) and (3, 5). - Although we have two 1s in the input, we should only return the number of unique pairs. - Example 2: - Input:[1, 2, 3, 4, 5], k = 1 - Output: 4 - Explanation: There are four 1-diff pairs in the array, (1, 2), (2, 3), (3, 4) and (4, 5). - Example 3: - Input: [1, 3, 1, 5, 4], k = 0 - Output: 1 - Explanation: There is one 0-diff pair in the array, (1, 1). - Note: - The pairs (i, j) and (j, i) count as the same pair. - The length of the array won't exceed 10,000. - All the integers in the given input belong to the range: [-1e7, 1e7]. - */ -public class KdiffPairsInanArray -{ - private Map map = new HashMap<>(); - private int count = 0; - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] nums = {1,2,3,4,5}; - System.out.println(new KdiffPairsInanArray().findPairs(nums, -1)); - } - - public int findPairs(int[] nums, int k) - { - if(nums.length == 0 || k < 0) return 0; - for(int i : nums) - { - map.put(i, map.getOrDefault(i, 0) + 1); - } - for(Map.Entry entry : map.entrySet()) - { - if(k == 0) - { - if(entry.getValue() > 1) - count ++; - } - else - { - if(map.containsKey(entry.getKey() + k)) - count ++; - } - } - return count; - } - -} diff --git a/problems/src/hashing/SortCharByFrequency.java b/problems/src/hashing/SortCharByFrequency.java deleted file mode 100644 index cf4da160..00000000 --- a/problems/src/hashing/SortCharByFrequency.java +++ /dev/null @@ -1,95 +0,0 @@ -package hashing; - -import java.util.*; - -/** - * Created by gouthamvidyapradhan on 25/03/2017. - Given a string, sort it in decreasing order based on the frequency of characters. - - Example 1: - - Input: - "tree" - - Output: - "eert" - - Explanation: - 'e' appears twice while 'r' and 't' both appear once. - So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer. - Example 2: - - Input: - "cccaaa" - - Output: - "cccaaa" - - Explanation: - Both 'c' and 'a' appear three times, so "aaaccc" is also a valid answer. - Note that "cacaca" is incorrect, as the same characters must be together. - - Example 3: - - Input: - "Aabb" - - Output: - "bbAa" - - Explanation: - "bbaA" is also a valid answer, but "Aabb" is incorrect. - Note that 'A' and 'a' are treated as two different characters. - - */ -public class SortCharByFrequency -{ - class Freq - { - int i; - int c; - } - - private int[] buff = new int[256]; - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - System.out.println(new SortCharByFrequency().frequencySort("askdfkasdkfasdkljfklasdjfkl")); - } - - public String frequencySort(String s) - { - if(s == null || s.isEmpty()) return s; - Arrays.fill(buff, 0); - StringBuilder sb = new StringBuilder(); - for(int i = 0, l = s.length(); i < l; i ++) - buff[s.charAt(i)]++; - - List fList = new ArrayList<>(); - for(int i = 0; i < 256; i ++) - { - if(buff[i] > 0) - { - Freq f = new Freq(); - f.i = i; - f.c = buff[i]; - fList.add(f); - } - } - - Collections.sort(fList, (o1, o2) -> Integer.compare(o2.c, o1.c)); - - for(Freq f : fList) - { - char c = (char)f.i; - int freq = f.c; - while(freq-- > 0) - sb.append(c); - } - return sb.toString(); - } -} diff --git a/problems/src/hashing/TwoSum.java b/problems/src/hashing/TwoSum.java deleted file mode 100644 index 84ee1f30..00000000 --- a/problems/src/hashing/TwoSum.java +++ /dev/null @@ -1,75 +0,0 @@ -package hashing; - -import java.util.HashMap; - -/** - * Created by gouthamvidyapradhan on 09/03/2017. - Given an array of integers, return indices of the two numbers such that they add up to a specific target. - - You may assume that each input would have exactly one solution, and you may not use the same element twice. - - Example: - Given nums = [2, 7, 11, 15], target = 9, - - Because nums[0] + nums[1] = 2 + 7 = 9, - return [0, 1]. - */ -public class TwoSum -{ - HashMap map = new HashMap<>(); - - public int[] twoSum(int[] nums, int target) - { - int[] result = new int[2]; - - for(int i : nums) - { - if(map.keySet().contains(i)) - { - int count = map.get(i); - map.put(i, ++count); - } - else - { - map.put(i, 1); - } - } - - for(int i = 0, l = nums.length; i < l; i ++) - { - int ele = nums[i]; - int req = target - ele; - if(map.keySet().contains(req)) - { - result[0] = i; - if(ele == req) - { - int count = map.get(req); - if(count > 1) - { - for(int j = i + 1; j < l; j++) - { - if(nums[j] == req) - { - result[1] = j; - return result; - } - } - } - } - else - { - for(int j = i + 1; j < l; j++) - { - if(nums[j] == req) - { - result[1] = j; - return result; - } - } - } - } - } - return result; - } -} diff --git a/problems/src/hashing/ValidAnagram.java b/problems/src/hashing/ValidAnagram.java deleted file mode 100644 index 3b01751f..00000000 --- a/problems/src/hashing/ValidAnagram.java +++ /dev/null @@ -1,52 +0,0 @@ -package hashing; - -/** - * Created by gouthamvidyapradhan on 10/03/2017. - Given two strings s and t, write a function to determine if t is an anagram of s. - - For example, - s = "anagram", t = "nagaram", return true. - s = "rat", t = "car", return false. - - Note: - You may assume the string contains only lowercase alphabets. - - Follow up: - What if the inputs contain unicode characters? How would you adapt your solution to such case? - */ -public class ValidAnagram -{ - private int[] S = new int[256]; - private int[] T = new int[256]; - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - System.out.println(new ValidAnagram().isAnagram("anagram", "nagaram")); - } - - public boolean isAnagram(String s, String t) - { - if(s.length() != t.length()) return false; - - for(int i = 0, l = s.length(); i < l; i ++) - { - S[s.charAt(i)]++; - } - - for(int i = 0, l = t.length(); i < l; i ++) - { - T[t.charAt(i)]++; - } - - for(int i = 0; i < 256; i ++) - { - if(S[i] != T[i]) return false; - } - - return true; - } -} diff --git a/problems/src/heap/SlidingWindowMaximum.java b/problems/src/heap/SlidingWindowMaximum.java deleted file mode 100644 index f457524e..00000000 --- a/problems/src/heap/SlidingWindowMaximum.java +++ /dev/null @@ -1,74 +0,0 @@ -package heap; - -import java.util.ArrayDeque; -import java.util.Deque; - -/** - * Created by gouthamvidyapradhan on 10/03/2017. - Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. - - For example, - Given nums = [1,3,-1,-3,5,3,6,7], and k = 3. - - Window position Max - --------------- ----- - [1 3 -1] -3 5 3 6 7 3 - 1 [3 -1 -3] 5 3 6 7 3 - 1 3 [-1 -3 5] 3 6 7 5 - 1 3 -1 [-3 5 3] 6 7 5 - 1 3 -1 -3 [5 3 6] 7 6 - 1 3 -1 -3 5 [3 6 7] 7 - Therefore, return the max sliding window as [3,3,5,5,6,7]. - - Note: - You may assume k is always valid, ie: 1 ≤ k ≤ input array's size for non-empty array. - */ -public class SlidingWindowMaximum -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] a = {1, 3, 1, 2, 0, 5}; - int[] result = new SlidingWindowMaximum().maxSlidingWindow(a, 3); - for(int i : result) - System.out.print(i + " "); - } - - /** - * - * @param nums - * @param k - * @return - */ - public int[] maxSlidingWindow(int[] nums, int k) - { - int[] result = new int[nums.length - (k - 1)]; - - if(nums.length == 0) return new int[0]; - - Deque queue = new ArrayDeque<>(); - for(int i = 0, j = 0, l = nums.length; i < l; i ++) - { - int head = i - (k - 1); - if(head >= 0) - { - //remove out of range - if(queue.peek() != null && queue.peek() < head) - queue.poll(); - } - while(queue.peekLast() != null && nums[queue.peekLast()] <= nums[i]) - { - queue.pollLast(); - } - queue.offer(i); - if(i >= k - 1) - result[j++] = nums[queue.peek()]; - } - - return result; - } -} diff --git a/problems/src/linked_list/IntersectionOfTwoLists.java b/problems/src/linked_list/IntersectionOfTwoLists.java deleted file mode 100644 index 19cfbab6..00000000 --- a/problems/src/linked_list/IntersectionOfTwoLists.java +++ /dev/null @@ -1,105 +0,0 @@ -package linked_list; - -/** - * Created by gouthamvidyapradhan on 24/02/2017. - Write a program to find the node at which the intersection of two singly linked lists begins. - - - For example, the following two linked lists: - - A: a1 → a2 - ↘ - c1 → c2 → c3 - ↗ - B: b1 → b2 → b3 - begin to intersect at node c1. - - - Notes: - - If the two linked lists have no intersection at all, return null. - The linked lists must retain their original structure after the function returns. - You may assume there are no cycles anywhere in the entire linked structure. - Your code should preferably run in O(n) time and use only O(1) memory. - - */ -public class IntersectionOfTwoLists -{ - - public static class ListNode - { - int val; - ListNode next; - ListNode(int x) - { - val = x; - next = null; - } - } - - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - ListNode node1 = new ListNode(2); - ListNode node2 = new ListNode(3); - node1.next = node2; - System.out.println(new IntersectionOfTwoLists().getIntersectionNode(node1, node2)); - } - - public ListNode getIntersectionNode(ListNode headA, ListNode headB) - { - if(headA == null || headB == null) - return null; - - int l1len = 0, l2len = 0; - ListNode temp1 = headA; - while(temp1 != null) - { - temp1 = temp1.next; - l1len ++; - } - temp1 = headB; - - while(temp1 != null) - { - temp1 = temp1.next; - l2len ++; - } - - - int diff = Math.abs(l1len - l2len); - - ListNode temp2; - - if(l1len > l2len) - { - temp1 = headA; - temp2 = headB; - } - else - { - temp1 = headB; - temp2 = headA; - } - - while(diff != 0) - { - temp1 = temp1.next; - diff--; - } - while(!temp1.equals(temp2) ) - { - temp1 = temp1.next; - temp2 = temp2.next; - if(temp1 == null || temp2 == null) return null; - } - - if(temp1.equals(temp2)) - return temp1; - return null; - } -} diff --git a/problems/src/linked_list/LinkedListCycle.java b/problems/src/linked_list/LinkedListCycle.java deleted file mode 100644 index ec218f89..00000000 --- a/problems/src/linked_list/LinkedListCycle.java +++ /dev/null @@ -1,59 +0,0 @@ -package linked_list; - -import java.util.HashSet; -import java.util.Set; - -/** - * Created by gouthamvidyapradhan on 23/02/2017. - Given a linked list, determine if it has a cycle in it. - - Follow up: - Can you solve it without using extra space? - */ -public class LinkedListCycle -{ - private static Set hashCode = new HashSet<>(); - static class ListNode - { - int val; - ListNode next; - ListNode(int x) - { - val = x; - next = null; - } - } - - /** - * Main method - * @param args - */ - public static void main(String[] args) throws Exception - { - ListNode node1 = new ListNode(1); - ListNode node2 = new ListNode(2); - ListNode node3 = new ListNode(3); - node1.next = node2; - node2.next = node3; - node3.next = node1; - System.out.println(new LinkedListCycle().hasCycle(node1)); - } - - public boolean hasCycle(ListNode head) - { - ListNode slow = head; - ListNode fast = head; - while(slow != null && fast != null) - { - slow = slow.next; - fast = fast.next; - if(fast != null) - fast = fast.next; - else break; - if(fast != null && slow != null) - if(fast.equals(slow)) return true; - } - return false; - } - -} diff --git a/problems/src/linked_list/MergeKSortedLists.java b/problems/src/linked_list/MergeKSortedLists.java deleted file mode 100644 index c15b5a80..00000000 --- a/problems/src/linked_list/MergeKSortedLists.java +++ /dev/null @@ -1,111 +0,0 @@ -package linked_list; - -/** - * Created by gouthamvidyapradhan on 11/03/2017. - Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. - */ -public class MergeKSortedLists -{ - public static class ListNode - { - int val; - ListNode next; - ListNode(int x) - { - val = x; - next = null; - } - } - - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - ListNode node2 = new ListNode(-1); - ListNode node3 = new ListNode(5); - ListNode node4 = new ListNode(11); - - ListNode node6 = new ListNode(6); - ListNode node10 = new ListNode(10); - - - /*ListNode node1 = new ListNode(2); - ListNode node5 = new ListNode(3); - ListNode node7 = new ListNode(7); - ListNode node26 = new ListNode(26); - ListNode node111 = new ListNode(111); - - - ListNode node11 = new ListNode(1); - ListNode node9 = new ListNode(9); - ListNode node10 = new ListNode(10); - ListNode node12 = new ListNode(12); - ListNode node119 = new ListNode(119); - */ - - node2.next = node3; - node3.next = node4; - - node6.next = node10; - - /*node1.next = node5; - node5.next = node7; - node7.next = node26; - node26.next = node111; - - node11.next = node9; - node9.next = node10; - node10.next = node12; - node12.next = node119;*/ - ListNode[] list = new ListNode[4]; - list[0] = null; - list[1] = node2; - list[2] = null; - list[3] = node6; - ListNode result = new MergeKSortedLists().mergeKLists(list); - } - - public ListNode mergeKLists(ListNode[] lists) - { - if(lists.length == 0) return null; - if(lists.length == 1) return lists[0]; - return merge(lists, 0, lists.length - 1); - } - - private ListNode merge(ListNode[] lists, int s, int e) - { - if(s == e) return lists[s]; - int m = s + (e - s) / 2; - ListNode left = merge(lists, s, m); - ListNode right = merge(lists, m + 1, e); - ListNode prev, temp; - ListNode headNode = new ListNode(0); - headNode.next = left; - prev = headNode; - if(left == null && right == null) return null; - else if(left == null) return right; - else if(right == null) return left; - while(left != null && right != null) - { - if(left.val > right.val) - { - temp = right; - right = right.next; - prev.next = temp; - temp.next = left; - prev = prev.next; - } - else - { - left = left.next; - prev = prev.next; - } - } - if(left == null && right != null) - prev.next = right; - return headNode.next; - } -} diff --git a/problems/src/linked_list/MergeTwoSortedList.java b/problems/src/linked_list/MergeTwoSortedList.java deleted file mode 100644 index c0eba315..00000000 --- a/problems/src/linked_list/MergeTwoSortedList.java +++ /dev/null @@ -1,61 +0,0 @@ -package linked_list; - -/** - * Created by gouthamvidyapradhan on 18/03/2017. - Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists. - */ -public class MergeTwoSortedList -{ - public static class ListNode - { - int val; - ListNode next; - ListNode(int x) - { - val = x; - next = null; - } - } - - public static void main(String[] args) throws Exception - { - ListNode head = new ListNode(0); - ListNode head1 = new ListNode(3); - ListNode head2 = new ListNode(8); - - ListNode head3 = new ListNode(1); - ListNode head4 = new ListNode(2); - ListNode head5 = new ListNode(7); - ListNode head6 = new ListNode(10); - - head.next = head1; - head1.next = head2; - - head3.next = head4; - head4.next = head5; - head5.next = head6; - - ListNode newHead = new MergeTwoSortedList().mergeTwoLists(head, head3); - ListNode link = newHead; - while(link != null) - { - System.out.println(link.val); - link = link.next; - } - } - public ListNode mergeTwoLists(ListNode l1, ListNode l2) - { - if(l1 == null) return l2; - else if(l2 == null) return l1; - if(l1.val <= l2.val) - { - l1.next = mergeTwoLists(l1.next, l2); - return l1; - } - else - { - l2.next = mergeTwoLists(l1, l2.next); - return l2; - } - } -} diff --git a/problems/src/linked_list/PaliandromeList.java b/problems/src/linked_list/PaliandromeList.java deleted file mode 100644 index 63c90e67..00000000 --- a/problems/src/linked_list/PaliandromeList.java +++ /dev/null @@ -1,93 +0,0 @@ -package linked_list; - -/** - * Created by gouthamvidyapradhan on 25/02/2017. - Given a singly linked list, determine if it is a palindrome. - - Follow up: - Could you do it in O(n) time and O(1) space? - */ -public class PaliandromeList -{ - public static class ListNode - { - int val; - ListNode next; - ListNode(int x) - { - val = x; - next = null; - } - } - - ListNode headNode; - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - ListNode node1 = new ListNode(1); - //ListNode node2 = new ListNode(2); - //ListNode node3 = new ListNode(3); - //ListNode node4 = new ListNode(3); - //ListNode node5 = new ListNode(2); - //ListNode node6 = new ListNode(1); - //node1.next = node2; - //node2.next = node3; - //node3.next = node5; - //node4.next = node5; - //node5.next = node6; - System.out.println(new PaliandromeList().isPalindrome(node1)); - } - - public boolean isPalindrome(ListNode head) - { - int length = 0, count = 0; - if(head == null) return true; - ListNode temp = head; - while(temp != null) - { - temp = temp.next; - length++; - } - if(length == 1) return true; - - int halfLen = length / 2; - - temp = head; - while(count < halfLen - 1) - { - temp = temp.next; - count++; - } - - ListNode newHead = temp.next; - temp.next = null; - reverse(newHead); - ListNode first = head, second = headNode; - for(int i = 0; i < halfLen; i ++) - { - if(first.val != second.val) - return false; - first = first.next; - second = second.next; - } - return true; - } - - private ListNode reverse(ListNode node) - { - if(node.next == null) - { - headNode = node; - return node; - } - ListNode prev = reverse(node.next); - node.next = null; - prev.next = node; - return node; - } - -} diff --git a/problems/src/linked_list/ReverseLinkedList.java b/problems/src/linked_list/ReverseLinkedList.java deleted file mode 100644 index 451b219b..00000000 --- a/problems/src/linked_list/ReverseLinkedList.java +++ /dev/null @@ -1,63 +0,0 @@ -package linked_list; - -/** - * Created by gouthamvidyapradhan on 24/02/2017. - Reverse a singly linked list. - */ -public class ReverseLinkedList -{ - private ListNode newHead; - - public static class ListNode - { - int val; - ListNode next; - ListNode(int x) - { - val = x; - next = null; - } - } - - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - ListNode node1 = new ListNode(1); - ListNode node2 = new ListNode(2); - ListNode node3 = new ListNode(3); - ListNode node4 = new ListNode(4); - ListNode node5 = new ListNode(5); - ListNode node6 = new ListNode(6); - node1.next = node2; - node2.next = node3; - node3.next = node4; - node4.next = node5; - //node5.next = node6; - ListNode newNode = new ReverseLinkedList().reverseList(node1); - System.out.println(newNode.val); - } - - public ListNode reverseList(ListNode head) - { - if(head == null) return null; - else if(head.next == null) return head; - reverse(head).next = null; - return newHead; - } - - private ListNode reverse(ListNode head) - { - if(head.next == null) - { - newHead = head; - return head; - } - ListNode node = reverse(head.next); - node.next = head; - return head; - } -} diff --git a/problems/src/math/AddTwoNumbers.java b/problems/src/math/AddTwoNumbers.java deleted file mode 100644 index 1d30a8fa..00000000 --- a/problems/src/math/AddTwoNumbers.java +++ /dev/null @@ -1,85 +0,0 @@ -package math; - -/** - * Created by gouthamvidyapradhan on 13/03/2017. - You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. - - You may assume the two numbers do not contain any leading zero, except the number 0 itself. - - Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) - Output: 7 -> 0 -> 8 - */ -public class AddTwoNumbers -{ - public static class ListNode - { - int val; - ListNode next; - ListNode(int x) - { - val = x; - next = null; - } - } - - public static void main(String[] args) - { - ListNode node = new ListNode(2); - node.next = new ListNode(4); - node.next.next = new ListNode(4); - - ListNode node1 = new ListNode(5); - node1.next = new ListNode(6); - node1.next.next = new ListNode(6); - - ListNode result = new AddTwoNumbers().addTwoNumbers(node, node1); - } - - private ListNode addTwoNumbers(ListNode l1, ListNode l2) - { - if(l1 == null && l2 == null) return null; - ListNode first = l1; - ListNode second = l2; - int carry = 0; - ListNode head = new ListNode(0); - ListNode prev = head; - while(first != null && second != null) - { - int q = (first.val + second.val + carry) / 10; - int r = (first.val + second.val + carry) % 10; - carry = q; - ListNode node = new ListNode(r); - prev.next = node; - prev = node; - first = first.next; - second = second.next; - } - - while(first != null) - { - int q = (first.val + carry) / 10; - int r = (first.val + carry) % 10; - carry = q; - ListNode node = new ListNode(r); - prev.next = node; - prev = node; - first = first.next; - } - - while(second != null) - { - int q = (second.val + carry) / 10; - int r = (second.val + carry) % 10; - carry = q; - ListNode node = new ListNode(r); - prev.next = node; - prev = node; - second = second.next; - } - - if(carry != 0) - prev.next = new ListNode(carry); - - return head.next; - } -} diff --git a/problems/src/math/CountPrimes.java b/problems/src/math/CountPrimes.java deleted file mode 100644 index 645eb5fe..00000000 --- a/problems/src/math/CountPrimes.java +++ /dev/null @@ -1,48 +0,0 @@ -package math; - -import java.util.BitSet; - -/** - * Created by gouthamvidyapradhan on 21/03/2017. - Description: - - Count the number of prime numbers less than a non-negative number, n. - */ -public class CountPrimes -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - System.out.println(new CountPrimes().countPrimes(999187)); - } - - public int countPrimes(int n) - { - if(n == 0 || n == 1 || n == 2) return 0; - else if(n == 3) return 1; - BitSet set = new BitSet(); - n = n - 1; - int sqRt = new Double(Math.sqrt(n)).intValue(); - int count = n; - for(int i = 2; i <= sqRt; i ++) - { - if(!set.get(i)) - { - for(int j = 2; (i * j) <= n; j ++) - { - if(!set.get(i * j)) - { - count --; - set.set(i * j); - } - } - } - } - return count - 1; - } - -} diff --git a/problems/src/math/RotateFunction.java b/problems/src/math/RotateFunction.java deleted file mode 100644 index 775b5dc3..00000000 --- a/problems/src/math/RotateFunction.java +++ /dev/null @@ -1,59 +0,0 @@ -package math; - -/** - * Created by gouthamvidyapradhan on 18/03/2017. - Given an array of integers A and let n to be its length. - - Assume Bk to be an array obtained by rotating the array A k positions clock-wise, we define a "rotation function" F on A as follow: - - F(k) = 0 * Bk[0] + 1 * Bk[1] + ... + (n-1) * Bk[n-1]. - - Calculate the maximum value of F(0), F(1), ..., F(n-1). - - Note: - n is guaranteed to be less than 105. - - Example: - - A = [4, 3, 2, 6] - - F(0) = (0 * 4) + (1 * 3) + (2 * 2) + (3 * 6) = 0 + 3 + 4 + 18 = 25 - F(1) = (0 * 6) + (1 * 4) + (2 * 3) + (3 * 2) = 0 + 4 + 6 + 6 = 16 - F(2) = (0 * 2) + (1 * 6) + (2 * 4) + (3 * 3) = 0 + 6 + 8 + 9 = 23 - F(3) = (0 * 3) + (1 * 2) + (2 * 6) + (3 * 4) = 0 + 2 + 12 + 12 = 26 - - So the maximum value of F(0), F(1), F(2), F(3) is F(3) = 26. - */ -public class RotateFunction -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] a = {4, 3, 2, 6}; - System.out.println(new RotateFunction().maxRotateFunction(a)); - } - - public int maxRotateFunction(int[] A) - { - if(A.length == 0 || A.length == 1) return 0; - int max = Integer.MIN_VALUE; - int l = A.length; - int sum = 0, prodSum = 0; - for(int i = 0; i < l; i ++) - { - prodSum += (A[i] * i); - sum += A[i]; - } - max = Math.max(max, prodSum); - for(int i = 0; i < l - 1; i ++) - { - prodSum = (prodSum - sum + A[i] + ((l - 1) * A[i])); - max = Math.max(max, prodSum); - } - return max; - } -} diff --git a/problems/src/stack/MinStack.java b/problems/src/stack/MinStack.java deleted file mode 100644 index a5ea3f25..00000000 --- a/problems/src/stack/MinStack.java +++ /dev/null @@ -1,88 +0,0 @@ -package stack; - -import java.util.Stack; - -/** - * Created by gouthamvidyapradhan on 08/03/2017. - Design a stack that supports push, pop, top, and retrieving the minimum element in constant time. - - push(x) -- Push element x onto stack. - pop() -- Removes the element on top of the stack. - top() -- Get the top element. - getMin() -- Retrieve the minimum element in the stack. - Example: - MinStack minStack = new MinStack(); - minStack.push(-2); - minStack.push(0); - minStack.push(-3); - minStack.getMin(); --> Returns -3. - minStack.pop(); - minStack.top(); --> Returns 0. - minStack.getMin(); --> Returns -2. - */ -public class MinStack -{ - class Node - { - int value, min; - Node(int value, int min) - { - this.value = value; - this.min = min; - } - } - - private Stack stack = new Stack<>(); - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - MinStack minStack = new MinStack(); - minStack.push(-2); - minStack.push(0); - minStack.push(-3); - System.out.println(minStack.getMin()); - minStack.pop(); - System.out.println(minStack.top()); - System.out.println(minStack.getMin()); - } - - public MinStack() - { - - } - - public void push(int x) - { - Node node; - if(!stack.isEmpty()) - { - Node top = stack.peek(); - node = new Node(x, Math.min(top.min, x)); - } - else - { - node = new Node(x, x); - } - stack.push(node); - } - - public void pop() - { - stack.pop(); - } - - public int top() - { - return stack.peek().value; - } - - public int getMin() - { - return stack.peek().min; - } - -} diff --git a/problems/src/stack/ValidParentheses.java b/problems/src/stack/ValidParentheses.java deleted file mode 100644 index fdabe184..00000000 --- a/problems/src/stack/ValidParentheses.java +++ /dev/null @@ -1,57 +0,0 @@ -package stack; - -import java.util.HashMap; -import java.util.Map; -import java.util.Stack; - -/** - * Created by gouthamvidyapradhan on 25/02/2017. - Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid. - - The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and "([)]" are not. - */ -public class ValidParentheses -{ - public static void main(String[] args) - { - System.out.println(hasBalancedBrackets("(h[e")); - } - private static Map MAP = new HashMap<>(); - - // METHOD SIGNATURE BEGINS, THIS METHOD IS REQUIRED - public static int hasBalancedBrackets(String str) - { - if(str == null) return 1; - - MAP.put(')', '('); - MAP.put('}', '{'); - MAP.put('>', '<'); - MAP.put(']', '['); - - Stack stack = new Stack<>(); - for(int i = 0, l = str.length(); i < l; i ++) - { - switch (str.charAt(i)) - { - case '(': - case '{': - case '[': - case '<': - stack.push(str.charAt(i)); - break; - - case ')': - case '}': - case ']': - case '>': - if(stack.isEmpty()) return 0; - char top = stack.pop(); - if(top != MAP.get(str.charAt(i))) return 0; - break; - - default: //ignore - } - } - return stack.isEmpty() ? 1 : 0; - } -} diff --git a/problems/src/string/FirstUniqueCharacterInAString.java b/problems/src/string/FirstUniqueCharacterInAString.java deleted file mode 100644 index fc04dc06..00000000 --- a/problems/src/string/FirstUniqueCharacterInAString.java +++ /dev/null @@ -1,44 +0,0 @@ -package string; - -/** - * Created by gouthamvidyapradhan on 09/03/2017. - Given a string, find the first non-repeating character in it and return it's index. If it doesn't exist, return -1. - - Examples: - - s = "leetcode" - return 0. - - s = "loveleetcode", - return 2. - Note: You may assume the string contain only lowercase letters. - */ -public class FirstUniqueCharacterInAString -{ - int[] CHAR = new int[256]; - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - System.out.println(new FirstUniqueCharacterInAString().firstUniqChar("loveleetcode")); - } - - public int firstUniqChar(String s) - { - if(s == null || s.isEmpty()) return -1; - - for(int i = 0, l = s.length(); i < l; i ++) - CHAR[s.charAt(i)]++; - - for(int i = 0, l = s.length(); i < l; i ++) - { - if(CHAR[s.charAt(i)] == 1) - return i; - } - - return -1; - } -} diff --git a/problems/src/string/RepeatedSubstringPattern.java b/problems/src/string/RepeatedSubstringPattern.java deleted file mode 100644 index 0245e4a6..00000000 --- a/problems/src/string/RepeatedSubstringPattern.java +++ /dev/null @@ -1,61 +0,0 @@ -package string; - -/** - * Created by gouthamvidyapradhan on 25/03/2017. - Given a non-empty string check if it can be constructed by taking a substring of it and appending multiple copies of the substring together. You may assume the given string consists of lowercase English letters only and its length will not exceed 10000. - - Example 1: - Input: "abab" - - Output: True - - Explanation: It's the substring "ab" twice. - Example 2: - Input: "aba" - - Output: False - Example 3: - Input: "abcabcabcabc" - - Output: True - - Explanation: It's the substring "abc" four times. (And the substring "abcabc" twice.) - */ -public class RepeatedSubstringPattern -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - System.out.println(new RepeatedSubstringPattern().repeatedSubstringPattern("a")); - } - - public boolean repeatedSubstringPattern(String s) - { - boolean found; - for(int i = 1, l = s.length(); i < l; i ++) - { - found = true; - String subI = s.substring(0, i); - int j = i; - if(j >= l) return false; - while(j < l) - { - if((j + i) >= l + 1) - return false; - String subJ = s.substring(j , j + i); - if(!subI.equals(subJ)) - { - found = false; - break; - } - j += i; - } - if(found) return true; - } - return false; - } -} diff --git a/problems/src/string/ReverseWordsII.java b/problems/src/string/ReverseWordsII.java deleted file mode 100644 index 0f6de4de..00000000 --- a/problems/src/string/ReverseWordsII.java +++ /dev/null @@ -1,78 +0,0 @@ -package string; - -/** - * Created by gouthamvidyapradhan on 21/03/2017. - Given an input string, reverse the string word by word. A word is defined as a sequence of non-space characters. - - The input string does not contain leading or trailing spaces and the words are always separated by a single space. - - For example, - Given s = "the sky is blue", - return "blue is sky the". - - Could you do it in-place without allocating extra space? - */ -public class ReverseWordsII -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - char[] c = {'t','h','e', ' ', 's', 'k', 'y', ' ', 'i', 's', ' ', 'b', 'l', 'u', 'e'}; - new ReverseWordsII().reverseWords(c); - for (char i : c) - System.out.print(i); - } - - public void reverseWords(char[] s) - { - for(int i = 0, j = s.length - 1; i < j; i ++, j --) - { - char temp = s[i]; - s[i] = s[j]; - s[j] = temp; - } - for(int i = 0, j = 0, l = s.length; i < l;) - { - if(s[i] == ' ') - { - if(s[i - 1] == ' ') - { - j = i; - i ++; j ++; - } - else - { - i = i - 1; - for(int p = j, q = i; p < q; p ++, q--) - { - char temp = s[p]; - s[p] = s[q]; - s[q] = temp; - } - i = i + 1; - j = i; - i ++; j ++; - } - } - else if(i == l - 1) - { - for(int p = j, q = i; p < q; p ++, q--) - { - char temp = s[p]; - s[p] = s[q]; - s[q] = temp; - } - j = i; - i ++; j ++; - } - else - { - i ++; - } - } - } -} diff --git a/problems/src/string/StringToInteger.java b/problems/src/string/StringToInteger.java deleted file mode 100644 index e172f121..00000000 --- a/problems/src/string/StringToInteger.java +++ /dev/null @@ -1,69 +0,0 @@ -package string; - -/** - * Created by gouthamvidyapradhan on 21/03/2017. - Implement atoi to convert a string to an integer. - - Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases. - - Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front. - */ -public class StringToInteger -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - System.out.println(new StringToInteger().myAtoi(" 2147483649a sdfasdf")); - } - - public int myAtoi(String str) - { - boolean isPositive = true; - if(str == null || str.trim().isEmpty()) return 0; - str = str.trim(); - if(str.charAt(0) == '+') - { - isPositive = true; - str = str.substring(1, str.length()); - } - else if(str.charAt(0) == '-') - { - isPositive = false; - str = str.substring(1, str.length()); - } - - else if(str.charAt(0) > '9' || str.charAt(0) < '0') - return 0; - int i = 0; - for(int l = str.length(); i < l; i ++) - { - if(str.charAt(i) > '9' || str.charAt(i) < '0') - break; - } - str = str.substring(0, i); - long num = 0; - for(int j = 0, l = str.length(); j < l; j++) - { - int n = (str.charAt(j) - '0'); - num *= 10; - num += n; - if(isPositive) - { - if(num > Integer.MAX_VALUE) return Integer.MAX_VALUE; - } - else - { - if((num * -1) < Integer.MIN_VALUE) return Integer.MIN_VALUE; - } - } - if(isPositive) - return (int)num; - else return (int)(num * -1); - } - - -} diff --git a/problems/src/string/TextJustification.java b/problems/src/string/TextJustification.java deleted file mode 100644 index 420bd24c..00000000 --- a/problems/src/string/TextJustification.java +++ /dev/null @@ -1,99 +0,0 @@ -package string; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by gouthamvidyapradhan on 09/03/2017. - Given an array of words and a length L, format the text such that each line has exactly L characters and is fully (left and right) justified. - - You should pack your words in a greedy approach; that is, pack as many words as you can in each line. Pad extra spaces ' ' when necessary so that each line has exactly L characters. - - Extra spaces between words should be distributed as evenly as possible. If the number of spaces on a line do not divide evenly between words, the empty slots on the left will be assigned more spaces than the slots on the right. - - For the last line of text, it should be left justified and no extra space is inserted between words. - - For example, - words: ["This", "is", "an", "example", "of", "text", "justification."] - L: 16. - - Return the formatted lines as: - [ - "This is an", - "example of text", - "justification. " - ] - Note: Each word is guaranteed not to exceed L in length. - */ -public class TextJustification -{ - public List fullJustify(String[] words, int L) - { - int wCount = 0, charCount = 0; - List line = new ArrayList<>(); - List result = new ArrayList<>(); - StringBuilder sb = new StringBuilder(); - - for(int i = 0, l = words.length; i < l; i++) - { - String next = words[i]; - if( (L - (charCount + wCount)) >= next.length()) - { - line.add(next); - charCount += next.length(); - wCount++; - } - else - { - //justify and add to list - sb.append(line.get(0)); - StringBuilder space = new StringBuilder(); - if(line.size() > 1) - { - int spaceCount = (L - charCount) / (wCount - 1); - int remaining = (L - charCount) % (wCount - 1); - - for(int j = 0; j < spaceCount; j++) - space.append(' '); - - for(int k = 1, kl = line.size(); k < kl; k++) - { - sb.append(space); - if(remaining > 0) - { - sb.append(' '); - --remaining; - } - sb.append(line.get(k)); - } - } - else - { - int balance = L - (charCount + (wCount - 1)); - for(int j = 0; j < balance; j ++) - sb.append(' '); - } - result.add(sb.toString()); - sb = new StringBuilder(); - line.clear(); - line.add(next); - charCount = next.length(); - wCount = 1; - } - } - if(!line.isEmpty()) - { - sb.append(line.get(0)); - for(int i = 1, l = line.size(); i < l; i++) - { - sb.append(' '); - sb.append(line.get(i)); - } - } - int balance = L - (charCount + (wCount - 1)); - for(int i = 0; i < balance; i ++) - sb.append(' '); - result.add(sb.toString()); - return result; - } -} diff --git a/problems/src/tree/BinarayTreeRightSideView.java b/problems/src/tree/BinarayTreeRightSideView.java deleted file mode 100644 index d4aa5ad9..00000000 --- a/problems/src/tree/BinarayTreeRightSideView.java +++ /dev/null @@ -1,72 +0,0 @@ -package tree; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by gouthamvidyapradhan on 12/03/2017. - Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom. - - For example: - Given the following binary tree, - 1 <--- - / \ - 2 3 <--- - \ \ - 5 4 <--- - You should return [1, 3, 4]. - */ - -public class BinarayTreeRightSideView -{ - public static class TreeNode - { - int val; - TreeNode left; - TreeNode right; - TreeNode(int x) { val = x; } - } - - private int maxHeigh = Integer.MIN_VALUE; - List list = new ArrayList<>(); - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - TreeNode root = new TreeNode(2); - root.left = new TreeNode(3); - root.right = new TreeNode(4); - root.right.right = new TreeNode(5); - root.right.left = new TreeNode(4); - root.right.left.right = new TreeNode(8); - root.right.left.left = new TreeNode(7); - root.right.left.left.right = new TreeNode(10); - root.right.left.left.left = new TreeNode(7); - - List list = new BinarayTreeRightSideView().rightSideView(root); - } - - public List rightSideView(TreeNode root) - { - if(root == null) return list; - dfs(root, 0); - return list; - } - - private void dfs(TreeNode node, int height) - { - if(node != null) - { - if(height > maxHeigh) - { - list.add(node.val); - maxHeigh = height; - } - dfs(node.right, height + 1); - dfs(node.left, height + 1); - } - } -} diff --git a/problems/src/tree/BinaryTreeMaximumPathSum.java b/problems/src/tree/BinaryTreeMaximumPathSum.java deleted file mode 100644 index 2180737a..00000000 --- a/problems/src/tree/BinaryTreeMaximumPathSum.java +++ /dev/null @@ -1,63 +0,0 @@ -package tree; - -/** - * Created by gouthamvidyapradhan on 03/04/2017. - Given a binary tree, find the maximum path sum. - - For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root. - - For example: - Given the below binary tree, - - 1 - / \ - 2 3 - Return 6. - */ -public class BinaryTreeMaximumPathSum -{ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - TreeNode(int x) { val = x; } - } - - private int max = Integer.MIN_VALUE; - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - TreeNode root = new TreeNode(5); - root.left = new TreeNode(4); - root.left.left = new TreeNode(3); - root.left.left.left = new TreeNode(-1); - root.right = new TreeNode(7); - root.right.left = new TreeNode(2); - root.right.left.left = new TreeNode(9); - System.out.println(new BinaryTreeMaximumPathSum().maxPathSum(root)); - } - public int maxPathSum(TreeNode root) - { - if(root == null) return 0; - dfs(root); - return max; - } - - private int dfs(TreeNode root) - { - if(root == null) return 0; - int left = dfs(root.left); - int right = dfs(root.right); - max = Math.max(max, root.val); - max = Math.max(max, root.val + left); - max = Math.max(max, root.val + right); - max = Math.max(max, root.val + left + right); - int leftVal = Math.max(root.val, root.val + left); - int rightVal = Math.max(root.val, root.val + right); - return Math.max(leftVal, rightVal); - } -} diff --git a/problems/src/tree/BoundaryOfBinaryTree.java b/problems/src/tree/BoundaryOfBinaryTree.java deleted file mode 100644 index b219798b..00000000 --- a/problems/src/tree/BoundaryOfBinaryTree.java +++ /dev/null @@ -1,163 +0,0 @@ -package tree; - -import java.util.*; - -/** - * Created by gouthamvidyapradhan on 27/03/2017. - Given a binary tree, return the values of its boundary in anti-clockwise direction starting from root. Boundary includes left boundary, leaves, and right boundary in order without duplicate nodes. - - Left boundary is defined as the path from root to the left-most node. Right boundary is defined as the path from root to the right-most node. If the root doesn't have left subtree or right subtree, then the root itself is left boundary or right boundary. Note this definition only applies to the input binary tree, and not applies to any subtrees. - - The left-most node is defined as a leaf node you could reach when you always firstly travel to the left subtree if exists. If not, travel to the right subtree. Repeat until you reach a leaf node. - - The right-most node is also defined by the same way with left and right exchanged. - - Example 1 - Input: - 1 - \ - 2 - / \ - 3 4 - - Ouput: - [1, 3, 4, 2] - - Explanation: - The root doesn't have left subtree, so the root itself is left boundary. - The leaves are node 3 and 4. - The right boundary are node 1,2,4. Note the anti-clockwise direction means you should output reversed right boundary. - So order them in anti-clockwise without duplicates and we have [1,3,4,2]. - Example 2 - Input: - ____1_____ - / \ - 2 3 - / \ / - 4 5 6 - / \ / \ - 7 8 9 10 - - Ouput: - [1,2,4,7,8,9,10,6,3] - - Explanation: - The left boundary are node 1,2,4. (4 is the left-most node according to definition) - The leaves are node 4,7,8,9,10. - The right boundary are node 1,3,6,10. (10 is the right-most node). - So order them in anti-clockwise without duplicate nodes we have [1,2,4,7,8,9,10,6,3]. - */ -public class BoundaryOfBinaryTree -{ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - TreeNode(int x) { val = x; } - } - - private Set done = new HashSet<>(); - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - TreeNode root = new TreeNode(1); - /*root.right = new TreeNode(2); - root.right.right = new TreeNode(3); - root.right.right.right = new TreeNode(4); - root.right.right.right.left = new TreeNode(5); - root.right.right.right.left.right = new TreeNode(6); - /*root.left = new TreeNode(2); - root.left.left = new TreeNode(4); - root.left.right = new TreeNode(5); - root.left.right.left = new TreeNode(7); - root.left.right.right = new TreeNode(8); - root.right = new TreeNode(3); - root.right.left = new TreeNode(6); - root.right.left.left = new TreeNode(9); - root.right.left.right = new TreeNode(10);*/ - System.out.println(new BoundaryOfBinaryTree().boundaryOfBinaryTree(root)); - } - - public List boundaryOfBinaryTree(TreeNode root) - { - if(root == null) return new ArrayList<>(); - List antiClockwiseCollection = new ArrayList<>(); - List collection = new ArrayList<>(); - - if(root.left != null) - leftShoulder(root, collection); - else - { - if(!done.contains(root)) - { - done.add(root); - collection.add(root.val); - } - } - - antiClockwiseCollection.addAll(collection); - collection.clear(); - leafNode(root, collection); - antiClockwiseCollection.addAll(collection); - collection.clear(); - - if(root.right != null) - rightShoulder(root, collection); - else - { - if(!done.contains(root)) - { - done.add(root); - collection.add(root.val); - } - } - - Stack stack = new Stack<>(); - stack.addAll(collection); - while(!stack.isEmpty()) - antiClockwiseCollection.add(stack.pop()); - return new ArrayList<>(antiClockwiseCollection); - } - - private void leftShoulder(TreeNode node, List list) - { - if(node == null) return; - if(!done.contains(node)) - { - list.add(node.val); - done.add(node); - } - - if(node.left != null) leftShoulder(node.left, list); - else if(node.right != null) leftShoulder(node.right, list); - } - - private void rightShoulder(TreeNode node, List list) - { - if(node == null) return; - if(!done.contains(node)) - { - list.add(node.val); - done.add(node); - } - if(node.right != null) rightShoulder(node.right, list); - else if(node.left != null) rightShoulder(node.left, list); - } - - private void leafNode(TreeNode node, List list) - { - if(node == null) return; - if(node.left == null && node.right == null) - if(!done.contains(node)) - { - list.add(node.val); - done.add(node); - } - leafNode(node.left, list); - leafNode(node.right, list); - } -} diff --git a/problems/src/tree/ConvertSortedArrayToBST.java b/problems/src/tree/ConvertSortedArrayToBST.java deleted file mode 100644 index 4690acec..00000000 --- a/problems/src/tree/ConvertSortedArrayToBST.java +++ /dev/null @@ -1,38 +0,0 @@ -package tree; - -/** - * Created by gouthamvidyapradhan on 09/03/2017. - Given an array where elements are sorted in ascending order, convert it to a height balanced BST. - */ -public class ConvertSortedArrayToBST -{ - public class TreeNode - { - int val; - TreeNode left; - TreeNode right; - TreeNode(int x) { val = x; } - } - - public TreeNode sortedArrayToBST(int[] nums) - { - if(nums.length == 0) return null; - return build(0, nums.length - 1, nums); - } - - private TreeNode build(int s, int e, int[] nums) - { - if(s > e) return null; - - int m = (e - s) / 2; - int node = nums[s + m]; - TreeNode root = new TreeNode(node); - if(s == e) - return root; - - root.left = build(s, s + m - 1, nums); - root.right = build(s + m + 1, e, nums); - - return root; - } -} diff --git a/problems/src/tree/LCA.java b/problems/src/tree/LCA.java deleted file mode 100644 index 9cfd76b5..00000000 --- a/problems/src/tree/LCA.java +++ /dev/null @@ -1,52 +0,0 @@ -package tree; - -/** - * Created by gouthamvidyapradhan on 21/03/2017. - Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. - - According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).” - - _______3______ - / \ - ___5__ ___1__ - / \ / \ - 6 _2 0 8 - / \ - 7 4 - For example, the lowest common ancestor (LCA) of nodes 5 and 1 is 3. Another example is LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition. - */ -public class LCA -{ - public class TreeNode { - int val; - TreeNode left; - TreeNode right; - TreeNode(int x) { val = x; } - } - - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - - } - - public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) - { - if(root != null) - { - if(root.equals(p) || root.equals(q)) return root; - TreeNode left = lowestCommonAncestor(root.left, p, q); - TreeNode right = lowestCommonAncestor(root.right, p, q); - if(left != null && right != null) return root; - else if(left != null) return left; - else return right; - } - return null; - } - - -} diff --git a/problems/src/tree/LowestCommonAncestorBST.java b/problems/src/tree/LowestCommonAncestorBST.java deleted file mode 100644 index 3ba76954..00000000 --- a/problems/src/tree/LowestCommonAncestorBST.java +++ /dev/null @@ -1,49 +0,0 @@ -package tree; - -/** - * Created by gouthamvidyapradhan on 09/03/2017. - Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST. - - According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).” - - _______6______ - / \ - ___2__ ___8__ - / \ / \ - 0 _4 7 9 - / \ - 3 5 - For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6. Another example is LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition. - */ - -public class LowestCommonAncestorBST -{ - class TreeNode - { - int val; - TreeNode left; - TreeNode right; - TreeNode(int x) { val = x; } - } - - public static void main(String[] args) throws Exception - { - - } - - private TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) - { - if(root == null) return null; - - if(p.val == root.val || q.val == root.val) return root; - - else if((p.val < root.val && q.val > root.val) || (q.val < root.val && p.val > root.val)) - return root; - - else if(p.val < root.val && q.val < root.val) - return lowestCommonAncestor(root.left, p, q); - - else - return lowestCommonAncestor(root.right, p, q); - } -} diff --git a/problems/src/tree/MostFrequentSubtreeSum.java b/problems/src/tree/MostFrequentSubtreeSum.java deleted file mode 100644 index b68f3a0f..00000000 --- a/problems/src/tree/MostFrequentSubtreeSum.java +++ /dev/null @@ -1,90 +0,0 @@ -package tree; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Created by gouthamvidyapradhan on 27/03/2017. - Given the root of a tree, you are asked to find the most frequent subtree sum. The subtree sum of a node is defined as the sum of all the node values formed by the subtree rooted at that node (including the node itself). So what is the most frequent subtree sum value? If there is a tie, return all the values with the highest frequency in any order. - - Examples 1 - Input: - - 5 - / \ - 2 -3 - return [2, -3, 4], since all the values happen only once, return all of them in any order. - Examples 2 - Input: - - 5 - / \ - 2 -5 - return [2], since 2 happens twice, however -5 only occur once. - Note: You may assume the sum of values in any subtree is in the range of 32-bit signed integer. - */ -public class MostFrequentSubtreeSum -{ - static class TreeNode - { - int val; - TreeNode left; - TreeNode right; - TreeNode(int x) { val = x; } - } - - private Map> fList = new HashMap<>(); - private Map fCount = new HashMap<>(); - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - MostFrequentSubtreeSum mfs = new MostFrequentSubtreeSum(); - TreeNode node = new TreeNode(5); - //node.left = new TreeNode(2); - //node.right = new TreeNode(-5); - int[] result = mfs.findFrequentTreeSum(node); - } - - public int[] findFrequentTreeSum(TreeNode root) - { - int[] resArr = new int[0]; - if(root == null) return resArr; - postOrder(root); - for (Map.Entry entry : fCount.entrySet()) - { - int frequency = entry.getValue(); - List list = fList.get(frequency); - if(list == null) - list = new ArrayList<>(); - list.add(entry.getKey()); - fList.put(frequency, list); - } - int max = Integer.MIN_VALUE; - List result; - for(int key : fList.keySet()) - max = Math.max(max, key); - result = fList.get(max); - resArr = new int[result.size()]; - for(int i = 0, l = resArr.length; i < l; i ++) - resArr[i] = result.get(i); - return resArr; - } - - private int postOrder(TreeNode root) - { - if(root == null) return 0; - int sum = postOrder(root.left) + postOrder(root.right) + root.val; - Integer fSum = fCount.get(sum); - if(fSum == null) - fCount.put(sum, 1); - else fCount.put(sum, fSum + 1); - return sum; - } - -} diff --git a/problems/src/tree/PathSumIII.java b/problems/src/tree/PathSumIII.java deleted file mode 100644 index 455579bb..00000000 --- a/problems/src/tree/PathSumIII.java +++ /dev/null @@ -1,77 +0,0 @@ -package tree; - -import java.util.HashMap; -import java.util.Map; - -/** - * Created by gouthamvidyapradhan on 08/04/2017. - You are given a binary tree in which each node contains an integer value. - - Find the number of paths that sum to a given value. - - The path does not need to start or end at the root or a leaf, but it must go downwards (traveling only from parent nodes to child nodes). - - The tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000. - - Example: - - root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8 - - 10 - / \ - 5 -3 - / \ \ - 3 2 11 - / \ \ - 3 -2 1 - - Return 3. The paths that sum to 8 are: - - 1. 5 -> 3 - 2. 5 -> 2 -> 1 - 3. -3 -> 11 - */ - -public class PathSumIII -{ - /** - * - */ - public static class TreeNode - { - int val; - TreeNode left; - TreeNode right; - TreeNode(int x) { val = x; } - } - - private Map pathCount = new HashMap<>(); - private int totalCount; - - public static void main(String[] args) throws Exception - { - TreeNode node = new TreeNode(1); - System.out.println(new PathSumIII().pathSum(node, 0)); - } - - public int pathSum(TreeNode root, int sum) - { - if(root == null) return 0; - dfs(root, sum, 0); - return totalCount; - } - - private void dfs(TreeNode root, int target, int pSum) - { - if(root != null) - { - pSum += root.val; - if(pSum == target) totalCount++; - totalCount += pathCount.getOrDefault(pSum - target, 0); - pathCount.put(pSum, pathCount.getOrDefault(pSum, 0) + 1); - dfs(root.left, target, pSum); - dfs(root.right, target, pSum); - pathCount.put(pSum, pathCount.get(pSum) - 1); - } - } -} diff --git a/problems/src/tree/PostorderToBT.java b/problems/src/tree/PostorderToBT.java deleted file mode 100644 index 8a36f0df..00000000 --- a/problems/src/tree/PostorderToBT.java +++ /dev/null @@ -1,80 +0,0 @@ -package tree; - -import java.util.HashMap; -import java.util.Map; - -/** - * Created by gouthamvidyapradhan on 23/02/2017. - Given inorder and postorder traversal of a tree, construct the binary tree. - - Note: - You may assume that duplicates do not exist in the tree. - */ -public class PostorderToBT -{ - - private Map INDEX = new HashMap<>(); - private static int postIndex; - - public class TreeNode { - int val; - TreeNode left; - TreeNode right; - TreeNode(int x) { val = x; } - } - - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int in[] = new int[]{1, 2}; - int post[] = new int[]{1, 2}; - TreeNode root = new PostorderToBT().buildTree(in, post); - new PostorderToBT().preorderPrint(root); - } - - public TreeNode buildTree(int[] inorder, int[] postorder) - { - int count = 0; - for(int i : inorder) - INDEX.put(i, count++); - postIndex = postorder.length - 1; - return build(0, inorder.length - 1, postorder); - } - - private void preorderPrint(TreeNode root) - { - if(root != null) - { - System.out.print(root.val + " "); - preorderPrint(root.left); - preorderPrint(root.right); - } - } - - private TreeNode build(int s, int e, int[] postorder) - { - if(postIndex >= 0 && s <= e) - { - int poi = postorder[postIndex]; - - int ini = INDEX.get(poi); - - TreeNode node = new TreeNode(poi); - postIndex--; - - if(s == e) - return node; //leaf node - - node.right = build(ini + 1, e, postorder); - node.left = build(s, ini - 1, postorder); - - return node; - } - return null; - } - -} diff --git a/problems/src/tree/PreorderToBT.java b/problems/src/tree/PreorderToBT.java deleted file mode 100644 index fd2992ca..00000000 --- a/problems/src/tree/PreorderToBT.java +++ /dev/null @@ -1,58 +0,0 @@ -package tree; - -import java.util.HashMap; -import java.util.Map; - -/** - * Created by gouthamvidyapradhan on 25/02/2017. - Given preorder and inorder traversal of a tree, construct the binary tree. - - Note: - You may assume that duplicates do not exist in the tree. - */ -public class PreorderToBT -{ - public class TreeNode { - int val; - TreeNode left; - TreeNode right; - TreeNode(int x) { val = x; } - } - - Map MAP = new HashMap<>(); - private int index = 0, totalLen = 0; - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] perorder = {7,-10,-4,3,-1,2,-8,11}; - int[] inorder = {-4,-10,3,-1,7,11,-8,2}; - new PreorderToBT().buildTree(perorder, inorder); - } - - public TreeNode buildTree(int[] preorder, int[] inorder) - { - for(int i = 0, l = inorder.length; i < l; i ++) - MAP.put(inorder[i], i); - totalLen = preorder.length; - return build(preorder, 0, inorder.length - 1); - } - - private TreeNode build(int[] preorder, int s, int e) - { - if (s > e || index >= totalLen) return null; - - int n = preorder[index++]; - int pos = MAP.get(n); - - TreeNode node = new TreeNode(n); - if(s == e) return node; - - node.left = build(preorder, s, pos - 1); - node.right = build(preorder, pos + 1, e); - return node; - } -} diff --git a/problems/src/tree/SortedArrayToBST.java b/problems/src/tree/SortedArrayToBST.java deleted file mode 100644 index c89d6ef1..00000000 --- a/problems/src/tree/SortedArrayToBST.java +++ /dev/null @@ -1,63 +0,0 @@ -package tree; - -/** - * Created by gouthamvidyapradhan on 25/02/2017. - Given an array where elements are sorted in ascending order, convert it to a height balanced BST. - */ -public class SortedArrayToBST -{ - public class TreeNode { - int val; - TreeNode left; - TreeNode right; - TreeNode(int x) { val = x; } - } - - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] A = {1, 2, 3, 4, 5, 6}; - new SortedArrayToBST().sortedArrayToBST(A); - - } - - public TreeNode sortedArrayToBST(int[] nums) - { - if(nums.length == 0) return null; - - TreeNode root = new SortedArrayToBST().build(0, nums.length - 1, nums); - preorder(root); - return root; - } - - private void preorder(TreeNode node) - { - if(node != null) - { - preorder(node.left); - System.out.println(node.val); - preorder(node.right); - } - } - - private TreeNode build(int s, int e, int[] nums) - { - if(s > e) return null; - - int m = (e - s) / 2; - int node = nums[s + m]; - TreeNode root = new TreeNode(node); - if(s == e) - return root; - - root.left = build(s, s + m - 1, nums); - root.right = build(s + m + 1, e, nums); - - return root; - } - -} diff --git a/problems/src/tree/ValidBinarySearchTree.java b/problems/src/tree/ValidBinarySearchTree.java deleted file mode 100644 index b355bf0b..00000000 --- a/problems/src/tree/ValidBinarySearchTree.java +++ /dev/null @@ -1,81 +0,0 @@ -package tree; - -/** - * Created by gouthamvidyapradhan on 09/03/2017. - Given a binary tree, determine if it is a valid binary search tree (BST). - - Assume a BST is defined as follows: - - The left subtree of a node contains only nodes with keys less than the node's key. - The right subtree of a node contains only nodes with keys greater than the node's key. - Both the left and right subtrees must also be binary search trees. - Example 1: - 2 - / \ - 1 3 - Binary tree [2,1,3], return true. - Example 2: - 1 - / \ - 2 3 - Binary tree [1,2,3], return false. - */ -public class ValidBinarySearchTree -{ - class Range - { - long low, high; - } - - static class TreeNode - { - int val; - TreeNode left; - TreeNode right; - TreeNode(int x) { val = x; } - } - - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - TreeNode root = new TreeNode(Integer.MIN_VALUE); - root.right = new TreeNode(Integer.MAX_VALUE); - System.out.println(new ValidBinarySearchTree().isValidBST(root)); - } - - private boolean isValidBST(TreeNode root) - { - if(root == null || - (root.right == null && root.left == null)) return true; - Range range = new Range(); - range.high = Long.MAX_VALUE; - range.low = Long.MIN_VALUE; - return validate(root, range); - } - - private boolean validate(TreeNode root, Range range) - { - if((root.val > range.low) && (root.val < range.high)) - { - long temp = range.high; - if(root.left != null) - { - range.high = root.val; - if(!validate(root.left, range)) return false; - } - if(root.right != null) - { - range.high = temp; - range.low = root.val; - if(!validate(root.right, range)) return false; - } - return true; - } - else return false; - } - -} diff --git a/problems/src/two_pointers/FourSum.java b/problems/src/two_pointers/FourSum.java deleted file mode 100644 index 639da11b..00000000 --- a/problems/src/two_pointers/FourSum.java +++ /dev/null @@ -1,78 +0,0 @@ -package two_pointers; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Created by gouthamvidyapradhan on 29/03/2017. - Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target. - - Note: The solution set must not contain duplicate quadruplets. - - For example, given array S = [1, 0, -1, 0, -2, 2], and target = 0. - - A solution set is: - [ - [-1, 0, 0, 1], - [-2, -1, 1, 2], - [-2, 0, 0, 2] - ] - */ -public class FourSum -{ - - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] nums = {1, 0, -1, 0, -2, 2}; - System.out.println(new FourSum().fourSum(nums, 0)); - } - - public List> fourSum(int[] nums, int target) - { - List> result = new ArrayList<>(); - if(nums.length < 4) return result; - Arrays.sort(nums); - for(int i = 0; i < nums.length - 3; i++) - { - if(i == 0 || nums[i] != nums[i - 1]) - { - for(int j = i + 1; j < nums.length - 2; j ++) - { - if(j == i + 1 || nums[j] != nums[j - 1]) - { - int k = j + 1, l = nums.length - 1; - while(k < l) - { - if(k != j + 1 && nums[k] == nums[k + 1]) - { - k++; continue; - } - int sum = nums[i] + nums[j] + nums[k] + nums[l]; - if(sum == target) - { - result.add(Arrays.asList(nums[i], nums[j], nums[k], nums[l])); - k++; l --; - } - else if(sum < target) - { - k ++; - } - else - { - l --; - } - } - } - } - } - } - return result; - } - -} diff --git a/problems/src/two_pointers/LongestSubstringWitoutRepeats.java b/problems/src/two_pointers/LongestSubstringWitoutRepeats.java deleted file mode 100644 index 67b389bb..00000000 --- a/problems/src/two_pointers/LongestSubstringWitoutRepeats.java +++ /dev/null @@ -1,49 +0,0 @@ -package two_pointers; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -/** - * Created by gouthamvidyapradhan on 09/03/2017. - Given a string, find the length of the longest substring without repeating characters. - - Examples: - - Given "abcabcbb", the answer is "abc", which the length is 3. - - Given "bbbbb", the answer is "b", with the length of 1. - - Given "pwwkew", the answer is "wke", with the length of 3. Note that the answer must be a substring, "pwke" is a subsequence and not a substring. - */ -public class LongestSubstringWitoutRepeats -{ - Set set = new HashSet<>(); - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - System.out.println(new LongestSubstringWitoutRepeats().lengthOfLongestSubstring("asdfsdfsdfsdfasdfdjdjjdjjdjjjjjajsdjjdjdjjd")); - } - - private int lengthOfLongestSubstring(String s) - { - if(s == null || s.isEmpty()) return 0; - Map map = new HashMap<>(); - int i = 0, max = Integer.MIN_VALUE; - for(int j = 0, l = s.length(); j < l; j ++) - { - if(map.keySet().contains(s.charAt(j))) - { - i = Math.max(map.get(s.charAt(j)) + 1, i); - } - map.put(s.charAt(j), j); - max = Math.max(max, (j - i) + 1); - } - return max; - } -} diff --git a/problems/src/two_pointers/ThreeSum.java b/problems/src/two_pointers/ThreeSum.java deleted file mode 100644 index 9e105ae7..00000000 --- a/problems/src/two_pointers/ThreeSum.java +++ /dev/null @@ -1,64 +0,0 @@ -package two_pointers; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Created by gouthamvidyapradhan on 29/03/2017. - Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero. - - Note: The solution set must not contain duplicate triplets. - - For example, given array S = [-1, 0, 1, 2, -1, -4], - - A solution set is: - [ - [-1, 0, 1], - [-1, -1, 2] - ] - */ -public class ThreeSum -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] nums = {-1,0,1,2,-1,-4,-1,0,1,2,-1,-4,-1,0,1,2,-1,-4,-1,0,1,2,-1,-4,-1,0,1,2,-1,-4,-1,0,1,2,-1,-4,-1,0,1,2,-1,-4,-1,0,1,2,-1,-4}; - System.out.println(new ThreeSum().threeSum(nums)); - } - - public List> threeSum(int[] nums) - { - List> result = new ArrayList<>(); - if(nums.length < 3) return result; - Arrays.sort(nums); - for(int i = 0, l = nums.length; i < l - 2; i ++) - { - if(i == 0 || nums[i] != nums[i - 1]) - { - int j = i + 1, k = l - 1; - while(k > j) - { - if(j != i + 1 && nums[j] == nums[j - 1]) - { - j ++; - continue; - } - int sum = nums[i] + nums[j] + nums[k]; - if(sum == 0) - { - result.add(Arrays.asList(nums[i], nums[j], nums[k])); - k--; j++; - } - else if(sum > 0) k--; - else j++; - } - } - } - return result; - } -} diff --git a/problems/src/two_pointers/TrappingRainWater.java b/problems/src/two_pointers/TrappingRainWater.java deleted file mode 100644 index d45cb2ad..00000000 --- a/problems/src/two_pointers/TrappingRainWater.java +++ /dev/null @@ -1,56 +0,0 @@ -package two_pointers; - -/** - * Created by gouthamvidyapradhan on 08/03/2017. - Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining. - - For example, - Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6. - */ -public class TrappingRainWater -{ - /** - * Main method - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception - { - int[] height = {0,1,0,2,1,0,1,3,2,1,2,1}; - System.out.println(new TrappingRainWater().trap(height)); - } - - private int trap(int[] height) - { - if(height.length == 0) return 0; - - int[] left = new int[height.length]; - int[] right = new int[height.length]; - int max = 0; - left[0] = 0; - right[height.length - 1] = 0; - - int total = 0; - - for(int i = 1, l = height.length; i < l; i ++) - { - left[i] = Math.max(max, height[i - 1]); - max = left[i]; - } - max = 0; - for(int i = height.length - 2; i >= 0; i --) - { - right[i] = Math.max(max, height[i + 1]); - max = right[i]; - } - for(int i = 0, l = height.length; i < l; i++) - { - int min = Math.min(left[i], right[i]); - if(min > height[i]) - { - total += (min - height[i]); - } - } - return total; - } -} diff --git a/src/main/java/array/AddToArrayFormOfInteger.java b/src/main/java/array/AddToArrayFormOfInteger.java new file mode 100644 index 00000000..8b8e7eef --- /dev/null +++ b/src/main/java/array/AddToArrayFormOfInteger.java @@ -0,0 +1,51 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.math.BigInteger; +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 25/07/2019 + * + *

For a non-negative integer X, the array-form of X is an array of its digits in left to right + * order. For example, if X = 1231, then the array form is [1,2,3,1]. + * + *

Given the array-form A of a non-negative integer X, return the array-form of the integer X+K. + * + *

Example 1: + * + *

Input: A = [1,2,0,0], K = 34 Output: [1,2,3,4] Explanation: 1200 + 34 = 1234 Example 2: + * + *

Input: A = [2,7,4], K = 181 Output: [4,5,5] Explanation: 274 + 181 = 455 Example 3: + * + *

Input: A = [2,1,5], K = 806 Output: [1,0,2,1] Explanation: 215 + 806 = 1021 Example 4: + * + *

Input: A = [9,9,9,9,9,9,9,9,9,9], K = 1 Output: [1,0,0,0,0,0,0,0,0,0,0] Explanation: + * 9999999999 + 1 = 10000000000 + * + *

Note: + * + *

1 <= A.length <= 10000 0 <= A[i] <= 9 0 <= K <= 10000 If A.length > 1, then A[0] != 0 + * + *

Solution: O(N) use BigInteger to add long numbers + */ +public class AddToArrayFormOfInteger { + public static void main(String[] args) { + // + } + + public List addToArrayForm(int[] A, int K) { + StringBuilder sb = new StringBuilder(); + for (int a : A) { + sb.append(a); + } + BigInteger big = new BigInteger(sb.toString()); + BigInteger result = big.add(BigInteger.valueOf(K)); + String resultStr = result.toString(); + List list = new ArrayList<>(); + for (char a : resultStr.toCharArray()) { + list.add(Integer.parseInt(String.valueOf(a))); + } + return list; + } +} diff --git a/src/main/java/array/ArrayNesting.java b/src/main/java/array/ArrayNesting.java new file mode 100644 index 00000000..05686dc3 --- /dev/null +++ b/src/main/java/array/ArrayNesting.java @@ -0,0 +1,57 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 09/10/2019 A zero-indexed array A of length N contains all + * integers from 0 to N-1. Find and return the longest length of set S, where S[i] = {A[i], A[A[i]], + * A[A[A[i]]], ... } subjected to the rule below. + * + *

Suppose the first element in S starts with the selection of element A[i] of index = i, the + * next element in S should be A[A[i]], and then A[A[A[i]]]… By that analogy, we stop adding right + * before a duplicate element occurs in S. + * + *

Example 1: + * + *

Input: A = [5,4,0,3,1,6,2] Output: 4 Explanation: A[0] = 5, A[1] = 4, A[2] = 0, A[3] = 3, A[4] + * = 1, A[5] = 6, A[6] = 2. + * + *

One of the longest S[K]: S[0] = {A[0], A[5], A[6], A[2]} = {5, 6, 2, 0} + * + *

Note: + * + *

N is an integer within the range [1, 20,000]. The elements of A are all distinct. Each element + * of A is an integer within the range [0, N-1]. + */ +public class ArrayNesting { + public static void main(String[] args) { + int[] A = {5, 4, 0, 3, 1, 6, 2}; + System.out.println(new ArrayNesting().arrayNesting(A)); + } + + Set done; + int count; + + public int arrayNesting(int[] nums) { + done = new HashSet<>(); + int max = 0; + for (int i = 0; i < nums.length; i++) { + if (!done.contains(i)) { + count = 0; + dfs(i, nums); + max = Math.max(max, count); + } + } + return max; + } + + private void dfs(int i, int[] nums) { + done.add(i); + count++; + int n = nums[i]; + if (!done.contains(n)) { + dfs(n, nums); + } + } +} diff --git a/src/main/java/array/ArrayPartitionI.java b/src/main/java/array/ArrayPartitionI.java new file mode 100644 index 00000000..c0ac8770 --- /dev/null +++ b/src/main/java/array/ArrayPartitionI.java @@ -0,0 +1,34 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 14/08/2019 Given an array of 2n integers, your task is to group + * these integers into n pairs of integer, say (a1, b1), (a2, b2), ..., (an, bn) which makes sum of + * min(ai, bi) for all i from 1 to n as large as possible. + * + *

Example 1: Input: [1,4,3,2] + * + *

Output: 4 Explanation: n is 2, and the maximum sum of pairs is 4 = min(1, 2) + min(3, 4). + * Note: n is a positive integer, which is in the range of [1, 10000]. All the integers in the array + * will be in the range of [-10000, 10000]. + * + *

Solution: O(n log n) General idea is to pair the smallest with the next smallest value inorder + * to get the max sum of minimum. + */ +public class ArrayPartitionI { + public static void main(String[] args) { + int[] A = {1, 2, 3, 4}; + System.out.println(new ArrayPartitionI().arrayPairSum(A)); + } + + public int arrayPairSum(int[] nums) { + Arrays.sort(nums); + int sum = 0; + for (int i = 1; i < nums.length; i += 2) { + sum += Math.min(nums[i - 1], nums[i]); + } + return sum; + } +} diff --git a/src/main/java/array/BattleshipsInABoard.java b/src/main/java/array/BattleshipsInABoard.java new file mode 100644 index 00000000..f714ea45 --- /dev/null +++ b/src/main/java/array/BattleshipsInABoard.java @@ -0,0 +1,55 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 12/08/2017. Given an 2D board, count how many battleships are + * in it. The battleships are represented with 'X's, empty slots are represented with '.'s. You may + * assume the following rules: + * + *

You receive a valid board, made of only battleships or empty slots. Battleships can only be + * placed horizontally or vertically. In other words, they can only be made of the shape 1xN (1 row, + * N columns) or Nx1 (N rows, 1 column), where N can be of any size. At least one horizontal or + * vertical cell separates between two battleships - there are no adjacent battleships. Example: + * X..X ...X ...X In the above board there are 2 battleships. Invalid Example: ...X XXXX ...X This + * is an invalid board that you will not receive - as battleships will always have a cell separating + * between them. + * + *

Follow up: Could you do it in one-pass, using only O(1) extra memory and without modifying the + * value of the board? + * + *

Solution: The below solution works in one pass using only O(1) memory. Iterate through each + * cell and add one to count if and only if the current cell equals 'X' and its adjacent upper and + * left cell does not contain 'X' + */ +public class BattleshipsInABoard { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + char[][] board = {{'X', '.', '.', 'X'}, {'.', '.', '.', 'X'}, {'.', '.', '.', 'X'}}; + System.out.println(new BattleshipsInABoard().countBattleships(board)); + } + + public int countBattleships(char[][] board) { + int count = 0; + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + if (board[i][j] == 'X') { + if (i - 1 >= 0) { // check for the boundary condition + if (board[i - 1][j] == 'X') continue; + } + if (j - 1 >= 0) { + if (board[i][j - 1] == 'X') { + continue; + } + } + count++; + } + } + } + return count; + } +} diff --git a/src/main/java/array/BestMeetingPoint.java b/src/main/java/array/BestMeetingPoint.java new file mode 100644 index 00000000..6252d428 --- /dev/null +++ b/src/main/java/array/BestMeetingPoint.java @@ -0,0 +1,77 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 10/03/2019 A group of two or more people wants to meet and + * minimize the total travel distance. You are given a 2D grid of values 0 or 1, where each 1 marks + * the home of someone in the group. The distance is calculated using Manhattan Distance, where + * distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|. + * + *

Example: + * + *

Input: + * + *

1 - 0 - 0 - 0 - 1 | | | | | 0 - 0 - 0 - 0 - 0 | | | | | 0 - 0 - 1 - 0 - 0 + * + *

Output: 6 + * + *

Explanation: Given three people living at (0,0), (0,4), and (2,2): The point (0,2) is an ideal + * meeting point, as the total travel distance of 2+2+2=6 is minimal. So return 6. + * + *

Solution: O(N ^ 2 + M ^ 2) + O(N x M): Calculate the total number of persons in each row and + * each column and then take a minimum of cartesian product of each row and each column. + */ +public class BestMeetingPoint { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[][] grid = {{1, 0, 0, 0, 1}, {0, 0, 0, 0, 0}, {0, 0, 1, 0, 0}}; + System.out.println(new BestMeetingPoint().minTotalDistance(grid)); + } + + public int minTotalDistance(int[][] grid) { + int[] countR = new int[grid.length]; + int[] countC = new int[grid[0].length]; + + int[] distR = new int[grid.length]; + int[] distC = new int[grid[0].length]; + + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 1) { + countR[i]++; + countC[j]++; + } + } + } + + for (int i = 0; i < distR.length; i++) { + for (int j = 0; j < distR.length; j++) { + if (countR[j] != 0) { + distR[i] += Math.abs(j - i) * countR[j]; + } + } + } + + for (int i = 0; i < distC.length; i++) { + for (int j = 0; j < distC.length; j++) { + if (countC[j] != 0) { + distC[i] += Math.abs(j - i) * countC[j]; + } + } + } + + int min = Integer.MAX_VALUE; + for (int i = 0; i < distR.length; i++) { + for (int j = 0; j < distC.length; j++) { + min = Math.min(min, distR[i] + distC[j]); + } + } + + return min; + } +} diff --git a/src/main/java/array/CanPlaceFlowers.java b/src/main/java/array/CanPlaceFlowers.java new file mode 100644 index 00000000..8936f37d --- /dev/null +++ b/src/main/java/array/CanPlaceFlowers.java @@ -0,0 +1,49 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 10/06/2017. Accepted + * + *

Suppose you have a long flowerbed in which some of the plots are planted and some are not. + * However, flowers cannot be planted in adjacent plots - they would compete for water and both + * would die. + * + *

Given a flowerbed (represented as an array containing 0 and 1, where 0 means empty and 1 means + * not empty), and a number n, return if n new flowers can be planted in it without violating the + * no-adjacent-flowers rule. + * + *

Example 1: Input: flowerbed = [1,0,0,0,1], n = 1 Output: True Example 2: Input: flowerbed = + * [1,0,0,0,1], n = 2 Output: False Note: The input array won't violate no-adjacent-flowers rule. + * The input array size is in the range of [1, 20000]. n is a non-negative integer which won't + * exceed the input array size. + */ +public class CanPlaceFlowers { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] n = {1, 0, 0, 0, 1}; + System.out.println(new CanPlaceFlowers().canPlaceFlowers(n, 1)); + } + + public boolean canPlaceFlowers(int[] flowerbed, int n) { + + int[] T = new int[flowerbed.length + 4]; + for (int i = 0, j = 2; i < flowerbed.length; i++) T[j++] = flowerbed[i]; + T[0] = 1; + T[T.length - 1] = 1; + int total = 0, count = 0; + for (int i = 1; i < T.length; i++) { + if (T[i] == 0) count++; + else { + if ((count % 2) == 0) total += ((count / 2) - 1); + else total += (count / 2); + count = 0; // reset + } + } + return (total >= n); + } +} diff --git a/src/main/java/array/CardFilipGame.java b/src/main/java/array/CardFilipGame.java new file mode 100644 index 00000000..1b145691 --- /dev/null +++ b/src/main/java/array/CardFilipGame.java @@ -0,0 +1,61 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 04/05/2018. + * + *

On a table are N cards, with a positive integer printed on the front and back of each card + * (possibly different). + * + *

We flip any number of cards, and after we choose one card. + * + *

If the number X on the back of the chosen card is not on the front of any card, then this + * number X is good. + * + *

What is the smallest number that is good? If no number is good, output 0. + * + *

Here, fronts[i] and backs[i] represent the number on the front and back of card i. + * + *

A flip swaps the front and back numbers, so the value on the front is now on the back and vice + * versa. + * + *

Example: + * + *

Input: fronts = [1,2,4,4,7], backs = [1,3,4,1,3] Output: 2 Explanation: If we flip the second + * card, the fronts are [1,3,4,4,7] and the backs are [1,2,4,1,3]. We choose the second card, which + * has number 2 on the back, and it isn't on the front of any card, so 2 is good. + * + *

Note: + * + *

1 <= fronts.length == backs.length <= 1000. 1 <= fronts[i] <= 2000. 1 <= backs[i] <= 2000. + */ +public class CardFilipGame { + + public static void main(String[] args) {} + + public int flipgame(int[] fronts, int[] backs) { + List numbers = new ArrayList<>(); + for (int i = 0; i < fronts.length; i++) { + numbers.add(fronts[i]); + numbers.add(backs[i]); + } + Collections.sort(numbers); + for (int n : numbers) { + boolean success = true; + for (int i = 0; i < fronts.length; i++) { + if (n == fronts[i] && n == backs[i]) { + success = false; + break; + } + } + if (success) { + return n; + } + } + return 0; + } +} diff --git a/src/main/java/array/ChampagneTower.java b/src/main/java/array/ChampagneTower.java new file mode 100644 index 00000000..2cfec24d --- /dev/null +++ b/src/main/java/array/ChampagneTower.java @@ -0,0 +1,70 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 28/03/2019 We stack glasses in a pyramid, where the first row + * has 1 glass, the second row has 2 glasses, and so on until the 100th row. Each glass holds one + * cup (250ml) of champagne. + * + *

Then, some champagne is poured in the first glass at the top. When the top most glass is full, + * any excess liquid poured will fall equally to the glass immediately to the left and right of it. + * When those glasses become full, any excess champagne will fall equally to the left and right of + * those glasses, and so on. (A glass at the bottom row has it's excess champagne fall on the + * floor.) + * + *

For example, after one cup of champagne is poured, the top most glass is full. After two cups + * of champagne are poured, the two glasses on the second row are half full. After three cups of + * champagne are poured, those two cups become full - there are 3 full glasses total now. After four + * cups of champagne are poured, the third row has the middle glass half full, and the two outside + * glasses are a quarter full, as pictured below. + * + *

Now after pouring some non-negative integer cups of champagne, return how full the j-th glass + * in the i-th row is (both i and j are 0 indexed.) + * + *

Example 1: Input: poured = 1, query_glass = 1, query_row = 1 Output: 0.0 Explanation: We + * poured 1 cup of champange to the top glass of the tower (which is indexed as (0, 0)). There will + * be no excess liquid so all the glasses under the top glass will remain empty. + * + *

Example 2: Input: poured = 2, query_glass = 1, query_row = 1 Output: 0.5 Explanation: We + * poured 2 cups of champange to the top glass of the tower (which is indexed as (0, 0)). There is + * one cup of excess liquid. The glass indexed as (1, 0) and the glass indexed as (1, 1) will share + * the excess liquid equally, and each will get half cup of champange. + * + *

Note: + * + *

poured will be in the range of [0, 10 ^ 9]. query_glass and query_row will be in the range of + * [0, 99]. + * + *

Solution: Calculate for every glass and for each row at a time. Use the value from the + * previous row to calculate the current value. + * + * @see PascalsTriangle + */ +public class ChampagneTower { + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + System.out.println(new ChampagneTower().champagneTower(4, 2, 1)); + } + + public double champagneTower(int poured, int query_row, int query_glass) { + double[][] A = new double[query_row + 1][query_row + 1]; + A[0][0] = poured; + for (int i = 1; i <= query_row; i++) { + for (int j = 0; j <= query_row; j++) { + if (A[i - 1][j] > 1.0) { + A[i][j] += (A[i - 1][j] - 1.0) / 2; + } + if (j == 0) continue; + if (A[i - 1][j - 1] > 1.0) { + A[i][j] += (A[i - 1][j - 1] - 1.0) / 2; + } + } + } + if (A[query_row][query_glass] > 1.0) return 1; + else return A[query_row][query_glass]; + } +} diff --git a/src/main/java/array/EmployeeFreeTime.java b/src/main/java/array/EmployeeFreeTime.java new file mode 100644 index 00000000..4eb584c1 --- /dev/null +++ b/src/main/java/array/EmployeeFreeTime.java @@ -0,0 +1,118 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 08/03/2019 We are given a list schedule of employees, which + * represents the working time for each employee. + * + *

Each employee has a list of non-overlapping Intervals, and these intervals are in sorted + * order. + * + *

Return the list of finite intervals representing common, positive-length free time for all + * employees, also in sorted order. + * + *

Example 1: Input: schedule = [[[1,2],[5,6]],[[1,3]],[[4,10]]] Output: [[3,4]] Explanation: + * There are a total of three employees, and all common free time intervals would be [-inf, 1], [3, + * 4], [10, inf]. We discard any intervals that contain inf as they aren't finite. Example 2: Input: + * schedule = [[[1,3],[6,7]],[[2,4]],[[2,5],[9,12]]] Output: [[5,6],[7,9]] (Even though we are + * representing Intervals in the form [x, y], the objects inside are Intervals, not lists or arrays. + * For example, schedule[0][0].start = 1, schedule[0][0].end = 2, and schedule[0][0][0] is not + * defined.) + * + *

Also, we wouldn't include intervals like [5, 5] in our answer, as they have zero length. + * + *

Note: + * + *

schedule and schedule[i] are lists with lengths in range [1, 50]. 0 <= schedule[i].start < + * schedule[i].end <= 10^8. + * + *

Solution: O(L X N x N) Where L is the number of schedules, N is the length of schedules for + * each employee. Merge all the intervals to form a single merged array, now by using this array + * form a result array with the intervals which form the free time. + */ +public class EmployeeFreeTime { + + public static class Interval { + int start; + int end; + + Interval() { + start = 0; + end = 0; + } + + Interval(int s, int e) { + start = s; + end = e; + } + } + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + List> schedule = new ArrayList<>(); + List ints1 = new ArrayList<>(); + ints1.add(new Interval(45, 56)); + ints1.add(new Interval(89, 96)); + + List ints3 = new ArrayList<>(); + ints3.add(new Interval(5, 21)); + ints3.add(new Interval(57, 74)); + + schedule.add(ints1); + schedule.add(ints3); + + List result = new EmployeeFreeTime().employeeFreeTime(schedule); + for (Interval i : result) { + System.out.println(i.start + " " + i.end); + } + } + + public List employeeFreeTime(List> schedule) { + if (schedule.isEmpty()) return new ArrayList<>(); + List merged = schedule.get(0); + for (int i = 1, l = schedule.size(); i < l; i++) { + List employeeInt = schedule.get(i); + for (Interval in : employeeInt) { + merged = merge(merged, in); + } + } + List result = new ArrayList<>(); + for (int i = 0, l = merged.size(); i + 1 < l; i++) { + if (merged.get(i).end != merged.get(i + 1).start) { + result.add(new Interval(merged.get(i).end, merged.get(i + 1).start)); + } + } + return result; + } + + private List merge(List list, Interval interval) { + List result = new ArrayList<>(); + for (int i = 0, l = list.size(); i < l; i++) { + Interval curr = list.get(i); + if (interval.start >= curr.start && interval.end <= curr.end) { + return list; + } else if (interval.start >= curr.start && interval.start <= curr.end) { + interval = new Interval(curr.start, interval.end); + } else if (interval.end >= curr.start && interval.end <= curr.end) { + interval = new Interval(interval.start, curr.end); + } else if (interval.end < curr.start) { + result.add(interval); + for (int j = i; j < l; j++) { + result.add(list.get(j)); + } + return result; + } else if (interval.start > curr.end) { + result.add(curr); + } + } + result.add(interval); + return result; + } +} diff --git a/src/main/java/array/FindPivotIndex.java b/src/main/java/array/FindPivotIndex.java new file mode 100644 index 00000000..7bb8aeda --- /dev/null +++ b/src/main/java/array/FindPivotIndex.java @@ -0,0 +1,67 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 06/08/2019 Given an array of integers nums, write a method that + * returns the "pivot" index of this array. + * + *

We define the pivot index as the index where the sum of the numbers to the left of the index + * is equal to the sum of the numbers to the right of the index. + * + *

If no such index exists, we should return -1. If there are multiple pivot indexes, you should + * return the left-most pivot index. + * + *

Example 1: + * + *

Input: nums = [1, 7, 3, 6, 5, 6] Output: 3 Explanation: The sum of the numbers to the left of + * index 3 (nums[3] = 6) is equal to the sum of numbers to the right of index 3. Also, 3 is the + * first index where this occurs. + * + *

Example 2: + * + *

Input: nums = [1, 2, 3] Output: -1 Explanation: There is no index that satisfies the + * conditions in the problem statement. + * + *

Note: + * + *

The length of nums will be in the range [0, 10000]. Each element nums[i] will be an integer in + * the range [-1000, 1000]. + * + *

Solution: O(N) maintain a prefix and posfix sum array and then use this to arrive at the + * answer. + */ +public class FindPivotIndex { + public static void main(String[] args) {} + + public int pivotIndex(int[] nums) { + if (nums.length == 1) return 0; + int[] left = new int[nums.length]; + int[] right = new int[nums.length]; + left[0] = nums[0]; + for (int i = 1; i < nums.length; i++) { + left[i] = left[i - 1] + nums[i]; + } + right[nums.length - 1] = nums[nums.length - 1]; + for (int i = nums.length - 2; i >= 0; i--) { + right[i] = right[i + 1] + nums[i]; + } + for (int i = 0; i < nums.length; i++) { + int l, r; + if (i == 0) { + l = 0; + } else { + l = left[i - 1]; + } + + if (i == nums.length - 1) { + r = 0; + } else { + r = right[i + 1]; + } + if (l == r) return i; + } + return -1; + } +} diff --git a/src/main/java/array/FindTheCelebrity.java b/src/main/java/array/FindTheCelebrity.java new file mode 100644 index 00000000..c4b4b5ca --- /dev/null +++ b/src/main/java/array/FindTheCelebrity.java @@ -0,0 +1,109 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Created by gouthamvidyapradhan on 25/11/2017. + * + *

Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, there may + * exist one celebrity. The definition of a celebrity is that all the other n - 1 people know + * him/her but he/she does not know any of them. + * + *

Now you want to find out who the celebrity is or verify that there is not one. The only thing + * you are allowed to do is to ask questions like: "Hi, A. Do you know B?" to get information of + * whether A knows B. You need to find out the celebrity (or verify there is not one) by asking as + * few questions as possible (in the asymptotic sense). + * + *

You are given a helper function bool knows(a, b) which tells you whether A knows B. Implement + * a function int findCelebrity(n), your function should minimize the number of calls to knows. + * + *

Note: There will be exactly one celebrity if he/she is in the party. Return the celebrity's + * label if there is a celebrity in the party. If there is no celebrity, return -1. + */ +public class FindTheCelebrity { + + private static Map> map = new HashMap<>(); + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + // initialize relationship + map.put(0, new HashSet<>()); + map.put(1, new HashSet<>()); + map.put(2, new HashSet<>()); + map.put(3, new HashSet<>()); + map.put(4, new HashSet<>()); + map.put(5, new HashSet<>()); + map.put(6, new HashSet<>()); + map.get(0).add(3); + map.get(0).add(1); + map.get(0).add(2); + map.get(0).add(4); + map.get(0).add(5); + map.get(0).add(6); + + map.get(1).add(0); + map.get(1).add(3); + map.get(1).add(2); + + map.get(2).add(1); + map.get(2).add(3); + map.get(2).add(4); + + map.get(4).add(2); + map.get(4).add(3); + map.get(4).add(5); + + map.get(5).add(4); + map.get(5).add(3); + map.get(5).add(6); + + map.get(6).add(5); + map.get(6).add(3); + map.get(6).add(0); + + System.out.println(new FindTheCelebrity().findCelebrity(0)); + } + + /** + * Find celebrity + * + * @param n + * @return + */ + public int findCelebrity(int n) { + int candidate = -1, i = 0, next = 1; + while (i < n) { + if (next >= n) break; + if (knows(i, next) && !knows(next, i)) { + i = next; + next = i + 1; + } else if ((!knows(i, next) && !knows(next, i)) || (knows(i, next) && knows(next, i))) { + i = next + 1; + next = i + 1; + } else { + next++; + } + candidate = i; + } + if (candidate == -1 || candidate >= n) return -1; + for (int j = 0; j < candidate; j++) { + if (!knows(j, candidate) || knows(candidate, j)) { + candidate = -1; + break; + } + } + return candidate; + } + + private boolean knows(int a, int b) { + return map.get(a).contains(b); + } +} diff --git a/src/main/java/array/FirstMissingPositive.java b/src/main/java/array/FirstMissingPositive.java new file mode 100644 index 00000000..b589eb20 --- /dev/null +++ b/src/main/java/array/FirstMissingPositive.java @@ -0,0 +1,44 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 24/06/2017. Given an unsorted integer array, find the first + * missing positive integer. + * + *

For example, Given [1,2,0] return 3, and [3,4,-1,1] return 2. + * + *

Your algorithm should run in O(n) time and uses constant space. + */ +public class FirstMissingPositive { + private int L; + + public static void main(String[] args) throws Exception { + int[] nums = {1, 3, 5, 9}; + System.out.println(new FirstMissingPositive().firstMissingPositive(nums)); + } + + public int firstMissingPositive(int[] nums) { + L = nums.length; + for (int i = 0; i < L; i++) { + if (nums[i] > 0 && nums[i] <= L && nums[i] != i + 1) { + int v = nums[i]; + nums[i] = -1; + replace(v, nums); + } + } + + for (int i = 0; i < L; i++) { + if (nums[i] != i + 1) return i + 1; + } + + return L + 1; + } + + private void replace(int i, int[] nums) { + if (i > 0 && i <= L && i != nums[i - 1]) { + int v = nums[i - 1]; + nums[i - 1] = i; + replace(v, nums); + } + } +} diff --git a/src/main/java/array/FruitIntoBaskets.java b/src/main/java/array/FruitIntoBaskets.java new file mode 100644 index 00000000..10a3d9be --- /dev/null +++ b/src/main/java/array/FruitIntoBaskets.java @@ -0,0 +1,88 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.Stack; + +/** + * Created by gouthamvidyapradhan on 02/03/2019 In a row of trees, the i-th tree produces fruit with + * type tree[i]. + * + *

You start at any tree of your choice, then repeatedly perform the following steps: + * + *

Add one piece of fruit from this tree to your baskets. If you cannot, stop. Move to the next + * tree to the right of the current tree. If there is no tree to the right, stop. Note that you do + * not have any choice after the initial choice of starting tree: you must perform step 1, then step + * 2, then back to step 1, then step 2, and so on until you stop. + * + *

You have two baskets, and each basket can carry any quantity of fruit, but you want each + * basket to only carry one type of fruit each. + * + *

What is the total amount of fruit you can collect with this procedure? + * + *

Example 1: + * + *

Input: [1,2,1] Output: 3 Explanation: We can collect [1,2,1]. Example 2: + * + *

Input: [0,1,2,2] Output: 3 Explanation: We can collect [1,2,2]. If we started at the first + * tree, we would only collect [0, 1]. Example 3: + * + *

Input: [1,2,3,2,2] Output: 4 Explanation: We can collect [2,3,2,2]. If we started at the first + * tree, we would only collect [1, 2]. Example 4: + * + *

Input: [3,3,3,1,2,1,1,2,3,3,4] Output: 5 Explanation: We can collect [1,2,1,1,2]. If we + * started at the first tree or the eighth tree, we would only collect 4 fruits. + * + *

Note: + * + *

1 <= tree.length <= 40000 0 <= tree[i] < tree.length + */ +public class FruitIntoBaskets { + + private int count = 0; + private int max = 0; + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[] trees = {1, 0, 3, 4, 3}; + System.out.println(new FruitIntoBaskets().totalFruit(trees)); + } + + public int totalFruit(int[] tree) { + int t1 = -1, t2 = -1; + Stack stack = new Stack<>(); + for (int i : tree) { + if (i == t1 || i == t2) { + countAndMax(stack, i); + } else { + if (t1 == -1) { + t1 = i; + countAndMax(stack, i); + } else if (t2 == -1) { + t2 = i; + countAndMax(stack, i); + } else { + Stack temp = new Stack<>(); + count = 0; + t1 = stack.pop(); + countAndMax(temp, t1); + while (!stack.isEmpty() && stack.peek() == t1) { + countAndMax(temp, stack.pop()); + } + t2 = i; + stack = temp; + countAndMax(stack, i); + } + } + } + return max; + } + + private void countAndMax(Stack stack, int i) { + count++; + stack.push(i); + max = Math.max(max, count); + } +} diff --git a/src/main/java/array/HIndex.java b/src/main/java/array/HIndex.java new file mode 100644 index 00000000..5360b375 --- /dev/null +++ b/src/main/java/array/HIndex.java @@ -0,0 +1,56 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 12/12/2017. Given an array of citations (each citation is a + * non-negative integer) of a researcher, write a function to compute the researcher's h-index. + * + *

According to the definition of h-index on Wikipedia: "A scientist has index h if h of his/her + * N papers have at least h citations each, and the other N − h papers have no more than h citations + * each." + * + *

For example, given citations = [3, 0, 6, 1, 5], which means the researcher has 5 papers in + * total and each of them had received 3, 0, 6, 1, 5 citations respectively. Since the researcher + * has 3 papers with at least 3 citations each and the remaining two with no more than 3 citations + * each, his h-index is 3. + * + *

Note: If there are several possible values for h, the maximum one is taken as the h-index. + * + *

Solution O(n) Replace all the citations which are greater than n with n, the result will not + * change with this operation. Maintain a count array with count of each citations. Sum up all the + * counts from n -> 0 and store this in a array S. Value in array index Si is number of papers + * having citations at least i. + * + *

The first value at index i, from right to left in array S which has i <= Si is the answer. + */ +public class HIndex { + + public static void main(String[] args) throws Exception { + int[] A = {3, 0, 6, 1, 5}; + System.out.println(new HIndex().hIndex(A)); + } + + public int hIndex(int[] citations) { + int n = citations.length; + int[] count = new int[n + 1]; + int[] S = new int[n + 1]; + for (int i = 0; i < citations.length; i++) { + if (citations[i] > n) { + citations[i] = n; + } + } + for (int citation : citations) { + count[citation]++; + } + S[n] = count[n]; + for (int i = n - 1; i >= 0; i--) { + S[i] = count[i] + S[i + 1]; + } + for (int i = n; i >= 0; i--) { + if (i <= S[i]) { + return i; + } + } + return 0; + } +} diff --git a/src/main/java/array/ImageSmoother.java b/src/main/java/array/ImageSmoother.java new file mode 100644 index 00000000..af1d4903 --- /dev/null +++ b/src/main/java/array/ImageSmoother.java @@ -0,0 +1,44 @@ +/* (C) 2024 YourCompanyName */ +package array; +/** + * Created by gouthamvidyapradhan on 17/02/2018. * Given a 2D integer matrix M representing the gray + * scale of an image, you need to design a smoother to make the gray scale of each cell becomes the + * average gray scale (rounding down) of all the 8 surrounding cells and itself. If a cell has less + * than 8 surrounding cells, then use as many as you can. + * + *

Example 1: Input: [[1,1,1], [1,0,1], [1,1,1]] Output: [[0, 0, 0], [0, 0, 0], [0, 0, 0]] + * Explanation: For the point (0,0), (0,2), (2,0), (2,2): floor(3/4) = floor(0.75) = 0 For the point + * (0,1), (1,0), (1,2), (2,1): floor(5/6) = floor(0.83333333) = 0 For the point (1,1): floor(8/9) = + * floor(0.88888889) = 0 Note: The value in the given matrix is in the range of [0, 255]. The length + * and width of the given matrix are in the range of [1, 150]. + */ +public class ImageSmoother { + + int[] R = {1, -1, 0, 0, 1, -1, 1, -1}; + int[] C = {0, 0, -1, 1, 1, 1, -1, -1}; + + public static void main(String[] args) throws Exception {} + + public int[][] imageSmoother(int[][] M) { + int[][] result = new int[M.length][M[0].length]; + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M[0].length; j++) { + int numCount = 0; + int totalCount = 1; + for (int k = 0; k < 8; k++) { + int newR = i + R[k]; + int newC = j + C[k]; + if (newR >= 0 && newC >= 0 && newR < M.length && newC < M[0].length) { + if (M[newR][newC] > 0) { + numCount += M[newR][newC]; + } + totalCount++; + } + } + if (M[i][j] == 1) numCount++; + result[i][j] = numCount / totalCount; + } + } + return result; + } +} diff --git a/src/main/java/array/IncreasingTripletSubsequence.java b/src/main/java/array/IncreasingTripletSubsequence.java new file mode 100644 index 00000000..02fe1d96 --- /dev/null +++ b/src/main/java/array/IncreasingTripletSubsequence.java @@ -0,0 +1,45 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 17/12/2017. Given an unsorted array return whether an + * increasing subsequence of length 3 exists or not in the array. + * + *

Formally the function should: Return true if there exists i, j, k such that arr[i] < arr[j] < + * arr[k] given 0 ≤ i < j < k ≤ n-1 else return false. Your algorithm should run in O(n) time + * complexity and O(1) space complexity. + * + *

Examples: Given [1, 2, 3, 4, 5], return true. + * + *

Given [5, 4, 3, 2, 1], return false. + */ +public class IncreasingTripletSubsequence { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 2, 3, 4, 5}; + System.out.println(new IncreasingTripletSubsequence().increasingTriplet(A)); + } + + public boolean increasingTriplet(int[] nums) { + int[] A = new int[3]; + Arrays.fill(A, Integer.MAX_VALUE); + for (int num : nums) { + if (num < A[0]) { + A[0] = num; + } else if (num < A[1] && num > A[0]) { + A[1] = num; + } else if (num < A[2] && num > A[1]) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/array/InsertInterval.java b/src/main/java/array/InsertInterval.java new file mode 100644 index 00000000..8216e270 --- /dev/null +++ b/src/main/java/array/InsertInterval.java @@ -0,0 +1,97 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 15/12/2017. Given a set of non-overlapping intervals, insert a + * new interval into the intervals (merge if necessary). + * + *

You may assume that the intervals were initially sorted according to their start times. + * + *

Example 1: Given intervals [1,3],[6,9], insert and merge [2,5] in as [1,5],[6,9]. + * + *

Example 2: Given [1,2],[3,5],[6,7],[8,10],[12,16], insert and merge [4,9] in as + * [1,2],[3,10],[12,16]. + * + *

This is because the new interval [4,9] overlaps with [3,5],[6,7],[8,10]. + * + *

Solution: O(n): Iterate through each interval and check for each overlapping case + */ +public class InsertInterval { + + public static class Interval { + int start; + int end; + + Interval() { + start = 0; + end = 0; + } + + Interval(int s, int e) { + start = s; + end = e; + } + } + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + Interval i1 = new Interval(1, 2); + Interval i2 = new Interval(3, 5); + Interval i3 = new Interval(6, 7); + Interval i4 = new Interval(8, 10); + Interval i5 = new Interval(12, 16); + List list = Arrays.asList(i1, i2, i3, i4, i5); + List result = new InsertInterval().insert(list, new Interval(2, 5)); + result.stream().map(x -> x.start + " " + x.end).forEach(System.out::println); + } + + public List insert(List intervals, Interval newInterval) { + List result = new ArrayList<>(); + for (int i = 0, l = intervals.size(); i < l; i++) { + Interval curr = intervals.get(i); + if (newInterval.start >= curr.start && newInterval.end <= curr.end) { + insertRest(intervals, result, i); + return result; // easy case + } else if (newInterval.start < curr.start && newInterval.end > curr.end) { + newInterval = new Interval(newInterval.start, newInterval.end); + // merge and continue + } else if (newInterval.start >= curr.start + && newInterval.start <= curr.end + && newInterval.end > curr.end) { + newInterval = new Interval(curr.start, newInterval.end); + // merge and continue + } else if (newInterval.start < curr.start + && newInterval.end >= curr.start + && newInterval.end <= curr.end) { + Interval newI = new Interval(newInterval.start, curr.end); + result.add(newI); + insertRest(intervals, result, i + 1); + return result; + } else if (newInterval.start > curr.end) { + result.add(curr); + } else { + result.add(newInterval); + insertRest(intervals, result, i); + return result; + } + } + result.add(newInterval); + return result; + } + + private void insertRest(List intervals, List result, int i) { + int l = intervals.size(); + while (i < l) { + result.add(intervals.get(i)); + i++; + } + } +} diff --git a/src/main/java/array/KEmptySlots.java b/src/main/java/array/KEmptySlots.java new file mode 100644 index 00000000..f83dc515 --- /dev/null +++ b/src/main/java/array/KEmptySlots.java @@ -0,0 +1,62 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.TreeSet; + +/** + * Created by gouthamvidyapradhan on 01/01/2018. There is a garden with N slots. In each slot, there + * is a flower. The N flowers will bloom one by one in N days. In each day, there will be exactly + * one flower blooming and it will be in the status of blooming since then. + * + *

Given an array flowers consists of number from 1 to N. Each number in the array represents the + * place where the flower will open in that day. + * + *

For example, flowers[i] = x means that the unique flower that blooms at day i will be at + * position x, where i and x will be in the range from 1 to N. + * + *

Also given an integer k, you need to output in which day there exists two flowers in the + * status of blooming, and also the number of flowers between them is k and these flowers are not + * blooming. + * + *

If there isn't such day, output -1. + * + *

Example 1: Input: flowers: [1,3,2] k: 1 Output: 2 Explanation: In the second day, the first + * and the third flower have become blooming. Example 2: Input: flowers: [1,2,3] k: 1 Output: -1 + * Note: The given array will be in the range [1, 20000]. + * + *

Solution: O(n log n). Maintain a tree-set of bloomed flowers and for every element in the + * array find the upper and lower bound bloomed flowers and calculate their difference with the + * current. If the difference is k return the current day, if none found then return -1 + */ +public class KEmptySlots { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 3, 2}; + System.out.println(new KEmptySlots().kEmptySlots(A, 2)); + } + + public int kEmptySlots(int[] flowers, int k) { + TreeSet set = new TreeSet<>(); + for (int i = 0; i < flowers.length; i++) { + Integer lowerBound = set.floor(flowers[i]); + Integer upperBound = set.ceiling(flowers[i]); + if (lowerBound != null) { + if ((Math.abs(flowers[i] - lowerBound) + 1) == k) { + return i + 1; + } + } + if (upperBound != null) { + if ((Math.abs(flowers[i] - upperBound) + 1) == k) { + return i + 1; + } + } + set.add(flowers[i]); + } + return -1; + } +} diff --git a/src/main/java/array/LargestNumberAtLeastTwice.java b/src/main/java/array/LargestNumberAtLeastTwice.java new file mode 100644 index 00000000..03905711 --- /dev/null +++ b/src/main/java/array/LargestNumberAtLeastTwice.java @@ -0,0 +1,55 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 09/02/2018. In a given integer array nums, there is always + * exactly one largest element. + * + *

Find whether the largest element in the array is at least twice as much as every other number + * in the array. + * + *

If it is, return the index of the largest element, otherwise return -1. + * + *

Example 1: + * + *

Input: nums = [3, 6, 1, 0] Output: 1 Explanation: 6 is the largest integer, and for every + * other number in the array x, 6 is more than twice as big as x. The index of value 6 is 1, so we + * return 1. + * + *

Example 2: + * + *

Input: nums = [1, 2, 3, 4] Output: -1 Explanation: 4 isn't at least as big as twice the value + * of 3, so we return -1. + * + *

Note: + * + *

nums will have a length in the range [1, 50]. Every nums[i] will be an integer in the range + * [0, 99]. + */ +public class LargestNumberAtLeastTwice { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception {} + + public int dominantIndex(int[] nums) { + int index = 0, max = Integer.MIN_VALUE; + for (int i = 0; i < nums.length; i++) { + if (nums[i] > max) { + max = nums[i]; + index = i; + } + } + for (int i = 0; i < nums.length; i++) { + if (i == index) continue; + if (((long) nums[i] * 2) > max) { + return -1; + } + } + return index; + } +} diff --git a/src/main/java/array/LargestTimeForGivenDigits.java b/src/main/java/array/LargestTimeForGivenDigits.java new file mode 100644 index 00000000..d934f6f9 --- /dev/null +++ b/src/main/java/array/LargestTimeForGivenDigits.java @@ -0,0 +1,55 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 06/08/2019 Given an array of 4 digits, return the largest 24 + * hour time that can be made. + * + *

The smallest 24 hour time is 00:00, and the largest is 23:59. Starting from 00:00, a time is + * larger if more time has elapsed since midnight. + * + *

Return the answer as a string of length 5. If no valid time can be made, return an empty + * string. + * + *

Example 1: + * + *

Input: [1,2,3,4] Output: "23:41" Example 2: + * + *

Input: [5,5,5,5] Output: "" + * + *

Note: + * + *

A.length == 4 0 <= A[i] <= 9 Solution O(N ^ 4) Check all combinations of time possible and + * return the maximum possible as the answer. + */ +public class LargestTimeForGivenDigits { + public static void main(String[] args) { + int[] A = {2, 0, 6, 6}; + System.out.println(new LargestTimeForGivenDigits().largestTimeFromDigits(A)); + } + + public String largestTimeFromDigits(int[] A) { + int max = -1; + String result = ""; + for (int i = 0; i < A.length; i++) { + if (A[i] > 2) continue; + for (int j = 0; j < A.length; j++) { + if (j == i) continue; + if (A[i] == 2 && A[j] > 3) continue; + for (int k = 0; k < A.length; k++) { + if (k == i || k == j) continue; + if (A[k] > 5) continue; + for (int l = 0; l < A.length; l++) { + if (l == i || l == j || l == k) continue; + int value = ((A[i] * 10 + A[j]) * 60) + A[k] * 10 + A[l]; + if (value > max) { + max = value; + result = A[i] + "" + A[j] + ":" + A[k] + "" + A[l]; + } + } + } + } + } + return result; + } +} diff --git a/src/main/java/array/LongestIncreasingSubsequence.java b/src/main/java/array/LongestIncreasingSubsequence.java new file mode 100644 index 00000000..5d009116 --- /dev/null +++ b/src/main/java/array/LongestIncreasingSubsequence.java @@ -0,0 +1,47 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 03/12/2017. + * + *

Given an unsorted array of integers, find the length of longest continuous increasing + * subsequence (subarray). + * + *

Example 1: Input: [1,3,5,4,7] Output: 3 Explanation: The longest continuous increasing + * subsequence is [1,3,5], its length is 3. Even though [1,3,5,7] is also an increasing subsequence, + * it's not a continuous one where 5 and 7 are separated by 4. Example 2: Input: [2,2,2,2,2] Output: + * 1 Explanation: The longest continuous increasing subsequence is [2], its length is 1. Note: + * Length of the array will not exceed 10,000. + */ +public class LongestIncreasingSubsequence { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 3, 5, 4, 7}; + System.out.println(new LongestIncreasingSubsequence().findLengthOfLCIS(A)); + } + + public int findLengthOfLCIS(int[] nums) { + int max = 1, count = 1; + if (nums.length == 1) return max; + if (nums.length == 0) return 0; + for (int i = 0, j = i + 1; j < nums.length; ) { + if (nums[j] > nums[i]) { + count++; + i++; + j++; + } else { + max = Math.max(max, count); + count = 0; + i = j; + j = i + 1; + } + } + return max; + } +} diff --git a/src/main/java/array/LongestLineofConsecutiveOneinMatrix.java b/src/main/java/array/LongestLineofConsecutiveOneinMatrix.java new file mode 100644 index 00000000..4e03d461 --- /dev/null +++ b/src/main/java/array/LongestLineofConsecutiveOneinMatrix.java @@ -0,0 +1,118 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 14/08/2019 Given a 01 matrix M, find the longest line of + * consecutive one in the matrix. The line could be horizontal, vertical, diagonal or anti-diagonal. + * Example: Input: [[0,1,1,0], [0,1,1,0], [0,0,0,1]] Output: 3 Hint: The number of elements in the + * given matrix will not exceed 10,000. + * + *

Solution O(N x M) for each cell keep track of maximum value possible horizontally, vertically + * and diagonally. Start iterating from left-right and top-bottom and repeat the same from + * right-left and top to bottom to get max for anti-diagonal and return the max value. + */ +public class LongestLineofConsecutiveOneinMatrix { + final int[] R = {0, 0, -1, 1}; + final int[] C = {1, -1, 0, 0}; + + public static void main(String[] args) { + int[][] M = { + {1, 1, 0, 0, 1, 0, 0, 1, 1, 0}, + {1, 0, 0, 1, 0, 1, 1, 1, 1, 1}, + {1, 1, 1, 0, 0, 1, 1, 1, 1, 0}, + {0, 1, 1, 1, 0, 1, 1, 1, 1, 1}, + {0, 0, 1, 1, 1, 1, 1, 1, 1, 0}, + {1, 1, 1, 1, 1, 1, 0, 1, 1, 1}, + {0, 1, 1, 1, 1, 1, 1, 0, 0, 1}, + {1, 1, 1, 1, 1, 0, 0, 1, 1, 1}, + {0, 1, 0, 1, 1, 0, 1, 1, 1, 1}, + {1, 1, 1, 0, 1, 0, 1, 1, 1, 1} + }; + System.out.println(new LongestLineofConsecutiveOneinMatrix().longestLine(M)); + } + + class Cell { + int h, v, d; + + Cell(int h, int v, int d) { + this.h = h; + this.v = v; + this.d = d; + } + } + + public int longestLine(int[][] M) { + if (M.length == 0) return 0; + int max = 0; + Cell[][] cells = new Cell[M.length][M[0].length]; + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M[0].length; j++) { + int h = 0, v = 0, d = 0; + if (M[i][j] == 1) { + h = 1; + v = 1; + d = 1; + max = Math.max(max, 1); + if (j - 1 >= 0) { + Cell left = cells[i][j - 1]; + if (left.h > 0) { + h += left.h; + max = Math.max(max, h); + } + } + if (i - 1 >= 0) { + Cell top = cells[i - 1][j]; + if (top.v > 0) { + v += top.v; + max = Math.max(max, v); + } + } + if (i - 1 >= 0 && j - 1 >= 0) { + Cell diagonal = cells[i - 1][j - 1]; + if (diagonal.d > 0) { + d += diagonal.d; + max = Math.max(max, d); + } + } + } + cells[i][j] = new Cell(h, v, d); + } + } + + for (int i = 0; i < M.length; i++) { + for (int j = M[0].length - 1; j >= 0; j--) { + int h = 0, v = 0, d = 0; + if (M[i][j] == 1) { + h = 1; + v = 1; + d = 1; + max = Math.max(max, 1); + if (j + 1 < M[0].length) { + Cell left = cells[i][j + 1]; + if (left.h > 0) { + h += left.h; + max = Math.max(max, h); + } + } + if (i - 1 >= 0) { + Cell top = cells[i - 1][j]; + if (top.v > 0) { + v += top.v; + max = Math.max(max, v); + } + } + if (i - 1 >= 0 && j + 1 < M[0].length) { + Cell diagonal = cells[i - 1][j + 1]; + if (diagonal.d > 0) { + d += diagonal.d; + max = Math.max(max, d); + } + } + } + cells[i][j] = new Cell(h, v, d); + } + } + + return max; + } +} diff --git a/src/main/java/array/MatrixCellsinDistanceOrder.java b/src/main/java/array/MatrixCellsinDistanceOrder.java new file mode 100644 index 00000000..2efe7f7a --- /dev/null +++ b/src/main/java/array/MatrixCellsinDistanceOrder.java @@ -0,0 +1,68 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 15/08/2019 We are given a matrix with R rows and C columns has + * cells with integer coordinates (r, c), where 0 <= r < R and 0 <= c < C. + * + *

Additionally, we are given a cell in that matrix with coordinates (r0, c0). + * + *

Return the coordinates of all cells in the matrix, sorted by their distance from (r0, c0) from + * smallest distance to largest distance. Here, the distance between two cells (r1, c1) and (r2, c2) + * is the Manhattan distance, |r1 - r2| + |c1 - c2|. (You may return the answer in any order that + * satisfies this condition.) + * + *

Example 1: + * + *

Input: R = 1, C = 2, r0 = 0, c0 = 0 Output: [[0,0],[0,1]] Explanation: The distances from (r0, + * c0) to other cells are: [0,1] Example 2: + * + *

Input: R = 2, C = 2, r0 = 0, c0 = 1 Output: [[0,1],[0,0],[1,1],[1,0]] Explanation: The + * distances from (r0, c0) to other cells are: [0,1,1,2] The answer [[0,1],[1,1],[0,0],[1,0]] would + * also be accepted as correct. Example 3: + * + *

Input: R = 2, C = 3, r0 = 1, c0 = 2 Output: [[1,2],[0,2],[1,1],[0,1],[1,0],[0,0]] Explanation: + * The distances from (r0, c0) to other cells are: [0,1,1,2,2,3] There are other answers that would + * also be accepted as correct, such as [[1,2],[1,1],[0,2],[1,0],[0,1],[0,0]]. + * + *

Note: + * + *

1 <= R <= 100 1 <= C <= 100 0 <= r0 < R 0 <= c0 < C + * + *

Solution: O (log (R x C)) Straight forward solution, find the Manhattan distance from the + * given cell to all the cells in the grid and sort by min distance and return their coordinates. + */ +public class MatrixCellsinDistanceOrder { + public static void main(String[] args) { + // + } + + class Cell { + int max, i, j; + + Cell(int max, int i, int j) { + this.max = max; + this.i = i; + this.j = j; + } + } + + public int[][] allCellsDistOrder(int R, int C, int r0, int c0) { + List list = new ArrayList<>(); + for (int i = 0; i < R; i++) { + for (int j = 0; j < C; j++) { + int sum = Math.abs(r0 - i) + Math.abs(c0 - j); + list.add(new Cell(sum, i, j)); + } + } + list.sort(Comparator.comparingInt(o -> o.max)); + int[][] A = new int[list.size()][2]; + for (int i = 0; i < A.length; i++) { + A[i][0] = list.get(i).i; + A[i][1] = list.get(i).j; + } + return A; + } +} diff --git a/src/main/java/array/MaxConsecutiveOnes.java b/src/main/java/array/MaxConsecutiveOnes.java new file mode 100644 index 00000000..95b3f749 --- /dev/null +++ b/src/main/java/array/MaxConsecutiveOnes.java @@ -0,0 +1,37 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 08/05/2019 Given a binary array, find the maximum number of + * consecutive 1s in this array. + * + *

Example 1: Input: [1,1,0,1,1,1] Output: 3 Explanation: The first two digits or the last three + * digits are consecutive 1s. The maximum number of consecutive 1s is 3. Note: + * + *

The input array will only contain 0 and 1. The length of input array is a positive integer and + * will not exceed 10,000 + */ +public class MaxConsecutiveOnes { + public static void main(String[] args) { + // + } + + public int findMaxConsecutiveOnes(int[] nums) { + int max = 0; + boolean flag = false; + int count = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] == 1) { + if (!flag) { + flag = true; + } + count++; + max = Math.max(max, count); + } else { + count = 0; + flag = false; + } + } + return max; + } +} diff --git a/src/main/java/array/MaxConsecutiveOnesII.java b/src/main/java/array/MaxConsecutiveOnesII.java new file mode 100644 index 00000000..f42b0ab3 --- /dev/null +++ b/src/main/java/array/MaxConsecutiveOnesII.java @@ -0,0 +1,72 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 08/05/2019 Given a binary array, find the maximum number of + * consecutive 1s in this array if you can flip at most one 0. + * + *

Example 1: Input: [1,0,1,1,0] Output: 4 Explanation: Flip the first zero will get the the + * maximum number of consecutive 1s. After flipping, the maximum number of consecutive 1s is 4. + * Note: + * + *

The input array will only contain 0 and 1. The length of input array is a positive integer and + * will not exceed 10,000 Follow up: What if the input numbers come in one by one as an infinite + * stream? In other words, you can't store all numbers coming from the stream as it's too large to + * hold in memory. Could you solve it efficiently? + * + *

Solution: O(N) Maintain a left and right auxiliary array with counts of contagious 1's from + * both directions. Now, iterate through the array and flip a 0 to 1 and sum up left and right + * contagious sum of 1's and return the max sum as the answer + */ +public class MaxConsecutiveOnesII { + public static void main(String[] args) { + // + } + + public int findMaxConsecutiveOnes(int[] nums) { + int[] L = new int[nums.length]; + int[] R = new int[nums.length]; + boolean flag = false; + int count = 0; + int max = 0; + for (int j = 0; j < nums.length; j++) { + if (nums[j] == 1) { + if (!flag) { + flag = true; + } + count++; + L[j] = count; + } else { + count = 0; + flag = false; + L[j] = count; + } + max = Math.max(max, count); + } + + flag = false; + count = 0; + for (int j = nums.length - 1; j >= 0; j--) { + if (nums[j] == 1) { + if (!flag) { + flag = true; + } + count++; + R[j] = count; + } else { + count = 0; + flag = false; + R[j] = count; + } + } + + for (int i = 0; i < nums.length; i++) { + if (nums[i] == 0) { + int l = i == 0 ? 0 : L[i - 1]; + int r = i == nums.length - 1 ? 0 : R[i + 1]; + max = Math.max(max, l + r + 1); + } + } + return max; + } +} diff --git a/src/main/java/array/MaxProductOfThreeNumbers.java b/src/main/java/array/MaxProductOfThreeNumbers.java new file mode 100644 index 00000000..eb3972d0 --- /dev/null +++ b/src/main/java/array/MaxProductOfThreeNumbers.java @@ -0,0 +1,26 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 27/06/2017. Given an integer array, find three numbers whose + * product is maximum and output the maximum product. + * + *

Example 1: Input: [1,2,3] Output: 6 Example 2: Input: [1,2,3,4] Output: 24 Note: The length of + * the given array will be in range [3,104] and all elements are in the range [-1000, 1000]. + * Multiplication of any three numbers in the input won't exceed the range of 32-bit signed integer. + */ +public class MaxProductOfThreeNumbers { + public static void main(String[] args) { + int[] A = {1, 2, 3}; + System.out.println(new MaxProductOfThreeNumbers().maximumProduct(A)); + } + + public int maximumProduct(int[] nums) { + Arrays.sort(nums); + int prod1 = nums[nums.length - 1] * nums[nums.length - 2] * nums[nums.length - 3]; + int prod2 = nums[nums.length - 1] * nums[0] * nums[1]; + return prod1 > prod2 ? prod1 : prod2; + } +} diff --git a/src/main/java/array/MaximumSumofTwoNonOverlappingSubarrays.java b/src/main/java/array/MaximumSumofTwoNonOverlappingSubarrays.java new file mode 100644 index 00000000..bf2b7fdc --- /dev/null +++ b/src/main/java/array/MaximumSumofTwoNonOverlappingSubarrays.java @@ -0,0 +1,81 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 15/08/2019 Given an array A of non-negative integers, return + * the maximum sum of elements in two non-overlapping (contiguous) subarrays, which have lengths L + * and M. (For clarification, the L-length subarray could occur before or after the M-length + * subarray.) + * + *

Formally, return the largest V for which V = (A[i] + A[i+1] + ... + A[i+L-1]) + (A[j] + A[j+1] + * + ... + A[j+M-1]) and either: + * + *

0 <= i < i + L - 1 < j < j + M - 1 < A.length, or 0 <= j < j + M - 1 < i < i + L - 1 < + * A.length. + * + *

Example 1: + * + *

Input: A = [0,6,5,2,2,5,1,9,4], L = 1, M = 2 Output: 20 Explanation: One choice of subarrays + * is [9] with length 1, and [6,5] with length 2. Example 2: + * + *

Input: A = [3,8,1,3,2,1,8,9,0], L = 3, M = 2 Output: 29 Explanation: One choice of subarrays + * is [3,8,1] with length 3, and [8,9] with length 2. Example 3: + * + *

Input: A = [2,1,5,6,0,9,5,0,3,8], L = 4, M = 3 Output: 31 Explanation: One choice of subarrays + * is [5,6,0,9] with length 4, and [3,8] with length 3. + * + *

Note: + * + *

L >= 1 M >= 1 L + M <= A.length <= 1000 0 <= A[i] <= 1000 Solution O(N ^ 2) Find prefix sum of + * array of length L and array of length M and keep track of their begin and end indices. Now, + * brute-force compare pairs of prefix array sum where their indices don't overlap and return the + * max possible answer. + */ +public class MaximumSumofTwoNonOverlappingSubarrays { + public static void main(String[] args) { + int[] A = {2, 1, 5, 6, 0, 9, 5, 0, 3, 8}; + System.out.println(new MaximumSumofTwoNonOverlappingSubarrays().maxSumTwoNoOverlap(A, 4, 3)); + } + + class MaxWithIndex { + int max, i, j; + + MaxWithIndex(int max, int i, int j) { + this.max = max; + this.i = i; + this.j = j; + } + } + + public int maxSumTwoNoOverlap(int[] A, int L, int M) { + List first = getMax(A, L); + List second = getMax(A, M); + int max = 0; + for (MaxWithIndex f : first) { + for (MaxWithIndex s : second) { + if (f.j < s.i || s.j < f.i) { + max = Math.max(max, f.max + s.max); + } + } + } + return max; + } + + private List getMax(int[] A, int L) { + List list = new ArrayList<>(); + int i = 0, j = L; + int sum = 0; + for (; i < L; i++) { + sum += A[i]; + } + list.add(new MaxWithIndex(sum, 0, j - 1)); + for (i = 1; j < A.length; i++, j++) { + sum -= A[i - 1]; + sum += A[j]; + list.add(new MaxWithIndex(sum, i, j)); + } + return list; + } +} diff --git a/src/main/java/array/MaximumSwap.java b/src/main/java/array/MaximumSwap.java new file mode 100644 index 00000000..8093da65 --- /dev/null +++ b/src/main/java/array/MaximumSwap.java @@ -0,0 +1,47 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 10/12/2017. Given a non-negative integer, you could swap two + * digits at most once to get the maximum valued number. Return the maximum valued number you could + * get. + * + *

Example 1: Input: 2736 Output: 7236 Explanation: Swap the number 2 and the number 7. Example + * 2: Input: 9973 Output: 9973 Explanation: No swap. Note: The given number is in the range [0, 108] + * + *

Solution O(n): Create a array of digit index. Iterate through the digits starting from left + * and in each iteration check if there is any digit which is greater than the current digit and + * appearing after the current index, if found then swap and return the new integer. + */ +public class MaximumSwap { + + public static void main(String[] args) throws Exception { + System.out.println(new MaximumSwap().maximumSwap(2736)); + } + + public int maximumSwap(int num) { + int[] D = new int[10]; + char[] A = String.valueOf(num).toCharArray(); + for (int i = 0; i < A.length; i++) { + D[A[i] - '0'] = i; + } + + boolean found = false; + + for (int i = 0; i < A.length; i++) { + int digit = A[i] - '0'; + for (int j = 9; j > digit; j--) { + if (D[j] > i) { + char temp = A[i]; + A[i] = (char) (j + '0'); + A[D[j]] = temp; + found = true; + break; + } + } + if (found) break; + } + + return Integer.parseInt(String.valueOf(A)); + } +} diff --git a/src/main/java/array/MeetingRooms.java b/src/main/java/array/MeetingRooms.java new file mode 100644 index 00000000..b5626f4a --- /dev/null +++ b/src/main/java/array/MeetingRooms.java @@ -0,0 +1,49 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 27/11/2017. Given an array of meeting time intervals consisting + * of start and end times [[s1,e1],[s2,e2],...] (si < ei), determine if a person could attend all + * meetings. + * + *

For example, Given [[0, 30],[5, 10],[15, 20]], return false. + * + *

Solution: Sort the interval based on the start interval. Then, for every interval check if the + * previous interval ends before the start of the current interval. + */ +public class MeetingRooms { + + public static class Interval { + int start; + int end; + + Interval() { + start = 0; + end = 0; + } + + Interval(int s, int e) { + start = s; + end = e; + } + } + + public static void main(String[] args) throws Exception { + Interval i1 = new Interval(0, 30); + Interval i2 = new Interval(5, 10); + Interval i3 = new Interval(15, 20); + Interval[] intervals = {i1, i2, i3}; + + System.out.println(new MeetingRooms().canAttendMeetings(intervals)); + } + + public boolean canAttendMeetings(Interval[] intervals) { + Arrays.sort(intervals, (a, b) -> Integer.compare(a.start, b.start)); + for (int i = 1; i < intervals.length; i++) { + if (intervals[i].start < intervals[i - 1].end) return false; + } + return true; + } +} diff --git a/src/main/java/array/MeetingScheduler.java b/src/main/java/array/MeetingScheduler.java new file mode 100644 index 00000000..1039599c --- /dev/null +++ b/src/main/java/array/MeetingScheduler.java @@ -0,0 +1,87 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 19/11/2019 Given the availability time slots arrays slots1 and + * slots2 of two people and a meeting duration duration, return the earliest time slot that works + * for both of them and is of duration duration. + * + *

If there is no common time slot that satisfies the requirements, return an empty array. + * + *

The format of a time slot is an array of two elements [start, end] representing an inclusive + * time range from start to end. + * + *

It is guaranteed that no two availability slots of the same person intersect with each other. + * That is, for any two time slots [start1, end1] and [start2, end2] of the same person, either + * start1 > end2 or start2 > end1. + * + *

Example 1: + * + *

Input: slots1 = [[10,50],[60,120],[140,210]], slots2 = [[0,15],[60,70]], duration = 8 Output: + * [60,68] Example 2: + * + *

Input: slots1 = [[10,50],[60,120],[140,210]], slots2 = [[0,15],[60,70]], duration = 12 Output: + * [] + * + *

Constraints: + * + *

1 <= slots1.length, slots2.length <= 10^4 slots1[i].length, slots2[i].length == 2 slots1[i][0] + * < slots1[i][1] slots2[i][0] < slots2[i][1] 0 <= slots1[i][j], slots2[i][j] <= 10^9 1 <= duration + * <= 10^6 + */ +public class MeetingScheduler { + public static void main(String[] args) { + int[][] slots1 = {{10, 50}, {60, 120}, {140, 210}}; + int[][] slots2 = {{0, 15}, {60, 70}}; + List result = new MeetingScheduler().minAvailableDuration(slots1, slots2, 12); + System.out.println(); + } + + private class Node { + int s, e, type; + + Node(int s, int e, int type) { + this.s = s; + this.e = e; + this.type = type; + } + } + + public List minAvailableDuration(int[][] slots1, int[][] slots2, int duration) { + PriorityQueue pq = + new PriorityQueue<>( + (o1, o2) -> { + int r = Integer.compare(o1.s, o2.s); + if (r == 0) { + return Integer.compare(o1.e, o2.e); + } else return r; + }); + for (int[] s : slots1) { + pq.offer(new Node(s[0], s[1], 1)); + } + for (int[] s : slots2) { + pq.offer(new Node(s[0], s[1], 2)); + } + Node prev = null; + while (!pq.isEmpty()) { + Node node = pq.poll(); + if (prev == null) { + prev = node; + } else { + if (prev.type != node.type) { + int s = Math.max(prev.s, node.s); + int e = Math.min(prev.e, node.e); + if ((e - s) >= duration) { + return Arrays.asList(s, s + duration); + } + } + if (node.e > prev.e) { + prev = node; + } + } + } + return new ArrayList<>(); + } +} diff --git a/src/main/java/array/MergeIntervals.java b/src/main/java/array/MergeIntervals.java new file mode 100644 index 00000000..d3657670 --- /dev/null +++ b/src/main/java/array/MergeIntervals.java @@ -0,0 +1,63 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 13/06/2017. Given a collection of intervals, merge all + * overlapping intervals. + * + *

For example, Given [1,3],[2,6],[8,10],[15,18], return [1,6],[8,10],[15,18]. + * + *

Solution: O(N log N) where N is the number of intervals 1. Sort the intervals based on start + * index 2. Mark the first interval as the current interval 3. For every ith interval starting 1 -> + * N, if the ith interval overlaps with the current interval then create a new current interval. + * Else, add the current interval to result set and begin a new current interval. + */ +public class MergeIntervals { + public static class Interval { + int start; + int end; + + Interval() { + start = 0; + end = 0; + } + + Interval(int s, int e) { + start = s; + end = e; + } + } + + public static void main(String[] args) throws Exception { + Interval i1 = new Interval(1, 2); + Interval i2 = new Interval(3, 4); + Interval i3 = new Interval(5, 6); + Interval i4 = new Interval(1, 10); + List result = new MergeIntervals().merge(Arrays.asList(i1, i2, i3, i4)); + result.forEach((I) -> System.out.println(I.start + " " + I.end)); + } + + public List merge(List intervals) { + if (intervals.isEmpty()) return new ArrayList<>(); + Collections.sort(intervals, (o1, o2) -> Integer.compare(o1.start, o2.start)); + List result = new ArrayList<>(); + Interval curr = intervals.get(0); + for (int i = 1, l = intervals.size(); i < l; i++) { + Interval I = intervals.get(i); + if (I.start >= curr.start + && I.start <= curr.end) { // check if the new interval overlaps with the current + curr.end = curr.end > I.end ? curr.end : I.end; + } else { + result.add(curr); + curr = I; + } + } + result.add(curr); + return result; + } +} diff --git a/src/main/java/array/MergeSortedArray.java b/src/main/java/array/MergeSortedArray.java new file mode 100644 index 00000000..472fb9e2 --- /dev/null +++ b/src/main/java/array/MergeSortedArray.java @@ -0,0 +1,25 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 29/07/2017. Given two sorted integer arrays nums1 and nums2, + * merge nums2 into nums1 as one sorted array. + * + *

Note: You may assume that nums1 has enough space (size that is greater or equal to m + n) to + * hold additional elements from nums2. The number of elements initialized in nums1 and nums2 are m + * and n respectively. + */ +public class MergeSortedArray { + public static void main(String[] args) throws Exception { + int[] A = {0}; + int[] B = {1}; + new MergeSortedArray().merge(A, 0, B, 1); + for (int i : A) System.out.println(i); + } + + public void merge(int[] nums1, int m, int[] nums2, int n) { + int i = m + n - 1, j = m - 1, k = n - 1; + while (j >= 0 && k >= 0) nums1[i--] = (nums1[j] > nums2[k]) ? nums1[j--] : nums2[k--]; + while (k >= 0) nums1[i--] = nums2[k--]; + } +} diff --git a/src/main/java/array/MinimumIndexSumOfTwoLists.java b/src/main/java/array/MinimumIndexSumOfTwoLists.java new file mode 100644 index 00000000..a550910b --- /dev/null +++ b/src/main/java/array/MinimumIndexSumOfTwoLists.java @@ -0,0 +1,73 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 11/04/2018. Suppose Andy and Doris want to choose a restaurant + * for dinner, and they both have a list of favorite restaurants represented by strings. + * + *

You need to help them find out their common interest with the least list index sum. If there + * is a choice tie between answers, output all of them with no order requirement. You could assume + * there always exists an answer. + * + *

Example 1: Input: ["Shogun", "Tapioca Express", "Burger King", "KFC"] ["Piatti", "The Grill at + * Torrey Pines", "Hungry Hunter Steakhouse", "Shogun"] Output: ["Shogun"] Explanation: The only + * restaurant they both like is "Shogun". Example 2: Input: ["Shogun", "Tapioca Express", "Burger + * King", "KFC"] ["KFC", "Shogun", "Burger King"] Output: ["Shogun"] Explanation: The restaurant + * they both like and have the least index sum is "Shogun" with index sum 1 (0+1). Note: The length + * of both lists will be in the range of [1, 1000]. The length of strings in both lists will be in + * the range of [1, 30]. The index is starting from 0 to the list length minus 1. No duplicates in + * both lists. + * + *

Solution:O(N) maintain index of each restaurant in a list using a HashMap, find the min sum of + * indices and list all the restaurants which match the min sum of indices + */ +public class MinimumIndexSumOfTwoLists { + /** + * Main method + * + * @param args + */ + public static void main(String[] args) throws Exception { + String[] A1 = {"Shogun", "Tapioca Express", "Burger King", "KFC"}; + String[] A2 = {"Tapioca Express", "Shogun", "Burger King"}; + String[] ans = new MinimumIndexSumOfTwoLists().findRestaurant(A1, A2); + for (String s : ans) { + System.out.println(s); + } + } + + public String[] findRestaurant(String[] list1, String[] list2) { + int min = Integer.MAX_VALUE; + List result = new ArrayList<>(); + if (list2.length == 0) return new String[0]; + Map index = new HashMap<>(); + for (int i = 0; i < list2.length; i++) { + index.put(list2[i], i); + } + for (int i = 0; i < list1.length; i++) { + String s = list1[i]; + if (index.containsKey(s)) { + int sum = i + index.get(s); + min = Math.min(min, sum); + } + } + + for (int i = 0; i < list1.length; i++) { + String s = list1[i]; + if (index.containsKey(s)) { + int sum = i + index.get(s); + if (sum == min) { + result.add(s); + } + } + } + String[] resArr = new String[result.size()]; + result.toArray(resArr); + return resArr; + } +} diff --git a/src/main/java/array/MinimumMovesToEqualArray.java b/src/main/java/array/MinimumMovesToEqualArray.java new file mode 100644 index 00000000..c65394d6 --- /dev/null +++ b/src/main/java/array/MinimumMovesToEqualArray.java @@ -0,0 +1,68 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 17/02/2018. Given a non-empty integer array, find the minimum + * number of moves required to make all array elements equal, where a move is incrementing a + * selected element by 1 or decrementing a selected element by 1. + * + *

You may assume the array's length is at most 10,000. + * + *

Example: + * + *

Input: [1,2,3] + * + *

Output: 2 + * + *

Explanation: Only two moves are needed (remember each move increments or decrements one + * element): + * + *

[1,2,3] => [2,2,3] => [2,2,2] + * + *

Solution: O(n log n): Sort the array and find the median of the array. Use the median of array + * to increment/decrement other value of array. Sum up the difference and return the answer. + */ +public class MinimumMovesToEqualArray { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 2, 3}; + System.out.println(new MinimumMovesToEqualArray().minMoves2(A)); + } + + public int minMoves2(int[] nums) { + if (nums.length == 1) return 0; + else if (nums.length == 2) return Math.abs(nums[0] - nums[1]); + Arrays.sort(nums); + int median; + if ((nums.length % 2) == 1) { + median = (nums.length / 2); + int sum = 0; + for (int i = 0; i < nums.length; i++) { + sum += Math.abs(nums[i] - nums[median]); + } + return sum; + } else { + median = (nums.length / 2) - 1; + int sum = 0; + int min; + for (int i = 0; i < nums.length; i++) { + sum += Math.abs(nums[i] - nums[median]); + } + min = sum; + sum = 0; + median = (nums.length / 2); + for (int i = 0; i < nums.length; i++) { + sum += Math.abs(nums[i] - nums[median]); + } + min = Math.min(min, sum); + return min; + } + } +} diff --git a/src/main/java/array/MinimumSwapsToGroupAll1Together.java b/src/main/java/array/MinimumSwapsToGroupAll1Together.java new file mode 100644 index 00000000..c1d699e6 --- /dev/null +++ b/src/main/java/array/MinimumSwapsToGroupAll1Together.java @@ -0,0 +1,62 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 23/10/2019 Given a binary array data, return the minimum number + * of swaps required to group all 1’s present in the array together in any place in the array. + * + *

Example 1: + * + *

Input: [1,0,1,0,1] Output: 1 Explanation: There are 3 ways to group all 1's together: + * [1,1,1,0,0] using 1 swap. [0,1,1,1,0] using 2 swaps. [0,0,1,1,1] using 1 swap. The minimum is 1. + * Example 2: + * + *

Input: [0,0,0,1,0] Output: 0 Explanation: Since there is only one 1 in the array, no swaps + * needed. Example 3: + * + *

Input: [1,0,1,0,1,0,0,1,1,0,1] Output: 3 Explanation: One possible solution that uses 3 swaps + * is [0,0,0,0,0,1,1,1,1,1,1]. Solution: O(N) All the 1s to be grouped together would mean that all + * 1s should occupy a small window in a array, this window could be in any part of the array - a + * window with minimum number of 0s is the minimum number of swap required. + */ +public class MinimumSwapsToGroupAll1Together { + public static void main(String[] args) { + // + } + + public int minSwaps(int[] data) { + int one = 0; + int zero = 0; + for (int i = 0; i < data.length; i++) { + if (data[i] == 1) { + one++; + } else zero++; + } + if (one == 0) return 0; + int window = one; + one = 0; + zero = 0; + int i = 0, j = window - 1; + for (int k = i; k <= j; k++) { + if (data[k] == 1) { + one++; + } else zero++; + } + i++; + j++; + int min = zero; + for (; j < data.length; i++, j++) { + if (data[j] == 0) { + zero++; + } else one++; + + if (data[i - 1] == 0) { + zero--; + } else one--; + min = Math.min(min, zero); + } + return min; + } +} diff --git a/src/main/java/array/MinimumTimeDifference.java b/src/main/java/array/MinimumTimeDifference.java new file mode 100644 index 00000000..92acfd51 --- /dev/null +++ b/src/main/java/array/MinimumTimeDifference.java @@ -0,0 +1,48 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Created by gouthamvidyapradhan on 30/07/2019 Given a list of 24-hour clock time points in + * "Hour:Minutes" format, find the minimum minutes difference between any two time points in the + * list. Example 1: Input: ["23:59","00:00"] Output: 1 Note: The number of time points in the given + * list is at least 2 and won't exceed 20000. The input time is legal and ranges from 00:00 to + * 23:59. + * + *

Solution: O(N log N) convert each time value of the form hh:mm to minutes and sort the array. + * For every pair (i, j) where j = i + 1 (also for the case where i = 0 and j = N - 1) check the + * minute difference and return the minimum time difference as the answer. + */ +public class MinimumTimeDifference { + public static void main(String[] args) { + List list = Arrays.asList("23:59", "00:00"); + System.out.println(new MinimumTimeDifference().findMinDifference(list)); + } + + public int findMinDifference(List timePoints) { + List timeInMinutes = + timePoints + .stream() + .map( + t -> { + String[] strings = t.split(":"); + return Integer.parseInt(strings[0]) * 60 + Integer.parseInt(strings[1]); + }) + .sorted(Integer::compareTo) + .collect(Collectors.toList()); + int min = Integer.MAX_VALUE; + for (int i = 1, l = timeInMinutes.size(); i < l; i++) { + int prev = timeInMinutes.get(i - 1); + int curr = timeInMinutes.get(i); + min = Math.min(min, curr - prev); + min = Math.min(min, ((24 * 60) - curr) + prev); + } + int prev = timeInMinutes.get(0); + int curr = timeInMinutes.get(timeInMinutes.size() - 1); + min = Math.min(min, curr - prev); + min = Math.min(min, ((24 * 60) - curr) + prev); + return min; + } +} diff --git a/src/main/java/array/MissingNumber.java b/src/main/java/array/MissingNumber.java new file mode 100644 index 00000000..9532902b --- /dev/null +++ b/src/main/java/array/MissingNumber.java @@ -0,0 +1,30 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 04/07/2017. Given an array containing n distinct numbers taken + * from 0, 1, 2, ..., n, find the one that is missing from the array. + * + *

For example, Given nums = [0, 1, 3] return 2. + * + *

Note: Your algorithm should run in linear runtime complexity. Could you implement it using + * only constant extra space complexity? + */ +public class MissingNumber { + + public static void main(String[] args) throws Exception { + int[] nums = {0}; + System.out.println(new MissingNumber().missingNumber(nums)); + } + + public int missingNumber(int[] nums) { + int sum = 0; + int n = nums.length; + for (int num : nums) { + sum += num; + } + int arrSum = (((n + 1)) * n) / 2; + if (arrSum == sum) return 0; + else return arrSum - sum; + } +} diff --git a/src/main/java/array/MyCalendarThree.java b/src/main/java/array/MyCalendarThree.java new file mode 100644 index 00000000..267eb8ea --- /dev/null +++ b/src/main/java/array/MyCalendarThree.java @@ -0,0 +1,89 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 12/03/2019 Implement a MyCalendarThree class to store your + * events. A new event can always be added. + * + *

Your class will have one method, book(int start, int end). Formally, this represents a booking + * on the half open interval [start, end), the range of real numbers x such that start <= x < end. + * + *

A K-booking happens when K events have some non-empty intersection (ie., there is some time + * that is common to all K events.) + * + *

For each call to the method MyCalendar.book, return an integer K representing the largest + * integer such that there exists a K-booking in the calendar. + * + *

Your class will be called like this: MyCalendarThree cal = new MyCalendarThree(); + * MyCalendarThree.book(start, end) Example 1: + * + *

MyCalendarThree(); MyCalendarThree.book(10, 20); // returns 1 MyCalendarThree.book(50, 60); // + * returns 1 MyCalendarThree.book(10, 40); // returns 2 MyCalendarThree.book(5, 15); // returns 3 + * MyCalendarThree.book(5, 10); // returns 3 MyCalendarThree.book(25, 55); // returns 3 Explanation: + * The first two events can be booked and are disjoint, so the maximum K-booking is a 1-booking. The + * third event [10, 40) intersects the first event, and the maximum K-booking is a 2-booking. The + * remaining events cause the maximum K-booking to be only a 3-booking. Note that the last event + * locally causes a 2-booking, but the answer is still 3 because eg. [10, 20), [10, 40), and [5, 15) + * are still triple booked. + */ +public class MyCalendarThree { + + private List events; + private int max; + + private class Node { + int n, index; + + Node(int n, int index) { + this.n = n; + this.index = index; + } + + public int getN() { + return n; + } + + public int getIndex() { + return index; + } + } + + public MyCalendarThree() { + events = new ArrayList<>(); + max = 0; + } + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + MyCalendarThree calendar = new MyCalendarThree(); + System.out.println(calendar.book(10, 20)); + System.out.println(calendar.book(50, 60)); + System.out.println(calendar.book(10, 40)); + System.out.println(calendar.book(5, 15)); + System.out.println(calendar.book(5, 10)); + System.out.println(calendar.book(25, 55)); + } + + public int book(int start, int end) { + events.add(new Node(start, 1)); + events.add(new Node(end, 0)); + events.sort((Comparator.comparing(Node::getN).thenComparing(Node::getIndex))); + int count = 0; + for (Node node : events) { + if (node.index == 1 && node.n >= end) { + break; + } + count += node.index == 1 ? 1 : -1; + if (node.getN() >= start) { + max = Math.max(max, count); + } + } + return max; + } +} diff --git a/src/main/java/array/NextGreaterElementI.java b/src/main/java/array/NextGreaterElementI.java new file mode 100644 index 00000000..33c7f426 --- /dev/null +++ b/src/main/java/array/NextGreaterElementI.java @@ -0,0 +1,62 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 09/02/2018. You are given two arrays (without duplicates) nums1 + * and nums2 where nums1’s elements are subset of nums2. Find all the next greater numbers for + * nums1's elements in the corresponding places of nums2. + * + *

The Next Greater Number of a number x in nums1 is the first greater number to its right in + * nums2. If it does not exist, output -1 for this number. + * + *

Example 1: Input: nums1 = [4,1,2], nums2 = [1,3,4,2]. Output: [-1,3,-1] Explanation: For + * number 4 in the first array, you cannot find the next greater number for it in the second array, + * so output -1. For number 1 in the first array, the next greater number for it in the second array + * is 3. For number 2 in the first array, there is no next greater number for it in the second + * array, so output -1. Example 2: Input: nums1 = [2,4], nums2 = [1,2,3,4]. Output: [3,-1] + * Explanation: For number 2 in the first array, the next greater number for it in the second array + * is 3. For number 4 in the first array, there is no next greater number for it in the second + * array, so output -1. Note: All elements in nums1 and nums2 are unique. The length of both nums1 + * and nums2 would not exceed 1000. + */ +public class NextGreaterElementI { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {4, 1, 2}; + int[] B = {1, 3, 4, 2}; + int[] result = new NextGreaterElementI().nextGreaterElement(A, B); + System.out.println(result); + } + + public int[] nextGreaterElement(int[] nums1, int[] nums2) { + int[] result = new int[nums1.length]; + for (int i = 0; i < nums1.length; i++) { + int n = nums1[i]; + boolean found = false; + int nF = 0; + for (int j = 0; j < nums2.length; j++) { + if (nums2[j] == n) { + found = true; + } + if (found) { + if (nums2[j] > n) { + nF = nums2[j]; + break; + } + } + } + if (found) { + result[i] = nF; + } else { + result[i] = -1; + } + } + return result; + } +} diff --git a/src/main/java/array/PascalsTriangle.java b/src/main/java/array/PascalsTriangle.java new file mode 100644 index 00000000..32c8ada8 --- /dev/null +++ b/src/main/java/array/PascalsTriangle.java @@ -0,0 +1,45 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 25/03/2017. + * + *

Given an index k, return the kth row of the Pascal's triangle. + * + *

For example, given k = 3, Return [1,3,3,1]. + * + *

Note: Could you optimize your algorithm to use only O(k) extra space? + */ +public class PascalsTriangle { + public static void main(String[] args) throws Exception { + System.out.println(new PascalsTriangle().getRow(3)); + } + + public List getRow(int rowIndex) { + int k = rowIndex; + if (k == 0) return Arrays.asList(1); + else if (k == 1) return Arrays.asList(1, 1); + else if (k == 2) return Arrays.asList(1, 2, 1); + List result = new ArrayList<>(); + result.add(2); + k = k - 2; + int p, c; + while (k-- > 0) { + p = 1; + int i = 0; + for (int l = result.size(); i < l; i++) { + c = result.get(i); + result.set(i, p + c); + p = c; + } + result.add(p + 1); + } + result.add(0, 1); + result.add(1); + return result; + } +} diff --git a/src/main/java/array/PourWater.java b/src/main/java/array/PourWater.java new file mode 100644 index 00000000..e0c5ed20 --- /dev/null +++ b/src/main/java/array/PourWater.java @@ -0,0 +1,117 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 03/02/2018. We are given an elevation map, heights[i] + * representing the height of the terrain at that index. The width at each index is 1. After V units + * of water fall at index K, how much water is at each index? + * + *

Water first drops at index K and rests on top of the highest terrain or water at that index. + * Then, it flows according to the following rules: + * + *

If the droplet would eventually fall by moving left, then move left. Otherwise, if the droplet + * would eventually fall by moving right, then move right. Otherwise, rise at it's current position. + * Here, "eventually fall" means that the droplet will eventually be at a lower level if it moves in + * that direction. Also, "level" means the height of the terrain plus any water in that column. We + * can assume there's infinitely high terrain on the two sides out of bounds of the array. Also, + * there could not be partial water being spread out evenly on more than 1 grid block - each unit of + * water has to be in exactly one block. + * + *

Example 1: Input: heights = [2,1,1,2,1,2,2], V = 4, K = 3 Output: [2,2,2,3,2,2,2] Explanation: + * # # # # ## # ### ######### 0123456 <- index + * + *

The first drop of water lands at index K = 3: + * + *

# # # w # ## # ### ######### 0123456 + * + *

When moving left or right, the water can only move to the same level or a lower level. (By + * level, we mean the total height of the terrain plus any water in that column.) Since moving left + * will eventually make it fall, it moves left. (A droplet "made to fall" means go to a lower height + * than it was at previously.) + * + *

# # # # ## w# ### ######### 0123456 + * + *

Since moving left will not make it fall, it stays in place. The next droplet falls: + * + *

# # # w # ## w# ### ######### 0123456 + * + *

Since the new droplet moving left will eventually make it fall, it moves left. Notice that the + * droplet still preferred to move left, even though it could move right (and moving right makes it + * fall quicker.) + * + *

# # # w # ## w# ### ######### 0123456 + * + *

# # # # ##ww# ### ######### 0123456 + * + *

After those steps, the third droplet falls. Since moving left would not eventually make it + * fall, it tries to move right. Since moving right would eventually make it fall, it moves right. + * + *

# # # w # ##ww# ### ######### 0123456 + * + *

# # # # ##ww#w### ######### 0123456 + * + *

Finally, the fourth droplet falls. Since moving left would not eventually make it fall, it + * tries to move right. Since moving right would not eventually make it fall, it stays in place: + * + *

# # # w # ##ww#w### ######### 0123456 + * + *

The final answer is [2,2,2,3,2,2,2]: + * + *

# ####### ####### 0123456 Example 2: Input: heights = [1,2,3,4], V = 2, K = 2 Output: + * [2,3,3,4] Explanation: The last droplet settles at index 1, since moving further left would not + * cause it to eventually fall to a lower height. Example 3: Input: heights = [3,1,3], V = 5, K = 1 + * Output: [4,4,4] Note: + * + *

heights will have length in [1, 100] and contain integers in [0, 99]. V will be in range [0, + * 2000]. K will be in range [0, heights.length - 1]. + * + *

Solution: Check first left and then right to see if there are any lower levels, if yes then + * drop the water at this point. Else maintain the drop at the start position + */ +public class PourWater { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {2, 1, 1, 2, 1, 2, 2}; + int[] result = new PourWater().pourWater(A, 4, 3); + for (int i : result) { + System.out.print(i + " "); + } + } + + public int[] pourWater(int[] heights, int V, int K) { + while (V-- > 0) { + heights[K] += 1; + int index = K; + int min = heights[K]; + for (int i = K - 1; i >= 0; i--) { + if (heights[i] + 1 > min) { + break; + } else if (heights[i] + 1 < min) { + min = heights[i] + 1; + index = i; + } + } + if (index == K) { + for (int i = K + 1; i < heights.length; i++) { + if (heights[i] + 1 > min) { + break; + } else if (heights[i] + 1 < min) { + min = heights[i] + 1; + index = i; + } + } + } + if (index != K) { + heights[K]--; + heights[index]++; + } + } + return heights; + } +} diff --git a/src/main/java/array/ProductOfArrayExceptSelf.java b/src/main/java/array/ProductOfArrayExceptSelf.java new file mode 100644 index 00000000..e905ce2f --- /dev/null +++ b/src/main/java/array/ProductOfArrayExceptSelf.java @@ -0,0 +1,36 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 04/05/2017. + * + *

Given an array of n integers where n > 1, nums, return an array output such that output[i] is + * equal to the product of all the elements of nums except nums[i]. + * + *

Solve it without division and in O(n). + * + *

For example, given [1,2,3,4], return [24,12,8,6]. + * + *

Follow up: Could you solve it with constant space complexity? (Note: The output array does not + * count as extra space for the purpose of space complexity analysis.) + */ +public class ProductOfArrayExceptSelf { + public static void main(String[] args) { + int[] nums = {1, 2, 3, 4}; + int[] result = new ProductOfArrayExceptSelf().productExceptSelf(nums); + for (int r : result) System.out.print(r + " "); + } + + public int[] productExceptSelf(int[] nums) { + int[] result = new int[nums.length]; + for (int i = 0, temp = 1, l = nums.length; i < l; i++) { + result[i] = temp; + temp *= nums[i]; + } + for (int i = nums.length - 1, temp = 1; i >= 0; i--) { + result[i] = result[i] * temp; + temp *= nums[i]; + } + return result; + } +} diff --git a/src/main/java/array/ReadNCharacters.java b/src/main/java/array/ReadNCharacters.java new file mode 100644 index 00000000..75017539 --- /dev/null +++ b/src/main/java/array/ReadNCharacters.java @@ -0,0 +1,48 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 09/12/2017. The API: int read4(char *buf) reads 4 characters at + * a time from a file. + * + *

The return value is the actual number of characters read. For example, it returns 3 if there + * is only 3 characters left in the file. + * + *

By using the read4 API, implement the function int read(char *buf, int n) that reads n + * characters from the file. + * + *

Note: The read function will only be called once for each test case. + */ +public class ReadNCharacters { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) {} + + /** + * @param buf + * @param n + * @return + */ + public int read(char[] buf, int n) { + int i = 0; + int toRead = Math.min(n, buf.length); + while (i < toRead) { + char[] temp = new char[4]; + int r = read4(temp); + for (int j = 0; j < r && i < toRead; j++) { + buf[i] = temp[j]; + i++; + } + if (r < 4) break; + } + return Math.min(i, toRead); + } + + private int read4(char[] buf) { + return 1; // return fake value just to resolve compilation error + } +} diff --git a/src/main/java/array/RelativeRanks.java b/src/main/java/array/RelativeRanks.java new file mode 100644 index 00000000..adfbf31f --- /dev/null +++ b/src/main/java/array/RelativeRanks.java @@ -0,0 +1,63 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 09/02/2018. Given scores of N athletes, find their relative + * ranks and the people with the top three highest scores, who will be awarded medals: "Gold Medal", + * "Silver Medal" and "Bronze Medal". + * + *

Example 1: Input: [5, 4, 3, 2, 1] Output: ["Gold Medal", "Silver Medal", "Bronze Medal", "4", + * "5"] Explanation: The first three athletes got the top three highest scores, so they got "Gold + * Medal", "Silver Medal" and "Bronze Medal". For the left two athletes, you just need to output + * their relative ranks according to their scores. Note: N is a positive integer and won't exceed + * 10,000. All the scores of athletes are guaranteed to be unique. + */ +public class RelativeRanks { + + class Position { + int score, poisition; + + Position(int score, int position) { + this.score = score; + this.poisition = position; + } + } + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {5, 4, 3, 2, 1}; + String[] S = new RelativeRanks().findRelativeRanks(A); + for (String i : S) { + System.out.println(i); + } + } + + public String[] findRelativeRanks(int[] nums) { + String[] S = new String[nums.length]; + List list = new ArrayList<>(); + for (int i = 0; i < nums.length; i++) { + list.add(new Position(nums[i], i)); + } + list.sort((o1, o2) -> Integer.compare(o2.score, o1.score)); + // Collections.reverse(list); + for (int i = 0; i < list.size(); i++) { + if (i == 0) { + S[list.get(i).poisition] = "Gold Medal"; + } else if (i == 1) { + S[list.get(i).poisition] = "Silver Medal"; + } else if (i == 2) { + S[list.get(i).poisition] = "Bronze Medal"; + } else { + S[list.get(i).poisition] = String.valueOf(i + 1); + } + } + return S; + } +} diff --git a/src/main/java/array/RelativeSortArray.java b/src/main/java/array/RelativeSortArray.java new file mode 100644 index 00000000..8244f7c0 --- /dev/null +++ b/src/main/java/array/RelativeSortArray.java @@ -0,0 +1,61 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 05/12/2019 Given two arrays arr1 and arr2, the elements of arr2 + * are distinct, and all elements in arr2 are also in arr1. + * + *

Sort the elements of arr1 such that the relative ordering of items in arr1 are the same as in + * arr2. Elements that don't appear in arr2 should be placed at the end of arr1 in ascending order. + * + *

Example 1: + * + *

Input: arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6] Output: [2,2,2,1,4,3,3,9,6,7,19] + * + *

Constraints: + * + *

arr1.length, arr2.length <= 1000 0 <= arr1[i], arr2[i] <= 1000 Each arr2[i] is distinct. Each + * arr2[i] is in arr1. + */ +public class RelativeSortArray { + public static void main(String[] args) { + // + } + + public int[] relativeSortArray(int[] arr1, int[] arr2) { + List notPresent = new ArrayList<>(); + Map map = new HashMap<>(); + Set set = new HashSet<>(); + for (int i : arr2) { + set.add(i); + } + for (int i : arr1) { + map.putIfAbsent(i, 0); + map.put(i, map.get(i) + 1); + } + List result = new ArrayList<>(); + for (int i : arr2) { + int count = map.get(i); + for (int j = 0; j < count; j++) { + result.add(i); + } + } + for (int k : map.keySet()) { + if (!set.contains(k)) { + int count = map.get(k); + for (int i = 0; i < count; i++) { + notPresent.add(k); + } + } + } + notPresent.sort(Comparator.comparingInt(o -> o)); + result.addAll(notPresent); + int[] resA = new int[result.size()]; + for (int i = 0; i < result.size(); i++) { + resA[i] = result.get(i); + } + return resA; + } +} diff --git a/src/main/java/array/RevealCardsInIncreasingOrder.java b/src/main/java/array/RevealCardsInIncreasingOrder.java new file mode 100644 index 00000000..dea70a6d --- /dev/null +++ b/src/main/java/array/RevealCardsInIncreasingOrder.java @@ -0,0 +1,63 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.ArrayDeque; +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 12/08/2019 In a deck of cards, every card has a unique integer. + * You can order the deck in any order you want. + * + *

Initially, all the cards start face down (unrevealed) in one deck. + * + *

Now, you do the following steps repeatedly, until all cards are revealed: + * + *

Take the top card of the deck, reveal it, and take it out of the deck. If there are still + * cards in the deck, put the next top card of the deck at the bottom of the deck. If there are + * still unrevealed cards, go back to step 1. Otherwise, stop. Return an ordering of the deck that + * would reveal the cards in increasing order. + * + *

The first entry in the answer is considered to be the top of the deck. + * + *

Example 1: + * + *

Input: [17,13,11,2,3,5,7] Output: [2,13,3,11,5,17,7] Explanation: We get the deck in the order + * [17,13,11,2,3,5,7] (this order doesn't matter), and reorder it. After reordering, the deck starts + * as [2,13,3,11,5,17,7], where 2 is the top of the deck. We reveal 2, and move 13 to the bottom. + * The deck is now [3,11,5,17,7,13]. We reveal 3, and move 11 to the bottom. The deck is now + * [5,17,7,13,11]. We reveal 5, and move 17 to the bottom. The deck is now [7,13,11,17]. We reveal + * 7, and move 13 to the bottom. The deck is now [11,17,13]. We reveal 11, and move 17 to the + * bottom. The deck is now [13,17]. We reveal 13, and move 17 to the bottom. The deck is now [17]. + * We reveal 17. Since all the cards revealed are in increasing order, the answer is correct. + * + *

Note: + * + *

1 <= A.length <= 1000 1 <= A[i] <= 10^6 A[i] != A[j] for all i != j + * + *

Solution: O(N) General idea is to start from the last element and build the array of element + * in the backwards order. Use a doubly-ended queue which allows you to poll from either end of a + * queue. + */ +public class RevealCardsInIncreasingOrder { + public static void main(String[] args) { + int[] A = {17, 13, 11, 2, 3, 5, 7}; + int[] R = new RevealCardsInIncreasingOrder().deckRevealedIncreasing(A); + } + + public int[] deckRevealedIncreasing(int[] deck) { + Arrays.sort(deck); + ArrayDeque queue = new ArrayDeque<>(); + for (int i = deck.length - 1; i >= 0; i--) { + queue.offer(deck[i]); + if (i == 0) break; + int temp = queue.pollFirst(); + queue.offer(temp); + } + int[] answer = new int[deck.length]; + int i = 0; + while (!queue.isEmpty()) { + answer[i++] = queue.pollLast(); + } + return answer; + } +} diff --git a/src/main/java/array/RotateArray.java b/src/main/java/array/RotateArray.java new file mode 100644 index 00000000..863c60f1 --- /dev/null +++ b/src/main/java/array/RotateArray.java @@ -0,0 +1,43 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 01/08/2017. Rotate an array of n elements to the right by k + * steps. + * + *

For example, with n = 7 and k = 3, the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4]. + * + *

Note: Try to come up as many solutions as you can, there are at least 3 different ways to + * solve this problem. + * + *

Hint: Could you do it in-place with O(1) extra space? Related problem: Reverse Words in a + * String II + */ +public class RotateArray { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 2, 3, 4, 5, 6}; + new RotateArray().rotate(A, 2); + for (int i : A) System.out.print(i + " "); + } + + public void rotate(int[] nums, int k) { + k = k % nums.length; + reverse(nums, 0, nums.length - 1); + reverse(nums, 0, k - 1); + reverse(nums, k, nums.length - 1); + } + + private void reverse(int[] nums, int s, int e) { + for (int i = s, j = e; i < j; i++, j--) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } + } +} diff --git a/src/main/java/array/RotateMatrix.java b/src/main/java/array/RotateMatrix.java new file mode 100644 index 00000000..42251de7 --- /dev/null +++ b/src/main/java/array/RotateMatrix.java @@ -0,0 +1,49 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 21/03/2017. You are given an n x n 2D matrix representing an + * image. + * + *

Rotate the image by 90 degrees (clockwise). + * + *

Follow up: Could you do this in-place? + */ +public class RotateMatrix { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] A = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + new RotateMatrix().rotate(A); + for (int i = 0; i < A.length; i++) { + for (int j = 0; j < A[0].length; j++) { + System.out.println(A[i][j]); + } + } + } + + public void rotate(int[][] matrix) { + int lc = 0, tr = 0, rc = matrix[0].length - 1, br = matrix.length - 1; + while (tr < br) { + for (int i = lc, j = tr, k = rc, l = br; + i < rc && j < br && k > lc && l > tr; + i++, j++, k--, l--) { + int temp1 = matrix[j][rc]; + matrix[j][rc] = matrix[tr][i]; + int temp2 = matrix[br][k]; + matrix[br][k] = temp1; + temp1 = matrix[l][lc]; + matrix[l][lc] = temp2; + matrix[tr][i] = temp1; + } + lc++; + tr++; + rc--; + br--; + } + } +} diff --git a/src/main/java/array/SetMatrixZeroes.java b/src/main/java/array/SetMatrixZeroes.java new file mode 100644 index 00000000..c30b919e --- /dev/null +++ b/src/main/java/array/SetMatrixZeroes.java @@ -0,0 +1,56 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.HashSet; +import java.util.Set; + +/** + * Created by pradhang on 3/28/2017. Given a m x n matrix, if an element is 0, set its entire row + * and column to 0. Do it in place. + * + *

click to show follow up. + * + *

Follow up: Did you use extra space? A straight forward solution using O(mn) space is probably + * a bad idea. A simple improvement uses O(m + n) space, but still not the best solution. Could you + * devise a constant space solution? + */ +public class SetMatrixZeroes { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] matrix = {{0, 8, 7}, {9, 0, 8}, {9, 9, 0}}; + + new SetMatrixZeroes().setZeroes(matrix); + } + + public void setZeroes(int[][] matrix) { + Set row = new HashSet<>(); + Set col = new HashSet<>(); + int m = matrix.length; + int n = matrix[0].length; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (matrix[i][j] == 0) { + row.add(i); + col.add(j); + } + } + } + + for (int r : row) { + for (int j = 0; j < n; j++) { + matrix[r][j] = 0; + } + } + + for (int c : col) { + for (int i = 0; i < m; i++) { + matrix[i][c] = 0; + } + } + } +} diff --git a/src/main/java/array/SortArrayByParityII.java b/src/main/java/array/SortArrayByParityII.java new file mode 100644 index 00000000..b3fea546 --- /dev/null +++ b/src/main/java/array/SortArrayByParityII.java @@ -0,0 +1,44 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 20/08/2019 Given an array A of non-negative integers, half of + * the integers in A are odd, and half of the integers are even. + * + *

Sort the array so that whenever A[i] is odd, i is odd; and whenever A[i] is even, i is even. + * + *

You may return any answer array that satisfies this condition. + * + *

Example 1: + * + *

Input: [4,2,5,7] Output: [4,5,2,7] Explanation: [4,7,2,5], [2,5,4,7], [2,7,4,5] would also + * have been accepted. + * + *

Note: + * + *

2 <= A.length <= 20000 A.length % 2 == 0 0 <= A[i] <= 1000 Solution: O(N) straight forward + * linear solution, keep track of odd and even indices and increment by 2 every time a value is + * added at the index. + */ +public class SortArrayByParityII { + public static void main(String[] args) { + // + } + + public int[] sortArrayByParityII(int[] A) { + int[] R = new int[A.length]; + int i = 0, j = 1; + for (int a : A) { + if (a % 2 == 0) { + R[i] = a; + i += 2; + } else { + R[j] = a; + j += 2; + } + } + return R; + } +} diff --git a/src/main/java/array/SortColors.java b/src/main/java/array/SortColors.java new file mode 100644 index 00000000..14d563c2 --- /dev/null +++ b/src/main/java/array/SortColors.java @@ -0,0 +1,65 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 06/08/2017. Given an array with n objects colored red, white or + * blue, sort them so that objects of the same color are adjacent, with the colors in the order red, + * white and blue. + * + *

Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue + * respectively. + * + *

Note: You are not suppose to use the library's sort function for this problem. + * + *

Follow up: A rather straight forward solution is a two-pass algorithm using counting sort. + * First, iterate the array counting number of 0's, 1's, and 2's, then overwrite array with total + * number of 0's, then 1's and followed by 2's. + * + *

Could you come up with an one-pass algorithm using only constant space? + * + *

Solution: The below solution works with one pass. The basic idea is to keep track of start and + * end index of contiguous 1s and push the 0s to left of 1s and 2 to right of 1s. + */ +public class SortColors { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] nums = {2, 1, 0, 0, 1}; + new SortColors().sortColors(nums); + for (int i : nums) System.out.println(i); + } + + public void sortColors(int[] nums) { + int s = nums[0]; // save the first index value + nums[0] = 1; // overwrite with 1 + int l = 0, r = 0; // left and right index indicating the start and end index of 1s + for (int i = 1; i < nums.length; i++) { + switch (nums[i]) { + case 0: + nums[l] = 0; + nums[r + 1] = 1; + if (r + 1 != i) { + nums[i] = 2; + } + l++; + r++; + break; + + case 1: + nums[r + 1] = 1; + if (r + 1 != i) { + nums[i] = 2; + } + r++; + break; + } + } + // replace the initial overwritten value with the original value + if (s == 0) nums[l] = 0; + else if (s == 2) nums[r] = 2; + } +} diff --git a/src/main/java/array/SparseMatrixMultiplication.java b/src/main/java/array/SparseMatrixMultiplication.java new file mode 100644 index 00000000..c8d2f669 --- /dev/null +++ b/src/main/java/array/SparseMatrixMultiplication.java @@ -0,0 +1,73 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 03/12/2017. + * + *

Given two sparse matrices A and B, return the result of AB. + * + *

You may assume that A's column number is equal to B's row number. + * + *

Example: + * + *

A = [ [ 1, 0, 0], [-1, 0, 3] ] + * + *

B = [ [ 7, 0, 0 ], [ 0, 0, 0 ], [ 0, 0, 1 ] ] + * + *

| 1 0 0 | | 7 0 0 | | 7 0 0 | AB = | -1 0 3 | x | 0 0 0 | = | -7 0 3 | | 0 0 1 | + * + *

Solution: Skip the rows and columns which you already know would result in zero after + * multiplication. + */ +public class SparseMatrixMultiplication { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] A = {{1, 0, 0, 1}}; + int[][] B = {{7, 0, 0}, {0, 0, 0}, {0, 0, 1}, {0, 0, 1}}; + int[][] C = new SparseMatrixMultiplication().multiply(A, B); + } + + public int[][] multiply(int[][] A, int[][] B) { + boolean[] AH = new boolean[A.length]; // Metadata for matrix A + boolean[] BH = new boolean[B[0].length]; // Metadata for matrix A + for (int i = 0; i < A.length; i++) { + for (int j = 0; j < A[0].length; j++) { + if (A[i][j] != 0) { + AH[i] = true; + break; + } + } + } + + for (int i = 0; i < B[0].length; i++) { + for (int j = 0; j < B.length; j++) { + if (B[j][i] != 0) { + BH[i] = true; + break; + } + } + } + + int[][] C = new int[A.length][B[0].length]; + for (int i = 0; i < C.length; i++) { + if (AH[i]) { + for (int j = 0; j < C[0].length; j++) { + if (BH[j]) { + int sum = 0; + for (int k = 0; k < A[0].length; k++) { + sum += A[i][k] * B[k][j]; + } + C[i][j] = sum; + } + } + } + } + return C; + } +} diff --git a/src/main/java/array/SubArraysWithBoundedMaximum.java b/src/main/java/array/SubArraysWithBoundedMaximum.java new file mode 100644 index 00000000..05baf09a --- /dev/null +++ b/src/main/java/array/SubArraysWithBoundedMaximum.java @@ -0,0 +1,60 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 29/03/2019 We are given an array A of positive integers, and + * two positive integers L and R (L <= R). + * + *

Return the number of (contiguous, non-empty) subarrays such that the value of the maximum + * array element in that subarray is at least L and at most R. + * + *

Example : Input: A = [2, 1, 4, 3] L = 2 R = 3 Output: 3 Explanation: There are three subarrays + * that meet the requirements: [2], [2, 1], [3]. Note: + * + *

L, R and A[i] will be an integer in the range [0, 10^9]. The length of A will be in the range + * of [1, 50000]. + */ +public class SubArraysWithBoundedMaximum { + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[] A = {2, 1, 4, 3}; + System.out.println(new SubArraysWithBoundedMaximum().numSubarrayBoundedMax(A, 2, 3)); + } + + public int numSubarrayBoundedMax(int[] A, int L, int R) { + int[] DP = new int[A.length]; + int v = -1; + for (int i = A.length - 1; i >= 0; i--) { + if (A[i] >= L && A[i] <= R) { + if (v != -1) { + DP[i] = v - i + 1; + } else { + DP[i] = 1; + v = i; + } + } else if (A[i] < L) { + if (v == -1) { + v = i; + } + if (i + 1 < A.length) { + if (A[i + 1] < L || (A[i + 1] >= L && A[i + 1] <= R)) { + DP[i] = DP[i + 1]; + } else { + DP[i] = 0; + } + } + } else { + v = -1; + } + } + int sum = 0; + for (int i = 0; i < DP.length; i++) { + sum += DP[i]; + } + return sum; + } +} diff --git a/src/main/java/array/SubarraySumEqualsK.java b/src/main/java/array/SubarraySumEqualsK.java new file mode 100644 index 00000000..3cd9ca34 --- /dev/null +++ b/src/main/java/array/SubarraySumEqualsK.java @@ -0,0 +1,63 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 03/01/2018. Given an array of integers and an integer k, you + * need to find the total number of continuous subarrays whose sum equals to k. + * + *

Example 1: Input:nums = [1,1,1], k = 2 Output: 2 Note: The length of the array is in range [1, + * 20,000]. The range of numbers in the array is [-1000, 1000] and the range of the integer k is + * [-1e7, 1e7]. + * + *

Solution: O(n) Maintain a hash-map of prefix sum and its count and check for range sum for + * each element. + */ +public class SubarraySumEqualsK { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 2, 1, -2, 3, -1, -1}; + System.out.println(new SubarraySumEqualsK().subarraySum(A, 2)); + } + + public int subarraySum(int[] nums, int k) { + Map map = new HashMap<>(); + int sum = 0; + for (int i : nums) { + sum += i; + Integer count = map.get(sum); + if (count == null) { + map.put(sum, 1); + } else { + map.put(sum, count + 1); + } + } + sum = 0; + int result = 0; + for (int i : nums) { + int key = sum + k; + if (map.containsKey(key)) { + int count = map.get(key); + result += count; + } + sum += i; + if (map.containsKey(sum)) { + int count = map.get(sum); + if (count - 1 > 0) { + map.put(sum, count - 1); + } else { + map.remove(sum); + } + } + } + return result; + } +} diff --git a/src/main/java/array/SurfaceAreaOfThreeDShapes.java b/src/main/java/array/SurfaceAreaOfThreeDShapes.java new file mode 100644 index 00000000..9c646c68 --- /dev/null +++ b/src/main/java/array/SurfaceAreaOfThreeDShapes.java @@ -0,0 +1,70 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 30/04/2019 On a N * N grid, we place some 1 * 1 * 1 cubes. + * + *

Each value v = grid[i][j] represents a tower of v cubes placed on top of grid cell (i, j). + * + *

Return the total surface area of the resulting shapes. + * + *

Example 1: + * + *

Input: [[2]] Output: 10 Example 2: + * + *

Input: [[1,2],[3,4]] Output: 34 Example 3: + * + *

Input: [[1,0],[0,2]] Output: 16 Example 4: + * + *

Input: [[1,1,1],[1,0,1],[1,1,1]] Output: 32 Example 5: + * + *

Input: [[2,2,2],[2,1,2],[2,2,2]] Output: 46 + * + *

Note: + * + *

1 <= N <= 50 0 <= grid[i][j] <= 50 + * + *

Solution: O(N x M) For each cell, check each adjacent cell and sum the value of (current cell + * - adjacent cell) if the current cell value is greater than adjacent cell. For every cell which + * has value grater then 0, the top surface area is by default 1 therefore add one to the sum of + * each cell. + */ +public class SurfaceAreaOfThreeDShapes { + + private final int[] R = {0, 0, -1, 1}; + private final int[] C = {1, -1, 0, 0}; + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[][] A = {{2}}; + System.out.println(new SurfaceAreaOfThreeDShapes().surfaceArea(A)); + } + + public int surfaceArea(int[][] grid) { + int sum = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[i].length; j++) { + int cell = grid[i][j]; + for (int k = 0; k < 4; k++) { + int newR = i + R[k]; + int newC = j + C[k]; + if (newR >= 0 && newC >= 0 && newR < grid.length && newC < grid[0].length) { + int adjacent = grid[newR][newC]; + if (cell > adjacent) { + sum += (cell - adjacent); + } + } else if (newR < 0 || newR >= grid.length || newC < 0 || newC >= grid[0].length) { + sum += cell; + } + } + if (cell > 0) { + sum += 2; + } + } + } + return sum; + } +} diff --git a/src/main/java/array/ThirdMaximumNumber.java b/src/main/java/array/ThirdMaximumNumber.java new file mode 100644 index 00000000..ba0e42c4 --- /dev/null +++ b/src/main/java/array/ThirdMaximumNumber.java @@ -0,0 +1,60 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 25/03/2017. Given a non-empty array of integers, return the + * third maximum number in this array. If it does not exist, return the maximum number. The time + * complexity must be in O(n). + * + *

Example 1: Input: [3, 2, 1] + * + *

Output: 1 + * + *

Explanation: The third maximum is 1. Example 2: Input: [1, 2] + * + *

Output: 2 + * + *

Explanation: The third maximum does not exist, so the maximum (2) is returned instead. Example + * 3: Input: [2, 2, 3, 1] + * + *

Output: 1 + * + *

Explanation: Note that the third maximum here means the third maximum distinct number. Both + * numbers with value 2 are both considered as second maximum. + */ +public class ThirdMaximumNumber { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] a = {1, 2}; + System.out.println(new ThirdMaximumNumber().thirdMax(a)); + } + + public int thirdMax(int[] nums) { + long[] max = {Long.MIN_VALUE, Long.MIN_VALUE, Long.MIN_VALUE}; + int count = 0; + for (int num : nums) { + for (int j = 0; j < 3; j++) { + if (max[j] > num) continue; + else if (max[j] == num) break; + int k = j; + long temp1, temp2; + temp1 = num; + count++; + while (k < 3) { + temp2 = max[k]; + max[k] = temp1; + temp1 = temp2; + k++; + } + break; + } + } + System.out.println(Integer.MIN_VALUE); + return (count >= 3) ? (int) max[2] : (int) max[0]; + } +} diff --git a/src/main/java/array/TwoSum.java b/src/main/java/array/TwoSum.java new file mode 100644 index 00000000..3b45668e --- /dev/null +++ b/src/main/java/array/TwoSum.java @@ -0,0 +1,63 @@ +/* (C) 2024 YourCompanyName */ +package array; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 11/07/2017. Given an array of integers, return indices of the + * two numbers such that they add up to a specific target. + * + *

You may assume that each input would have exactly one solution, and you may not use the same + * element twice. + * + *

Example: Given nums = [2, 7, 11, 15], target = 9, + * + *

Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1]. + * + *

Solution: O(n log n). Wrap index and element in a class and sort in increasing order. Do a two + * pointer sum and compare. An alternative solution is to use hashing which is a O(n) solution - For + * each element e check if element (target - e) is already found in hashset, if yes return their + * index, else add this to hash-set and continue. + */ +public class TwoSum { + + class NumIndex { + int i, e; + + NumIndex(int i, int e) { + this.i = i; + this.e = e; + } + } + + public static void main(String[] args) { + int[] nums = {3, 2, 4}; + int[] ans = new TwoSum().twoSum(nums, 6); + for (int i : ans) System.out.println(i); + } + + public int[] twoSum(int[] nums, int target) { + List list = new ArrayList<>(); + for (int i = 0; i < nums.length; i++) { + NumIndex n = new NumIndex(i, nums[i]); + list.add(n); + } + list.sort((o1, o2) -> Integer.compare(o1.e, o2.e)); + + int[] ans = new int[2]; + for (int i = 0, j = nums.length - 1; i < j; ) { + NumIndex numi = list.get(i); + NumIndex numj = list.get(j); + int sum = numi.e + numj.e; + if (sum == target) { + ans[0] = numi.i; + ans[1] = numj.i; + return ans; + } else if (sum > target) { + j--; + } else i++; + } + return ans; + } +} diff --git a/src/main/java/array/TwoSumII.java b/src/main/java/array/TwoSumII.java new file mode 100644 index 00000000..837dba97 --- /dev/null +++ b/src/main/java/array/TwoSumII.java @@ -0,0 +1,44 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 18/03/2017. Given an array of integers that is already sorted + * in ascending order, find two numbers such that they add up to a specific target number. + * + *

The function twoSum should return indices of the two numbers such that they add up to the + * target, where index1 must be less than index2. Please note that your returned answers (both + * index1 and index2) are not zero-based. + * + *

You may assume that each input would have exactly one solution and you may not use the same + * element twice. + * + *

Input: numbers={2, 7, 11, 15}, target=9 Output: index1=1, index2=2 + */ +public class TwoSumII { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] nums = {2, 7, 11, 15}; + int[] result = new TwoSumII().twoSum(nums, 23); + for (int i : result) System.out.println(i); + } + + public int[] twoSum(int[] numbers, int target) { + int i = 0, j = numbers.length - 1; + while (i < j) { + int x = (numbers[i] + numbers[j]); + if (x == target) { + int[] result = new int[2]; + result[0] = i + 1; + result[1] = j + 1; + return result; + } else if (x < target) i++; + else j--; + } + return new int[2]; + } +} diff --git a/src/main/java/array/ValidTicTacToeState.java b/src/main/java/array/ValidTicTacToeState.java new file mode 100644 index 00000000..22bc822b --- /dev/null +++ b/src/main/java/array/ValidTicTacToeState.java @@ -0,0 +1,83 @@ +/* (C) 2024 YourCompanyName */ +package array; + +/** + * Created by gouthamvidyapradhan on 29/03/2019 A Tic-Tac-Toe board is given as a string array + * board. Return True if and only if it is possible to reach this board position during the course + * of a valid tic-tac-toe game. + * + *

The board is a 3 x 3 array, and consists of characters " ", "X", and "O". The " " character + * represents an empty square. + * + *

Here are the rules of Tic-Tac-Toe: + * + *

Players take turns placing characters into empty squares (" "). The first player always places + * "X" characters, while the second player always places "O" characters. "X" and "O" characters are + * always placed into empty squares, never filled ones. The game ends when there are 3 of the same + * (non-empty) character filling any row, column, or diagonal. The game also ends if all squares are + * non-empty. No more moves can be played if the game is over. Example 1: Input: board = ["O ", " ", + * " "] Output: false Explanation: The first player always plays "X". + * + *

Example 2: Input: board = ["XOX", " X ", " "] Output: false Explanation: Players take turns + * making moves. + * + *

Example 3: Input: board = ["XXX", " ", "OOO"] Output: false + * + *

Example 4: Input: board = ["XOX", "O O", "XOX"] Output: true Note: + * + *

board is a length-3 array of strings, where each string board[i] has length 3. Each + * board[i][j] is a character in the set {" ", "X", "O"}. + * + *

Solution: Do a brute-force check for each row, column and diagonals and keep track of count of + * 'X' and 'O' + */ +public class ValidTicTacToeState { + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + String[] board = {"XXX", "XOO", "OO "}; + System.out.println(new ValidTicTacToeState().validTicTacToe(board)); + } + + public boolean validTicTacToe(String[] board) { + boolean xWon = hasWon(board, 'X'); + boolean oWon = hasWon(board, 'O'); + int xcount = 0, ocount = 0; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (board[i].charAt(j) == 'X') { + xcount++; + } else if (board[i].charAt(j) == 'O') { + ocount++; + } + } + } + if (xWon && oWon) return false; + if (xWon) { + return ((xcount - 1 == ocount)); + } else if (oWon) { + return ((xcount == ocount)); + } else { + return (xcount == ocount || xcount - 1 == ocount); + } + } + + private boolean hasWon(String[] board, char c) { + boolean diagnol = + ((board[0].charAt(0) == c && board[1].charAt(1) == c && board[2].charAt(2) == c) + || (board[0].charAt(2) == c && board[1].charAt(1) == c && board[2].charAt(0) == c)); + if (diagnol) return true; + for (int i = 0; i < 3; i++) { + if (board[i].charAt(0) == c && board[i].charAt(1) == c && board[i].charAt(2) == c) + return true; + } + for (int i = 0; i < 3; i++) { + if (board[0].charAt(i) == c && board[1].charAt(i) == c && board[2].charAt(i) == c) + return true; + } + return false; + } +} diff --git a/src/main/java/backtracking/CombinationSum.java b/src/main/java/backtracking/CombinationSum.java new file mode 100644 index 00000000..281dda21 --- /dev/null +++ b/src/main/java/backtracking/CombinationSum.java @@ -0,0 +1,56 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by pradhang on 3/14/2017. Given a set of candidate numbers (C) (without duplicates) and a + * target number (T), find all unique combinations in C where the candidate numbers sums to T. + * + *

The same repeated number may be chosen from C unlimited number of times. + * + *

Note: All numbers (including target) will be positive integers. The solution set must not + * contain duplicate combinations. For example, given candidate set [2, 3, 6, 7] and target 7, A + * solution set is: [ [7], [2, 2, 3] ] + */ +public class CombinationSum { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] candidates = {2, 3, 6, 7}; + + List> result = new CombinationSum().combinationSum(candidates, 7); + } + + public List> combinationSum(int[] candidates, int target) { + List> result = new ArrayList<>(); + List subList = new ArrayList<>(); + doNext(0, result, 0, candidates, target, subList); + return result; + } + + private void doNext( + int i, + List> result, + int count, + int[] candidates, + int target, + List subArr) { + if (target == 0) { + List subList = new ArrayList<>(); + for (int k = 0; k < count; k++) subList.add(subArr.get(k)); + result.add(subList); + } else if (target > 0) { + for (int j = i, l = candidates.length; j < l; j++) { + subArr.add(candidates[j]); + doNext(j, result, count + 1, candidates, target - candidates[j], subArr); + subArr.remove(subArr.size() - 1); + } + } + } +} diff --git a/src/main/java/backtracking/CombinationSumII.java b/src/main/java/backtracking/CombinationSumII.java new file mode 100644 index 00000000..4fa9f73d --- /dev/null +++ b/src/main/java/backtracking/CombinationSumII.java @@ -0,0 +1,50 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 14/03/2017. Given a collection of candidate numbers (C) and a + * target number (T), find all unique combinations in C where the candidate numbers sums to T. + * + *

Each number in C may only be used once in the combination. + * + *

Note: All numbers (including target) will be positive integers. The solution set must not + * contain duplicate combinations. For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and + * target 8, A solution set is: [ [1, 7], [1, 2, 5], [2, 6], [1, 1, 6] ] + */ +public class CombinationSumII { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] candidates = {1, 1, 2, 2}; + List> result = new CombinationSumII().combinationSum2(candidates, 4); + } + + public List> combinationSum2(int[] candidates, int target) { + Arrays.sort(candidates); + List> result = new ArrayList<>(); + combination(0, target, candidates, new ArrayList<>(), result); + return result; + } + + private void combination( + int i, int target, int[] candidates, List row, List> result) { + if (target == 0) { + result.add(new ArrayList<>(row)); + } else if (target > 0) { + for (int j = i, l = candidates.length; j < l; j++) { + if (j > i && candidates[j] == candidates[j - 1]) continue; + row.add(candidates[j]); + combination(j + 1, target - candidates[j], candidates, row, result); + row.remove(row.size() - 1); + } + } + } +} diff --git a/src/main/java/backtracking/Combinations.java b/src/main/java/backtracking/Combinations.java new file mode 100644 index 00000000..613c832e --- /dev/null +++ b/src/main/java/backtracking/Combinations.java @@ -0,0 +1,40 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by pradhang on 3/8/2017. Given two integers n and k, return all possible combinations of + * k numbers out of 1 ... n. + * + *

For example, If n = 4 and k = 2, a solution is: + * + *

[ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ] + */ +public class Combinations { + + public static void main(String[] args) throws Exception { + List> result = new Combinations().combine(3, 3); + } + + public List> combine(int n, int k) { + int[] subArr = new int[k]; + List> result = new ArrayList<>(); + getNext(0, 0, n, k, subArr, result); + return result; + } + + private void getNext(int i, int count, int n, int k, int[] subArr, List> result) { + if (k == 0) { + List subList = new ArrayList<>(); + for (int a : subArr) subList.add(a); + result.add(subList); + } else { + for (int j = i + 1; j <= n; j++) { + subArr[count] = j; + getNext(j, count + 1, n, k - 1, subArr, result); + } + } + } +} diff --git a/src/main/java/backtracking/ExpressionAddOperators.java b/src/main/java/backtracking/ExpressionAddOperators.java new file mode 100644 index 00000000..33d74351 --- /dev/null +++ b/src/main/java/backtracking/ExpressionAddOperators.java @@ -0,0 +1,72 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 05/12/2017. Given a string that contains only digits 0-9 and a + * target value, return all possibilities to add binary operators (not unary) +, -, or * between the + * digits so they evaluate to the target value. + * + *

Examples: "123", 6 -> ["1+2+3", "1*2*3"] "232", 8 -> ["2*3+2", "2+3*2"] "105", 5 -> + * ["1*0+5","10-5"] "00", 0 -> ["0+0", "0-0", "0*0"] "3456237490", 9191 -> [] + * + *

Solution: Backtrack and keep track of the total and product value. In case of + or - add/sub + * curr to total and curr becomes the new product In case of * take difference of total and prod and + * add (product of curr value with previous product and make this a new product for the next + * iteration) + * + *

Worst-case time complexity can be O(n * (2^n-1)) + */ +public class ExpressionAddOperators { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + List result = new ExpressionAddOperators().addOperators("202010201", 201); + result.stream().forEach(System.out::println); + } + + public List addOperators(String num, int target) { + List result = new ArrayList<>(); + backTrack("", result, 0, num, target, 0L, 0L); + return result; + } + + private void backTrack( + String exp, List list, int curr, String num, int target, long total, long prod) { + if (curr == num.length()) { + if (total == target) { + list.add(exp); + } + } else { + for (int i = curr, l = num.length(); i < l; i++) { + String newNum = num.substring(curr, i + 1); + if (newNum.length() > 1 && newNum.startsWith("0")) { + break; + } + long newNumL = Long.parseLong(newNum); + if (curr == 0) { + backTrack(newNum, list, i + 1, num, target, newNumL, newNumL); + } else { + backTrack(exp + "+" + newNum, list, i + 1, num, target, total + newNumL, newNumL); + + backTrack(exp + "-" + newNum, list, i + 1, num, target, total - newNumL, newNumL * -1L); + + backTrack( + exp + "*" + newNum, + list, + i + 1, + num, + target, + (total - prod + (prod * newNumL)), + prod * newNumL); + } + } + } + } +} diff --git a/src/main/java/backtracking/GenerateParentheses.java b/src/main/java/backtracking/GenerateParentheses.java new file mode 100644 index 00000000..6de5d66f --- /dev/null +++ b/src/main/java/backtracking/GenerateParentheses.java @@ -0,0 +1,37 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 24/06/2017. Given n pairs of parentheses, write a function to + * generate all combinations of well-formed parentheses. + * + *

For example, given n = 3, a solution set is: + * + *

[ "((()))", "(()())", "(())()", "()(())", "()()()" ] + */ +public class GenerateParentheses { + public static void main(String[] args) throws Exception { + System.out.println(new GenerateParentheses().generateParenthesis(4)); + } + + public List generateParenthesis(int n) { + List list = new ArrayList<>(); + backTrack(list, "", 0, 0, n); + return list; + } + + private void backTrack(List list, String str, int open, int close, int n) { + if (str.length() == n * 2) { + list.add(str); + } else { + if (open < n) backTrack(list, str.concat("("), open + 1, close, n); + if (close + < open) // number of close should be less than open or else it can result in unbalanced + // parentheses + backTrack(list, str.concat(")"), open, close + 1, n); + } + } +} diff --git a/src/main/java/backtracking/LetterCasePermutation.java b/src/main/java/backtracking/LetterCasePermutation.java new file mode 100644 index 00000000..935e27eb --- /dev/null +++ b/src/main/java/backtracking/LetterCasePermutation.java @@ -0,0 +1,56 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 12/04/2018. Given a string S, we can transform every letter + * individually to be lowercase or uppercase to create another string. Return a list of all possible + * strings we could create. + * + *

Examples: Input: S = "a1b2" Output: ["a1b2", "a1B2", "A1b2", "A1B2"] + * + *

Input: S = "3z4" Output: ["3z4", "3Z4"] + * + *

Input: S = "12345" Output: ["12345"] Note: + * + *

S will be a string with length at most 12. S will consist only of letters or digits. + * + *

Solution: O(N x 2 ^ N) Backtrack and generate all possible combinations. + */ +public class LetterCasePermutation { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new LetterCasePermutation().letterCasePermutation("a1b2")); + } + + public List letterCasePermutation(String S) { + List result = new ArrayList<>(); + backtrack(S, result, 0, ""); + return result; + } + + private void backtrack(String s, List result, int i, String r) { + if (i == s.length()) { + result.add(r); + } else { + if (Character.isAlphabetic(s.charAt(i))) { + backtrack(s, result, i + 1, r + s.charAt(i)); + if (Character.isLowerCase(s.charAt(i))) { + backtrack(s, result, i + 1, r + Character.toUpperCase(s.charAt(i))); + } else { + backtrack(s, result, i + 1, r + Character.toLowerCase(s.charAt(i))); + } + } else { + backtrack(s, result, i + 1, r + s.charAt(i)); + } + } + } +} diff --git a/src/main/java/backtracking/LetterPhoneNumber.java b/src/main/java/backtracking/LetterPhoneNumber.java new file mode 100644 index 00000000..e63a38fa --- /dev/null +++ b/src/main/java/backtracking/LetterPhoneNumber.java @@ -0,0 +1,54 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 09/03/2017. Given a digit string, return all possible letter + * combinations that the number could represent. + * + *

A mapping of digit to letters (just like on the telephone buttons) is given below. 1 2(abc) + * 3(def) 4(ghi) 5(jkl) 6(mno) 7(pqrs) 8(tuv) 9(wxyz) + * + *

+ * + *

Input:Digit string "23" Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. Note: + * Although the above answer is in lexicographical order, your answer could be in any order you + * want. + */ +public class LetterPhoneNumber { + private String[] NUMBER_ALPHA = { + "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" + }; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + List result = new LetterPhoneNumber().letterCombinations("23"); + result.forEach(System.out::println); + } + + private List letterCombinations(String digits) { + if (digits == null || digits.isEmpty() || digits.contains("1") || digits.contains("0")) + return new ArrayList<>(); + List prev = new ArrayList<>(); + prev.add(""); + for (int i = digits.length() - 1; i >= 0; i--) { + String str = NUMBER_ALPHA[Integer.parseInt(String.valueOf(digits.charAt(i)))]; + List newList = new ArrayList<>(); + for (int j = 0, l = str.length(); j < l; j++) { + for (String s : prev) { + s = str.charAt(j) + s; + newList.add(s); + } + } + prev = newList; + } + return prev; + } +} diff --git a/src/main/java/backtracking/MatchsticksToSquare.java b/src/main/java/backtracking/MatchsticksToSquare.java new file mode 100644 index 00000000..4e79a9ba --- /dev/null +++ b/src/main/java/backtracking/MatchsticksToSquare.java @@ -0,0 +1,117 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 25/05/2019 Remember the story of Little Match Girl? By now, you + * know exactly what matchsticks the little match girl has, please find out a way you can make one + * square by using up all those matchsticks. You should not break any stick, but you can link them + * up, and each matchstick must be used exactly one time. + * + *

Your input will be several matchsticks the girl has, represented with their stick length. Your + * output will either be true or false, to represent whether you could make one square using all the + * matchsticks the little match girl has. + * + *

Example 1: Input: [1,1,2,2,2] Output: true + * + *

Explanation: You can form a square with length 2, one side of the square came two sticks with + * length 1. Example 2: Input: [3,3,3,3,4] Output: false + * + *

Explanation: You cannot find a way to form a square with all the matchsticks. Note: The length + * sum of the given matchsticks is in the range of 0 to 10^9. The length of the given matchstick + * array will not exceed 15. + * + *

Solution: O(2 ^ N): Generate a power set of all combination of numbers for the given array + * which sum up to the length of a side of square. Now, to check if a square can be made using all + * the sides sticks of different length, generate a hash for for each of the combination which was + * generated in the previous step. The hash function should be such that it uses unique indexes of + * each match stick. If 4 different hash values are formed using unique and all indices then a + * square is possible. + */ +public class MatchsticksToSquare { + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[] A = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 6, 10, 10}; + System.out.println(new MatchsticksToSquare().makesquare(A)); + } + + class Pair { + int value, i; + + Pair(int value, int i) { + this.value = value; + this.i = i; + } + } + + public boolean makesquare(int[] nums) { + if (nums.length == 0) return false; + int sum = 0; + for (int n : nums) { + sum += n; + } + int side = sum / 4; + if ((sum % 4) != 0) return false; + List> list = powerSet(nums, side); + Set hashIndex = new HashSet<>(); + int cons = 0; + for (int i = 0; i < nums.length; i++) { + cons |= (1 << i); + } + for (int i = 0; i < list.size(); i++) { + for (int j = i + 1; j < list.size(); j++) { + Set indexList = new HashSet<>(); + List list1 = list.get(i); + List list2 = list.get(j); + int hash = 0; + for (Pair l1 : list1) { + indexList.add(l1.i); + hash |= (1 << l1.i); + } + boolean allUnique = true; + for (Pair l2 : list2) { + if (indexList.contains(l2.i)) { + allUnique = false; + break; + } + indexList.add(l2.i); + hash |= (1 << l2.i); + } + if (allUnique) { + hashIndex.add(hash); + int complement = ((~hash) & cons); + if (hashIndex.contains(complement)) return true; + } + } + } + return false; + } + + private List> powerSet(int[] nums, int expectedSum) { + List> result = new ArrayList<>(); + generate(0, nums, new ArrayList<>(), result, 0, expectedSum); + return result; + } + + private void generate( + int i, int[] nums, List subList, List> result, int sum, int expected) { + if (i >= nums.length) { + if (sum == expected) { + List pairs = new ArrayList<>(subList); + result.add(pairs); + } + } else { + if (sum + nums[i] <= expected) { + subList.add(new Pair(nums[i], i)); + generate(i + 1, nums, subList, result, sum + nums[i], expected); + subList.remove(subList.size() - 1); + } + generate(i + 1, nums, subList, result, sum, expected); + } + } +} diff --git a/src/main/java/backtracking/PalindromePartitioning.java b/src/main/java/backtracking/PalindromePartitioning.java new file mode 100644 index 00000000..f1aeb823 --- /dev/null +++ b/src/main/java/backtracking/PalindromePartitioning.java @@ -0,0 +1,59 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by pradhang on 3/15/2017. Given a string s, partition s such that every substring of the + * partition is a palindrome. + * + *

Return all possible palindrome partitioning of s. + * + *

For example, given s = "aab", Return + * + *

[ ["aa","b"], ["a","a","b"] ] + */ +public class PalindromePartitioning { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + List> result = new PalindromePartitioning().partition("aaaaaaaaaaaaaaaaaa"); + } + + public List> partition(String s) { + List> result = new ArrayList<>(); + doNext(0, new ArrayList<>(), s, result); + return result; + } + + private void doNext(int i, List row, String s, List> result) { + if (i == s.length()) { + List list = new ArrayList<>(row); + result.add(list); + } else { + for (int j = i, l = s.length(); j < l; j++) { + String sbStr = s.substring(i, j + 1); + if (isPalindrome(sbStr)) { + row.add(sbStr); + doNext(j + 1, row, s, result); + row.remove(row.size() - 1); + } + } + } + } + + private boolean isPalindrome(String s) { + int i = 0, j = s.length() - 1; + while (i <= j) { + if (s.charAt(i) != s.charAt(j)) return false; + i++; + j--; + } + return true; + } +} diff --git a/src/main/java/backtracking/Permutations.java b/src/main/java/backtracking/Permutations.java new file mode 100644 index 00000000..13a26e37 --- /dev/null +++ b/src/main/java/backtracking/Permutations.java @@ -0,0 +1,49 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 15/03/2017. Given a collection of distinct numbers, return all + * possible permutations. + * + *

For example, [1,2,3] have the following permutations: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], + * [3,1,2], [3,2,1] ] + */ +public class Permutations { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] nums = {1, 2, 3}; + List> result = new Permutations().permute(nums); + } + + public List> permute(int[] nums) { + List> result = new ArrayList<>(); + nextPermutation(0, nums, result); + return result; + } + + private void nextPermutation(int i, int[] nums, List> result) { + if (i == nums.length - 1) { + List list = new ArrayList<>(); + for (int n : nums) list.add(n); + result.add(list); + } else { + for (int j = i, l = nums.length; j < l; j++) { + int temp = nums[j]; + nums[j] = nums[i]; + nums[i] = temp; + nextPermutation(i + 1, nums, result); + temp = nums[j]; + nums[j] = nums[i]; + nums[i] = temp; + } + } + } +} diff --git a/src/main/java/backtracking/PermutationsII.java b/src/main/java/backtracking/PermutationsII.java new file mode 100644 index 00000000..56a9f5ca --- /dev/null +++ b/src/main/java/backtracking/PermutationsII.java @@ -0,0 +1,46 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 12/04/2017. Given a collection of numbers that might contain + * duplicates, return all possible unique permutations. + * + *

For example, [1,1,2] have the following unique permutations: [ [1,1,2], [1,2,1], [2,1,1] ] + */ +public class PermutationsII { + public static void main(String[] args) { + int[] A = {1, 2, 2}; + System.out.println(new PermutationsII().permuteUnique(A)); + } + + public List> permuteUnique(int[] nums) { + List> result = new ArrayList<>(); + Arrays.sort(nums); + nextPermutation(0, nums, result); + return result; + } + + private void nextPermutation(int i, int[] nums, List> result) { + if (i == nums.length - 1) { + List list = new ArrayList<>(); + for (int n : nums) list.add(n); + result.add(list); + } else { + for (int j = i, l = nums.length; j < l; j++) { + if (j > i && nums[j] == nums[i]) continue; + swap(nums, i, j); + nextPermutation(i + 1, Arrays.copyOf(nums, nums.length), result); + } + } + } + + private void swap(int[] a, int i, int j) { + int tmp = a[i]; + a[i] = a[j]; + a[j] = tmp; + } +} diff --git a/src/main/java/backtracking/RegularExpressionMatching.java b/src/main/java/backtracking/RegularExpressionMatching.java new file mode 100644 index 00000000..c31929f7 --- /dev/null +++ b/src/main/java/backtracking/RegularExpressionMatching.java @@ -0,0 +1,72 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +/** + * Created by gouthamvidyapradhan on 05/12/2017. + * + *

Implement regular expression matching with support for '.' and '*'. + * + *

'.' Matches any single character. '*' Matches zero or more of the preceding element. + * + *

The matching should cover the entire input string (not partial). + * + *

The function prototype should be: bool isMatch(const char *s, const char *p) + * + *

Some examples: isMatch("aa","a") → false isMatch("aa","aa") → true isMatch("aaa","aa") → false + * isMatch("aa", "a*") → true isMatch("aa", ".*") → true isMatch("ab", ".*") → true isMatch("aab", + * "c*a*b") → true + * + *

Solution: When a wildcard is encountered try to match all the possible prefixes including + * none, otherwise do a simple one to one match. If the end of string is reached simultaneously in + * both string and pattern then return true + */ +public class RegularExpressionMatching { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new RegularExpressionMatching().isMatch("aa", "a*a*a")); + } + + public boolean isMatch(String s, String p) { + return backTrack(0, 0, s, p); + } + + private boolean backTrack(int si, int pi, String s, String p) { + if (si >= s.length() && pi >= p.length()) + return true; // end of the string has been reached hence return true + else { + if (pi >= p.length()) return false; // pattern has exhausted hence return false + else if (si >= s.length()) { + if (pi + 1 < p.length() && p.charAt(pi + 1) == '*') { + return backTrack(si, pi + 2, s, p); + } else + return false; // string has exhausted and pattern does not contain wildcard hence return + // false + } else if (s.charAt(si) == p.charAt(pi) || p.charAt(pi) == '.') { + if (pi + 1 < p.length() && p.charAt(pi + 1) == '*') { + // match 0 or more repeated preceding element + if (backTrack(si, pi + 2, s, p)) return true; + for (int i = si, l = s.length(); i < l; i++) { + if (s.charAt(i) == p.charAt(pi) || p.charAt(pi) == '.') { + if (backTrack(i + 1, pi + 2, s, p)) return true; + } else { + return false; + } + } + return backTrack(s.length(), pi, s, p); + } else { + return backTrack(si + 1, pi + 1, s, p); // not wildcard match immediate chars + } + } else { + if (pi + 1 < p.length() && p.charAt(pi + 1) == '*') { + return backTrack(si, pi + 2, s, p); + } else return false; + } + } + } +} diff --git a/src/main/java/backtracking/RemoveInvalidParentheses.java b/src/main/java/backtracking/RemoveInvalidParentheses.java new file mode 100644 index 00000000..145dee39 --- /dev/null +++ b/src/main/java/backtracking/RemoveInvalidParentheses.java @@ -0,0 +1,84 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Created by gouthamvidyapradhan on 17/10/2017. Remove the minimum number of invalid parentheses in + * order to make the input string valid. Return all possible results. + * + *

Note: The input string may contain letters other than the parentheses ( and ). + * + *

Examples: "()())()" -> ["()()()", "(())()"] "(a)())()" -> ["(a)()()", "(a())()"] ")(" -> [""] + * + *

Solution: O(N x 2 ^ N) backtrack and generate all combination of unique parentheses. Keep + * track of a counter which keeps track of validity of parentheses. Prune the search space by + * checking for validity of parenthesis on the fly by checking if the counter goes below 0 in which + * case a valid combination is impossible and also keep track of selected count and total count of + * characters in each state to check if the difference between them is above the min threshold. + */ +public class RemoveInvalidParentheses { + + private Set done; + private int maxLen = Integer.MIN_VALUE; + private int minDiff = Integer.MAX_VALUE; + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + List result = new RemoveInvalidParentheses().removeInvalidParentheses("())())"); + result.forEach(System.out::println); + } + + public List removeInvalidParentheses(String s) { + done = new HashSet<>(); + List result = new ArrayList<>(); + backTrack(s, 0, 0, result, "", 0, 0); + return result; + } + + private void backTrack( + String s, int i, int count, List result, String state, int selected, int total) { + if (i >= s.length()) { + if (count == 0) { + if (selected >= maxLen) { + result.add(state); + maxLen = selected; + minDiff = total - selected; + } + } + } else { + done.add(state); + char c = s.charAt(i); + if (c == '(') { + if (!done.contains(state + "(")) { + backTrack(s, i + 1, count + 1, result, state + "(", selected + 1, total + 1); + } + if ((total - selected + 1) <= minDiff) { + backTrack(s, i + 1, count, result, state, selected, total + 1); + } + } else if (c == ')') { + if (count - 1 < 0) { + if ((total - selected + 1) <= minDiff) { + backTrack(s, i + 1, count, result, state, selected, total + 1); + } + } else { + if (!done.contains(state + ")")) { + backTrack(s, i + 1, count - 1, result, state + ")", selected + 1, total + 1); + } + if ((total - selected + 1) <= minDiff) { + backTrack(s, i + 1, count, result, state, selected, total + 1); + } + } + } else { + backTrack(s, i + 1, count, result, state + c, selected + 1, total + 1); + } + } + } +} diff --git a/src/main/java/backtracking/Subsets.java b/src/main/java/backtracking/Subsets.java new file mode 100644 index 00000000..3251446a --- /dev/null +++ b/src/main/java/backtracking/Subsets.java @@ -0,0 +1,41 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 14/03/2017. Given a set of distinct integers, nums, return all + * possible subsets. + * + *

Note: The solution set must not contain duplicate subsets. + * + *

For example, If nums = [1,2,3], a solution is: + * + *

[ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ] + */ +public class Subsets { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] n = {1, 2, 3}; + List> result = new Subsets().subsets(n); + } + + public List> subsets(int[] nums) { + List> result = new ArrayList<>(); + result.add(new ArrayList<>()); // empty subset + for (int i = 0, l = nums.length; i < l; i++) { + for (int j = 0, resLen = result.size(); j < resLen; j++) { + List newList = new ArrayList<>(result.get(j)); + newList.add(nums[i]); + result.add(newList); + } + } + return result; + } +} diff --git a/src/main/java/backtracking/SubsetsII.java b/src/main/java/backtracking/SubsetsII.java new file mode 100644 index 00000000..76d4e7b2 --- /dev/null +++ b/src/main/java/backtracking/SubsetsII.java @@ -0,0 +1,49 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 14/03/2017. Given a collection of integers that might contain + * duplicates, nums, return all possible subsets. + * + *

Note: The solution set must not contain duplicate subsets. + * + *

For example, If nums = [1,2,2], a solution is: + * + *

[ [2], [1], [1,2,2], [2,2], [1,2], [] ] + */ +public class SubsetsII { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] n = {1, 2, 3}; + List> result = new SubsetsII().subsetsWithDup(n); + } + + public List> subsetsWithDup(int[] nums) { + List> result = new ArrayList<>(); + result.add(new ArrayList<>()); // empty subset + int start = 0, newStart = 0; + Arrays.sort(nums); + for (int i = 0, l = nums.length; i < l; i++) { + newStart = result.size(); + if (i == 0 || nums[i] != nums[i - 1]) { + start = 0; + } + for (int j = start, resLen = result.size(); j < resLen; j++) { + List newList = new ArrayList<>(result.get(j)); + newList.add(nums[i]); + result.add(newList); + } + start = newStart; + } + return result; + } +} diff --git a/src/main/java/backtracking/TargetSum.java b/src/main/java/backtracking/TargetSum.java new file mode 100644 index 00000000..e586d33a --- /dev/null +++ b/src/main/java/backtracking/TargetSum.java @@ -0,0 +1,50 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +/** + * Created by gouthamvidyapradhan on 09/12/2017. You are given a list of non-negative integers, a1, + * a2, ..., an, and a target, S. Now you have 2 symbols + and -. For each integer, you should choose + * one from + and - as its new symbol. + * + *

Find out how many ways to assign symbols to make sum of integers equal to target S. + * + *

Example 1: Input: nums is [1, 1, 1, 1, 1], S is 3. Output: 5 Explanation: + * + *

-1+1+1+1+1 = 3 +1-1+1+1+1 = 3 +1+1-1+1+1 = 3 +1+1+1-1+1 = 3 +1+1+1+1-1 = 3 + * + *

There are 5 ways to assign symbols to make the sum of nums be target 3. Note: The length of + * the given array is positive and will not exceed 20. The sum of elements in the given array will + * not exceed 1000. Your output answer is guaranteed to be fitted in a 32-bit integer. + */ +public class TargetSum { + + private static int n; + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 1, 1, 1, 1}; + n = 0; + new TargetSum().findTargetSumWays(A, 3); + System.out.println(n); + } + + public int findTargetSumWays(int[] nums, int S) { + backtrack(nums, S, 0, 0); + return n; + } + + private void backtrack(int[] nums, int target, int sum, int i) { + if (i == nums.length) { + if (sum == target) { + n++; + } + } else { + backtrack(nums, target, sum + nums[i], i + 1); + backtrack(nums, target, sum - nums[i], i + 1); + } + } +} diff --git a/src/main/java/backtracking/WildcardMatching.java b/src/main/java/backtracking/WildcardMatching.java new file mode 100644 index 00000000..811aee77 --- /dev/null +++ b/src/main/java/backtracking/WildcardMatching.java @@ -0,0 +1,69 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +/** + * Created by gouthamvidyapradhan on 21/01/2018. Implement wildcard pattern matching with support + * for '?' and '*'. + * + *

'?' Matches any single character. '*' Matches any sequence of characters (including the empty + * sequence). + * + *

The matching should cover the entire input string (not partial). + * + *

The function prototype should be: bool isMatch(const char *s, const char *p) + * + *

Some examples: isMatch("aa","a") → false isMatch("aa","aa") → true isMatch("aaa","aa") → false + * isMatch("aa", "*") → true isMatch("aa", "a*") → true isMatch("ab", "?*") → true isMatch("aab", + * "c*a*b") → false + * + *

Solution: Maintain two indexes one for string and other one for the pattern. 1. If the + * characters match in both the indexes or if the char at pattern is '?' then increment both the + * indexes. 2. If a star(*) is encountered save the position of star in the given string as + * 'startPosAtStr' and position of star in the pattern as 'starIdx' and this time increment only + * index for pattern. 3. If the characters do not match and if the start is not encountered + * previously return false else increment 'startPosAtStr' and assign this as the new index for + * string and start the new pattern index from starIdx + 1 + */ +public class WildcardMatching { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new WildcardMatching().isMatch("abebd", "?be******e")); + } + + public boolean isMatch(String s, String p) { + int starIdx = -1; + int starPosAtStr = -1; + int j = 0; + for (int i = 0, l = s.length(); i < l; ) { + if (j < p.length()) { + if (s.charAt(i) == p.charAt(j) || p.charAt(j) == '?') { + i++; + j++; + } else if (p.charAt(j) == '*') { + starIdx = j; + starPosAtStr = i; + j++; // increment only pattern index. This is because '*' can match also empty string. + } else if (starIdx != -1) { + i = ++starPosAtStr; + j = starIdx + 1; + } else return false; + } else if (starIdx != -1) { + i = ++starPosAtStr; + j = starIdx + 1; + } else return false; + } + // check if the remaining characters in pattern contains only '*' + while (j < p.length()) { + if (p.charAt(j) == '*') { + j++; + } else break; + } + return j == p.length(); + } +} diff --git a/src/main/java/backtracking/WordSearch.java b/src/main/java/backtracking/WordSearch.java new file mode 100644 index 00000000..c6c2abdd --- /dev/null +++ b/src/main/java/backtracking/WordSearch.java @@ -0,0 +1,69 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +/** + * Created by PRADHANG on 4/13/2017. Given a 2D board and a word, find if the word exists in the + * grid. + * + *

The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells + * are those horizontally or vertically neighboring. The same letter cell may not be used more than + * once. + * + *

For example, Given board = + * + *

[ ['A','B','C','E'], ['S','F','C','S'], ['A','D','E','E'] ] word = "ABCCED", -> returns true, + * word = "SEE", -> returns true, word = "ABCB", -> returns false. + */ +public class WordSearch { + private static final int[] R = {0, 0, 1, -1}; + private static final int[] C = {1, -1, 0, 0}; + private static boolean[][] visited; + private static int length = 0, N, M; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + char[][] board = {{'A'}}; + System.out.println(new WordSearch().exist(board, "A")); + } + + public boolean exist(char[][] board, String word) { + N = board.length; + M = board[0].length; + if (N * M < word.length()) return false; + visited = new boolean[N][M]; + length = word.length(); + for (int i = 0; i < N; i++) { + for (int j = 0; j < M; j++) { + if (board[i][j] == word.charAt(0)) { + if (dfs(i, j, board, word, 1)) return true; + visited[i][j] = false; + } + } + } + return false; + } + + private boolean dfs(int r, int c, char[][] board, String word, int pos) { + if (pos < length) { + visited[r][c] = true; + for (int i = 0; i < 4; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR >= 0 && newR < N && newC >= 0 && newC < M) { + if (!visited[newR][newC]) { + if (board[newR][newC] == word.charAt(pos)) { + if (dfs(newR, newC, board, word, pos + 1)) return true; + visited[newR][newC] = false; + } + } + } + } + } else return true; + return false; + } +} diff --git a/src/main/java/backtracking/WordSearchII.java b/src/main/java/backtracking/WordSearchII.java new file mode 100644 index 00000000..4cf67e8b --- /dev/null +++ b/src/main/java/backtracking/WordSearchII.java @@ -0,0 +1,106 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.*; + +/** + * Created by pradhang on 7/4/2017. Given a 2D board and a list of words from the dictionary, find + * all words in the board. + * + *

Each word must be constructed from letters of sequentially adjacent cell, where "adjacent" + * cells are those horizontally or vertically neighboring. The same letter cell may not be used more + * than once in a word. + * + *

For example, Given words = ["oath","pea","eat","rain"] and board = + * + *

[ ['o','a','a','n'], ['e','t','a','e'], ['i','h','k','r'], ['i','f','l','v'] ] Return + * ["eat","oath"]. Note: You may assume that all inputs are consist of lowercase letters a-z. + */ +public class WordSearchII { + private final int[] R = {0, 0, -1, 1}; + private final int[] C = {-1, 1, 0, 0}; + boolean[][] visited; + private Set dictionary; + + public static void main(String[] args) throws Exception { + char[][] board = { + {'o', 'a', 'a', 'n'}, {'e', 't', 'a', 'e'}, {'i', 'h', 'k', 'r'}, {'i', 'f', 'l', 'v'} + }; + String[] words = {"oath", "pea", "eat", "rain"}; + System.out.println(new WordSearchII().findWords(board, words)); + } + + public List findWords(char[][] board, String[] words) { + dictionary = new HashSet<>(); + Trie trie = new Trie(); + for (String w : words) { + trie.insert(w); + dictionary.add(w); + } + visited = new boolean[board.length][board[0].length]; + Set resultSet = new HashSet<>(); + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + dfs(i, j, board, resultSet, trie, String.valueOf(board[i][j])); + } + } + return new ArrayList<>(resultSet); + } + + private void dfs(int r, int c, char[][] board, Set result, Trie trie, String s) { + char newChar = board[r][c]; + Trie subTrie = trie.next(newChar); + if (subTrie == null) return; + visited[r][c] = true; + if (dictionary.contains(s)) result.add(s); + for (int i = 0; i < 4; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR >= 0 && newC >= 0 && newR < board.length && newC < board[0].length) { + if (!visited[newR][newC]) { + dfs(newR, newC, board, result, subTrie, s + board[newR][newC]); + } + } + } + visited[r][c] = false; + } + + private class Trie { + + private Map map; + + /** Initialize your data structure here. */ + public Trie() { + map = new HashMap<>(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + if (word != null) { + add(0, word, word.length()); + } + } + + private void add(int i, String word, int length) { + if (i < length) { + char c = word.charAt(i); + Trie subTrie = map.get(c); + if (subTrie == null) { + subTrie = new Trie(); + map.put(c, subTrie); + } + subTrie.add(i + 1, word, length); + } else map.put(null, new Trie()); // use null to indicate end of string + } + + /** + * Get next Trie node + * + * @param c char c + * @return return Trie + */ + public Trie next(char c) { + return this.map.get(c); + } + } +} diff --git a/src/main/java/backtracking/ZumaGame.java b/src/main/java/backtracking/ZumaGame.java new file mode 100644 index 00000000..5d905143 --- /dev/null +++ b/src/main/java/backtracking/ZumaGame.java @@ -0,0 +1,94 @@ +/* (C) 2024 YourCompanyName */ +package backtracking; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 14/05/2019 Think about Zuma Game. You have a row of balls on + * the table, colored red(R), yellow(Y), blue(B), green(G), and white(W). You also have several + * balls in your hand. + * + *

Each time, you may choose a ball in your hand, and insert it into the row (including the + * leftmost place and rightmost place). Then, if there is a group of 3 or more balls in the same + * color touching, remove these balls. Keep doing this until no more balls can be removed. + * + *

Find the minimal balls you have to insert to remove all the balls on the table. If you cannot + * remove all the balls, output -1. + * + *

Examples: + * + *

Input: "WRRBBW", "RB" Output: -1 Explanation: WRRBBW -> WRR[R]BBW -> WBBW -> WBB[B]W -> WW + * + *

Input: "WWRRBBWW", "WRBRW" Output: 2 Explanation: WWRRBBWW -> WWRR[R]BBWW -> WWBBWW -> + * WWBB[B]WW -> WWWW -> empty + * + *

Input:"G", "GGGGG" Output: 2 Explanation: G -> G[G] -> GG[G] -> empty + * + *

Input: "RBYYBBRRB", "YRBGB" Output: 3 Explanation: RBYYBBRRB -> RBYY[Y]BBRRB -> RBBBRRB -> + * RRRB -> B -> B[B] -> BB[B] -> empty + * + *

Note: You may assume that the initial row of balls on the table won’t have any 3 or more + * consecutive balls with the same color. The number of balls on the table won't exceed 20, and the + * string represents these balls is called "board" in the input. The number of balls in your hand + * won't exceed 5, and the string represents these balls is called "hand" in the input. Both input + * strings will be non-empty and only contain characters 'R','Y','B','G','W'. + * + *

Solution: Maintain a count of each colored balls. Reduce the string to a new string by + * removing the contiguous same coloured balls which exceeds the count of 3 starting from index i = + * 0. Each new string formed (by adding a new ball to a position i) makes a new state. Backtrack and + * traverse the search space and keep track of count of balls used. Maintain a minimum count + * variable and return that as the answer. + */ +public class ZumaGame { + public static void main(String[] args) { + System.out.println(new ZumaGame().findMinStep("BBWWRRYYRRWWBB", "Y")); + } + + Map map; + int min = Integer.MAX_VALUE; + + public int findMinStep(String board, String hand) { + map = new HashMap<>(); + for (char c : hand.toCharArray()) { + map.putIfAbsent(c, 0); + map.put(c, map.get(c) + 1); + } + backtrack(board, 0); + return min == Integer.MAX_VALUE ? -1 : min; + } + + private void backtrack(String board, int total) { + if (board.isEmpty()) { + min = Math.min(min, total); + } else { + int i = 0, j = 0; + for (int l = board.length(); i < l; ) { + if (j < l && board.charAt(j) == board.charAt(i)) { + j++; + } else { + if (j - i > 2) { + backtrack(board.substring(0, i) + ((j < l) ? board.substring(j) : ""), total); + } else { + int a = j - i; + char c = board.charAt(i); + if (map.containsKey(c)) { + int count = map.get(c); + if (count >= (3 - a)) { + if ((count - (3 - a)) == 0) { + map.remove(c); + } else { + map.put(c, count - (3 - a)); + } + backtrack( + board.substring(0, i) + ((j < l) ? board.substring(j) : ""), total + (3 - a)); + map.put(c, count); + } + } + } + i = j; + j++; + } + } + } + } +} diff --git a/src/main/java/binary_search/ArmstrongNumber.java b/src/main/java/binary_search/ArmstrongNumber.java new file mode 100644 index 00000000..c3c13c8d --- /dev/null +++ b/src/main/java/binary_search/ArmstrongNumber.java @@ -0,0 +1,46 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 26/11/2019 The k-digit number N is an Armstrong number if and + * only if the k-th power of each digit sums to N. + * + *

Given a positive integer N, return true if and only if it is an Armstrong number. + * + *

Example 1: + * + *

Input: 153 Output: true Explanation: 153 is a 3-digit number, and 153 = 1^3 + 5^3 + 3^3. + * Example 2: + * + *

Input: 123 Output: false Explanation: 123 is a 3-digit number, and 123 != 1^3 + 2^3 + 3^3 = + * 36. + * + *

Note: + * + *

1 <= N <= 10^8 + */ +public class ArmstrongNumber { + public static void main(String[] args) { + // + } + + public boolean isArmstrong(int N) { + int s = String.valueOf(N).length(); + long sum = 0; + for (char c : String.valueOf(N).toCharArray()) { + int i = Integer.parseInt(String.valueOf(c)); + sum += power(i, s); + } + return (sum == N); + } + + private long power(int n, int p) { + long res = 1L; + for (int i = 0; i < p; i++) { + res *= n; + } + return res; + } +} diff --git a/src/main/java/binary_search/FindPeakElement.java b/src/main/java/binary_search/FindPeakElement.java new file mode 100644 index 00000000..8c5b9d5e --- /dev/null +++ b/src/main/java/binary_search/FindPeakElement.java @@ -0,0 +1,54 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +/** + * Created by gouthamvidyapradhan on 10/07/2017. A peak element is an element that is greater than + * its neighbors. + * + *

Given an input array where num[i] ≠ num[i+1], find a peak element and return its index. + * + *

The array may contain multiple peaks, in that case return the index to any one of the peaks is + * fine. + * + *

You may imagine that num[-1] = num[n] = -∞. + * + *

For example, in array [1, 2, 3, 1], 3 is a peak element and your function should return the + * index number 2. + * + *

Note: Your solution should be in logarithmic complexity. + * + *

Solution: O(log N) check if the first or the last element is the peak element, if yes then + * return this index. Else binary search for the answer - check mid element if this is a peak + * element return this index, else if the left element is greater than current element search left + * else search right. + */ +public class FindPeakElement { + public static void main(String[] args) throws Exception { + int[] nums = {3, 4, 3, 2, 1}; + System.out.println(new FindPeakElement().findPeakElement(nums)); + } + + public int findPeakElement(int[] nums) { + if (nums.length == 1) return 0; + if (nums[0] > nums[1]) return 0; + else if (nums[nums.length - 1] > nums[nums.length - 2]) return nums.length - 1; + + int l = 0, h = nums.length - 1; + int ans = 0; + while (l <= h) { + int m = l + (h - l) / 2; + if (m - 1 >= 0 && m + 1 < nums.length) { + if (nums[m] > nums[m - 1] && nums[m] > nums[m + 1]) { + return m; + } + } + if (m - 1 >= 0 && nums[m - 1] > nums[m]) { // search left + h = m - 1; + } else { + ans = l; // mark this as the answer and search right + l = m + 1; + } + } + return ans; + } +} diff --git a/src/main/java/binary_search/FirstBadVersion.java b/src/main/java/binary_search/FirstBadVersion.java new file mode 100644 index 00000000..0e1c0a89 --- /dev/null +++ b/src/main/java/binary_search/FirstBadVersion.java @@ -0,0 +1,38 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +/** + * Created by gouthamvidyapradhan on 29/11/2017. + * + *

You are a product manager and currently leading a team to develop a new product. + * Unfortunately, the latest version of your product fails the quality check. Since each version is + * developed based on the previous version, all the versions after a bad version are also bad. + * + *

Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one, which + * causes all the following ones to be bad. + * + *

You are given an API bool isBadVersion(version) which will return whether version is bad. + * Implement a function to find the first bad version. You should minimize the number of calls to + * the API. + */ +public class FirstBadVersion { + public static void main(String[] args) throws Exception { + System.out.println(new FirstBadVersion().firstBadVersion(2126753390)); + } + + public int firstBadVersion(int n) { + int low = 0, high = n; + while (low < high) { + int mid = (low + high) >>> 1; + if (isBadVersion(mid)) { + high = mid; + } else low = mid + 1; + } + return high; + } + + private boolean isBadVersion(int n) { + if (n >= 1702766719) return true; + return false; + } +} diff --git a/src/main/java/binary_search/HIndexII.java b/src/main/java/binary_search/HIndexII.java new file mode 100644 index 00000000..5450d3b3 --- /dev/null +++ b/src/main/java/binary_search/HIndexII.java @@ -0,0 +1,45 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +/** + * Created by gouthamvidyapradhan on 11/12/2017. + * + *

Follow up for H-Index: What if the citations array is sorted in ascending order? Could you + * optimize your algorithm? + * + * @see array.HIndex + */ +public class HIndexII { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 1, 1, 1, 1, 15, 20}; + System.out.println(new HIndexII().hIndex(A)); + } + + public int hIndex(int[] citations) { + if (citations.length == 0) return 0; + int s = 0, e = citations.length; + int ans = -1; + while (s < e) { + int m = (s + e) >>> 1; + int cit = citations.length - m; + if (citations[m] > cit) { + if (ans < cit) { + ans = cit; + } + e = m; + } else { + if (ans < citations[m]) { + ans = citations[m]; + } + s = m + 1; + } + } + return ans; + } +} diff --git a/src/main/java/binary_search/KokoEatingBananas.java b/src/main/java/binary_search/KokoEatingBananas.java new file mode 100644 index 00000000..bd5c3400 --- /dev/null +++ b/src/main/java/binary_search/KokoEatingBananas.java @@ -0,0 +1,76 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +/** + * Created by gouthamvidyapradhan on 23/08/2019 Koko loves to eat bananas. There are N piles of + * bananas, the i-th pile has piles[i] bananas. The guards have gone and will come back in H hours. + * + *

Koko can decide her bananas-per-hour eating speed of K. Each hour, she chooses some pile of + * bananas, and eats K bananas from that pile. If the pile has less than K bananas, she eats all of + * them instead, and won't eat any more bananas during this hour. + * + *

Koko likes to eat slowly, but still wants to finish eating all the bananas before the guards + * come back. + * + *

Return the minimum integer K such that she can eat all the bananas within H hours. + * + *

Example 1: + * + *

Input: piles = [3,6,7,11], H = 8 Output: 4 Example 2: + * + *

Input: piles = [30,11,23,4,20], H = 5 Output: 30 Example 3: + * + *

Input: piles = [30,11,23,4,20], H = 6 Output: 23 + * + *

Note: + * + *

1 <= piles.length <= 10^4 piles.length <= H <= 10^9 1 <= piles[i] <= 10^9 + * + *

Solution: O(N x log Max(piles[i])) Binary search for the minimum possible value between (1 and + * max(piles[i])) + */ +public class KokoEatingBananas { + public static void main(String[] args) { + int[] A = {312884470}; + System.out.println(new KokoEatingBananas().minEatingSpeed(A, 968709470)); + } + + public int minEatingSpeed(int[] piles, int H) { + int max = 0; + for (int i = 0; i < piles.length; i++) { + max = Math.max(max, piles[i]); + } + if (H == piles.length) return max; + int h = max, l = 1; + int answer = H; + while (l <= h) { + int m = l + (h - l) / 2; + boolean status = check(piles, H, m); + if (status) { + answer = m; + h = m - 1; + } else { + l = m + 1; + } + } + return answer; + } + + private boolean check(int[] piles, int H, int k) { + for (int p : piles) { + if (p <= k) { + H--; + } else { + int q = p / k; + if ((p % k) > 0) { + q++; + } + H -= q; + } + if (H < 0) { + return false; + } + } + return true; + } +} diff --git a/src/main/java/binary_search/MedianOfTwoSortedArrays.java b/src/main/java/binary_search/MedianOfTwoSortedArrays.java new file mode 100644 index 00000000..221a1228 --- /dev/null +++ b/src/main/java/binary_search/MedianOfTwoSortedArrays.java @@ -0,0 +1,86 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 23/05/2017. There are two sorted arrays nums1 and nums2 of size + * m and n respectively. + * + *

Find the median of the two sorted arrays. The overall run time complexity should be O(log + * (m+n)). + * + *

Example 1: nums1 = [1, 3] nums2 = [2] + * + *

The median is 2.0 Example 2: nums1 = [1, 2] nums2 = [3, 4] + * + *

The median is (2 + 3)/2 = 2.5 + * + *

Solution: Works in worst case time complexity of O(log min(m, n)) + * + *

The basic idea is that if you are given two arrays A and B and know the length of each, you + * can check whether an element A[i] is the median in constant time. Suppose that the median is + * A[i]. Since the array is sorted, it is greater than exactly i − 1 values in array A. Then if it + * is the median, it is also greater than exactly j = [n / 2] − (i − 1) elements in B. It requires + * constant time to check if B[j] A[i] <= B[j + 1]. If A[i] is not the median, then depending on + * whether A[i] is greater or less than B[j] and B[j + 1], you know that A[i] is either greater than + * or less than the median. Thus you can binary search for A[i] in O(log N) worst-case time + */ +public class MedianOfTwoSortedArrays { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 2, 5, 8, 44, 45, 45}; + int[] B = {1, 2, 3, 4, 5, 6, 7, 23, 23, 23, 33, 44, 45, 45, 56, 77, 5555}; + System.out.println(new MedianOfTwoSortedArrays().findMedianSortedArrays(A, B)); + } + + /** + * Find median + * + * @param nums1 array one + * @param nums2 array two + * @return + */ + public double findMedianSortedArrays(int[] nums1, int[] nums2) { + if (nums1.length > nums2.length) + return findMedianSortedArrays(nums2, nums1); // ensure always nums1 is the shortest array + int T = nums1.length + nums2.length, low = -1, high = -1; + int median = (T - 1) / 2; + boolean isOdd = false; + if ((T % 2) != 0) isOdd = true; + + int s = 0, e = nums1.length - 1; + while (s <= e) { + int m = s + (e - s) / 2; + if ((median - m - 1) < 0 || nums1[m] >= nums2[median - m - 1]) { + e = m - 1; + low = m; + high = median - m; + } else s = m + 1; + } + + if (low == -1) { + if (isOdd) return nums2[median - nums1.length]; + else return (double) (nums2[median - nums1.length] + nums2[median - nums1.length + 1]) / 2.0D; + } else { + if (isOdd) return nums1[low] < nums2[high] ? nums1[low] : nums2[high]; + else { + // Always sorts maximum of 4 elements hence works in O(1) + List list = new ArrayList<>(); + list.add(nums1[low]); + if (low + 1 < nums1.length) list.add(nums1[low + 1]); + list.add(nums2[high]); + if (high + 1 < nums2.length) list.add(nums2[high + 1]); + Collections.sort(list); + return (double) (list.get(0) + list.get(1)) / 2.0; + } + } + } +} diff --git a/src/main/java/binary_search/MinSortedRotatedArray.java b/src/main/java/binary_search/MinSortedRotatedArray.java new file mode 100644 index 00000000..3a3d7f3c --- /dev/null +++ b/src/main/java/binary_search/MinSortedRotatedArray.java @@ -0,0 +1,39 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +/** + * Created by gouthamvidyapradhan on 10/04/2017. Suppose an array sorted in ascending order is + * rotated at some pivot unknown to you beforehand. + * + *

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). + * + *

Find the minimum element. + * + *

You may assume no duplicate exists in the array. + */ +public class MinSortedRotatedArray { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {5, 1, 2, 3, 4}; + System.out.println(new MinSortedRotatedArray().findMin(A)); + } + + public int findMin(int[] nums) { + if (nums.length == 0) return 0; + else if (nums.length == 1) return nums[0]; + int low = 0, high = nums.length - 1; + while (low < high) { + int mid = (low + high) / 2; + if (mid > 0 && nums[mid] < nums[mid - 1]) return nums[mid]; + if (nums[low] > nums[mid]) high = mid - 1; + else if (nums[high] < nums[mid]) low = mid + 1; + else high = mid - 1; + } + return nums[low]; + } +} diff --git a/src/main/java/binary_search/MinimizeTheMaximumAdjacentElementDifference.java b/src/main/java/binary_search/MinimizeTheMaximumAdjacentElementDifference.java new file mode 100644 index 00000000..260cc55d --- /dev/null +++ b/src/main/java/binary_search/MinimizeTheMaximumAdjacentElementDifference.java @@ -0,0 +1,108 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class MinimizeTheMaximumAdjacentElementDifference { + record Interval(int s, int e, boolean hasMoreThanOne){ + static boolean check(int a, int mid, int b, int range){ + return Math.abs(mid - a) <= range && Math.abs(mid - b) <= range; + } + static boolean check(int a, int mid1, int mid2, int b, int range){ + return Math.abs(mid1 - a) <= range && Math.abs(mid1 - mid2) <= range && Math.abs(mid2 - b) <= range; + } + } + + public static void main(String[] args) { + int[] nums = new int[]{-1,10,-1,8}; + int res = new MinimizeTheMaximumAdjacentElementDifference().minDifference(nums); + System.out.println(res); + } + + public int minDifference(int[] nums) { + boolean noPositiveNum = Arrays.stream(nums).filter(i -> i != -1).findAny().isEmpty(); + if(noPositiveNum){ + return 0; + } + int currentMax = getCurrentMax(nums); + List intervals = buildIntervals(nums); + int minStart = Integer.MAX_VALUE, maxEnd = Integer.MIN_VALUE; + for (Interval interval : intervals) { + minStart = Math.min(minStart, Math.min(interval.e, interval.s)); + maxEnd = Math.max(maxEnd, Math.max(interval.e, interval.s)); + } + int l = 0, h = maxEnd, m; + int ans = -1; + while(l <= h){ + m = l + (h - l) / 2; + boolean result = checkIfThisNumberSatisfiesAllIntervals(intervals, minStart + m, maxEnd - m, m); + if(result){ + ans = m; + h = m - 1; + } else { + l = m + 1; + } + } + return Math.max(ans, currentMax); + } + + private int getCurrentMax(int[] nums){ + int currMax = Integer.MIN_VALUE; + int previous = nums[0]; + for(int i = 1; i < nums.length; i ++){ + if(nums[i] != -1){ + if(previous != -1){ + currMax = Math.max(currMax, Math.abs(previous - nums[i])); + } + previous = nums[i]; + } else { + previous = -1; + } + } + return currMax; + } + + private List buildIntervals(int[] nums) { + int previous = -1; + int minusOneCount = 0; + List intervals = new ArrayList<>(); + for (int num : nums) { + if (num == -1) { + minusOneCount ++; + } else { + if (minusOneCount > 0) { + intervals.add(new Interval(previous != -1 ? previous : num, num, minusOneCount > 1)); + minusOneCount = 0; + } + previous = num; + } + } + if(nums[nums.length - 1] == -1){ + intervals.add(new Interval(previous, previous, minusOneCount > 1)); + } + return intervals; + } + + boolean checkIfThisNumberSatisfiesAllIntervals(List intervals, int minStart, int maxEnd, int maxDiff){ + for (Interval interval : intervals) { + if (interval.hasMoreThanOne) { + boolean res1 = Interval.check(interval.s, minStart, minStart, interval.e, maxDiff); + boolean res2 = Interval.check(interval.s, minStart, maxEnd, interval.e, maxDiff); + boolean res3 = Interval.check(interval.s, maxEnd, minStart, interval.e, maxDiff); + boolean res4 = Interval.check(interval.s, maxEnd, maxEnd, interval.e, maxDiff); + if (!res1 && !res2 && !res3 && !res4) { + return false; + } + } else { + boolean res1 = Interval.check(interval.s, minStart, interval.e, maxDiff); + boolean res2 = Interval.check(interval.s, maxEnd, interval.e, maxDiff); + if (!res1 && !res2) { + return false; + } + } + } + return true; + } +} diff --git a/src/main/java/binary_search/MinimumWindowSubsequence.java b/src/main/java/binary_search/MinimumWindowSubsequence.java new file mode 100644 index 00000000..0d92648f --- /dev/null +++ b/src/main/java/binary_search/MinimumWindowSubsequence.java @@ -0,0 +1,84 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 06/08/2019 Given strings S and T, find the minimum (contiguous) + * substring W of S, so that T is a subsequence of W. + * + *

If there is no such window in S that covers all characters in T, return the empty string "". + * If there are multiple such minimum-length windows, return the one with the left-most starting + * index. + * + *

Example 1: + * + *

Input: S = "abcdebdde", T = "bde" Output: "bcde" Explanation: "bcde" is the answer because it + * occurs before "bdde" which has the same length. "deb" is not a smaller window because the + * elements of T in the window must occur in order. + * + *

Note: + * + *

All the strings in the input will only contain lowercase letters. The length of S will be in + * the range [1, 20000]. The length of T will be in the range [1, 100]. + * + *

Solution O(S x T x log S) General idea is to first find the left-most left (l) and right (r) + * index where r - l is minimum and the minimum window contains the sub-sequence and iteratively + * check the next left-most indices and continue for the entire string S. A naive implementation + * would result in O(S ^ 2) therefore to speed up we have to maintain a hashtable of character as + * key and all its index of occurrence in a sorted list. Now, since this list is sorted we can + * easily find the next left-most by binarySearch or even better by using a TreeSet higher or ceil + * function. + */ +public class MinimumWindowSubsequence { + public static void main(String[] args) { + System.out.println(new MinimumWindowSubsequence().minWindow("abcdebdde", "x")); + } + + public String minWindow(String S, String T) { + if (T.isEmpty() || S.isEmpty()) return ""; + Map> charMap = new HashMap<>(); + for (int i = 0, l = S.length(); i < l; i++) { + char c = S.charAt(i); + charMap.putIfAbsent(c, new TreeSet<>()); + charMap.get(c).add(i); + } + int min = Integer.MAX_VALUE; + int start = -1, end; + int ansStart = -1, ansEnd = -1; + boolean finished = false; + while (true) { + int index = start; + end = -1; + for (int i = 0, l = T.length(); i < l; i++) { + char c = T.charAt(i); + if (!charMap.containsKey(c)) { + return ""; + } else { + TreeSet indicies = charMap.get(c); + Integer found = indicies.higher(index); + if (found == null) { + finished = true; + break; + } else { + index = found; + if (i == 0) { + start = index; + } + if (i == l - 1) { + end = index; + } + } + } + } + if (start != -1 && end != -1) { + if ((end - start) < min) { + min = end - start; + ansStart = start; + ansEnd = end; + } + } + if (finished) return ansStart == -1 ? "" : S.substring(ansStart, ansEnd + 1); + } + } +} diff --git a/src/main/java/binary_search/PowXN.java b/src/main/java/binary_search/PowXN.java new file mode 100644 index 00000000..e45def72 --- /dev/null +++ b/src/main/java/binary_search/PowXN.java @@ -0,0 +1,33 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +/** + * Created by gouthamvidyapradhan on 23/05/2017. + * + *

Implement pow(x, n). + * + *

Solution: Works with O(log n) + */ +public class PowXN { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(1 / new PowXN().myPow(2.00000, -2147483648)); + } + + public double myPow(double x, int n) { + if (n == 0) return 1D; + long N = n; // use long to avoid overflow. + return solve(n < 0 ? (1 / x) : x, N < 0 ? (N * -1) : N); + } + + public double solve(double x, long n) { + if (n == 1) return x; + double val = solve(x, n / 2); + return val * val * ((n % 2) == 0 ? 1 : x); + } +} diff --git a/src/main/java/binary_search/SearchForARange.java b/src/main/java/binary_search/SearchForARange.java new file mode 100644 index 00000000..a53816e6 --- /dev/null +++ b/src/main/java/binary_search/SearchForARange.java @@ -0,0 +1,61 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +/** + * Created by gouthamvidyapradhan on 20/05/2017. Given an array of integers sorted in ascending + * order, find the starting and ending position of a given target value. + * + *

Your algorithm's runtime complexity must be in the order of O(log n). + * + *

If the target is not found in the array, return [-1, -1]. + * + *

For example, Given [5, 7, 7, 8, 8, 10] and target value 8, return [3, 4]. + * + *

Solution: Works with worst case time complexity of O(log n). Recursively binary search to find + * the target index. + */ +public class SearchForARange { + public static void main(String[] args) throws Exception { + int[] test = { + 5, 7, 7, 8, 8, 10, 10, 10, 10, 18, 19, 20, 21, 21, 21, 21, 22, 23, 28, 28, 90, 101, 101, 101, + 200, 200, 200, 200, 200, 200 + }; + int[] result = new SearchForARange().searchRange(test, 200); + for (int i : result) System.out.print(i + " "); + } + + public int[] searchRange(int[] nums, int target) { + int low = findIndex(nums, target, true); + int high = findIndex(nums, target, false); + int[] result = new int[2]; + result[0] = low; + result[1] = high; + return result; + } + + /** + * Find index + * + * @param nums nums array + * @param target target + * @param isLowerIndex true if target is to find lower index, false otherwise + * @return index + */ + private int findIndex(int[] nums, int target, boolean isLowerIndex) { + int result = -1; + int s = 0, e = nums.length - 1; + while (s <= e) { + int m = s + (e - s) / 2; + if (nums[m] == target) { + result = m; + if (isLowerIndex) + e = m - 1; // if searching for the lower index then search the lower bound, + // else search the upper bound + else s = m + 1; + } else if (nums[m] < target) { + s = m + 1; + } else e = m - 1; + } + return result; + } +} diff --git a/src/main/java/binary_search/SearchInsertPosition.java b/src/main/java/binary_search/SearchInsertPosition.java new file mode 100644 index 00000000..78312a18 --- /dev/null +++ b/src/main/java/binary_search/SearchInsertPosition.java @@ -0,0 +1,31 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +/** + * Created by gouthamvidyapradhan on 22/05/2017. Given a sorted array and a target value, return the + * index if the target is found. If not, return the index where it would be if it were inserted in + * order. + * + *

You may assume no duplicates in the array. + * + *

Here are few examples. [1,3,5,6], 5 → 2 [1,3,5,6], 2 → 1 [1,3,5,6], 7 → 4 [1,3,5,6], 0 → 0 + */ +public class SearchInsertPosition { + public static void main(String[] args) throws Exception { + int[] A = {1, 3, 5, 6}; + new SearchInsertPosition().searchInsert(A, 5); + } + + public int searchInsert(int[] nums, int target) { + int pos = nums.length; + int s = 0, e = nums.length - 1; + while (s <= e) { + int m = s + (e - s) / 2; + if (nums[m] >= target) { + pos = m; + e = m - 1; + } else s = m + 1; + } + return pos; + } +} diff --git a/src/main/java/binary_search/SearchRotatedSortedArray.java b/src/main/java/binary_search/SearchRotatedSortedArray.java new file mode 100644 index 00000000..e6edcc7c --- /dev/null +++ b/src/main/java/binary_search/SearchRotatedSortedArray.java @@ -0,0 +1,42 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +/** + * Created by gouthamvidyapradhan on 10/04/2017. Suppose an array sorted in ascending order is + * rotated at some pivot unknown to you beforehand. + * + *

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). + * + *

You are given a target value to search. If found in the array return its index, otherwise + * return -1. + * + *

You may assume no duplicate exists in the array. + */ +public class SearchRotatedSortedArray { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {5, 4, 3, 2, 1}; + System.out.println(new SearchRotatedSortedArray().search(A, 4)); + } + + public int search(int[] nums, int target) { + if (nums.length == 0) return -1; + if (nums.length == 1) { + return (nums[0] == target) ? 0 : -1; + } + int low = 0, high = nums.length - 1; + while (low < high) { + int mid = (low + high) >>> 1; + if (nums[mid] == target) return mid; + if ((nums[mid] <= nums[low]) && (target > nums[mid] && target <= nums[high]) + || (nums[low] <= nums[mid] && (target < nums[low] || target > nums[mid]))) low = mid + 1; + else high = mid - 1; + } + return (nums[low] == target) ? low : -1; + } +} diff --git a/src/main/java/binary_search/SingleElementInASortedArray.java b/src/main/java/binary_search/SingleElementInASortedArray.java new file mode 100644 index 00000000..29d5a503 --- /dev/null +++ b/src/main/java/binary_search/SingleElementInASortedArray.java @@ -0,0 +1,57 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +/** + * Created by gouthamvidyapradhan on 30/01/2020 You are given a sorted array consisting of only + * integers where every element appears exactly twice, except for one element which appears exactly + * once. Find this single element that appears only once. + * + *

Example 1: + * + *

Input: [1,1,2,3,3,4,4,8,8] Output: 2 Example 2: + * + *

Input: [3,3,7,7,10,11,11] Output: 10 + * + *

Note: Your solution should run in O(log n) time and O(1) space. + */ +public class SingleElementInASortedArray { + public static void main(String[] args) { + int[] A = {3, 3, 7, 7, 10, 11, 11}; + System.out.println(new SingleElementInASortedArray().singleNonDuplicate(A)); + } + + public int singleNonDuplicate(int[] nums) { + if (nums.length == 1) return nums[0]; + int l = 0, h = nums.length - 1; + while (l <= h) { + int m = l + ((h - l) / 2); + int N = nums[m]; + if (m + 1 >= nums.length) { + if (nums[m - 1] != N) { + return N; + } + h = m - 1; + } else if (m - 1 < 0) { + if (nums[m + 1] != N) { + return N; + } + l = m + 1; + } else { + if (m % 2 == 0) { + if (nums[m + 1] != N && nums[m - 1] != N) { + return N; + } else if (nums[m + 1] != N) { + h = m - 1; + } else l = m + 1; + } else { + if (nums[m + 1] != N && nums[m - 1] != N) { + return N; + } else if (nums[m - 1] != N) { + h = m - 1; + } else l = m + 1; + } + } + } + return -1; + } +} diff --git a/src/main/java/binary_search/SqrtX.java b/src/main/java/binary_search/SqrtX.java new file mode 100644 index 00000000..e3cb34a3 --- /dev/null +++ b/src/main/java/binary_search/SqrtX.java @@ -0,0 +1,27 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +/** + * Created by gouthamvidyapradhan on 22/05/2017. Implement int sqrt(int x). + * + *

Compute and return the square root of x. + */ +public class SqrtX { + public static void main(String[] args) throws Exception { + System.out.println(new SqrtX().mySqrt(Integer.MAX_VALUE)); + } + + public int mySqrt(int x) { + int s = 0, e = x; + long ans = 0L; + while (s <= e) { + long m = s + (e - s) / 2; + long prod = m * m; + if (prod <= x) { + s = (int) (m + 1); + ans = m; + } else e = (int) m - 1; + } + return (int) ans; + } +} diff --git a/src/main/java/binary_search/SwimInRisingWater.java b/src/main/java/binary_search/SwimInRisingWater.java new file mode 100644 index 00000000..5f13d9a1 --- /dev/null +++ b/src/main/java/binary_search/SwimInRisingWater.java @@ -0,0 +1,117 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +/** + * Created by gouthamvidyapradhan on 07/04/2019 On an N x N grid, each square grid[i][j] represents + * the elevation at that point (i,j). + * + *

Now rain starts to fall. At time t, the depth of the water everywhere is t. You can swim from + * a square to another 4-directionally adjacent square if and only if the elevation of both squares + * individually are at most t. You can swim infinite distance in zero time. Of course, you must stay + * within the boundaries of the grid during your swim. + * + *

You start at the top left square (0, 0). What is the least time until you can reach the bottom + * right square (N-1, N-1)? + * + *

Example 1: + * + *

Input: [[0,2],[1,3]] Output: 3 Explanation: At time 0, you are in grid location (0, 0). You + * cannot go anywhere else because 4-directionally adjacent neighbors have a higher elevation than t + * = 0. + * + *

You cannot reach point (1, 1) until time 3. When the depth of water is 3, we can swim anywhere + * inside the grid. Example 2: + * + *

Input: [[0,1,2,3,4],[24,23,22,21,5],[12,13,14,15,16],[11,17,18,19,20],[10,9,8,7,6]] Output: 16 + * Explanation: 0 1 2 3 4 24 23 22 21 5 12 13 14 15 16 11 17 18 19 20 10 9 8 7 6 + * + *

The final route is marked in bold. We need to wait until time 16 so that (0, 0) and (4, 4) are + * connected. Note: + * + *

2 <= N <= 50. grid[i][j] is a permutation of [0, ..., N*N - 1]. + * + *

Solution: O(N ^ 2 x log N ^ 2) Binary search for the possible answers in the range [0 to N * + * N-1] and dfs through the grid to check if the destination is reachable + */ +public class SwimInRisingWater { + + private final int[] R = {0, 0, 1, -1}; + private final int[] C = {1, -1, 0, 0}; + + class Pair { + int r, c; + + Pair(int r, int c) { + this.r = r; + this.c = c; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Pair)) return false; + Pair pair = (Pair) o; + return r == pair.r && c == pair.c; + } + + @Override + public int hashCode() { + return Objects.hash(r, c); + } + } + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[][] grid = { + {0, 1, 2, 3, 4}, + {24, 23, 22, 21, 5}, + {12, 13, 14, 15, 16}, + {11, 17, 18, 19, 20}, + {10, 9, 8, 7, 6} + }; + System.out.println(new SwimInRisingWater().swimInWater(grid)); + } + + public int swimInWater(int[][] grid) { + int l = 0, h = (grid.length * grid.length); + int ans = 0; + while (l <= h) { + int m = l + (h - l) / 2; + Set done = new HashSet<>(); + if (dfs(grid, 0, 0, done, m)) { + ans = m; + h = m - 1; + } else { + l = m + 1; + } + } + return ans; + } + + private boolean dfs(int[][] grid, int r, int c, Set done, int V) { + if (r == grid.length - 1 && c == grid[0].length - 1) return true; + done.add(new Pair(r, c)); + for (int i = 0; i < 4; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR >= 0 && newR < grid.length && newC >= 0 && newC < grid[0].length) { + int childH = Math.max(V, grid[newR][newC]); + int curH = Math.max(V, grid[r][c]); + if (curH == childH) { + Pair child = new Pair(newR, newC); + if (!done.contains(child)) { + if (dfs(grid, newR, newC, done, V)) return true; + } + } + } + } + return false; + } +} diff --git a/src/main/java/binary_search/TimeBasedKeyValuePair.java b/src/main/java/binary_search/TimeBasedKeyValuePair.java new file mode 100644 index 00000000..c94ff317 --- /dev/null +++ b/src/main/java/binary_search/TimeBasedKeyValuePair.java @@ -0,0 +1,85 @@ +/* (C) 2024 YourCompanyName */ +package binary_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 07/05/2019 Create a timebased key-value store class TimeMap, + * that supports two operations. + * + *

1. set(string key, string value, int timestamp) + * + *

Stores the key and value, along with the given timestamp. 2. get(string key, int timestamp) + * + *

Returns a value such that set(key, value, timestamp_prev) was called previously, with + * timestamp_prev <= timestamp. If there are multiple such values, it returns the one with the + * largest timestamp_prev. If there are no values, it returns the empty string (""). + * + *

Example 1: + * + *

Input: inputs = ["TimeMap","set","get","get","set","get","get"], inputs = + * [[],["foo","bar",1],["foo",1],["foo",3],["foo","bar2",4],["foo",4],["foo",5]] Output: + * [null,null,"bar","bar",null,"bar2","bar2"] Explanation: TimeMap kv; kv.set("foo", "bar", 1); // + * store the key "foo" and value "bar" along with timestamp = 1 kv.get("foo", 1); // output "bar" + * kv.get("foo", 3); // output "bar" since there is no value corresponding to foo at timestamp 3 and + * timestamp 2, then the only value is at timestamp 1 ie "bar" kv.set("foo", "bar2", 4); + * kv.get("foo", 4); // output "bar2" kv.get("foo", 5); //output "bar2" + * + *

Example 2: + * + *

Input: inputs = ["TimeMap","set","set","get","get","get","get","get"], inputs = + * [[],["love","high",10],["love","low",20],["love",5],["love",10],["love",15],["love",20],["love",25]] + * Output: [null,null,null,"","high","high","low","low"] + * + *

Note: + * + *

All key/value strings are lowercase. All key/value strings have length in the range [1, 100] + * The timestamps for all TimeMap.set operations are strictly increasing. 1 <= timestamp <= 10^7 + * TimeMap.set and TimeMap.get functions will be called a total of 120000 times (combined) per test + * case. + * + *

Solution O(log N) where N is the number of values for the same key (but different timestamp) + * Idea is to use the HashMap to store the unique key and a TreeMap as value containing all + * different timestamps and value. Use the floor function in treemap to get the value for a given + * timestamp. + */ +public class TimeBasedKeyValuePair { + + private Map> map; + + public TimeBasedKeyValuePair() { + map = new HashMap<>(); + } + + public void set(String key, String value, int timestamp) { + map.putIfAbsent(key, new TreeMap<>()); + TreeMap treeMap = map.get(key); + treeMap.put(timestamp, value); + } + + public String get(String key, int timestamp) { + if (!map.containsKey(key)) { + return ""; + } else { + TreeMap treeMap = map.get(key); + Map.Entry entry = treeMap.floorEntry(timestamp); + if (entry == null) { + return ""; + } else { + return entry.getValue(); + } + } + } + + public static void main(String[] args) { + TimeBasedKeyValuePair task = new TimeBasedKeyValuePair(); + task.set("foo", "bar", 1); + System.out.println(task.get("foo", 1)); + System.out.println(task.get("foo", 3)); + System.out.println(task.get("foo", 0)); + task.set("foo", "bar2", 4); + System.out.println(task.get("foo", 3)); + System.out.println(task.get("foo", 4)); + System.out.println(task.get("foo", 5)); + } +} diff --git a/src/main/java/bit_manipulation/BinaryNumberWithAlternatingBits.java b/src/main/java/bit_manipulation/BinaryNumberWithAlternatingBits.java new file mode 100644 index 00000000..bced945e --- /dev/null +++ b/src/main/java/bit_manipulation/BinaryNumberWithAlternatingBits.java @@ -0,0 +1,33 @@ +/* (C) 2024 YourCompanyName */ +package bit_manipulation; +/** + * Created by gouthamvidyapradhan on 28/05/2019\ Given a positive integer, check whether it has + * alternating bits: namely, if two adjacent bits will always have different values. + * + *

Example 1: Input: 5 Output: True Explanation: The binary representation of 5 is: 101 Example + * 2: Input: 7 Output: False Explanation: The binary representation of 7 is: 111. Example 3: Input: + * 11 Output: False Explanation: The binary representation of 11 is: 1011. Example 4: Input: 10 + * Output: True Explanation: The binary representation of 10 is: 1010. + */ +public class BinaryNumberWithAlternatingBits { + public static void main(String[] args) { + System.out.println(new BinaryNumberWithAlternatingBits().hasAlternatingBits(18)); + } + + public boolean hasAlternatingBits(int n) { + int curr = n & 1; + int pos = 0; + for (int i = 0; i < 32; i++) { + if ((n & (1 << i)) > 0) { + pos = i; + } + } + + for (int i = 1; i <= pos; i++) { + int temp = (1 << i) & n; + if ((temp > 0 && curr > 0) || (temp == 0 && curr == 0)) return false; + curr = temp; + } + return true; + } +} diff --git a/src/main/java/bit_manipulation/BinaryWatch.java b/src/main/java/bit_manipulation/BinaryWatch.java new file mode 100644 index 00000000..34fa3f48 --- /dev/null +++ b/src/main/java/bit_manipulation/BinaryWatch.java @@ -0,0 +1,56 @@ +/* (C) 2024 YourCompanyName */ +package bit_manipulation; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 05/11/2019 A binary watch has 4 LEDs on the top which represent + * the hours (0-11), and the 6 LEDs on the bottom represent the minutes (0-59). + * + *

Each LED represents a zero or one, with the least significant bit on the right. + * + *

For example, the above binary watch reads "3:25". + * + *

Given a non-negative integer n which represents the number of LEDs that are currently on, + * return all possible times the watch could represent. + * + *

Example: + * + *

Input: n = 1 Return: ["1:00", "2:00", "4:00", "8:00", "0:01", "0:02", "0:04", "0:08", "0:16", + * "0:32"] Note: The order of output does not matter. The hour must not contain a leading zero, for + * example "01:00" is not valid, it should be "1:00". The minute must be consist of two digits and + * may contain a leading zero, for example "10:2" is not valid, it should be "10:02". + */ +public class BinaryWatch { + public static void main(String[] args) { + System.out.println(new BinaryWatch().readBinaryWatch(1)); + } + + public List readBinaryWatch(int num) { + int H = 11, M = 59; + List result = new ArrayList<>(); + if (num == 0) { + result.add("0:00"); + return result; + } + for (int i = 0; i <= H; i++) { + for (int j = 0; j <= M; j++) { + int count = 0; + for (int k = 0; k < 4; k++) { + if (((1 << k) & i) > 0) { + count++; + } + } + for (int k = 0; k < 6; k++) { + if (((1 << k) & j) > 0) { + count++; + } + } + if (count == num) { + result.add(i + ":" + ((String.valueOf(j).length() == 1) ? ("0" + j) : j)); + } + } + } + return result; + } +} diff --git a/src/main/java/bit_manipulation/DivideTwoIntegers.java b/src/main/java/bit_manipulation/DivideTwoIntegers.java new file mode 100644 index 00000000..0929dfc6 --- /dev/null +++ b/src/main/java/bit_manipulation/DivideTwoIntegers.java @@ -0,0 +1,48 @@ +/* (C) 2024 YourCompanyName */ +package bit_manipulation; + +/** + * Created by gouthamvidyapradhan on 13/02/2018. Divide two integers without using multiplication, + * division and mod operator. + * + *

If it is overflow, return MAX_INT. + */ +public class DivideTwoIntegers { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new DivideTwoIntegers().divide(0, 775)); + } + + public int divide(int dividend, int divisor) { + if (divisor == 0) return Integer.MAX_VALUE; + else if (dividend == Integer.MIN_VALUE && divisor == -1) return Integer.MAX_VALUE; + else if (divisor == 1) return dividend; + boolean isNegative = ((dividend < 0 && divisor > 0) || (dividend > 0 && divisor < 0)); + dividend = (dividend < 0) ? -dividend : dividend; + divisor = (divisor < 0) ? -divisor : divisor; + int sum, result = 0; + while (true) { + int d1 = divisor; + sum = 0; + if (dividend - d1 == 0) { + sum += 1; + result += sum; + break; + } + if (dividend - d1 < 0) break; + while (dividend - (d1 << 1) > 0) { + d1 <<= 1; + sum += 1; + } + result += (1 << sum); + dividend = dividend - d1; + } + return isNegative ? -result : result; + } +} diff --git a/src/main/java/bit_manipulation/GrayCode.java b/src/main/java/bit_manipulation/GrayCode.java new file mode 100644 index 00000000..d08695fa --- /dev/null +++ b/src/main/java/bit_manipulation/GrayCode.java @@ -0,0 +1,40 @@ +/* (C) 2024 YourCompanyName */ +package bit_manipulation; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 16/03/2017. The gray code is a binary numeral system where two + * successive values differ in only one bit. + * + *

Given a non-negative integer n representing the total number of bits in the code, print the + * sequence of gray code. A gray code sequence must begin with 0. + * + *

For example, given n = 2, return [0,1,3,2]. Its gray code sequence is: + * + *

00 - 0 01 - 1 11 - 3 10 - 2 Note: For a given n, a gray code sequence is not uniquely defined. + * + *

For example, [0,2,3,1] is also a valid gray code sequence according to the above definition. + * + *

For now, the judge is able to judge based on one instance of gray code sequence. Sorry about + * that. + */ +public class GrayCode { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + List result = new GrayCode().grayCode(3); + } + + public List grayCode(int n) { + List result = new ArrayList<>(); + for (int i = 0; i <= ((1 << n) - 1); i++) result.add(i ^ (i >> 1)); + return result; + } +} diff --git a/src/main/java/bit_manipulation/HammingDistance.java b/src/main/java/bit_manipulation/HammingDistance.java new file mode 100644 index 00000000..d800eda0 --- /dev/null +++ b/src/main/java/bit_manipulation/HammingDistance.java @@ -0,0 +1,44 @@ +/* (C) 2024 YourCompanyName */ +package bit_manipulation; + +/** + * Created by gouthamvidyapradhan on 16/12/2017. The Hamming distance between two integers is the + * number of positions at which the corresponding bits are different. + * + *

Given two integers x and y, calculate the Hamming distance. + * + *

Note: 0 ≤ x, y < 231. + * + *

Example: + * + *

Input: x = 1, y = 4 + * + *

Output: 2 + * + *

Explanation: 1 (0 0 0 1) 4 (0 1 0 0) ↑ ↑ + * + *

The above arrows point to positions where the corresponding bits are different. + * + *

Solution O(1): XOR (x, y) and count the number of bits set + */ +public class HammingDistance { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception {} + + public int hammingDistance(int x, int y) { + int z = (x ^ y); + int count = 0; + for (int i = 0; i < 31; i++) { + if ((z & (1 << i)) > 0) { + count++; + } + } + return count; + } +} diff --git a/src/main/java/bit_manipulation/TotalHammingDistance.java b/src/main/java/bit_manipulation/TotalHammingDistance.java new file mode 100644 index 00000000..b685dced --- /dev/null +++ b/src/main/java/bit_manipulation/TotalHammingDistance.java @@ -0,0 +1,48 @@ +/* (C) 2024 YourCompanyName */ +package bit_manipulation; + +/** + * Created by gouthamvidyapradhan on 01/12/2017. The Hamming distance between two integers is the + * number of positions at which the corresponding bits are different. + * + *

Now your job is to find the total Hamming distance between all pairs of the given numbers. + * + *

Example: Input: 4, 14, 2 + * + *

Output: 6 + * + *

Explanation: In binary representation, the 4 is 0100, 14 is 1110, and 2 is 0010 (just showing + * the four bits relevant in this case). So the answer will be: HammingDistance(4, 14) + + * HammingDistance(4, 2) + HammingDistance(14, 2) = 2 + 2 + 2 = 6. Note: Elements of the given array + * are in the range of 0 to 10^9 Length of the array will not exceed 10^4. + * + *

Solution: O(N * 32): Count the number of set bits in each of 32 bit positions and then take + * the sum of product of number of set bits x number of un-set bits + */ +public class TotalHammingDistance { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1000000000, 4, 14, 2}; + System.out.println(new TotalHammingDistance().totalHammingDistance(A)); + } + + public int totalHammingDistance(int[] nums) { + int sum = 0; + for (int i = 0; i < 32; i++) { + int numOfOnes = 0; + int p = (1 << i); + for (int num : nums) { + if ((num & p) > 0) { + numOfOnes++; + } + } + sum += ((nums.length - numOfOnes) * numOfOnes); + } + return sum; + } +} diff --git a/src/main/java/breadth_first_search/BinarayTreeLevelOrderTraversal.java b/src/main/java/breadth_first_search/BinarayTreeLevelOrderTraversal.java new file mode 100644 index 00000000..8e8bd36a --- /dev/null +++ b/src/main/java/breadth_first_search/BinarayTreeLevelOrderTraversal.java @@ -0,0 +1,84 @@ +/* (C) 2024 YourCompanyName */ +package breadth_first_search; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.List; +import java.util.Queue; + +/** + * Created by gouthamvidyapradhan on 13/03/2017. Given a binary tree, return the level order + * traversal of its nodes' values. (ie, from left to right, level by level). + * + *

For example: Given binary tree [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 return its level + * order traversal as: [ [3], [9,20], [15,7] ] + */ +public class BinarayTreeLevelOrderTraversal { + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + private class LevelNode { + TreeNode node; + int level; + + LevelNode(TreeNode node, int level) { + this.node = node; + this.level = level; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(2); + root.left = new TreeNode(3); + root.right = new TreeNode(4); + root.right.right = new TreeNode(5); + root.right.left = new TreeNode(4); + root.right.left.right = new TreeNode(8); + root.right.left.left = new TreeNode(7); + root.right.left.left.right = new TreeNode(10); + root.right.left.left.left = new TreeNode(9); + + List> result = new BinarayTreeLevelOrderTraversal().levelOrder(root); + } + + public List> levelOrder(TreeNode root) { + List> result = new ArrayList<>(); + if (root == null) return result; + Queue queue = new ArrayDeque<>(); + queue.offer(new LevelNode(root, 0)); + int currentLevel = 0; + List row = new ArrayList<>(); + while (!queue.isEmpty()) { + LevelNode levelNode = queue.poll(); + if (levelNode.node != null) { + if (levelNode.level != currentLevel) { + result.add(row); + row = new ArrayList<>(); + currentLevel++; + } + row.add(levelNode.node.val); + TreeNode left = levelNode.node.left; + TreeNode right = levelNode.node.right; + LevelNode lNodeL = new LevelNode(left, levelNode.level + 1); + LevelNode lNodeR = new LevelNode(right, levelNode.level + 1); + queue.offer(lNodeL); + queue.offer(lNodeR); + } + } + result.add(row); + return result; + } +} diff --git a/src/main/java/breadth_first_search/BusRoutes.java b/src/main/java/breadth_first_search/BusRoutes.java new file mode 100644 index 00000000..dbb3e892 --- /dev/null +++ b/src/main/java/breadth_first_search/BusRoutes.java @@ -0,0 +1,111 @@ +/* (C) 2024 YourCompanyName */ +package breadth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 25/08/2018 We have a list of bus routes. Each routes[i] is a + * bus route that the i-th bus repeats forever. For example if routes[0] = [1, 5, 7], this means + * that the first bus (0-th indexed) travels in the sequence 1->5->7->1->5->7->1->. .. forever. + * + *

We start at bus stop S (initially not on a bus), and we want to go to bus stop T. Travelling + * by buses only, what is the least number of buses we must take to reach our destination? Return -1 + * if it is not possible. + * + *

Example: Input: routes = [[1, 2, 7], [3, 6, 7]] S = 1 T = 6 Output: 2 Explanation: The best + * strategy is take the first bus to the bus stop 7, then take the second bus to the bus stop 6. + * Note: + * + *

1 <= routes.length <= 500. 1 <= routes[i].length <= 500. 0 <= routes[i][j] < 10 ^ 6. + * + *

Solution: Model a graph based on interconnection of routes and then run a BFS to find the + * shortest distance. + */ +public class BusRoutes { + + private class Node { + int v, dist; + + Node(int v, int dist) { + this.v = v; + this.dist = dist; + } + } + + private Map> routeGraph = new HashMap<>(); + private Map> stationRouteMap = new HashMap<>(); + private BitSet done = new BitSet(); + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[][] R = { + {1, 2, 3, 9}, {9, 3, 4, 5, 8}, {5, 6, 7, 8}, {9, 8, 10, 11}, {12, 13, 14, 6, 1, 2, 3, 5, 7} + }; + System.out.println(new BusRoutes().numBusesToDestination(R, 1, 14)); + } + + public int numBusesToDestination(int[][] routes, int S, int T) { + if (S == T) return 0; + for (int i = 0; i < routes.length; i++) { + Arrays.sort(routes[i]); + int[] n = routes[i]; + for (int j : n) { + if (j == S || j == T) { + stationRouteMap.putIfAbsent(j, new ArrayList<>()); + stationRouteMap.get(j).add(i); + } + } + } + for (int i = 0; i < routes.length; i++) { + int[] A = routes[i]; + for (int j = i + 1; j < routes.length; j++) { + int[] B = routes[j]; + if (intersect(A, B)) { + routeGraph.putIfAbsent(i, new HashSet<>()); + routeGraph.putIfAbsent(j, new HashSet<>()); + routeGraph.get(i).add(j); + routeGraph.get(j).add(i); + } + } + } + List start = stationRouteMap.get(S); + if (!stationRouteMap.containsKey(T)) return -1; + Set destination = new HashSet<>(stationRouteMap.get(T)); + Queue queue = new ArrayDeque<>(); + for (int r : start) { + if (destination.contains(r)) return 1; + done.set(r); + queue.offer(new Node(r, 0)); + } + while (!queue.isEmpty()) { + Node curr = queue.poll(); + Set children = routeGraph.get(curr.v); + if (children != null) { + for (int c : children) { + if (!done.get(c)) { + done.set(c); + Node child = new Node(c, curr.dist + 1); + if (destination.contains(child.v)) { + return child.dist + 1; + } else { + queue.offer(child); + } + } + } + } + } + return -1; + } + + private boolean intersect(int[] A, int[] B) { + for (int i = 0, j = 0; i < A.length && j < B.length; ) { + if (A[i] == B[j]) return true; + else if (A[i] < B[j]) i++; + else j++; + } + return false; + } +} diff --git a/src/main/java/breadth_first_search/CutOffTreesForGolfEvent.java b/src/main/java/breadth_first_search/CutOffTreesForGolfEvent.java new file mode 100644 index 00000000..1bc7df05 --- /dev/null +++ b/src/main/java/breadth_first_search/CutOffTreesForGolfEvent.java @@ -0,0 +1,114 @@ +/* (C) 2024 YourCompanyName */ +package breadth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 23/06/2018. + * + *

You are asked to cut off trees in a forest for a golf event. The forest is represented as a + * non-negative 2D map, in this map: + * + *

0 represents the obstacle can't be reached. 1 represents the ground can be walked through. The + * place with number bigger than 1 represents a tree can be walked through, and this positive number + * represents the tree's height. You are asked to cut off all the trees in this forest in the order + * of tree's height - always cut off the tree with lowest height first. And after cutting, the + * original place has the tree will become a grass (value 1). + * + *

You will start from the point (0, 0) and you should output the minimum steps you need to walk + * to cut off all the trees. If you can't cut off all the trees, output -1 in that situation. + * + *

You are guaranteed that no two trees have the same height and there is at least one tree needs + * to be cut off. + * + *

Example 1: Input: [ [1,2,3], [0,0,4], [7,6,5] ] Output: 6 Example 2: Input: [ [1,2,3], + * [0,0,0], [7,6,5] ] Output: -1 Example 3: Input: [ [2,3,4], [0,0,5], [8,7,6] ] Output: 6 + * Explanation: You started from the point (0,0) and you can cut off the tree in (0,0) directly + * without walking. Hint: size of the given matrix will not exceed 50x50. + * + *

Solution: O(N x M) ^ 2: Bfs to each height starting from 1 and calculate the total sum of + * distance. + */ +public class CutOffTreesForGolfEvent { + + public static void main(String[] args) throws Exception {} + + private static final int[] R = {0, 0, 1, -1}; + private static final int[] C = {1, -1, 0, 0}; + + static class Cell implements Comparable { + int r, c; + int distance; + int height; + + Cell(int r, int c) { + this.r = r; + this.c = c; + } + + @Override + public int compareTo(Cell o) { + return Integer.compare(this.height, o.height); + } + } + + public int cutOffTree(List> forest) { + int distance = 0; + List trees = new ArrayList<>(); + for (int i = 0; i < forest.size(); i++) { + for (int j = 0; j < forest.get(0).size(); j++) { + if (forest.get(i).get(j) > 1) { + Cell cell = new Cell(i, j); + cell.height = forest.get(i).get(j); + trees.add(cell); + } + } + } + Collections.sort(trees); + int sR = 0, sC = 0; + for (Cell t : trees) { + int dist = bfs(forest, t.height, sR, sC); + if (dist == -1) return -1; + else distance += dist; + sR = t.r; + sC = t.c; + } + return distance; + } + + private int bfs(List> forest, int target, int sR, int sC) { + if (forest.get(sR).get(sC) == target) { + forest.get(sR).set(sC, 1); + return 0; + } + Cell start = new Cell(sR, sC); + start.distance = 0; + Queue queue = new ArrayDeque<>(); + queue.add(start); + boolean[][] done = new boolean[forest.size()][forest.get(0).size()]; + done[sR][sC] = true; + while (!queue.isEmpty()) { + Cell cell = queue.poll(); + for (int i = 0; i < 4; i++) { + int newR = cell.r + R[i]; + int newC = cell.c + C[i]; + Cell newCell = new Cell(newR, newC); + if (newR >= 0 + && newR < forest.size() + && newC >= 0 + && newC < forest.get(0).size() + && forest.get(newR).get(newC) != 0 + && !done[newCell.r][newCell.c]) { + newCell.distance = cell.distance + 1; + if (forest.get(newR).get(newC) == target) { + forest.get(newR).set(newC, 1); + return newCell.distance; + } + done[newCell.r][newCell.c] = true; + queue.offer(newCell); + } + } + } + return -1; + } +} diff --git a/src/main/java/breadth_first_search/Matrix.java b/src/main/java/breadth_first_search/Matrix.java new file mode 100644 index 00000000..c2c63988 --- /dev/null +++ b/src/main/java/breadth_first_search/Matrix.java @@ -0,0 +1,91 @@ +/* (C) 2024 YourCompanyName */ +package breadth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 14/03/2019 Given a matrix consists of 0 and 1, find the + * distance of the nearest 0 for each cell. + * + *

The distance between two adjacent cells is 1. Example 1: Input: + * + *

0 0 0 0 1 0 0 0 0 Output: 0 0 0 0 1 0 0 0 0 Example 2: Input: + * + *

0 0 0 0 1 0 1 1 1 Output: 0 0 0 0 1 0 1 2 1 Note: The number of elements of the given matrix + * will not exceed 10,000. There are at least one 0 in the given matrix. The cells are adjacent in + * only four directions: up, down, left and right. + * + *

Solution: Add all the 0th cell to the queue and do a multi-source bfs to count the minimum + * distance + */ +public class Matrix { + private static class Node { + int r, c; + int d; + + Node(int r, int c) { + this.r = r; + this.c = c; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Node)) return false; + Node node = (Node) o; + return r == node.r && c == node.c; + } + + @Override + public int hashCode() { + return Objects.hash(r, c); + } + } + + private final int[] R = {0, 0, 1, -1}; + private final int[] C = {1, -1, 0, 0}; + private Set done; + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[][] temp = {{0, 0, 0}, {0, 1, 0}, {1, 1, 1}}; + int[][] result = new Matrix().updateMatrix(temp); + System.out.println(); + } + + public int[][] updateMatrix(int[][] matrix) { + int[][] temp = new int[matrix.length][matrix[0].length]; + done = new HashSet<>(); + Queue queue = new ArrayDeque<>(); + for (int i = 0; i < matrix.length; i++) { + for (int j = 0; j < matrix[0].length; j++) { + temp[i][j] = matrix[i][j]; + if (matrix[i][j] == 0) { + Node node = new Node(i, j); + queue.offer(node); + done.add(node); + } + } + } + while (!queue.isEmpty()) { + Node curr = queue.poll(); + for (int i = 0; i < 4; i++) { + int newR = curr.r + R[i]; + int newC = curr.c + C[i]; + if (newR >= 0 && newR < matrix.length && newC >= 0 && newC < matrix[0].length) { + Node child = new Node(newR, newC); + if (!done.contains(child)) { + done.add(child); + child.d = curr.d + 1; + temp[newR][newC] = child.d; + queue.offer(child); + } + } + } + } + return temp; + } +} diff --git a/src/main/java/breadth_first_search/OpenTheLock.java b/src/main/java/breadth_first_search/OpenTheLock.java new file mode 100644 index 00000000..3ad720a9 --- /dev/null +++ b/src/main/java/breadth_first_search/OpenTheLock.java @@ -0,0 +1,89 @@ +/* (C) 2024 YourCompanyName */ +package breadth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 09/02/2018. You have a lock in front of you with 4 circular + * wheels. Each wheel has 10 slots: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'. The wheels can + * rotate freely and wrap around: for example we can turn '9' to be '0', or '0' to be '9'. Each move + * consists of turning one wheel one slot. + * + *

The lock initially starts at '0000', a string representing the state of the 4 wheels. + * + *

You are given a list of deadends dead ends, meaning if the lock displays any of these codes, + * the wheels of the lock will stop turning and you will be unable to open it. + * + *

Given a target representing the value of the wheels that will unlock the lock, return the + * minimum total number of turns required to open the lock, or -1 if it is impossible. + * + *

Example 1: Input: deadends = ["0201","0101","0102","1212","2002"], target = "0202" Output: 6 + * Explanation: A sequence of valid moves would be "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> + * "1202" -> "0202". Note that a sequence like "0000" -> "0001" -> "0002" -> "0102" -> "0202" would + * be invalid, because the wheels of the lock become stuck after the display becomes the dead end + * "0102". Example 2: Input: deadends = ["8888"], target = "0009" Output: 1 Explanation: We can turn + * the last wheel in reverse to move from "0000" -> "0009". Example 3: Input: deadends = + * ["8887","8889","8878","8898","8788","8988","7888","9888"], target = "8888" Output: -1 + * Explanation: We can't reach the target without getting stuck. Example 4: Input: deadends = + * ["0000"], target = "8888" Output: -1 Note: The length of deadends will be in the range [1, 500]. + * target will not be in the list deadends. Every string in deadends and the string target will be a + * string of4 digits from the 10,000 possibilities '0000' to '9999'. + * + *

Solution: Perform a bfs of each state starting from 0000 and return the minimum distance. + */ +public class OpenTheLock { + + class State { + String state; + int dist; + + State(String state, int dist) { + this.state = state; + this.dist = dist; + } + } + + private Set done; + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + String[] A = {"0201", "0101", "0102", "1212", "2002"}; + System.out.println(new OpenTheLock().openLock(A, "0202")); + } + + public int openLock(String[] deadends, String target) { + done = new HashSet<>(); + Arrays.stream(deadends).forEach(e -> done.add(e)); + if (done.contains("0000")) return -1; + if (target.equals("0000")) return 0; + Queue queue = new ArrayDeque<>(); + queue.offer(new State("0000", 0)); + done.add("0000"); + while (!queue.isEmpty()) { + State state = queue.poll(); + if (state.state.equals(target)) return state.dist; + String currState = state.state; + for (int i = 0; i < 4; i++) { + char c = currState.charAt(i); + int cV = Integer.parseInt(String.valueOf(c)); + String prefix = currState.substring(0, i); + String postFix = currState.substring(i + 1, 4); + String newChild1 = prefix + (((cV + 1) > 9) ? 0 : (cV + 1)) + postFix; + if (!done.contains(newChild1)) { + queue.offer(new State(newChild1, state.dist + 1)); + done.add(newChild1); + } + String newChild2 = prefix + (((cV - 1) < 0) ? 9 : (cV - 1)) + postFix; + if (!done.contains(newChild2)) { + queue.offer(new State(newChild2, state.dist + 1)); + done.add(newChild2); + } + } + } + return -1; + } +} diff --git a/src/main/java/breadth_first_search/RaceCar.java b/src/main/java/breadth_first_search/RaceCar.java new file mode 100644 index 00000000..6cda24fc --- /dev/null +++ b/src/main/java/breadth_first_search/RaceCar.java @@ -0,0 +1,99 @@ +/* (C) 2024 YourCompanyName */ +package breadth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 19/08/2018 Your car starts at position 0 and speed +1 on an + * infinite number line. (Your car can go into negative positions.) + * + *

Your car drives automatically according to a sequence of instructions A (accelerate) and R + * (reverse). + * + *

When you get an instruction "A", your car does the following: position += speed, speed *= 2. + * + *

When you get an instruction "R", your car does the following: if your speed is positive then + * speed = -1 , otherwise speed = 1. (Your position stays the same.) + * + *

For example, after commands "AAR", your car goes to positions 0->1->3->3, and your speed goes + * to 1->2->4->-1. + * + *

Now for some target position, say the length of the shortest sequence of instructions to get + * there. + * + *

Example 1: Input: target = 3 Output: 2 Explanation: The shortest instruction sequence is "AA". + * Your position goes from 0->1->3. Example 2: Input: target = 6 Output: 5 Explanation: The shortest + * instruction sequence is "AAARA". Your position goes from 0->1->3->7->7->6. + * + *

Note: + * + *

1 <= target <= 10000. + * + *

Solution: O(n log n) Do a BFS and visit every possible state. Prune the search space by + * avoiding negative vertices and keep a boundary target of approximately (target * 2) - beyond this + * boundary target the race car should not progress in the forward direction. + */ +public class RaceCar { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + System.out.println(new RaceCar().racecar(1000)); + } + + private class Node { + int v, s, d; + + Node(int v, int s, int d) { + this.v = v; + this.s = s; + this.d = d; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Node)) return false; + Node node = (Node) o; + return v == node.v && s == node.s; + } + + @Override + public int hashCode() { + return Objects.hash(v, s); + } + } + + public int racecar(int target) { + if (target == 0) return 0; + Queue queue = new ArrayDeque<>(); + Set done = new HashSet<>(); + Node start = new Node(0, 1, 0); + done.add(start); + queue.offer(start); + while (!queue.isEmpty()) { + Node curr = queue.poll(); + if (curr.v < (target * 2)) { + Node c1 = new Node(curr.v + curr.s, curr.s * 2, curr.d + 1); + if (c1.v >= 0) { + if (!done.contains(c1)) { + queue.offer(c1); + done.add(c1); + if (target == c1.v) { + return c1.d; + } + } + } + } + Node c2 = new Node(curr.v, curr.s < 0 ? 1 : -1, curr.d + 1); + if (!done.contains(c2)) { + done.add(c2); + queue.offer(c2); + } + } + return -1; + } +} diff --git a/src/main/java/breadth_first_search/RottingOranges.java b/src/main/java/breadth_first_search/RottingOranges.java new file mode 100644 index 00000000..0d84292a --- /dev/null +++ b/src/main/java/breadth_first_search/RottingOranges.java @@ -0,0 +1,85 @@ +/* (C) 2024 YourCompanyName */ +package breadth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 04/12/2019 In a given grid, each cell can have one of three + * values: + * + *

the value 0 representing an empty cell; the value 1 representing a fresh orange; the value 2 + * representing a rotten orange. Every minute, any fresh orange that is adjacent (4-directionally) + * to a rotten orange becomes rotten. + * + *

Return the minimum number of minutes that must elapse until no cell has a fresh orange. If + * this is impossible, return -1 instead. + * + *

Example 1: + * + *

Input: [[2,1,1],[1,1,0],[0,1,1]] Output: 4 Example 2: + * + *

Input: [[2,1,1],[0,1,1],[1,0,1]] Output: -1 Explanation: The orange in the bottom left corner + * (row 2, column 0) is never rotten, because rotting only happens 4-directionally. Example 3: + * + *

Input: [[0,2]] Output: 0 Explanation: Since there are already no fresh oranges at minute 0, + * the answer is just 0. + * + *

Note: + * + *

1 <= grid.length <= 10 1 <= grid[0].length <= 10 grid[i][j] is only 0, 1, or 2. + */ +public class RottingOranges { + final int[] R = {1, -1, 0, 0}; + final int[] C = {0, 0, 1, -1}; + + public static void main(String[] args) { + int[][] A = {{2, 1, 1}, {1, 1, 0}, {0, 1, 1}}; + System.out.println(new RottingOranges().orangesRotting(A)); + } + + private class Node { + int r, c, v; + + Node(int r, int c, int v) { + this.r = r; + this.c = c; + this.v = v; + } + } + + public int orangesRotting(int[][] grid) { + Queue queue = new ArrayDeque<>(); + boolean[][] done = new boolean[grid.length][grid[0].length]; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 2) { + queue.offer(new Node(i, j, 0)); + done[i][j] = true; + } + } + } + int max = 0; + while (!queue.isEmpty()) { + Node curr = queue.poll(); + for (int i = 0; i < 4; i++) { + int newR = curr.r + R[i]; + int newC = curr.c + C[i]; + if (newR >= 0 && newR < grid.length && newC >= 0 && newC < grid[0].length) { + if (!done[newR][newC] && grid[newR][newC] != 0) { + done[newR][newC] = true; + max = Math.max(max, curr.v + 1); + queue.offer(new Node(newR, newC, curr.v + 1)); + } + } + } + } + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 1 && !done[i][j]) { + return -1; + } + } + } + return max; + } +} diff --git a/src/main/java/breadth_first_search/SlidingPuzzle.java b/src/main/java/breadth_first_search/SlidingPuzzle.java new file mode 100644 index 00000000..73a96103 --- /dev/null +++ b/src/main/java/breadth_first_search/SlidingPuzzle.java @@ -0,0 +1,141 @@ +/* (C) 2024 YourCompanyName */ +package breadth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 17/03/2019 On a 2x3 board, there are 5 tiles represented by the + * integers 1 through 5, and an empty square represented by 0. + * + *

A move consists of choosing 0 and a 4-directionally adjacent number and swapping it. + * + *

The state of the board is solved if and only if the board is [[1,2,3],[4,5,0]]. + * + *

Given a puzzle board, return the least number of moves required so that the state of the board + * is solved. If it is impossible for the state of the board to be solved, return -1. + * + *

Examples: + * + *

Input: board = [[1,2,3],[4,0,5]] Output: 1 Explanation: Swap the 0 and the 5 in one move. + * Input: board = [[1,2,3],[5,4,0]] Output: -1 Explanation: No number of moves will make the board + * solved. Input: board = [[4,1,2],[5,0,3]] Output: 5 Explanation: 5 is the smallest number of moves + * that solves the board. An example path: After move 0: [[4,1,2],[5,0,3]] After move 1: + * [[4,1,2],[0,5,3]] After move 2: [[0,1,2],[4,5,3]] After move 3: [[1,0,2],[4,5,3]] After move 4: + * [[1,2,0],[4,5,3]] After move 5: [[1,2,3],[4,5,0]] Input: board = [[3,2,4],[1,5,0]] Output: 14 + * Note: + * + *

board will be a 2 x 3 array as described above. board[i][j] will be a permutation of [0, 1, 2, + * 3, 4, 5]. + * + *

Solution: Do a bfs of each state of the board to find the least possible moves. + */ +public class SlidingPuzzle { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[][] board = {{1, 2, 3}, {4, 0, 5}}; + System.out.println(new SlidingPuzzle().slidingPuzzle(board)); + } + + class Node { + Node(Board b) { + this.b = b; + } + + Board b; + int dist; + } + + private static final int[] R = {-1, 0, 0, 1}; + private static final int[] C = {0, 1, -1, 0}; + private static final String result = "123450"; + + class Board { + int[][] board; + int r, c; + final String state; + + Board(int[][] board) { + this.board = board; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 3; j++) { + sb.append(board[i][j]); + } + } + state = sb.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Board)) return false; + Board board = (Board) o; + return Objects.equals(state, board.state); + } + + @Override + public int hashCode() { + return Objects.hash(state); + } + } + + private Set done; + + public int slidingPuzzle(int[][] board) { + done = new HashSet<>(); + Board b = new Board(board); + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + if (board[i][j] == 0) { + b.r = i; + b.c = j; + break; + } + } + } + if (b.state.equals(result)) return 0; + Queue queue = new ArrayDeque<>(); + queue.offer(new Node(b)); + while (!queue.isEmpty()) { + Node child = queue.poll(); + Board br = child.b; + done.add(br); + for (int i = 0; i < 4; i++) { + int newR = br.r + R[i]; + int newC = br.c + C[i]; + if (newR < 0 || newR >= 2 || newC < 0 || newC >= 3) continue; + int num = br.board[newR][newC]; + int[][] tempB = clone(br.board); + tempB[newR][newC] = 0; + tempB[br.r][br.c] = num; + Board tempBoard = new Board(tempB); + tempBoard.r = newR; + tempBoard.c = newC; + if (!done.contains(tempBoard)) { + if (tempBoard.state.equals(result)) { + return child.dist + 1; + } + Node newChild = new Node(tempBoard); + newChild.dist = child.dist + 1; + queue.offer(newChild); + } + } + } + return -1; + } + + private int[][] clone(int[][] original) { + int[][] cloned = new int[2][3]; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 3; j++) { + cloned[i][j] = original[i][j]; + } + } + return cloned; + } +} diff --git a/src/main/java/breadth_first_search/WallsAndGates.java b/src/main/java/breadth_first_search/WallsAndGates.java new file mode 100644 index 00000000..84136ba3 --- /dev/null +++ b/src/main/java/breadth_first_search/WallsAndGates.java @@ -0,0 +1,76 @@ +/* (C) 2024 YourCompanyName */ +package breadth_first_search; + +import java.util.ArrayDeque; +import java.util.Queue; + +/** + * Created by gouthamvidyapradhan on 26/12/2017. You are given a m x n 2D grid initialized with + * these three possible values. + * + *

-1 - A wall or an obstacle. 0 - A gate. INF - Infinity means an empty room. We use the value + * 231 - 1 = 2147483647 to represent INF as you may assume that the distance to a gate is less than + * 2147483647. Fill each empty room with the distance to its nearest gate. If it is impossible to + * reach a gate, it should be filled with INF. + * + *

For example, given the 2D grid: INF -1 0 INF INF INF INF -1 INF -1 INF -1 0 -1 INF INF After + * running your function, the 2D grid should be: 3 -1 0 1 2 2 1 -1 1 -1 2 -1 0 -1 3 4 + * + *

Solution: O(n x m): Treat each coordinate of grid with 0 as a source and destination as the + * coordinate of 2147483647 and perform a multi-sources BFS from each source. + */ +public class WallsAndGates { + + private static final int[] R = {0, 0, 1, -1}; + private static final int[] C = {1, -1, 0, 0}; + + private class Cell { + int r, c; + + Cell(int r, int c) { + this.r = r; + this.c = c; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] A = { + {Integer.MAX_VALUE, -1, 0, Integer.MAX_VALUE}, + {Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, -1}, + {Integer.MAX_VALUE, -1, Integer.MAX_VALUE, -1}, + {0, -1, Integer.MAX_VALUE, Integer.MAX_VALUE} + }; + new WallsAndGates().wallsAndGates(A); + } + + public void wallsAndGates(int[][] rooms) { + Queue queue = new ArrayDeque<>(); + for (int i = 0; i < rooms.length; i++) { + for (int j = 0; j < rooms[0].length; j++) { + if (rooms[i][j] == 0) { // treat each co-ordinates of gate as a source + Cell cell = new Cell(i, j); + queue.offer(cell); + } + } + } + while (!queue.isEmpty()) { + Cell top = queue.poll(); + for (int i = 0; i < 4; i++) { + int newR = top.r + R[i]; + int newC = top.c + C[i]; + if (newR >= 0 && newC >= 0 && newR < rooms.length && newC < rooms[0].length) { + if (rooms[newR][newC] == Integer.MAX_VALUE) { + rooms[newR][newC] = rooms[top.r][top.c] + 1; + queue.offer(new Cell(newR, newC)); + } + } + } + } + } +} diff --git a/src/main/java/breadth_first_search/WordLadder.java b/src/main/java/breadth_first_search/WordLadder.java new file mode 100644 index 00000000..1054b222 --- /dev/null +++ b/src/main/java/breadth_first_search/WordLadder.java @@ -0,0 +1,79 @@ +/* (C) 2024 YourCompanyName */ +package breadth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 21/03/2017. Given two words (beginWord and endWord), and a + * dictionary's word list, find the length of shortest transformation sequence from beginWord to + * endWord, such that: + * + *

Only one letter can be changed at a time. Each transformed word must exist in the word list. + * Note that beginWord is not a transformed word. For example, + * + *

Given: beginWord = "hit" endWord = "cog" wordList = ["hot","dot","dog","lot","log","cog"] As + * one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog", return its length 5. + * + *

Note: Return 0 if there is no such transformation sequence. All words have the same length. + * All words contain only lowercase alphabetic characters. You may assume no duplicates in the word + * list. You may assume beginWord and endWord are non-empty and are not the same. + */ +public class WordLadder { + + class State { + String word; + int len; + + State(String word, int len) { + this.word = word; + this.len = len; + } + } + + private static Queue queue = new ArrayDeque<>(); + private static Set dictionary = new HashSet<>(); + private static final String CONST = "abcdefghijklmnopqrstuvwxyz"; + private static Set done = new HashSet<>(); + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + List list = new ArrayList<>(); + list.add("hot"); + list.add("dot"); + list.add("dog"); + list.add("lot"); + list.add("log"); + list.add("cog"); + System.out.println(new WordLadder().ladderLength("hit", "cog", list)); + } + + public int ladderLength(String beginWord, String endWord, List wordList) { + dictionary.addAll(wordList); + queue.offer(new State(beginWord, 0)); + done.add(beginWord); + while (!queue.isEmpty()) { + State head = queue.poll(); + if (head.word.equals(endWord)) return head.len + 1; + for (int i = 0, l = CONST.length(); i < l; i++) { + StringBuilder word = new StringBuilder(head.word); + for (int j = 0, ln = word.length(); j < ln; j++) { + char old = word.charAt(j); + word.replace(j, j + 1, String.valueOf(CONST.charAt(i))); + if (!done.contains(word.toString())) { + if (dictionary.contains(word.toString())) { + done.add(word.toString()); + queue.offer(new State(word.toString(), head.len + 1)); + } + } + word.replace(j, j + 1, String.valueOf(old)); + } + } + } + return 0; + } +} diff --git a/src/main/java/breadth_first_search/WordLadderII.java b/src/main/java/breadth_first_search/WordLadderII.java new file mode 100644 index 00000000..d5374242 --- /dev/null +++ b/src/main/java/breadth_first_search/WordLadderII.java @@ -0,0 +1,169 @@ +/* (C) 2024 YourCompanyName */ +package breadth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 24/03/2017. Given two words (beginWord and endWord), and a + * dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, + * such that: + * + *

Only one letter can be changed at a time Each transformed word must exist in the word list. + * Note that beginWord is not a transformed word. For example, + * + *

Given: beginWord = "hit" endWord = "cog" wordList = ["hot","dot","dog","lot","log","cog"] + * Return [ ["hit","hot","dot","dog","cog"], ["hit","hot","lot","log","cog"] ] Note: Return an empty + * list if there is no such transformation sequence. All words have the same length. All words + * contain only lowercase alphabetic characters. You may assume no duplicates in the word list. You + * may assume beginWord and endWord are non-empty and are not the same. + */ +public class WordLadderII { + + private static Queue queue = new ArrayDeque<>(); + private static Set dictionary = new HashSet<>(); + private static final String CONST = "abcdefghijklmnopqrstuvwxyz"; + private static Map> graph = new HashMap<>(); + private static Map minDistance = new HashMap<>(); + private static List> result = new ArrayList<>(); + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + List dic = + Arrays.asList( + "kid", "tag", "pup", "ail", "tun", "woo", "erg", "luz", "brr", "gay", "sip", "kay", + "per", "val", "mes", "ohs", "now", "boa", "cet", "pal", "bar", "die", "war", "hay", + "eco", "pub", "lob", "rue", "fry", "lit", "rex", "jan", "cot", "bid", "ali", "pay", + "col", "gum", "ger", "row", "won", "dan", "rum", "fad", "tut", "sag", "yip", "sui", + "ark", "has", "zip", "fez", "own", "ump", "dis", "ads", "max", "jaw", "out", "btu", + "ana", "gap", "cry", "led", "abe", "box", "ore", "pig", "fie", "toy", "fat", "cal", + "lie", "noh", "sew", "ono", "tam", "flu", "mgm", "ply", "awe", "pry", "tit", "tie", + "yet", "too", "tax", "jim", "san", "pan", "map", "ski", "ova", "wed", "non", "wac", + "nut", "why", "bye", "lye", "oct", "old", "fin", "feb", "chi", "sap", "owl", "log", + "tod", "dot", "bow", "fob", "for", "joe", "ivy", "fan", "age", "fax", "hip", "jib", + "mel", "hus", "sob", "ifs", "tab", "ara", "dab", "jag", "jar", "arm", "lot", "tom", + "sax", "tex", "yum", "pei", "wen", "wry", "ire", "irk", "far", "mew", "wit", "doe", + "gas", "rte", "ian", "pot", "ask", "wag", "hag", "amy", "nag", "ron", "soy", "gin", + "don", "tug", "fay", "vic", "boo", "nam", "ave", "buy", "sop", "but", "orb", "fen", + "paw", "his", "sub", "bob", "yea", "oft", "inn", "rod", "yam", "pew", "web", "hod", + "hun", "gyp", "wei", "wis", "rob", "gad", "pie", "mon", "dog", "bib", "rub", "ere", + "dig", "era", "cat", "fox", "bee", "mod", "day", "apr", "vie", "nev", "jam", "pam", + "new", "aye", "ani", "and", "ibm", "yap", "can", "pyx", "tar", "kin", "fog", "hum", + "pip", "cup", "dye", "lyx", "jog", "nun", "par", "wan", "fey", "bus", "oak", "bad", + "ats", "set", "qom", "vat", "eat", "pus", "rev", "axe", "ion", "six", "ila", "lao", + "mom", "mas", "pro", "few", "opt", "poe", "art", "ash", "oar", "cap", "lop", "may", + "shy", "rid", "bat", "sum", "rim", "fee", "bmw", "sky", "maj", "hue", "thy", "ava", + "rap", "den", "fla", "auk", "cox", "ibo", "hey", "saw", "vim", "sec", "ltd", "you", + "its", "tat", "dew", "eva", "tog", "ram", "let", "see", "zit", "maw", "nix", "ate", + "gig", "rep", "owe", "ind", "hog", "eve", "sam", "zoo", "any", "dow", "cod", "bed", + "vet", "ham", "sis", "hex", "via", "fir", "nod", "mao", "aug", "mum", "hoe", "bah", + "hal", "keg", "hew", "zed", "tow", "gog", "ass", "dem", "who", "bet", "gos", "son", + "ear", "spy", "kit", "boy", "due", "sen", "oaf", "mix", "hep", "fur", "ada", "bin", + "nil", "mia", "ewe", "hit", "fix", "sad", "rib", "eye", "hop", "haw", "wax", "mid", + "tad", "ken", "wad", "rye", "pap", "bog", "gut", "ito", "woe", "our", "ado", "sin", + "mad", "ray", "hon", "roy", "dip", "hen", "iva", "lug", "asp", "hui", "yak", "bay", + "poi", "yep", "bun", "try", "lad", "elm", "nat", "wyo", "gym", "dug", "toe", "dee", + "wig", "sly", "rip", "geo", "cog", "pas", "zen", "odd", "nan", "lay", "pod", "fit", + "hem", "joy", "bum", "rio", "yon", "dec", "leg", "put", "sue", "dim", "pet", "yaw", + "nub", "bit", "bur", "sid", "sun", "oil", "red", "doc", "moe", "caw", "eel", "dix", + "cub", "end", "gem", "off", "yew", "hug", "pop", "tub", "sgt", "lid", "pun", "ton", + "sol", "din", "yup", "jab", "pea", "bug", "gag", "mil", "jig", "hub", "low", "did", + "tin", "get", "gte", "sox", "lei", "mig", "fig", "lon", "use", "ban", "flo", "nov", + "jut", "bag", "mir", "sty", "lap", "two", "ins", "con", "ant", "net", "tux", "ode", + "stu", "mug", "cad", "nap", "gun", "fop", "tot", "sow", "sal", "sic", "ted", "wot", + "del", "imp", "cob", "way", "ann", "tan", "mci", "job", "wet", "ism", "err", "him", + "all", "pad", "hah", "hie", "aim", "ike", "jed", "ego", "mac", "baa", "min", "com", + "ill", "was", "cab", "ago", "ina", "big", "ilk", "gal", "tap", "duh", "ola", "ran", + "lab", "top", "gob", "hot", "ora", "tia", "kip", "han", "met", "hut", "she", "sac", + "fed", "goo", "tee", "ell", "not", "act", "gil", "rut", "ala", "ape", "rig", "cid", + "god", "duo", "lin", "aid", "gel", "awl", "lag", "elf", "liz", "ref", "aha", "fib", + "oho", "tho", "her", "nor", "ace", "adz", "fun", "ned", "coo", "win", "tao", "coy", + "van", "man", "pit", "guy", "foe", "hid", "mai", "sup", "jay", "hob", "mow", "jot", + "are", "pol", "arc", "lax", "aft", "alb", "len", "air", "pug", "pox", "vow", "got", + "meg", "zoe", "amp", "ale", "bud", "gee", "pin", "dun", "pat", "ten", "mob"); + new WordLadderII().findLadders("cet", "ism", dic); + } + + public List> findLadders(String beginWord, String endWord, List wordList) { + dictionary.addAll(wordList); + bfs(beginWord, endWord, wordList); + List path = new ArrayList<>(); + path.add(beginWord); + dfs(beginWord, endWord, path); + System.out.println(result); + return result; + } + + /** + * Bfs + * + * @param beginWord begin word + * @param endWord end word + * @param wordList wordlist + */ + private void bfs(String beginWord, String endWord, List wordList) { + queue.offer(beginWord); + minDistance.put(beginWord, 0); + while (!queue.isEmpty()) { + String currWord = queue.poll(); + StringBuilder childSb = new StringBuilder(currWord); + for (int j = 0, ln = childSb.length(); j < ln; j++) { + for (int i = 0, l = CONST.length(); i < l; i++) { + char old = childSb.charAt(j); + childSb.replace(j, j + 1, String.valueOf(CONST.charAt(i))); + String child = childSb.toString(); + if (dictionary.contains(child)) { + if (minDistance.get(child) == null) { + minDistance.put(child, minDistance.get(currWord) + 1); + addChild(currWord, child); + if (!child.equals(endWord)) queue.offer(child); + } else { + if (minDistance.get(child) == (minDistance.get(currWord) + 1)) + addChild(currWord, child); + } + } + childSb.replace(j, j + 1, String.valueOf(old)); + } + } + } + } + + /** + * Add child + * + * @param parent parent + * @param child child + */ + private void addChild(String parent, String child) { + Set children = graph.get(parent); + if (children == null) children = new HashSet<>(); + children.add(child); + graph.put(parent, children); + } + + /** + * Dfs to build path + * + * @param currWord node + * @param endWord endword + * @param path path + */ + private void dfs(String currWord, String endWord, List path) { + if (currWord.equals(endWord)) { + result.add(new ArrayList<>(path)); + } else { + Set children = graph.get(currWord); + if (children != null) { + for (String c : children) { + path.add(c); + dfs(c, endWord, path); + path.remove(path.size() - 1); + } + } + } + } +} diff --git a/src/main/java/depth_first_search/AccountsMerge.java b/src/main/java/depth_first_search/AccountsMerge.java new file mode 100644 index 00000000..ab049aad --- /dev/null +++ b/src/main/java/depth_first_search/AccountsMerge.java @@ -0,0 +1,144 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 27/12/2017. Given a list accounts, each element accounts[i] is + * a list of strings, where the first element accounts[i][0] is a name, and the rest of the elements + * are emails representing emails of the account. + * + *

Now, we would like to merge these accounts. Two accounts definitely belong to the same person + * if there is some email that is common to both accounts. Note that even if two accounts have the + * same name, they may belong to different people as people could have the same name. A person can + * have any number of accounts initially, but all of their accounts definitely have the same name. + * + *

After merging the accounts, return the accounts in the following format: the first element of + * each account is the name, and the rest of the elements are emails in sorted order. The accounts + * themselves can be returned in any order. + * + *

Example 1: Input: accounts = [["John", "johnsmith@mail.com", "john00@mail.com"], ["John", + * "johnnybravo@mail.com"], ["John", "johnsmith@mail.com", "john_newyork@mail.com"], ["Mary", + * "mary@mail.com"]] Output: [["John", 'john00@mail.com', 'john_newyork@mail.com', + * 'johnsmith@mail.com'], ["John", "johnnybravo@mail .com"], ["Mary", "mary@mail.com"]] Explanation: + * The first and third John's are the same person as they have the common email + * "johnsmith@mail.com". The second John and Mary are different people as none of their email + * addresses are used by other accounts. We could return these lists in any order, for example the + * answer [['Mary', 'mary@mail.com'], ['John', 'johnnybravo@mail.com'], ['John', 'john00@mail.com', + * 'john_newyork@mail.com', 'johnsmith@mail.com']] would still be accepted. Note: + * + *

The length of accounts will be in the range [1, 1000]. The length of accounts[i] will be in + * the range [1, 10]. The length of accounts[i][j] will be in the range [1, 30]. + * + *

Solution: Consider each email_address as a vertex and link the emails of each account as + * bidirectional edges and perform a dfs on connected components and return the email addresses of + * connected components. + */ +public class AccountsMerge { + + private class Account { + String email, name; + + Account(String email, String name) { + this.email = email; + this.name = name; + } + } + + private Map numMap; // for simplicity mapping each email to a unique integer + private Map emailMap; + private Map> graph; + private BitSet done; + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + List account1 = new ArrayList<>(); + List> accounts = new ArrayList<>(); + account1.add("John"); + account1.add("johnsmith@mail.com"); + account1.add("john00@mail.com"); + accounts.add(account1); + + List account2 = new ArrayList<>(); + account2.add("John"); + account2.add("johnnybravo@mail.com"); + accounts.add(account2); + + List account3 = new ArrayList<>(); + account3.add("John"); + account3.add("johnsmith@mail.com"); + account3.add("john_newyork@mail.com"); + accounts.add(account3); + + List account4 = new ArrayList<>(); + account4.add("Mary"); + account4.add("mary@mail.com"); + accounts.add(account4); + + List> result = new AccountsMerge().accountsMerge(accounts); + System.out.println(result); + } + + public List> accountsMerge(List> accounts) { + done = new BitSet(); + numMap = new HashMap<>(); + emailMap = new HashMap<>(); + graph = new HashMap<>(); + int index = -1; + for (List account : accounts) { + String name = account.get(0); + int prev = -1; + for (int i = 1, l = account.size(); i < l; i++) { + String email = account.get(i); + int vertex; + if (!emailMap.containsKey(email)) { + vertex = ++index; + emailMap.put(email, vertex); + numMap.put(vertex, new Account(email, name)); + } else { + vertex = emailMap.get(email); + } + graph.putIfAbsent(vertex, new ArrayList<>()); + if (i != 1) { + // make bi-directional link + graph.get(prev).add(vertex); + graph.get(vertex).add(prev); + } + prev = vertex; + } + } + List> result = new ArrayList<>(); + for (int i : graph.keySet()) { + if (!done.get(i)) { + List list = new ArrayList<>(); + List account = new ArrayList<>(); + dfs(i, list); + list.stream().forEach(x -> account.add(numMap.get(x).email)); + account.sort(String::compareTo); + + // Add account user name + Account acc = numMap.get(list.get(0)); + account.add(0, acc.name); + result.add(account); + } + } + return result; + } + + private void dfs(int i, List list) { + done.set(i); + list.add(i); + List children = graph.get(i); + if (children != null) { + for (int c : children) { + if (!done.get(c)) { + dfs(c, list); + } + } + } + } +} diff --git a/src/main/java/depth_first_search/AlienDictionary.java b/src/main/java/depth_first_search/AlienDictionary.java new file mode 100644 index 00000000..6de53887 --- /dev/null +++ b/src/main/java/depth_first_search/AlienDictionary.java @@ -0,0 +1,126 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 02/12/2017. There is a new alien language which uses the latin + * alphabet. However, the order among letters are unknown to you. You receive a list of non-empty + * words from the dictionary, where words are sorted lexicographically by the rules of this new + * language. Derive the order of letters in this language. + * + *

Example 1: Given the following words in dictionary, + * + *

[ "wrt", "wrf", "er", "ett", "rftt" ] The correct order is: "wertf". + * + *

Example 2: Given the following words in dictionary, + * + *

[ "z", "x" ] The correct order is: "zx". + * + *

Example 3: Given the following words in dictionary, + * + *

[ "z", "x", "z" ] The order is invalid, so return "". + * + *

Note: You may assume all letters are in lowercase. You may assume that if a is a prefix of b, + * then a must appear before b in the given dictionary. If the order is invalid, return an empty + * string. There may be multiple valid order of letters, return any one of them is fine. + * + *

Solution: Build a graph with with character links and perform a topological sort. Topological + * sort can be performed only on a DAG hence if there is a cycle immediately return empty string + */ +public class AlienDictionary { + + private Map> graph; + private Set done; + private Set visited; + private Stack toposort; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + String[] words = {"z", "x", "z"}; + System.out.println(new AlienDictionary().alienOrder(words)); + } + + public String alienOrder(String[] words) { + graph = new HashMap<>(); + done = new HashSet<>(); + visited = new HashSet<>(); + toposort = new Stack<>(); + boolean[] A = new boolean[26]; + for (int i = 0; i < words.length - 1; i++) { + for (int j = 0, l = Math.min(words[i].length(), words[i + 1].length()); j < l; j++) { + if (words[i].charAt(j) != words[i + 1].charAt(j)) { + graph.putIfAbsent(words[i].charAt(j), new ArrayList<>()); + graph.get(words[i].charAt(j)).add(words[i + 1].charAt(j)); + break; + } + } + } + + for (String w : words) { + for (int i = 0, l = w.length(); i < l; i++) { + A[w.charAt(i) - 'a'] = true; + } + } + + for (char c : graph.keySet()) { + if (!done.contains(c)) { + if (!dfs(c)) return ""; + } + } + + StringBuilder sb = new StringBuilder(); + while (!toposort.isEmpty()) { + sb.append(toposort.pop()); + } + + // Add remaining elements. This can come in any order. + String result = sb.toString(); + StringBuilder remaining = new StringBuilder(); + for (int i = 0; i < 26; i++) { + if (A[i]) { + char c = (char) (i + 'a'); + boolean found = false; + for (char r : result.toCharArray()) { + if (r == c) { + found = true; + break; + } + } + if (!found) { + remaining.append(c); + } + } + } + return result.concat(remaining.toString().trim()); + } + + /** + * Dfs to toposort + * + * @param u + * @return + */ + private boolean dfs(char u) { + done.add(u); + visited.add(u); + List children = graph.get(u); + if (children != null) { + for (char c : children) { + if (visited.contains(c)) return false; // check cycle + if (!done.contains(c)) { + boolean status = dfs(c); + if (!status) return false; + } + } + } + toposort.push(u); + visited.remove(u); + return true; + } +} diff --git a/src/main/java/depth_first_search/AllPathsFromSourceToTarget.java b/src/main/java/depth_first_search/AllPathsFromSourceToTarget.java new file mode 100644 index 00000000..72f9f479 --- /dev/null +++ b/src/main/java/depth_first_search/AllPathsFromSourceToTarget.java @@ -0,0 +1,58 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 28/03/2019 Given a directed, acyclic graph of N nodes. Find all + * possible paths from node 0 to node N-1, and return them in any order. + * + *

The graph is given as follows: the nodes are 0, 1, ..., graph.length - 1. graph[i] is a list + * of all nodes j for which the edge (i, j) exists. + * + *

Example: Input: [[1,2], [3], [3], []] Output: [[0,1,3],[0,2,3]] Explanation: The graph looks + * like this: 0--->1 | | v v 2--->3 There are two paths: 0 -> 1 -> 3 and 0 -> 2 -> 3. Note: + * + *

The number of nodes in the graph will be in the range [2, 15]. You can print different paths + * in any order, but you should keep the order of nodes inside one path. + * + *

Solution: Do a dfs to reach every path. Since its a DAG there can be no cycles and safe to + * proceed without checking if the node has already been visited. Maintain a stack to keep track of + * the path and when a leaf node has been reached add the elements in the stack to the result array + */ +public class AllPathsFromSourceToTarget { + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[][] graph = {{1, 2}, {3}, {3}, {}}; + System.out.println(new AllPathsFromSourceToTarget().allPathsSourceTarget(graph)); + } + + public List> allPathsSourceTarget(int[][] graph) { + Set done = new HashSet<>(); + Stack stack = new Stack<>(); + List> result = new ArrayList<>(); + dfs(result, done, 0, stack, graph); + return result; + } + + private void dfs( + List> result, Set done, int i, Stack stack, int[][] graph) { + done.add(i); + stack.push(i); + int[] children = graph[i]; + if (children.length == 0) { + List childList = new ArrayList<>(stack); + result.add(childList); + } else { + for (int c : children) { + dfs(result, done, c, stack, graph); + } + } + stack.pop(); + done.remove(i); + } +} diff --git a/src/main/java/depth_first_search/AsFarfromLandAsPossible.java b/src/main/java/depth_first_search/AsFarfromLandAsPossible.java new file mode 100644 index 00000000..2a7a4efc --- /dev/null +++ b/src/main/java/depth_first_search/AsFarfromLandAsPossible.java @@ -0,0 +1,87 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 28/08/2019 Given an N x N grid containing only values 0 and 1, + * where 0 represents water and 1 represents land, find a water cell such that its distance to the + * nearest land cell is maximized and return the distance. + * + *

The distance used in this problem is the Manhattan distance: the distance between two cells + * (x0, y0) and (x1, y1) is |x0 - x1| + |y0 - y1|. + * + *

If no land or water exists in the grid, return -1. + * + *

Example 1: + * + *

Input: [[1,0,1],[0,0,0],[1,0,1]] Output: 2 Explanation: The cell (1, 1) is as far as possible + * from all the land with distance 2. Example 2: + * + *

Input: [[1,0,0],[0,0,0],[0,0,0]] Output: 4 Explanation: The cell (2, 2) is as far as possible + * from all the land with distance 4. + * + *

Note: + * + *

1 <= grid.length == grid[0].length <= 100 grid[i][j] is 0 or 1 + * + *

Solution: O(N x N) Do a multi-sources BFS starting from each of the water cell and end as soon + * as a land cell is found. Record the maximum distance to the land cell and return the value. + */ +public class AsFarfromLandAsPossible { + final int[] R = {1, -1, 0, 0}; + final int[] C = {0, 0, -1, 1}; + + public static void main(String[] args) { + int[][] G = {{1, 0, 1}, {0, 0, 0}, {1, 0, 1}}; + System.out.println(new AsFarfromLandAsPossible().maxDistance(G)); + } + + private class Node { + int r, c, d; + + Node(int r, int c, int d) { + this.r = r; + this.c = c; + this.d = d; + } + } + + public int maxDistance(int[][] grid) { + int[][] D = new int[grid.length][grid[0].length]; + Queue queue = new ArrayDeque<>(); + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 1) { + queue.offer(new Node(i, j, 0)); + } else { + D[i][j] = -1; + } + } + } + if (queue.isEmpty()) return -1; + while (!queue.isEmpty()) { + Node current = queue.poll(); + for (int i = 0; i < 4; i++) { + int newR = current.r + R[i]; + int newC = current.c + C[i]; + if (newR >= 0 && newC >= 0 && newR < grid.length && newC < grid[0].length) { + if (D[newR][newC] < 0) { + D[newR][newC] = current.d + 1; + Node child = new Node(newR, newC, current.d + 1); + queue.offer(child); + } + } + } + } + int max = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 0) { + max = Math.max(max, D[i][j]); + } + } + } + return max == 0 ? -1 : max; + } +} diff --git a/src/main/java/depth_first_search/BricksFallingWhenHit.java b/src/main/java/depth_first_search/BricksFallingWhenHit.java new file mode 100644 index 00000000..9b4baefb --- /dev/null +++ b/src/main/java/depth_first_search/BricksFallingWhenHit.java @@ -0,0 +1,227 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 01/07/2018. We have a grid of 1s and 0s; the 1s in a cell + * represent bricks. A brick will not drop if and only if it is directly connected to the top of the + * grid, or at least one of its (4-way) adjacent bricks will not drop. + * + *

We will do some erasures sequentially. Each time we want to do the erasure at the location (i, + * j), the brick (if it exists) on that location will disappear, and then some other bricks may drop + * because of that erasure. + * + *

Return an array representing the number of bricks that will drop after each erasure in + * sequence. + * + *

Example 1: Input: grid = [[1,0,0,0],[1,1,1,0]] hits = [[1,0]] Output: [2] Explanation: If we + * erase the brick at (1, 0), the brick at (1, 1) and (1, 2) will drop. So we should return 2. + * Example 2: Input: grid = [[1,0,0,0],[1,1,0,0]] hits = [[1,1],[1,0]] Output: [0,0] Explanation: + * When we erase the brick at (1, 0), the brick at (1, 1) has already disappeared due to the last + * move. So each erasure will cause no bricks dropping. Note that the erased brick (1, 0) will not + * be counted as a dropped brick. + * + *

Note: + * + *

The number of rows and columns in the grid will be in the range [1, 200]. The number of + * erasures will not exceed the area of the grid. It is guaranteed that each erasure will be + * different from any other erasure, and located inside the grid. An erasure may refer to a location + * with no brick - if it does, no bricks drop. + * + *

Solution: O(R x C): Erase all the bricks in the grid and do a union of all the bricks using a + * union-find disjoint set. (A modified union-find disjoint set is necessary to keep track of size + * of the connected component and to check if its connected to roof or not) Once you have the + * different connected components of the grid, solve the problem in the reverse order by iterating + * the hits in the reverse order. First set 1 in the grid for each hits and count the connected + * bricks in all four directions which are not linked to roof of the grid. + */ +public class BricksFallingWhenHit { + + private static final int[] R = {0, 0, 1, -1}; + private static final int[] C = {1, -1, 0, 0}; + + /** @author gouthamvidyapradhan Class to represent UnionFind Disjoint Set */ + private static class UnionFind { + private int[] p; + private int[] rank; + private boolean[] roof; + private int[] size; + + UnionFind(int s) { + this.p = new int[s]; + this.rank = new int[s]; + this.size = new int[s]; + this.roof = new boolean[s]; + init(); + } + /** Initialize with its same index as its parent */ + private void init() { + for (int i = 0; i < p.length; i++) { + p[i] = i; + size[i] = 1; + } + } + /** + * Find the representative vertex + * + * @param i + * @return + */ + private int findSet(int i) { + if (p[i] != i) { + p[i] = findSet(p[i]); + } + return p[i]; + } + + /** + * Set as roof + * + * @param i + */ + public void setAsRoof(int i) { + roof[i] = true; + } + /** + * Perform union of two vertex + * + * @param i + * @param j + * @return true if union is performed successfully, false otherwise + */ + public boolean union(int i, int j) { + int x = findSet(i); + int y = findSet(j); + if (x != y) { + if (rank[x] > rank[y]) { + p[y] = p[x]; + roof[x] = (roof[x] || roof[y]); + size[x] = size[x] + size[y]; + } else { + p[x] = p[y]; + roof[y] = (roof[x] || roof[y]); + size[y] = size[x] + size[y]; + if (rank[x] == rank[y]) { + rank[y]++; // increment the rank + } + } + return true; + } + return false; + } + + /** + * is attached to roof + * + * @param i + * @return + */ + public boolean isRoof(int i) { + return roof[findSet(i)]; + } + + /** + * is attached to roof + * + * @param i + * @return + */ + public int size(int i) { + return size[findSet(i)]; + } + } + + /** + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] grid = {{1, 1, 1, 1, 1}, {0, 0, 1, 0, 1}, {1, 0, 1, 0, 1}, {1, 1, 1, 0, 1}}; + int[][] hits = {{1, 2}, {2, 2}, {2, 4}, {0, 4}, {0, 0}}; + int[] r = new BricksFallingWhenHit().hitBricks(grid, hits); + for (int i = 0; i < r.length; i++) { + System.out.print(r[i] + " "); + } + } + + public int[] hitBricks(int[][] grid, int[][] hits) { + int nR = grid.length; + int nC = grid[0].length; + UnionFind unionFind = new UnionFind((nR * nC) + 1); + for (int i = 0; i < nC; i++) { + if (grid[0][i] == 1) { + unionFind.setAsRoof(i + 1); + } + } + for (int k = 0; k < hits.length; k++) { + int[] h = hits[k]; + if (grid[h[0]][h[1]] == 0) { + h[0] = -1; + h[1] = -1; + } else { + grid[h[0]][h[1]] = 0; + } + } + boolean[][] done = new boolean[grid.length][grid[0].length]; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 1 && !done[i][j]) { + dfs(i, j, grid, done, unionFind); + } + } + } + int[] result = new int[hits.length]; + for (int i = hits.length - 1; i >= 0; i--) { + int[] h = hits[i]; + int r = h[0]; + int c = h[1]; + if (r == -1) continue; + grid[r][c] = 1; + int cell = (r * nC) + c + 1; + int sum = 0; + List notLinkedToRoof = new ArrayList<>(); + List linkedToRoof = new ArrayList<>(); + for (int k = 0; k < 4; k++) { + int newR = r + R[k]; + int newC = c + C[k]; + if (newR >= 0 && newR < nR && newC >= 0 && newC < nC && grid[newR][newC] == 1) { + int newCell = (newR * nC) + newC + 1; + if (unionFind.isRoof(newCell)) { + linkedToRoof.add(newCell); + } else { + notLinkedToRoof.add(newCell); + } + } + } + for (int nr : notLinkedToRoof) { + unionFind.union(cell, nr); + } + if (!linkedToRoof.isEmpty() || unionFind.isRoof(cell)) { + sum += (unionFind.size(cell) - 1); + } + for (int rr : linkedToRoof) { + unionFind.union(cell, rr); + } + result[i] = sum; + } + return result; + } + + private void dfs(int r, int c, int[][] grid, boolean[][] done, UnionFind unionFind) { + done[r][c] = true; + int cell = (r * grid[0].length) + c + 1; + for (int i = 0; i < 4; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR >= 0 && newR < grid.length && newC >= 0 && newC < grid[0].length) { + if (grid[newR][newC] == 1 && !done[newR][newC]) { + int newCell = (newR * grid[0].length) + newC + 1; + unionFind.union(cell, newCell); + dfs(newR, newC, grid, done, unionFind); + } + } + } + } +} diff --git a/src/main/java/depth_first_search/CloneGraph.java b/src/main/java/depth_first_search/CloneGraph.java new file mode 100644 index 00000000..2ef7caed --- /dev/null +++ b/src/main/java/depth_first_search/CloneGraph.java @@ -0,0 +1,88 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 18/01/2018. Clone an undirected graph. Each node in the graph + * contains a label and a list of its neighbors. + * + *

OJ's undirected graph serialization: Nodes are labeled uniquely. + * + *

We use # as a separator for each node, and , as a separator for node label and each neighbor + * of the node. As an example, consider the serialized graph {0,1,2#1,2#2,2}. + * + *

The graph has a total of three nodes, and therefore contains three parts as separated by #. + * + *

First node is labeled as 0. Connect node 0 to both nodes 1 and 2. Second node is labeled as 1. + * Connect node 1 to node 2. Third node is labeled as 2. Connect node 2 to node 2 (itself), thus + * forming a self-cycle. Visually, the graph looks like the following: + * + *

1 / \ / \ 0 --- 2 / \ \_/ + * + *

Solution: O(V + E) maintain a hashmap of reference nodes and build the graph by dfs + */ +public class CloneGraph { + + static class UndirectedGraphNode { + int label; + List neighbors; + + UndirectedGraphNode(int x) { + label = x; + neighbors = new ArrayList<>(); + } + } + + private Map map; + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + UndirectedGraphNode node = new UndirectedGraphNode(0); + UndirectedGraphNode node1 = new UndirectedGraphNode(1); + UndirectedGraphNode node2 = new UndirectedGraphNode(2); + node.neighbors.add(node1); + node.neighbors.add(node2); + + node1.neighbors.add(node); + node1.neighbors.add(node2); + + node2.neighbors.add(node); + node2.neighbors.add(node1); + node2.neighbors.add(node2); + UndirectedGraphNode result = new CloneGraph().cloneGraph(node); + // print result + } + + public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) { + if (node == null) return null; + map = new HashMap<>(); + UndirectedGraphNode clone = new UndirectedGraphNode(node.label); + dfs(node, clone); + return clone; + } + + private void dfs(UndirectedGraphNode original, UndirectedGraphNode clone) { + map.put(clone.label, clone); + List oChildren = original.neighbors; // original child nodes + List cChildren = clone.neighbors; // clone child nodes + for (UndirectedGraphNode oChild : oChildren) { + if (map.containsKey(oChild.label)) { + // already visited node + cChildren.add(map.get(oChild.label)); + } else { + // a new node + UndirectedGraphNode newChildClone = new UndirectedGraphNode(oChild.label); + cChildren.add(newChildClone); + dfs(oChild, newChildClone); + } + } + } +} diff --git a/src/main/java/depth_first_search/ConnectingCitiesWithMinimumCost.java b/src/main/java/depth_first_search/ConnectingCitiesWithMinimumCost.java new file mode 100644 index 00000000..788c7336 --- /dev/null +++ b/src/main/java/depth_first_search/ConnectingCitiesWithMinimumCost.java @@ -0,0 +1,118 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 26/11/2019 There are N cities numbered from 1 to N. + * + *

You are given connections, where each connections[i] = [city1, city2, cost] represents the + * cost to connect city1 and city2 together. (A connection is bidirectional: connecting city1 and + * city2 is the same as connecting city2 and city1.) + * + *

Return the minimum cost so that for every pair of cities, there exists a path of connections + * (possibly of length 1) that connects those two cities together. The cost is the sum of the + * connection costs used. If the task is impossible, return -1. + * + *

Example 1: + * + *

Input: N = 3, connections = [[1,2,5],[1,3,6],[2,3,1]] Output: 6 Explanation: Choosing any 2 + * edges will connect all cities so we choose the minimum 2. Example 2: + * + *

Input: N = 4, connections = [[1,2,3],[3,4,4]] Output: -1 Explanation: There is no way to + * connect all cities even if all edges are used. + * + *

Note: + * + *

1 <= N <= 10000 1 <= connections.length <= 10000 1 <= connections[i][0], connections[i][1] <= + * N 0 <= connections[i][2] <= 10^5 connections[i][0] != connections[i][1] + */ +public class ConnectingCitiesWithMinimumCost { + + /** @author gouthamvidyapradhan Class to represent UnionFind Disjoint Set */ + private class UnionFind { + private int[] p; + private int[] rank; + private int numOfDisjoinSet; + + UnionFind(int s) { + this.p = new int[s]; + this.rank = new int[s]; + this.numOfDisjoinSet = s - 1; + init(); + } + + /** Initialize with its same index as its parent */ + public void init() { + for (int i = 0; i < p.length; i++) p[i] = i; + } + /** + * Find the representative vertex + * + * @param i + * @return + */ + private int findSet(int i) { + if (p[i] != i) p[i] = findSet(p[i]); + return p[i]; + } + /** + * Perform union of two vertex + * + * @param i + * @param j + * @return true if union is performed successfully, false otherwise + */ + public boolean union(int i, int j) { + int x = findSet(i); + int y = findSet(j); + if (x != y) { + if (rank[x] > rank[y]) p[y] = p[x]; + else { + p[x] = p[y]; + if (rank[x] == rank[y]) rank[y]++; // increment the rank + } + numOfDisjoinSet--; + return true; + } + return false; + } + } + + private class Edge { + int v1; + int v2; + int distance; + + Edge(int v1, int v2, int distance) { + this.v1 = v1; + this.v2 = v2; + this.distance = distance; + } + } + + private List edges = new ArrayList<>(); + int min = 0; + + public static void main(String[] args) { + int[][] A = {{1, 2, 3}, {3, 4, 4}}; + System.out.println(new ConnectingCitiesWithMinimumCost().minimumCost(4, A)); + } + + public int minimumCost(int N, int[][] connections) { + UnionFind uF = new UnionFind(N + 1); + for (int i = 0; i < connections.length; i++) { + edges.add(new Edge(connections[i][0], connections[i][1], connections[i][2])); + } + edges.sort(Comparator.comparingInt(o -> o.distance)); + for (Edge e : edges) { + if (uF.union(e.v1, e.v2)) { + min += e.distance; + } + if (uF.numOfDisjoinSet == 1) { + return min; + } + } + return -1; + } +} diff --git a/src/main/java/depth_first_search/CourseSchedule.java b/src/main/java/depth_first_search/CourseSchedule.java new file mode 100644 index 00000000..93383963 --- /dev/null +++ b/src/main/java/depth_first_search/CourseSchedule.java @@ -0,0 +1,90 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 22/06/2017. There are a total of n courses you have to take, + * labeled from 0 to n - 1. + * + *

Some courses may have prerequisites, for example to take course 0 you have to first take + * course 1, which is expressed as a pair: [0,1] + * + *

Given the total number of courses and a list of prerequisite pairs, is it possible for you to + * finish all courses? + * + *

For example: + * + *

2, [[1,0]] There are a total of 2 courses to take. To take course 1 you should have finished + * course 0. So it is possible. + * + *

2, [[1,0],[0,1]] There are a total of 2 courses to take. To take course 1 you should have + * finished course 0, and to take course 0 you should also have finished course 1. So it is + * impossible. + * + *

Note: The input prerequisites is a graph represented by a list of edges, not adjacency + * matrices. Read more about how a graph is represented. You may assume that there are no duplicate + * edges in the input prerequisites. + * + *

Solution: 1. Topologically sort the vertices. 2. Pick each sorted vertex and mark each of its + * neighbours as visited, if you encounter a vertex which is already visited then return false + * otherwise return true + */ +public class CourseSchedule { + private Map> graph; + private BitSet visited; + private Queue toposorted; + + public static void main(String[] args) throws Exception { + int[][] pre = {{1, 0}}; + System.out.println(new CourseSchedule().canFinish(2, pre)); + } + + public boolean canFinish(int numCourses, int[][] prerequisites) { + graph = new HashMap<>(); + visited = new BitSet(); + toposorted = new ArrayDeque<>(); + // build graph + for (int[] children : prerequisites) { + graph.putIfAbsent(children[0], new ArrayList<>()); + graph.get(children[0]).add(children[1]); + } + graph.keySet().stream().filter(v -> !visited.get(v)).forEach(this::dfs); + + visited.clear(); + + while (!toposorted.isEmpty()) { + int v = toposorted.poll(); + if (visited.get(v)) return false; + relax(v); + } + return true; + } + + /** + * Mark a vetex and its connected vertices as visited. + * + * @param v vertex + */ + private void relax(int v) { + visited.set(v); + List children = graph.get(v); + if (children != null) { + for (int c : children) visited.set(c); + } + } + + /** + * Toposort + * + * @param v vertex + */ + private void dfs(int v) { + visited.set(v); + List children = graph.get(v); + if (children != null) { + for (int c : children) if (!visited.get(c)) dfs(c); + } + toposorted.offer(v); + } +} diff --git a/src/main/java/depth_first_search/CourseScheduleII.java b/src/main/java/depth_first_search/CourseScheduleII.java new file mode 100644 index 00000000..cba31a4a --- /dev/null +++ b/src/main/java/depth_first_search/CourseScheduleII.java @@ -0,0 +1,100 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 23/06/2017. There are a total of n courses you have to take, + * labeled from 0 to n - 1. + * + *

Some courses may have prerequisites, for example to take course 0 you have to first take + * course 1, which is expressed as a pair: [0,1] + * + *

Given the total number of courses and a list of prerequisite pairs, return the ordering of + * courses you should take to finish all courses. + * + *

There may be multiple correct orders, you just need to return one of them. If it is impossible + * to finish all courses, return an empty array. + * + *

For example: + * + *

2, [[1,0]] There are a total of 2 courses to take. To take course 1 you should have finished + * course 0. So the correct course order is [0,1] + * + *

4, [[1,0],[2,0],[3,1],[3,2]] There are a total of 4 courses to take. To take course 3 you + * should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you + * finished course 0. So one correct course order is [0,1,2,3]. Another correct ordering + * is[0,2,1,3]. + * + *

Note: The input prerequisites is a graph represented by a list of edges, not adjacency + * matrices. Read more about how a graph is represented. You may assume that there are no duplicate + * edges in the input prerequisites. + */ +public class CourseScheduleII { + private Map> graph; + private BitSet visited; + private Queue toposorted; + + public static void main(String[] args) throws Exception { + int[][] pre = {{1, 0}}; + int[] result = new CourseScheduleII().findOrder(2, pre); + for (int i : result) System.out.print(i + " "); + System.out.println(); + } + + public int[] findOrder(int numCourses, int[][] prerequisites) { + int j = 0; + int[] courses = new int[numCourses]; + int[] result = new int[numCourses]; + for (int i = 0; i < numCourses; i++) courses[i] = j++; + graph = new HashMap<>(); + visited = new BitSet(); + toposorted = new ArrayDeque<>(); + // build graph + for (int[] children : prerequisites) { + graph.putIfAbsent(children[0], new ArrayList<>()); + graph.get(children[0]).add(children[1]); + } + graph.keySet().stream().filter(v -> !visited.get(v)).forEach(this::dfs); + + visited.clear(); + int i = 0; + while (!toposorted.isEmpty()) { + int v = toposorted.poll(); + if (visited.get(v)) return new int[0]; + relax(v); + result[i++] = v; + courses[v] = -1; + } + // add the remaining courses + for (int c : courses) if (c != -1) result[i++] = c; + return result; + } + + /** + * Mark a vetex and its connected vertices as visited. + * + * @param v vertex + */ + private void relax(int v) { + visited.set(v); + List children = graph.get(v); + if (children != null) { + for (int c : children) visited.set(c); + } + } + + /** + * Toposort + * + * @param v vertex + */ + private void dfs(int v) { + visited.set(v); + List children = graph.get(v); + if (children != null) { + for (int c : children) if (!visited.get(c)) dfs(c); + } + toposorted.offer(v); + } +} diff --git a/src/main/java/depth_first_search/CrackingTheSafe.java b/src/main/java/depth_first_search/CrackingTheSafe.java new file mode 100644 index 00000000..359dc597 --- /dev/null +++ b/src/main/java/depth_first_search/CrackingTheSafe.java @@ -0,0 +1,96 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.HashSet; +import java.util.Set; + +/** + * Created by gouthamvidyapradhan on 09/03/2019 There is a box protected by a password. The password + * is n digits, where each letter can be one of the first k digits 0, 1, ..., k-1. + * + *

You can keep inputting the password, the password will automatically be matched against the + * last n digits entered. + * + *

For example, assuming the password is "345", I can open it when I type "012345", but I enter a + * total of 6 digits. + * + *

Please return any string of minimum length that is guaranteed to open the box after the entire + * string is inputted. + * + *

Example 1: Input: n = 1, k = 2 Output: "01" Note: "10" will be accepted too. Example 2: Input: + * n = 2, k = 2 Output: "00110" Note: "01100", "10011", "11001" will be accepted too. Note: n will + * be in the range [1, 4]. k will be in the range [1, 10]. k^n will be at most 4096. + * + *

Solution O(n x k ^ n) Do a dfs and explore every possible states which form a n digit number + * with-in the given range k. Maintain a 'result' string and keep appending the new digit in every + * state, if the total number of states visited reaches k ^ n then, the result string will be the + * answer. + */ +public class CrackingTheSafe { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + System.out.println(new CrackingTheSafe().crackSafe(4, 5)); + } + + public String crackSafe(int n, int k) { + int states = getStates(n, k); + int[] N = new int[k]; + for (int i = 0; i < k; i++) { + N[i] = i; + } + return generate(N, n, 0, 0, "", k, states); + } + + private int getStates(int n, int k) { + if (n == 0) return 1; + if (n == 1) return k; + int result = 1; + for (int i = 0; i < n; i++) { + result *= k; + } + return result; + } + + private String generate(int[] N, int n, int i, int count, String num, int k, int states) { + if (count == n) { + return dfs(num, new StringBuilder(num), new HashSet<>(), k, states, 1); + } else { + for (int j = i; j < N.length; j++) { + String result = generate(N, n, j, count + 1, num + String.valueOf(N[j]), k, states); + if (!result.isEmpty()) { + return result; + } + } + } + return ""; + } + + private String dfs( + String num, StringBuilder result, Set done, int k, int states, int count) { + done.add(num); + if (states == count) { + return result.toString(); + } else { + for (int i = 0; i < k; i++) { + String newNum = (num + String.valueOf(i)); + String newState = newNum.substring(1); + if (!done.contains(newState)) { + String retValue = + dfs(newState, result.append(String.valueOf(i)), done, k, states, count + 1); + if (!retValue.isEmpty()) { + return retValue; + } else { + result.deleteCharAt(result.length() - 1); + } + } + } + } + done.remove(num); + return ""; + } +} diff --git a/src/main/java/depth_first_search/CriticalConnection.java b/src/main/java/depth_first_search/CriticalConnection.java new file mode 100644 index 00000000..57fd6f9f --- /dev/null +++ b/src/main/java/depth_first_search/CriticalConnection.java @@ -0,0 +1,80 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.*; + +/** Created by gouthamvidyapradhan on 05/12/2019 */ +public class CriticalConnection { + public static void main(String[] args) { + CriticalConnection task = new CriticalConnection(); + List c = new ArrayList<>(); + c.add(0); + c.add(1); + + List c1 = new ArrayList<>(); + c1.add(1); + c1.add(2); + + List c2 = new ArrayList<>(); + c2.add(2); + c2.add(0); + + List c3 = new ArrayList<>(); + c3.add(1); + c3.add(3); + + List> connections = new ArrayList<>(); + connections.add(c); + connections.add(c1); + connections.add(c2); + connections.add(c3); + List> result = task.criticalConnections(4, connections); + System.out.println(); + } + + private int[] dLow; + private int[] dNum; + private int num = 0; + + public List> criticalConnections(int n, List> connections) { + dLow = new int[n]; + dNum = new int[n]; + Map> graph = new HashMap<>(); + Arrays.fill(dLow, -1); + Arrays.fill(dNum, -1); + for (List connection : connections) { + graph.putIfAbsent(connection.get(0), new ArrayList<>()); + graph.putIfAbsent(connection.get(1), new ArrayList<>()); + graph.get(connection.get(0)).add(connection.get(1)); + graph.get(connection.get(1)).add(connection.get(0)); + } + dfs(-1, 0, graph); + List> result = new ArrayList<>(); + for (List connection : connections) { + if (dLow[connection.get(1)] > dNum[connection.get(0)] + || dLow[connection.get(0)] > dNum[connection.get(1)]) { + result.add(connection); + } + } + return result; + } + + private int dfs(int u, int v, Map> graph) { + int n = num++; + dNum[v] = n; + dLow[v] = n; + List children = graph.get(v); + if (children != null) { + for (int c : children) { + if (c != u) { + if (dNum[c] == -1) { + dLow[v] = Math.min(dLow[v], dfs(v, c, graph)); + } else { + dLow[v] = Math.min(dLow[c], dLow[v]); + } + } + } + } + return dLow[v]; + } +} diff --git a/src/main/java/depth_first_search/FloodFill.java b/src/main/java/depth_first_search/FloodFill.java new file mode 100644 index 00000000..834a7286 --- /dev/null +++ b/src/main/java/depth_first_search/FloodFill.java @@ -0,0 +1,45 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.*; + +/** Created by gouthamvidyapradhan on 29/01/2020 */ +public class FloodFill { + final int[] R = {1, -1, 0, 0}; + final int[] C = {0, 0, -1, 1}; + + public static void main(String[] args) { + // + } + + boolean done[][]; + + public int[][] floodFill(int[][] image, int sr, int sc, int newColor) { + done = new boolean[image.length][image[0].length]; + int[][] copy = new int[image.length][image[0].length]; + for (int i = 0; i < image.length; i++) { + for (int j = 0; j < image[0].length; j++) { + copy[i][j] = image[i][j]; + } + } + dfs(copy, sr, sc, image[sr][sc], newColor); + return copy; + } + + private void dfs(int[][] image, int r, int c, int c1, int c2) { + done[r][c] = true; + image[r][c] = c2; + for (int i = 0; i < 4; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR >= 0 + && newC >= 0 + && newR < image.length + && newC < image[0].length + && image[newR][newC] == c1 + && !done[newR][newC]) { + dfs(image, newR, newC, c1, c2); + } + } + } +} diff --git a/src/main/java/depth_first_search/GraphValidTree.java b/src/main/java/depth_first_search/GraphValidTree.java new file mode 100644 index 00000000..2b69ec1f --- /dev/null +++ b/src/main/java/depth_first_search/GraphValidTree.java @@ -0,0 +1,83 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 11/12/2017. Given n nodes labeled from 0 to n - 1 and a list of + * undirected edges (each edge is a pair of nodes), write a function to check whether these edges + * make up a valid tree. + * + *

For example: + * + *

Given n = 5 and edges = [[0, 1], [0, 2], [0, 3], [1, 4]], return true. + * + *

Given n = 5 and edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]], return false. + * + *

Note: you can assume that no duplicate edges will appear in edges. Since all edges are + * undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges. + * + *

Solution O(E + V). A graph is a tree if there are no cycles and number of connected components + * is 1. + */ +public class GraphValidTree { + + private List[] graph; + private BitSet done; + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] graph = {{1, 0}}; + System.out.println(new GraphValidTree().validTree(2, graph)); + } + + public boolean validTree(int n, int[][] edges) { + graph = new List[n]; + done = new BitSet(); + for (int i = 0; i < n; i++) { + graph[i] = new ArrayList<>(); + } + for (int i = 0; i < edges.length; i++) { + int u = edges[i][0]; + int v = edges[i][1]; + graph[u].add(v); + graph[v].add(u); + } + + int count = 0; + for (int i = 0; i < n; i++) { + if (!done.get(i)) { + if (!dfs(graph, 0, -1)) { + return false; + } + count++; // count number of connected components + } + } + return count <= 1; + } + + private boolean dfs(List[] graph, int u, int p) { + done.set(u); + List children = graph[u]; + if (children != null) { + for (int c : children) { + if (p != c) { // should not be equal to parent + if (!done.get(c)) { + if (!dfs(graph, c, u)) { + return false; + } + } else { + return false; + } + } + } + } + return true; + } +} diff --git a/src/main/java/depth_first_search/IslandPerimeter.java b/src/main/java/depth_first_search/IslandPerimeter.java new file mode 100644 index 00000000..3a020f91 --- /dev/null +++ b/src/main/java/depth_first_search/IslandPerimeter.java @@ -0,0 +1,69 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +/** + * Created by gouthamvidyapradhan on 16/02/2018. You are given a map in form of a two-dimensional + * integer grid where 1 represents land and 0 represents water. Grid cells are connected + * horizontally/vertically (not diagonally). The grid is completely surrounded by water, and there + * is exactly one island (i.e., one or more connected land cells). The island doesn't have "lakes" + * (water inside that isn't connected to the water around the island). One cell is a square with + * side length 1. The grid is rectangular, width and height don't exceed 100. Determine the + * perimeter of the island. + * + *

Example: + * + *

[[0,1,0,0], [1,1,1,0], [0,1,0,0], [1,1,0,0]] + * + *

Answer: 16 Explanation: The perimeter is the 16 yellow stripes in the image below: + * + *

Solution: Perform a dfs and count + 1 if any adjacent cell is a 0 or border + */ +public class IslandPerimeter { + + int[] R = {1, -1, 0, 0}; + int[] C = {0, 0, 1, -1}; + boolean[][] done; + int perimeter; + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] grid = {{0, 1, 0, 0}, {1, 1, 1, 0}, {0, 1, 0, 0}, {1, 1, 0, 0}}; + System.out.println(new IslandPerimeter().islandPerimeter(grid)); + } + + public int islandPerimeter(int[][] grid) { + done = new boolean[grid.length][grid[0].length]; + perimeter = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 1 && !done[i][j]) { + dfs(i, j, grid); + break; + } + } + } + + return perimeter; + } + + private void dfs(int r, int c, int[][] grid) { + done[r][c] = true; + for (int i = 0; i < 4; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR < 0 || newC < 0 || newR >= grid.length || newC >= grid[0].length) { + perimeter++; + } else if (grid[newR][newC] == 0) { + perimeter++; + } else { + if (!done[newR][newC]) { + dfs(newR, newC, grid); + } + } + } + } +} diff --git a/src/main/java/depth_first_search/LongestConsecutiveSequence.java b/src/main/java/depth_first_search/LongestConsecutiveSequence.java new file mode 100644 index 00000000..053cacbe --- /dev/null +++ b/src/main/java/depth_first_search/LongestConsecutiveSequence.java @@ -0,0 +1,74 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 15/12/2017. Given an unsorted array of integers, find the + * length of the longest consecutive elements sequence. + * + *

For example, Given [100, 4, 200, 1, 3, 2], The longest consecutive elements sequence is [1, 2, + * 3, 4]. Return its length: 4. + * + *

Your algorithm should run in O(n) complexity. + * + *

Solution: O(n) time and space complexity - Build a graph linking each number which is greater + * or lesser by one. Perform a dfs to count the depth of a graph. + * + *

Dfs using recursion fails due to StackOverFlowError(due to deep recursion) hence used a + * iterative approach with a stack + */ +public class LongestConsecutiveSequence { + + private Map> graph; + private Set done; + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] nums = {-1, 0, -3, -2, 1, 2, 3, 4, 5, 4}; + System.out.println(new LongestConsecutiveSequence().longestConsecutive(nums)); + } + + public int longestConsecutive(int[] nums) { + done = new HashSet<>(); + graph = new HashMap<>(); + for (int u : nums) { + graph.putIfAbsent(u, new HashSet<>()); + if (graph.keySet().contains(u - 1)) { + graph.get(u - 1).add(u); + graph.get(u).add(u - 1); + } + if (graph.keySet().contains(u + 1)) { + graph.get(u + 1).add(u); + graph.get(u).add(u + 1); + } + } + int max = 0; + for (int i : graph.keySet()) { + if (!done.contains(i)) { + Stack stack = new Stack<>(); + stack.add(i); + max = Math.max(max, dfs(0, stack)); + } + } + return max; + } + + private int dfs(int count, Stack stack) { + while (!stack.isEmpty()) { + int top = stack.pop(); + count++; + done.add(top); + + Set children = graph.get(top); + if (children != null) { + children.stream().filter(c -> !done.contains(c)).forEach(stack::push); + } + } + return count; + } +} diff --git a/src/main/java/depth_first_search/MaxAreaOfIsland.java b/src/main/java/depth_first_search/MaxAreaOfIsland.java new file mode 100644 index 00000000..c4001310 --- /dev/null +++ b/src/main/java/depth_first_search/MaxAreaOfIsland.java @@ -0,0 +1,77 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +/** + * Created by gouthamvidyapradhan on 28/05/2019 Given a non-empty 2D array grid of 0's and 1's, an + * island is a group of 1's (representing land) connected 4-directionally (horizontal or vertical.) + * You may assume all four edges of the grid are surrounded by water. + * + *

Find the maximum area of an island in the given 2D array. (If there is no island, the maximum + * area is 0.) + * + *

Example 1: + * + *

[[0,0,1,0,0,0,0,1,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,0,0,0], [0,1,1,0,1,0,0,0,0,0,0,0,0], + * [0,1,0,0,1,1,0,0,1,0,1,0,0], [0,1,0,0,1,1,0,0,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,1,0,0], + * [0,0,0,0,0,0,0,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,0,0,0,0]] Given the above grid, return 6. Note + * the answer is not 11, because the island must be connected 4-directionally. Example 2: + * + *

[[0,0,0,0,0,0,0,0]] Given the above grid, return 0. Note: The length of each dimension in the + * given grid does not exceed 50. + * + *

Solution: O(N x M) Do a dfs and keep track of max connected 1's + */ +public class MaxAreaOfIsland { + final int[] R = {0, 0, -1, 1}; + final int[] C = {1, -1, 0, 0}; + + int count = 0; + int max = 0; + boolean[][] done; + + public static void main(String[] args) { + int[][] grid = { + {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0}, + {0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0}, + {0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0} + }; + + System.out.println(new MaxAreaOfIsland().maxAreaOfIsland(grid)); + } + + public int maxAreaOfIsland(int[][] grid) { + done = new boolean[grid.length][grid[0].length]; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 1 && !done[i][j]) { + count = 0; + dfs(grid, i, j); + max = Math.max(max, count); + } + } + } + return max; + } + + private void dfs(int[][] grid, int r, int c) { + done[r][c] = true; + count++; + for (int i = 0; i < 4; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR >= 0 + && newC >= 0 + && newR < grid.length + && newC < grid[0].length + && !done[newR][newC] + && grid[newR][newC] == 1) { + dfs(grid, newR, newC); + } + } + } +} diff --git a/src/main/java/depth_first_search/Minesweeper.java b/src/main/java/depth_first_search/Minesweeper.java new file mode 100644 index 00000000..b2243211 --- /dev/null +++ b/src/main/java/depth_first_search/Minesweeper.java @@ -0,0 +1,112 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +/** + * Created by pradhang on 3/28/2017. You are given a 2D char matrix representing the game board. 'M' + * represents an unrevealed mine, 'E' represents an unrevealed empty square, 'B' represents a + * revealed blank square that has no adjacent (above, below, left, right, and all 4 diagonals) + * mines, digit ('1' to '8') represents how many mines are adjacent to this revealed square, and + * finally 'X' represents a revealed mine. + * + *

Now given the next click position (row and column indices) among all the unrevealed squares + * ('M' or 'E'), return the board after revealing this position according to the following rules: + * + *

If a mine ('M') is revealed, then the game is over - change it to 'X'. If an empty square + * ('E') with no adjacent mines is revealed, then change it to revealed blank ('B') and all of its + * adjacent unrevealed squares should be revealed recursively. If an empty square ('E') with at + * least one adjacent mine is revealed, then change it to a digit ('1' to '8') representing the + * number of adjacent mines. Return the board when no more squares will be revealed. Example 1: + * Input: + * + *

[['E', 'E', 'E', 'E', 'E'], ['E', 'E', 'M', 'E', 'E'], ['E', 'E', 'E', 'E', 'E'], ['E', 'E', + * 'E', 'E', 'E']] + * + *

Click : [3,0] + * + *

Output: + * + *

[['B', '1', 'E', '1', 'B'], ['B', '1', 'M', '1', 'B'], ['B', '1', '1', '1', 'B'], ['B', 'B', + * 'B', 'B', 'B']] + * + *

Example 2: Input: + * + *

[['B', '1', 'E', '1', 'B'], ['B', '1', 'M', '1', 'B'], ['B', '1', '1', '1', 'B'], ['B', 'B', + * 'B', 'B', 'B']] + * + *

Click : [1,2] + * + *

Output: + * + *

[['B', '1', 'E', '1', 'B'], ['B', '1', 'X', '1', 'B'], ['B', '1', '1', '1', 'B'], ['B', 'B', + * 'B', 'B', 'B']] + * + *

Note: The range of the input matrix's height and width is [1,50]. The click position will only + * be an unrevealed square ('M' or 'E'), which also means the input board contains at least one + * clickable square. The input board won't be a stage when game is over (some mines have been + * revealed). For simplicity, not mentioned rules should be ignored in this problem. For example, + * you don't need to reveal all the unrevealed mines when the game is over, consider any cases that + * you will win the game or flag any squares. + */ +public class Minesweeper { + private static final int[] R = {1, 1, 1, 0, 0, -1, -1, -1}; + private static final int[] C = {-1, 0, 1, -1, 1, -1, 0, 1}; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + char[][] board = { + {'E', 'E', 'E', 'E', 'E'}, + {'E', 'E', 'M', 'E', 'E'}, + {'E', 'E', 'E', 'E', 'E'}, + {'E', 'E', 'E', 'E', 'E'} + }; + int[] click = {3, 0}; + new Minesweeper().updateBoard(board, click); + for (int i = 0; i < board.length; i++) System.out.println(board[i]); + } + + public char[][] updateBoard(char[][] board, int[] click) { + int r = click[0]; + int c = click[1]; + dfs(board, r, c); + return board; + } + + private void dfs(char[][] board, int r, int c) { + if (board[r][c] == 'M') { + board[r][c] = 'X'; + } else { + int mineCount = 0; + for (int i = 0; i < 8; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR >= 0 + && newC >= 0 + && newR < board.length + && newC < board[0].length + && board[newR][newC] == 'M') // boundary check + mineCount++; + } + if (mineCount > 0) board[r][c] = (char) (mineCount + '0'); + else { + board[r][c] = 'B'; + for (int i = 0; i < 8; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR >= 0 + && newC >= 0 + && newR < board.length + && newC < board[0].length + && board[newR][newC] == 'E') // boundary check + { + dfs(board, newR, newC); + } + } + } + } + } +} diff --git a/src/main/java/depth_first_search/MinimizeMalwareSpread.java b/src/main/java/depth_first_search/MinimizeMalwareSpread.java new file mode 100644 index 00000000..4731f44d --- /dev/null +++ b/src/main/java/depth_first_search/MinimizeMalwareSpread.java @@ -0,0 +1,137 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 20/08/2019 In a network of nodes, each node i is directly + * connected to another node j if and only if graph[i][j] = 1. + * + *

Some nodes initial are initially infected by malware. Whenever two nodes are directly + * connected and at least one of those two nodes is infected by malware, both nodes will be infected + * by malware. This spread of malware will continue until no more nodes can be infected in this + * manner. + * + *

Suppose M(initial) is the final number of nodes infected with malware in the entire network, + * after the spread of malware stops. + * + *

We will remove one node from the initial list. Return the node that if removed, would minimize + * M(initial). If multiple nodes could be removed to minimize M(initial), return such a node with + * the smallest index. + * + *

Note that if a node was removed from the initial list of infected nodes, it may still be + * infected later as a result of the malware spread. + * + *

Example 1: + * + *

Input: graph = [[1,1,0],[1,1,0],[0,0,1]], initial = [0,1] Output: 0 Example 2: + * + *

Input: graph = [[1,0,0],[0,1,0],[0,0,1]], initial = [0,2] Output: 0 Example 3: + * + *

Input: graph = [[1,1,1],[1,1,1],[1,1,1]], initial = [1,2] Output: 1 + * + *

Note: + * + *

1 < graph.length = graph[0].length <= 300 0 <= graph[i][j] == graph[j][i] <= 1 graph[i][i] = 1 + * 1 <= initial.length < graph.length 0 <= initial[i] < graph.length + * + *

Solution: O(N x M x I) + O(I ^ 2) where N x M is number of nodes and I is the size of the + * initial Do a dfs from each of the initial nodes and color the reachable nodes with color i (color + * of initial node) and keep track of count of nodes reachable by this node - do not re-visit the + * already visited nodes. Check the list of initial nodes which have unique color which no other + * initial nodes have and mark this as eligible candidate. Sort the eligible candidates by pick the + * candidate which has maximum count of nodes reachable from it. + */ +public class MinimizeMalwareSpread { + public static void main(String[] args) { + int[][] graph = { + {1, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0}, + {0, 0, 1, 0, 0, 0}, + {0, 0, 0, 1, 1, 0}, + {0, 0, 0, 1, 1, 0}, + {0, 0, 0, 0, 0, 1} + }; + int[] i = {5, 0}; + new MinimizeMalwareSpread().minMalwareSpread(graph, i); + } + + Map> graphMap; + Map size; + Set done; + Map color; + int count = 0; + + public int minMalwareSpread(int[][] graph, int[] initial) { + graphMap = new HashMap<>(); + done = new HashSet<>(); + color = new HashMap<>(); + size = new HashMap<>(); + for (int i = 0; i < graph.length; i++) { + for (int j = 0; j < graph[0].length; j++) { + if (graph[i][j] == 1) { + graphMap.putIfAbsent(i, new ArrayList<>()); + graphMap.get(i).add(j); + graphMap.putIfAbsent(j, new ArrayList<>()); + graphMap.get(j).add(i); + } + } + } + for (int i : initial) { + if (!done.contains(i)) { + count = 0; + dfs(i, i); + size.put(i, count); + } + } + List eligible = new ArrayList<>(); + boolean candidate; + for (int i = 0; i < initial.length; i++) { + int iColor = color.get(initial[i]); + candidate = true; + for (int j = 0; j < initial.length; j++) { + if (j != i) { + if (color.get(initial[j]) == iColor) { + candidate = false; + break; + } + } + } + if (candidate) { + eligible.add(initial[i]); + } + } + Arrays.sort(initial); + eligible.sort(Comparator.comparingInt(o -> o)); + if (eligible.isEmpty()) { + return initial[0]; + } else { + int answer = initial[0]; + int max = 0; + for (int i = 0, l = eligible.size(); i < l; i++) { + int node = eligible.get(i); + if (size.containsKey(node)) { + if (size.get(node) > max) { + max = size.get(node); + answer = node; + } + } + } + return answer; + } + } + + private void dfs(int i, int col) { + done.add(i); + color.put(i, col); + count++; + List children = graphMap.get(i); + if (children != null && !children.isEmpty()) { + for (int c : children) { + if (!done.contains(c)) { + dfs(c, col); + } + } + } + } +} diff --git a/src/main/java/depth_first_search/MovieRecommend.java b/src/main/java/depth_first_search/MovieRecommend.java new file mode 100644 index 00000000..df6cf76b --- /dev/null +++ b/src/main/java/depth_first_search/MovieRecommend.java @@ -0,0 +1,63 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.*; + +/** Created by gouthamvidyapradhan on 25/02/2017. Accepted */ +public class MovieRecommend { + Set visited = new HashSet<>(); + List list = new ArrayList<>(); + + class Movie { + private int movieId; + private float rating; + private ArrayList similarMovies; + + public List getSimilarMovies() { + return similarMovies; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception {} + + public Set getMovieRecommendations(Movie movie, int N) { + dfs(movie); + Set result = new HashSet<>(); + Comparator cmp = + new Comparator() { + @Override + public int compare(Movie o1, Movie o2) { + return Float.compare(o2.rating, o1.rating); + } + }; + Collections.sort(list, cmp); + + if (list.size() < N) { + result.addAll(list); + return result; + } + + for (int i = 0; i < N; i++) { + result.add(list.get(i)); + } + + return result; + } + + private void dfs(Movie m) { + visited.add(m.movieId); // mark this visited + List movies = m.getSimilarMovies(); + for (Movie mo : movies) { + if (!visited.contains(mo.movieId)) { + list.add(mo); + dfs(mo); + } + } + } +} diff --git a/src/main/java/depth_first_search/NumberOfDistinctIslands.java b/src/main/java/depth_first_search/NumberOfDistinctIslands.java new file mode 100644 index 00000000..e774fb17 --- /dev/null +++ b/src/main/java/depth_first_search/NumberOfDistinctIslands.java @@ -0,0 +1,76 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.HashSet; +import java.util.Set; + +/** + * Created by gouthamvidyapradhan on 23/04/2018. Given a non-empty 2D array grid of 0's and 1's, an + * island is a group of 1's (representing land) connected 4-directionally (horizontal or vertical.) + * You may assume all four edges of the grid are surrounded by water. + * + *

Count the number of distinct islands. An island is considered to be the same as another if and + * only if one island can be translated (and not rotated or reflected) to equal the other. + * + *

Example 1: 11000 11000 00011 00011 Given the above grid map, return 1. Example 2: 11011 10000 + * 00001 11011 Given the above grid map, return 3. + * + *

Notice that: 11 1 and 1 11 are considered different island islands, because we do not consider + * reflection / rotation. Note: The length of each dimension in the given grid does not exceed 50. + * + *

Solution: O(N x M) create a signature of each island based on the direction and then use a + * hashset to count the islands. + */ +public class NumberOfDistinctIslands { + private int[] R = {0, 1, 0, -1}; + private int[] C = {1, 0, -1, 0}; + private boolean[][] done; + private Set islands; + /** + * Main method + * + * @param args + */ + public static void main(String[] args) throws Exception { + int[][] N = {{1, 1, 1, 1}, {1, 0, 1, 0}, {0, 0, 0, 0}, {0, 1, 1, 1}, {1, 1, 0, 1}}; + System.out.println(new NumberOfDistinctIslands().numDistinctIslands(N)); + } + + public int numDistinctIslands(int[][] grid) { + done = new boolean[grid.length][grid[0].length]; + islands = new HashSet<>(); + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (!done[i][j] && grid[i][j] == 1) { + StringBuilder sb = new StringBuilder(); + dfs(i, j, grid, sb); + islands.add(sb.toString()); + } + } + } + return islands.size(); + } + + private void dfs(int r, int c, int[][] grid, StringBuilder sb) { + done[r][c] = true; + for (int i = 0; i < 4; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR >= 0 && newC >= 0 && newR < grid.length && newC < grid[0].length) { + if (!done[newR][newC] && grid[newR][newC] == 1) { + if (i == 0) { + sb.append("R"); + } else if (i == 1) { + sb.append("D"); + } else if (i == 2) { + sb.append("L"); + } else { + sb.append("U"); + } + dfs(newR, newC, grid, sb); + } + } + } + sb.append("B"); + } +} diff --git a/src/main/java/depth_first_search/NumberOfDistinctIslandsII.java b/src/main/java/depth_first_search/NumberOfDistinctIslandsII.java new file mode 100644 index 00000000..84f30333 --- /dev/null +++ b/src/main/java/depth_first_search/NumberOfDistinctIslandsII.java @@ -0,0 +1,154 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Created by gouthamvidyapradhan on 27/04/2018. Given a non-empty 2D array grid of 0's and 1's, an + * island is a group of 1's (representing land) connected 4-directionally (horizontal or vertical.) + * You may assume all four edges of the grid are surrounded by water. + * + *

Count the number of distinct islands. An island is considered to be the same as another if + * they have the same shape, or have the same shape after rotation (90, 180, or 270 degrees only) or + * reflection (left/right direction or up/down direction). + * + *

Example 1: 11000 10000 00001 00011 Given the above grid map, return 1. + * + *

Notice that: 11 1 and 1 11 are considered same island shapes. Because if we make a 180 degrees + * clockwise rotation on the first island, then two islands will have the same shapes. Example 2: + * 11100 10001 01001 01110 Given the above grid map, return 2. + * + *

Here are the two distinct islands: 111 1 and 1 1 + * + *

Notice that: 111 1 and 1 111 are considered same island shapes. Because if we flip the first + * array in the up/down direction, then they have the same shapes. Note: The length of each + * dimension in the given grid does not exceed 50. + * + *

Solution: General idea is to get the co-ordinates of each shape using dfs and rotate/reflect + * each point in a shape to transform each shape to a new possible shape (there are 8 possible + * shapes after rotation and reflection). Sort the new coordinates of each transformed shape and + * reduce each shape to a canonical key. Use a hash-set to count total number of such keys. + * + *

Some background on rotation and reflection: ------------------------------------------- Rotate + * co-ordinates using formula [x′y′]=[[cosθ -sinθ], [sinθ cosθ]] [x y] where θ = {0, 90, 180, 270} + * There are 4 possible rotation points and for each rotation point obtain the reflection on each x + * and y axis. Rotation and reflection results in total of 8 points such as (x, y), (-x, y), (x, + * -y), (-x, -y), (y, x), (-y, x), (y, -x) and (-y, -x). + */ +public class NumberOfDistinctIslandsII { + private final int[] R = {0, 1, 0, -1}; + private final int[] C = {1, 0, -1, 0}; + private boolean[][] done; + + class Point implements Comparable { + int x; + int y; + + Point(int x, int y) { + this.x = x; + this.y = y; + } + + @Override + public int compareTo(Point o) { + if (this.x == o.x) { + return Integer.compare(this.y, o.y); + } + return Integer.compare(this.x, o.x); + } + } + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] grid = {{1, 1, 0, 0, 0}, {1, 0, 0, 0, 0}, {0, 0, 0, 0, 1}, {0, 0, 0, 1, 1}}; + System.out.println(new NumberOfDistinctIslandsII().numDistinctIslands2(grid)); + } + + public int numDistinctIslands2(int[][] grid) { + List> shapes = new ArrayList<>(); + done = new boolean[grid.length][grid[0].length]; + Set islands = new HashSet<>(); + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (!done[i][j] && grid[i][j] == 1) { + List points = new ArrayList<>(); + dfs(i, j, grid, points); + shapes.add(points); + } + } + } + for (List shape : shapes) { + List> eightShapes = rotateAndReflect(shape); + islands.add(genKey(eightShapes)); + } + return islands.size(); + } + + /** + * Generate a canonical key + * + * @param eighShapes + * @return + */ + private String genKey(List> eighShapes) { + List keys = new ArrayList<>(); + for (List shape : eighShapes) { + Collections.sort(shape); + Point first = shape.get(0); + keys.add( + shape + .stream() + .map(s -> new Point(s.x - first.x, s.y - first.y)) + .map(p -> p.x + ":" + p.y) + .collect(Collectors.joining(","))); + } + Collections.sort(keys); + return keys.get(0); + } + + /** + * Rotate and reflect a given shape to 8 possible shapes + * + * @param shape + * @return + */ + private List> rotateAndReflect(List shape) { + Map> map = new HashMap<>(); + for (int i = 0; i < 8; i++) { + map.put(i, new ArrayList<>()); + } + for (Point point : shape) { + map.get(0).add(new Point(point.x, point.y)); + map.get(1).add(new Point(-point.x, point.y)); + map.get(2).add(new Point(point.x, -point.y)); + map.get(3).add(new Point(-point.x, -point.y)); + map.get(4).add(new Point(point.y, point.x)); + map.get(5).add(new Point(-point.y, point.x)); + map.get(6).add(new Point(point.y, -point.x)); + map.get(7).add(new Point(-point.y, -point.x)); + } + return new ArrayList<>(map.values()); + } + + private void dfs(int r, int c, int[][] grid, List points) { + done[r][c] = true; + points.add(new Point(c, r)); + for (int i = 0; i < 4; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR >= 0 + && newC >= 0 + && newR < grid.length + && newC < grid[0].length + && grid[newR][newC] == 1 + && !done[newR][newC]) { + dfs(newR, newC, grid, points); + } + } + } +} diff --git a/src/main/java/depth_first_search/NumberOfEnclaves.java b/src/main/java/depth_first_search/NumberOfEnclaves.java new file mode 100644 index 00000000..a5b65dc6 --- /dev/null +++ b/src/main/java/depth_first_search/NumberOfEnclaves.java @@ -0,0 +1,76 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +/** + * Created by gouthamvidyapradhan on 31/07/2019 Given a 2D array A, each cell is 0 (representing + * sea) or 1 (representing land) + * + *

A move consists of walking from one land square 4-directionally to another land square, or off + * the boundary of the grid. + * + *

Return the number of land squares in the grid for which we cannot walk off the boundary of the + * grid in any number of moves. + * + *

Example 1: + * + *

Input: [[0,0,0,0],[1,0,1,0],[0,1,1,0],[0,0,0,0]] Output: 3 Explanation: There are three 1s + * that are enclosed by 0s, and one 1 that isn't enclosed because its on the boundary. Example 2: + * + *

Input: [[0,1,1,0],[0,0,1,0],[0,0,1,0],[0,0,0,0]] Output: 0 Explanation: All 1s are either on + * the boundary or can reach the boundary. + * + *

Note: + * + *

1 <= A.length <= 500 1 <= A[i].length <= 500 0 <= A[i][j] <= 1 All rows have the same size. + * Solution O(N x M) Do a dfs to count number of enclaves - in each dfs check if it violates the + * condition to be considered a enclave. + */ +public class NumberOfEnclaves { + + final int[] R = {0, 0, -1, 1}; + final int[] C = {1, -1, 0, 0}; + + boolean[][] done; + int count = 0; + int answer = 0; + boolean possible = true; + + public static void main(String[] args) { + int[][] A = {{0, 1, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 0, 0}}; + System.out.println(new NumberOfEnclaves().numEnclaves(A)); + } + + public int numEnclaves(int[][] A) { + done = new boolean[A.length][A[0].length]; + for (int i = 0; i < A.length; i++) { + for (int j = 0; j < A[0].length; j++) { + if (!done[i][j] && A[i][j] == 1) { + count = 0; + possible = true; + dfs(A, i, j); + if (possible) { + answer += count; + } + } + } + } + return answer; + } + + private void dfs(int[][] A, int r, int c) { + done[r][c] = true; + if (r == 0 || c == 0 || r == A.length - 1 || c == A[0].length - 1) { + possible = false; + } + count++; + for (int i = 0; i < 4; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR < A.length && newC < A[0].length && newR >= 0 && newC >= 0 && !done[newR][newC]) { + if (A[newR][newC] == 1) { + dfs(A, newR, newC); + } + } + } + } +} diff --git a/src/main/java/depth_first_search/NumberOfIslands.java b/src/main/java/depth_first_search/NumberOfIslands.java new file mode 100644 index 00000000..1d6925dd --- /dev/null +++ b/src/main/java/depth_first_search/NumberOfIslands.java @@ -0,0 +1,60 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +/** + * Created by gouthamvidyapradhan on 09/03/2017. Given a 2d grid map of '1's (land) and '0's + * (water), count the number of islands. An island is surrounded by water and is formed by + * connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid + * are all surrounded by water. + * + *

Example 1: + * + *

11110 11010 11000 00000 Answer: 1 + * + *

Example 2: + * + *

11000 11000 00100 00011 Answer: 3 + */ +public class NumberOfIslands { + int[] R = {0, 0, 1, -1}; + int[] C = {1, -1, 0, 0}; + private static int M, N; + private static char temp[][]; + + public int numIslands(char[][] grid) { + M = grid.length; + if (M == 0) return 0; + N = grid[0].length; + temp = new char[M][N]; + int count = 0; + + for (int i = 0; i < M; i++) { + System.arraycopy(grid[i], 0, temp[i], 0, N); + } + + for (int i = 0; i < M; i++) { + for (int j = 0; j < N; j++) { + if (temp[i][j] == '1') { + ++count; + dfs(i, j); + } + } + } + + return count; + } + + private void dfs(int r, int c) { + temp[r][c] = '0'; + for (int i = 0; i < 4; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR >= 0 && newC >= 0 && newR < M && newC < N) { + if (temp[newR][newC] != '0') // not visited + { + dfs(newR, newC); + } + } + } + } +} diff --git a/src/main/java/depth_first_search/ParallelCourses.java b/src/main/java/depth_first_search/ParallelCourses.java new file mode 100644 index 00000000..010ca8dc --- /dev/null +++ b/src/main/java/depth_first_search/ParallelCourses.java @@ -0,0 +1,91 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 26/11/2019 There are N courses, labelled from 1 to N. + * + *

We are given relations[i] = [X, Y], representing a prerequisite relationship between course X + * and course Y: course X has to be studied before course Y. + * + *

In one semester you can study any number of courses as long as you have studied all the + * prerequisites for the course you are studying. + * + *

Return the minimum number of semesters needed to study all courses. If there is no way to + * study all the courses, return -1. + * + *

Example 1: + * + *

Input: N = 3, relations = [[1,3],[2,3]] Output: 2 Explanation: In the first semester, courses + * 1 and 2 are studied. In the second semester, course 3 is studied. Example 2: + * + *

Input: N = 3, relations = [[1,2],[2,3],[3,1]] Output: -1 Explanation: No course can be studied + * because they depend on each other. + * + *

Note: + * + *

1 <= N <= 5000 1 <= relations.length <= 5000 relations[i][0] != relations[i][1] There are no + * repeated relations in the input. + */ +public class ParallelCourses { + public static void main(String[] args) { + int[][] A = {{1, 3}, {2, 3}}; + System.out.println(new ParallelCourses().minimumSemesters(3, A)); + } + + Map> graph; + Set done; + Set visited; + + public int minimumSemesters(int N, int[][] relations) { + graph = new HashMap<>(); + for (int[] E : relations) { + graph.putIfAbsent(E[0], new ArrayList<>()); + graph.get(E[0]).add(E[1]); + } + done = new HashSet<>(); + visited = new HashSet<>(); + Stack stack = new Stack<>(); + for (int v : graph.keySet()) { + if (!done.contains(v)) { + boolean status = dfs(v, stack); // toposort and return false if a cycle is found + if (!status) return -1; + } + } + int[] DP = new int[N + 1]; + int max = 0; + while (!stack.isEmpty()) { + int v = stack.pop(); + List children = graph.get(v); + if (children != null) { + for (int c : children) { + DP[c] = Math.max(DP[c], DP[v] + 1); + max = Math.max(max, DP[c]); + } + } + } + return max + 1; + } + + private boolean dfs(int v, Stack stack) { + done.add(v); + visited.add(v); + List children = graph.get(v); + if (children != null) { + for (int c : children) { + if (!visited.contains(c)) { + if (!done.contains(c)) { + boolean status = dfs(c, stack); + if (!status) return false; + } + } else { + return false; + } + } + } + visited.remove(v); + stack.push(v); + return true; + } +} diff --git a/src/main/java/depth_first_search/RobotRoomCleaner.java b/src/main/java/depth_first_search/RobotRoomCleaner.java new file mode 100644 index 00000000..9da6a0f5 --- /dev/null +++ b/src/main/java/depth_first_search/RobotRoomCleaner.java @@ -0,0 +1,126 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +/** + * Created by gouthamvidyapradhan on 08/03/2019 Given a robot cleaner in a room modeled as a grid. + * + *

Each cell in the grid can be empty or blocked. + * + *

The robot cleaner with 4 given APIs can move forward, turn left or turn right. Each turn it + * made is 90 degrees. + * + *

When it tries to move into a blocked cell, its bumper sensor detects the obstacle and it stays + * on the current cell. + * + *

Design an algorithm to clean the entire room using only the 4 given APIs shown below. + * + *

interface Robot { // returns true if next cell is open and robot moves into the cell. // + * returns false if next cell is obstacle and robot stays on the current cell. boolean move(); + * + *

// Robot will stay on the same cell after calling turnLeft/turnRight. // Each turn will be 90 + * degrees. void turnLeft(); void turnRight(); + * + *

// Clean the current cell. void clean(); } Example: + * + *

Input: room = [ [1,1,1,1,1,0,1,1], [1,1,1,1,1,0,1,1], [1,0,1,1,1,1,1,1], [0,0,0,1,0,0,0,0], + * [1,1,1,1,1,1,1,1] ], row = 1, col = 3 + * + *

Explanation: All grids in the room are marked by either 0 or 1. 0 means the cell is blocked, + * while 1 means the cell is accessible. The robot initially starts at the position of row=1, col=3. + * From the top left corner, its position is one row below and three columns right. Notes: + * + *

The input is only given to initialize the room and the robot's position internally. You must + * solve this problem "blindfolded". In other words, you must control the robot using only the + * mentioned 4 APIs, without knowing the room layout and the initial robot's position. The robot's + * initial position will always be in an accessible cell. The initial direction of the robot will be + * facing up. All accessible cells are connected, which means the all cells marked as 1 will be + * accessible by the robot. Assume all four edges of the grid are all surrounded by wall. + * + *

Solution: O(N x M) Maintain a direction and position of robot in each cell and perform a dfs + * to clean all rooms. Important to note here is that during call back in the dfs recursion the + * robot has to return back to its original cell and orientation + */ +public class RobotRoomCleaner { + + // direction + // UP 0, LEFT = 1, DOWN = 2, RIGHT = 3 + + private final int[] R = {-1, 0, 1, 0}; + private final int[] C = {0, -1, 0, 1}; + + interface Robot { + // Returns true if the cell in front is open and robot moves into the cell. + // Returns false if the cell in front is blocked and robot stays in the current cell. + public boolean move(); + + // Robot will stay in the same cell after calling turnLeft/turnRight. + // Each turn will be 90 degrees. + public void turnLeft(); + + public void turnRight(); + + // Clean the current cell. + public void clean(); + } + + static class Position { + int r, c; + + Position(int r, int c) { + this.r = r; + this.c = c; + } + + @Override + public boolean equals(Object obj) { + int r = ((Position) obj).r; + int c = ((Position) obj).c; + return (this.r == r && this.c == c); + } + + @Override + public int hashCode() { + return Objects.hash(r, c); + } + } + + private static Set done; + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) {} + + public void cleanRoom(Robot robot) { + done = new HashSet<>(); + dfs(1, 3, done, robot, 0); + } + + private void dfs(int r, int c, Set done, Robot robot, int direction) { + done.add(new Position(r, c)); + robot.clean(); + for (int i = 0; i < 4; i++) { + int newR = r + R[direction]; + int newC = c + C[direction]; + if (!done.contains(new Position(newR, newC))) { + boolean possible = robot.move(); + if (possible) { + dfs(newR, newC, done, robot, direction); + } + } + robot.turnLeft(); + direction = (direction + 1) % 4; + } + robot.turnLeft(); + robot.turnLeft(); + robot.move(); + robot.turnLeft(); + robot.turnLeft(); + } +} diff --git a/src/main/java/depth_first_search/SatisfiabilityOfEquations.java b/src/main/java/depth_first_search/SatisfiabilityOfEquations.java new file mode 100644 index 00000000..034f7247 --- /dev/null +++ b/src/main/java/depth_first_search/SatisfiabilityOfEquations.java @@ -0,0 +1,103 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 25/07/2019 Given an array equations of strings that represent + * relationships between variables, each string equations[i] has length 4 and takes one of two + * different forms: "a==b" or "a!=b". Here, a and b are lowercase letters (not necessarily + * different) that represent one-letter variable names. + * + *

Return true if and only if it is possible to assign integers to variable names so as to + * satisfy all the given equations. + * + *

Example 1: + * + *

Input: ["a==b","b!=a"] Output: false Explanation: If we assign say, a = 1 and b = 1, then the + * first equation is satisfied, but not the second. There is no way to assign the variables to + * satisfy both equations. Example 2: + * + *

Input: ["b==a","a==b"] Output: true Explanation: We could assign a = 1 and b = 1 to satisfy + * both equations. Example 3: + * + *

Input: ["a==b","b==c","a==c"] Output: true Example 4: + * + *

Input: ["a==b","b!=c","c==a"] Output: false Example 5: + * + *

Input: ["c==c","b==d","x!=z"] Output: true + * + *

Note: + * + *

1 <= equations.length <= 500 equations[i].length == 4 equations[i][0] and equations[i][3] are + * lowercase letters equations[i][1] is either '=' or '!' equations[i][2] is '=' + * + *

Solution: O(N) For all the equations which are of the form 'a==b' form a graph of connected + * components. Start assigning values to each of the connected components. All the nodes in the + * connected components should have the same value assigned - If any of the connected components + * fails this criteria then return false. + */ +public class SatisfiabilityOfEquations { + public static void main(String[] args) { + String[] input = {"c==c", "f!=a", "f==b", "b==c"}; + System.out.println(new SatisfiabilityOfEquations().equationsPossible(input)); + } + + private Set done; + private Map valueMap; + private int count = 0; + + public boolean equationsPossible(String[] equations) { + Map> graph = new HashMap<>(); + done = new HashSet<>(); + valueMap = new HashMap<>(); + for (String eq : equations) { + if (eq.charAt(1) == '=') { + graph.putIfAbsent(eq.charAt(0), new ArrayList<>()); + graph.get(eq.charAt(0)).add(eq.charAt(3)); + graph.putIfAbsent(eq.charAt(3), new ArrayList<>()); + graph.get(eq.charAt(3)).add(eq.charAt(0)); + } + } + for (char c : graph.keySet()) { + if (!done.contains(c)) { + dfs(c, graph, ++count); + } + } + + for (String eq : equations) { + if (eq.charAt(1) == '!') { + char a = eq.charAt(0); + char b = eq.charAt(3); + if (a == b) return false; + if (valueMap.containsKey(a) && valueMap.containsKey(b)) { + if (valueMap.get(a).intValue() == valueMap.get(b).intValue()) { + return false; + } + } + } + } + return true; + } + + private boolean dfs(char node, Map> graph, int value) { + done.add(node); + valueMap.put(node, value); + List children = graph.get(node); + if (!children.isEmpty()) { + for (char c : children) { + if (!done.contains(c)) { + boolean status = dfs(c, graph, value); + if (!status) { + return status; + } + } else { + if (valueMap.get(c) != value) { + return false; + } + } + } + } + return true; + } +} diff --git a/src/main/java/depth_first_search/SmallestRectangleEnclosingBlackPixels.java b/src/main/java/depth_first_search/SmallestRectangleEnclosingBlackPixels.java new file mode 100644 index 00000000..055f6026 --- /dev/null +++ b/src/main/java/depth_first_search/SmallestRectangleEnclosingBlackPixels.java @@ -0,0 +1,67 @@ +/* (C) 2024 YourCompanyName */ +package depth_first_search; + +/** + * Created by gouthamvidyapradhan on 24/06/2018. An image is represented by a binary matrix with 0 + * as a white pixel and 1 as a black pixel. The black pixels are connected, i.e., there is only one + * black region. Pixels are connected horizontally and vertically. Given the location (x, y) of one + * of the black pixels, return the area of the smallest (axis-aligned) rectangle that encloses all + * black pixels. + * + *

Example: + * + *

Input: [ "0010", "0110", "0100" ] and x = 0, y = 2 + * + *

Output: 6 + * + *

Solution: O(n x m) do a dfs and keep track of min and max length-breadth. Return the product + * of l x b + */ +public class SmallestRectangleEnclosingBlackPixels { + private final int[] R = {1, -1, 0, 0}; + private final int[] C = {0, 0, -1, 1}; + private boolean[][] done; + private int maxR, minR, minC, maxC; + + public static void main(String[] args) { + char[][] A = {{'0', '0', '1', '1'}, {'0', '1', '1', '0'}, {'0', '1', '0', '0'}}; + System.out.println(new SmallestRectangleEnclosingBlackPixels().minArea(A, 0, 2)); + } + + public int minArea(char[][] image, int x, int y) { + done = new boolean[image.length][image[0].length]; + maxR = 0; + maxC = 0; + minR = Integer.MAX_VALUE; + minC = Integer.MAX_VALUE; + maxR = Math.max(maxR, x); + minR = Math.min(minR, x); + + maxC = Math.max(maxC, y); + minC = Math.min(minC, y); + dfs(image, x, y); + return ((maxR - minR) + 1) * ((maxC - minC) + 1); + } + + private void dfs(char[][] image, int r, int c) { + done[r][c] = true; + for (int i = 0; i < 4; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR >= 0 + && newR < image.length + && newC >= 0 + && newC < image[0].length + && !done[newR][newC]) { + if (image[newR][newC] == '1') { + maxR = Math.max(maxR, newR); + minR = Math.min(minR, newR); + + maxC = Math.max(maxC, newC); + minC = Math.min(minC, newC); + dfs(image, newR, newC); + } + } + } + } +} diff --git a/src/main/java/design/AutocompleteSystem.java b/src/main/java/design/AutocompleteSystem.java new file mode 100644 index 00000000..105100d4 --- /dev/null +++ b/src/main/java/design/AutocompleteSystem.java @@ -0,0 +1,297 @@ +/* (C) 2024 YourCompanyName */ +package design; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 20/08/2017. + * + *

Design a search autocomplete system for a search engine. Users may input a sentence (at least + * one word and end with a special character '#'). For each character they type except '#', you need + * to return the top 3 historical hot sentences that have prefix the same as the part of sentence + * already typed. Here are the specific rules: + * + *

The hot degree for a sentence is defined as the number of times a user typed the exactly same + * sentence before. The returned top 3 hot sentences should be sorted by hot degree (The first is + * the hottest one). If several sentences have the same degree of hot, you need to use ASCII-code + * order (smaller one appears first). If less than 3 hot sentences exist, then just return as many + * as you can. When the input is a special character, it means the sentence ends, and in this case, + * you need to return an empty list. Your job is to implement the following functions: + * + *

The constructor function: + * + *

AutocompleteSystem(String[] sentences, int[] times): This is the constructor. The input is + * historical data. Sentences is a string array consists of previously typed sentences. Times is the + * corresponding times a sentence has been typed. Your system should record these historical data. + * + *

Now, the user wants to input a new sentence. The following function will provide the next + * character the user types: + * + *

List input(char c): The input c is the next character typed by the user. The character + * will only be lower-case letters ('a' to 'z'), blank space (' ') or a special character ('#'). + * Also, the previously typed sentence should be recorded in your system. The output will be the top + * 3 historical hot sentences that have prefix the same as the part of sentence already typed. + * + *

+ * + *

Example: Operation: AutocompleteSystem(["i love you", "island","ironman", "i love leetcode"], + * [5,3,2,2]) The system have already tracked down the following sentences and their corresponding + * times: "i love you" : 5 times "island" : 3 times "ironman" : 2 times "i love leetcode" : 2 times + * Now, the user begins another search: + * + *

Operation: input('i') Output: ["i love you", "island","i love leetcode"] Explanation: There + * are four sentences that have prefix "i". Among them, "ironman" and "i love leetcode" have same + * hot degree. Since ' ' has ASCII code 32 and 'r' has ASCII code 114, "i love leetcode" should be + * in front of "ironman". Also we only need to output top 3 hot sentences, so "ironman" will be + * ignored. + * + *

Operation: input(' ') Output: ["i love you","i love leetcode"] Explanation: There are only two + * sentences that have prefix "i ". + * + *

Operation: input('a') Output: [] Explanation: There are no sentences that have prefix "i a". + * + *

Operation: input('#') Output: [] Explanation: The user finished the input, the sentence "i a" + * should be saved as a historical sentence in system. And the following input will be counted as a + * new search. + * + *

Note: The input sentence will always start with a letter and end with '#', and only one blank + * space will exist between two words. The number of complete sentences that to be searched won't + * exceed 100. The length of each sentence including those in the historical data won't exceed 100. + * Please use double-quote instead of single-quote when you write test cases even for a character + * input. Please remember to RESET your class variables declared in class AutocompleteSystem, as + * static/class variables are persisted across multiple test cases. + * + *

Solution: Maintain a Trie (slightly modified) data-structure to all the input sentences where + * each node of the Trie is a node containing a hash-map of child character and node and a TreeSet + * containing the sorted order of all the possible child sentences starting from the current node. + * Maintain a cursor node 'curr' to indicate the current node of input, if the input character is + * absent then simply mark curr as null indicating no further auto-complete terms possible. On the + * other hand if the input character is present then simply pick the top 3 elements from the TreeSet + * object of curr node. Finally, use a StringBuilder to accumulate all the input characters and when + * a end of sentence is '#' is encountered simply update the trie with new sentence and degree. + */ +public class AutocompleteSystem { + + private Map hotTextMap; // Maintain a hash-map of sentences and degree + private Trie curr, trie, root; + private StringBuilder + currSentence; // StringBuilder class to maintain current input sentence (until '#') + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + String[] sentences = {"i love you", "island", "ironman", "i love leetcode"}; + int[] degree = {5, 3, 2, 2}; + AutocompleteSystem autocomplete = new AutocompleteSystem(sentences, degree); + List result = autocomplete.input('i'); + result.forEach(System.out::println); + result = autocomplete.input(' '); + result.forEach(System.out::println); + result = autocomplete.input('a'); + result.forEach(System.out::println); + result = autocomplete.input('#'); + result.forEach(System.out::println); + } + + /** + * Initialize the trie data-structure + * + * @param sentences array of sentences + * @param times degree + */ + public AutocompleteSystem(String[] sentences, int[] times) { + hotTextMap = new HashMap<>(); + trie = new Trie(); + for (int i = 0; i < sentences.length; i++) { + hotTextMap.put(sentences[i], times[i]); + trie.insert(sentences[i]); + trie.update(sentences[i]); + } + curr = trie; + root = trie; + currSentence = new StringBuilder(); + } + + /** + * Accept input and return hot-text for the current char + * + * @param c char + * @return List of top 3 hot-text + */ + public List input(char c) { + List result = new ArrayList<>(); + if (c == '#') { + String sentence = currSentence.toString(); + if (hotTextMap.containsKey(sentence)) { + // already a known sentence hence only update in necessary + hotTextMap.put(sentence, hotTextMap.get(sentence) + 1); + trie.update(sentence); + } else { + // insert a new sentence and update the degree + hotTextMap.put(sentence, 1); + trie.insert(sentence); + trie.update(sentence); + } + currSentence = new StringBuilder(); // reset StringBuilder + curr = root; // point to root of the trie + } else { + if (curr != null) { + if (curr.containsChild(c)) { + List hotText = curr.getSubtrie(c).getTop3HotText(); + hotText + .stream() + .forEach((x) -> result.add(currSentence.toString() + x)); // each node only returns + // the hot-text for the current and child nodes hence we have to attach the prefix string + curr = curr.getSubtrie(c); + } else { + curr = + null; // as soon as we encounter a empty node then set current to null indicating no + // further + // auto-complete terms are available + } + } + currSentence.append(c); + } + return result; + } + + /** Class HotText to store the text and degree */ + private class HotText { + private String text; + private int degree; + + HotText(String text, int degree) { + this.text = text; + this.degree = degree; + } + + private String getText() { + return text; + } + + private int getDegree() { + return degree; + } + } + + /** Class Trie */ + private class Trie { + private Map map = new HashMap<>(); + private TreeSet hotText = + new TreeSet<>( + (HotText o1, HotText o2) -> { + int cmp = Integer.compare(o2.getDegree(), o1.getDegree()); + return cmp == 0 ? o1.getText().compareTo(o2.getText()) : cmp; + }); + + /** + * Get hot-text + * + * @return HotText + */ + public TreeSet getHotText() { + return hotText; + } + + /** + * Return top 3 hottext + * + * @return hot text + */ + private List getTop3HotText() { + List hotText = new ArrayList<>(); + if (this.getHotText() != null) { + this.getHotText().stream().limit(3).forEach((x) -> hotText.add(x.getText())); + } + return hotText; + } + + /** Inserts a word into the trie. */ + private void insert(String word) { + if (word != null) { + add(0, word, word.length()); + } + } + + private void add(int i, String word, int length) { + if (i < length) { + char c = word.charAt(i); + Trie subTrie = map.get(c); + if (subTrie == null) { + subTrie = new Trie(); + map.put(c, subTrie); + } + subTrie.add(i + 1, word, length); + } else map.put(null, new Trie()); // use null to indicate end of string + } + + /** + * Update hottex and degree + * + * @param word word or sentence + */ + private void update(String word) { + if (word != null) { + update(0, word, word.length()); + } + } + + /** + * Update trie + * + * @param i curr position + * @param word sentence + * @param length length + * @return HotText + */ + private HotText update(int i, String word, int length) { + if (i < length) { + char c = word.charAt(i); + Trie subTrie = map.get(c); + HotText subTrieHotText = subTrie.update(i + 1, word, length); + HotText currHotText = + new HotText( + c + (subTrieHotText == null ? "" : subTrieHotText.getText()), hotTextMap.get(word)); + updateHotText(subTrie, currHotText); + return currHotText; + } + return null; + } + + /** + * Hot text update + * + * @param hotText hotText object + */ + private void updateHotText(Trie trie, HotText hotText) { + trie.getHotText() + .remove(new HotText(hotText.getText(), hotText.getDegree() - 1)); // remove already + // contained hot-text and add new + trie.getHotText().add(hotText); + } + + /** + * Contains child + * + * @param c char + * @return true if it contains child, false otherwise + */ + private boolean containsChild(char c) { + return this.map.containsKey(c); + } + + /** + * Return child tree + * + * @param c char + * @return child subTrie + */ + private Trie getSubtrie(char c) { + return this.map.get(c); + } + } +} diff --git a/src/main/java/design/BSTIterator.java b/src/main/java/design/BSTIterator.java new file mode 100644 index 00000000..107d86ba --- /dev/null +++ b/src/main/java/design/BSTIterator.java @@ -0,0 +1,88 @@ +/* (C) 2024 YourCompanyName */ +package design; + +import java.util.Stack; + +/** + * Created by gouthamvidyapradhan on 13/08/2017. Implement an iterator over a binary search tree + * (BST). Your iterator will be initialized with the root node of a BST. + * + *

Calling next() will return the next smallest number in the BST. + * + *

Note: next() and hasNext() should run in average O(1) time and uses O(h) memory, where h is + * the height of the tree. + * + *

Solution: The below solution works in average O(1) time and worst case O(h) time using O(h) + * memory. Use a stack to keep track of min value node. + */ +public class BSTIterator { + + private Stack stack; + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(10); + root.left = new TreeNode(5); + root.left.left = new TreeNode(4); + root.left.right = new TreeNode(8); + root.left.left.left = new TreeNode(1); + root.left.right.left = new TreeNode(7); + root.right = new TreeNode(12); + root.right.left = new TreeNode(11); + root.right.right = new TreeNode(15); + BSTIterator ite = new BSTIterator(root); + System.out.println("Hasnext: " + ite.hasNext()); + System.out.println("next: " + ite.next()); + System.out.println("next: " + ite.next()); + System.out.println("next: " + ite.next()); + System.out.println("next: " + ite.next()); + System.out.println("next: " + ite.next()); + System.out.println("next: " + ite.next()); + System.out.println("next: " + ite.next()); + System.out.println("next: " + ite.next()); + System.out.println("next: " + ite.next()); + System.out.println("Hasnext: " + ite.hasNext()); + } + + public BSTIterator(TreeNode root) { + stack = new Stack<>(); + fillStack(root); + } + + /** @return whether we have a next smallest number */ + public boolean hasNext() { + return !stack.isEmpty(); + } + + /** @return the next smallest number */ + public int next() { + if (!stack.isEmpty()) { + TreeNode top = stack.pop(); + fillStack(top.right); + return top.val; + } + return -1; + } + + /** + * Fill stack with min values + * + * @param node curr node to begin with + */ + private void fillStack(TreeNode node) { + TreeNode ite = node; + while (ite != null) { + stack.push(ite); + ite = ite.left; + } + } +} diff --git a/src/main/java/design/CopyListWithRandomPointer.java b/src/main/java/design/CopyListWithRandomPointer.java new file mode 100644 index 00000000..2c1c5eb6 --- /dev/null +++ b/src/main/java/design/CopyListWithRandomPointer.java @@ -0,0 +1,77 @@ +/* (C) 2024 YourCompanyName */ +package design; + +/** + * Created by gouthamvidyapradhan on 11/03/2017. A linked list is given such that each node contains + * an additional random pointer which could point to any node in the list or null. + * + *

Return a deep copy of the list. + */ +public class CopyListWithRandomPointer { + + static class RandomListNode { + int label; + RandomListNode next, random; + + RandomListNode(int x) { + this.label = x; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + RandomListNode one = new RandomListNode(1); + one.next = null; + one.random = one; + /*RandomListNode two = new RandomListNode(2); + RandomListNode three = new RandomListNode(3); + RandomListNode four = new RandomListNode(4); + RandomListNode five = new RandomListNode(5); + one.next = two; + two.next = three; + three.next = four; + four.next = five; + one.random = three; + two.random = five; + three.random = null; + four.random = two; + five.random = four;*/ + RandomListNode result = new CopyListWithRandomPointer().copyRandomList(one); + System.out.println(); + } + + private RandomListNode copyRandomList(RandomListNode head) { + if (head == null) return null; + RandomListNode ite = head, next; + while (ite != null) { + next = ite.next; + RandomListNode node = new RandomListNode(ite.label); + ite.next = node; + node.next = next; + ite = next; + } + + ite = head; + while (ite != null) { + if (ite.random != null) ite.next.random = ite.random.next; + ite = ite.next.next; + } + + ite = head; + RandomListNode copyIte = ite.next, copyHead = ite.next; + while (copyIte.next != null) { + ite.next = copyIte.next; + copyIte.next = ite.next.next; + copyIte = copyIte.next; + ite = ite.next; + } + ite.next = null; + + return copyHead; + } +} diff --git a/src/main/java/design/EncodeAndDecodeTinyURL.java b/src/main/java/design/EncodeAndDecodeTinyURL.java new file mode 100644 index 00000000..859a0684 --- /dev/null +++ b/src/main/java/design/EncodeAndDecodeTinyURL.java @@ -0,0 +1,44 @@ +/* (C) 2024 YourCompanyName */ +package design; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 11/04/2017. TinyURL is a URL shortening service where you enter + * a URL such as https://leetcode.com/problems/design-tinyurl and it returns a short URL such as + * http://tinyurl.com/4e9iAk. + * + *

Design the encode and decode methods for the TinyURL service. There is no restriction on how + * your encode/decode algorithm should work. You just need to ensure that a URL can be encoded to a + * tiny URL and the tiny URL can be decoded to the original URL. + */ +public class EncodeAndDecodeTinyURL { + private List list = new ArrayList<>(); + private static final String URL = "http://tinyurl.com/"; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + EncodeAndDecodeTinyURL encoder = new EncodeAndDecodeTinyURL(); + String shorterUrl = encoder.encode("https://leetcode.com/problems/design-tinyurl"); + System.out.println(encoder.decode(shorterUrl)); + } + + // Encodes a URL to a shortened URL. + public String encode(String longUrl) { + list.add(longUrl); + return URL.concat(String.valueOf(list.size())); + } + + // Decodes a shortened URL to its original URL. + public String decode(String shortUrl) { + String[] parts = shortUrl.split("http://tinyurl.com/"); + String code = parts[1]; + return list.get(Integer.parseInt(code) - 1); + } +} diff --git a/src/main/java/design/Excel.java b/src/main/java/design/Excel.java new file mode 100644 index 00000000..240acab5 --- /dev/null +++ b/src/main/java/design/Excel.java @@ -0,0 +1,215 @@ +/* (C) 2024 YourCompanyName */ +package design; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 16/09/2017. + * + *

Your task is to design the basic function of Excel and implement the function of sum formula. + * Specifically, you need to implement the following functions: + * + *

Excel(int H, char W): This is the constructor. The inputs represents the height and width of + * the Excel form. H is a positive integer, range from 1 to 26. It represents the height. W is a + * character range from 'A' to 'Z'. It represents that the width is the number of characters from + * 'A' to W. The Excel form content is represented by a height * width 2D integer array C, it should + * be initialized to zero. You should assume that the first row of C starts from 1, and the first + * column of C starts from 'A'. + * + *

+ * + *

void Set(int row, char column, int val): Change the value at C(row, column) to be val. + * + *

+ * + *

int Get(int row, char column): Return the value at C(row, column). + * + *

+ * + *

int Sum(int row, char column, List of Strings : numbers): This function calculate and set the + * value at C(row, column), where the value should be the sum of cells represented by numbers. This + * function return the sum result at C(row, column). This sum formula should exist until this cell + * is overlapped by another value or another sum formula. + * + *

numbers is a list of strings that each string represent a cell or a range of cells. If the + * string represent a single cell, then it has the following format : ColRow. For example, "F7" + * represents the cell at (7, F). + * + *

If the string represent a range of cells, then it has the following format : ColRow1:ColRow2. + * The range will always be a rectangle, and ColRow1 represent the position of the top-left cell, + * and ColRow2 represents the position of the bottom-right cell. + * + *

+ * + *

Example 1: Excel(3,"C"); // construct a 3*3 2D array with all zero. // A B C // 1 0 0 0 // 2 0 + * 0 0 // 3 0 0 0 + * + *

Set(1, "A", 2); // set C(1,"A") to be 2. // A B C // 1 2 0 0 // 2 0 0 0 // 3 0 0 0 + * + *

Sum(3, "C", ["A1", "A1:B2"]); // set C(3,"C") to be the sum of value at C(1,"A") and the + * values sum of the rectangle range whose top-left cell is C (1,"A") and bottom-right cell is + * C(2,"B"). Return 4. // A B C // 1 2 0 0 // 2 0 0 0 // 3 0 0 4 + * + *

Set(2, "B", 2); // set C(2,"B") to be 2. Note C(3, "C") should also be changed. // A B C // 1 + * 2 0 0 // 2 0 2 0 // 3 0 0 6 Note: You could assume that there won't be any circular sum + * reference. For example, A1 = sum(B1) and B1 = sum(A1). The test cases are using double-quotes to + * represent a character. Please remember to RESET your class variables declared in class Excel, as + * static/class variables are persisted across multiple test cases. + * + *

Solution: Build a graph and for each cell keep track of forward and backward links. When a + * cell is updated with a new value broadcast the new value to all the forward links and remove all + * the forward links pointing to this particular cell. + */ +public class Excel { + + private Map> fwdEdges; // Forward links from cell + private Map> backEdge; // All backward links from cell + private Map count; // Keep track of number of times the cell is linked + private int[][] grid; // excel grid + + /** + * Initialize datastructure + * + * @param H row + * @param W column + */ + public Excel(int H, char W) { + grid = new int[H][(Character.toUpperCase(W) - 'A') + 1]; + fwdEdges = new HashMap<>(); + backEdge = new HashMap<>(); + count = new HashMap<>(); + } + + public static void main(String[] args) throws Exception { + Excel excel = new Excel(26, 'Z'); + excel.set(1, 'A', 1); + excel.set(1, 'I', 1); + String[] arr = {"A1:D6", "A1:G3", "A1:C12"}; + String[] arr1 = {"A1:D7", "D1:F10", "D3:I8", "I1:I9"}; + System.out.println(excel.get(1, 'A')); + System.out.println(excel.sum(7, 'D', arr)); + System.out.println(excel.get(1, 'A')); + System.out.println(excel.sum(10, 'G', arr1)); + System.out.println(excel.get(1, 'A')); + } + + /** + * Set value to the grid + * + * @param r row + * @param c column + * @param v value + */ + public void set(int r, char c, int v) { + setValue(r, c, v); + removeForwardEdges(String.valueOf(c) + r); + } + + private void setValue(int r, char c, int v) { + int curr = grid[r - 1][Character.toUpperCase(c) - 'A']; + grid[r - 1][Character.toUpperCase(c) - 'A'] = v; + broadcast(v - curr, String.valueOf(c) + r); + } + + /** + * Remove all the links + * + * @param node node + */ + private void removeForwardEdges(String node) { + List parents = backEdge.get(node); + if (parents != null) { + for (String p : parents) { + Set children = fwdEdges.get(p); + if (children != null) { + count.remove(p + ":" + node); + children.remove(node); + } + } + } + } + + /** + * Broadcast to all the links + * + * @param v current node + * @param node node + */ + private void broadcast(int v, String node) { + Set children = fwdEdges.get(node); + if (children != null) { + for (String c : children) { + int order = count.get(node + ":" + c); + grid[Integer.parseInt(c.substring(1)) - 1][c.charAt(0) - 'A'] += (v * order); + broadcast(v, c); + } + } + } + + public int get(int r, char c) { + return grid[r - 1][c - 'A']; + } + + /** + * Sum range of cells + * + * @param r row + * @param c column + * @param strs Strings + * @return integer sum + */ + public int sum(int r, char c, String[] strs) { + int sum = 0; + // Remove all the forward and backward edges or links + removeForwardEdges(c + String.valueOf(r)); + backEdge.remove(c + String.valueOf(r)); + Set nodes = new HashSet<>(); + for (String s : strs) { + String[] range = s.split(":"); + if (range.length > 1) { + int startRow = Integer.parseInt(range[0].substring(1)) - 1; + int startColumn = range[0].charAt(0) - 'A'; + + int endRow = Integer.parseInt(range[1].substring(1)) - 1; + int endColumn = range[1].charAt(0) - 'A'; + + for (int i = startRow; i <= endRow; i++) { + for (int j = startColumn; j <= endColumn; j++) { + char newC = (char) ('A' + j); + nodes.add(newC + String.valueOf(i + 1)); + sum += grid[i][j]; + String key = newC + String.valueOf(i + 1) + ":" + (c + String.valueOf(r)); + if (count.putIfAbsent(key, 1) != null) { + count.put(key, (count.get(key) + 1)); + } + } + } + } else { + sum += grid[Integer.parseInt(range[0].substring(1)) - 1][range[0].charAt(0) - 'A']; + nodes.add(range[0]); + String key = range[0] + ":" + (c + String.valueOf(r)); + if (count.putIfAbsent(key, 1) != null) { + count.put(key, count.get(key) + 1); + } + } + } + // set value + setValue(r, c, sum); + + // make new forward-edges + for (String n : nodes) { + Set children = fwdEdges.get(n); + if (children == null) { + children = new HashSet<>(); + fwdEdges.put(n, children); + } + children.add(c + String.valueOf(r)); + } + + // make new back-edges + List backEdges = new ArrayList<>(); + backEdges.addAll(nodes); + backEdge.put(c + String.valueOf(r), backEdges); + return sum; + } +} diff --git a/src/main/java/design/LFUCache.java b/src/main/java/design/LFUCache.java new file mode 100644 index 00000000..3f5d2143 --- /dev/null +++ b/src/main/java/design/LFUCache.java @@ -0,0 +1,229 @@ +/* (C) 2024 YourCompanyName */ +package design; + +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 20/03/2017. Design and implement a data structure for Least + * Frequently Used (LFU) cache. It should support the following operations: get and put. + * + *

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, + * otherwise return -1. put(key, value) - Set or insert the value if the key is not already present. + * When the cache reaches its capacity, it should invalidate the least frequently used item before + * inserting a new item. For the purpose of this problem, when there is a tie (i.e., two or more + * keys that have the same frequency), the least recently used key would be evicted. + * + *

Follow up: Could you do both operations in O(1) time complexity? + * + *

Example: + * + *

LFUCache cache = new LFUCache( 2 /* capacity + */ +/*) + + cache.put(1, 1); + cache.put(2, 2); + cache.get(1); // returns 1 + cache.put(3, 3); // evicts key 2 + cache.get(2); // returns -1 (not found) + cache.get(3); // returns 3. + cache.put(4, 4); // evicts key 1. + cache.get(1); // returns -1 (not found) + cache.get(3); // returns 3 + cache.get(4); // returns 4 +*/ +public class LFUCache { + private class Node { + int frequency; + Node prev; + Node next; + LinkedHashSet hashSet; + + Node(int frequency, LinkedHashSet hashSet) { + this.frequency = frequency; + this.hashSet = hashSet; + prev = null; + next = null; + } + } + + private int capacity; + private int currentSize; + private Map cache; + private Map fMap; // frequency + private Node head; + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + LFUCache cache1 = new LFUCache(2); + cache1.put(1, 1); + cache1.put(2, 2); + System.out.println(cache1.get(1)); + cache1.put(3, 3); + System.out.println(cache1.get(2)); + // System.out.println(cache1.get(3)); + cache1.put(4, 4); + System.out.println(cache1.get(1)); + System.out.println(cache1.get(3)); + System.out.println(cache1.get(4)); + System.out.println(cache1.get(1)); + System.out.println(cache1.get(4)); + System.out.println(cache1.get(2)); + cache1.put(4, 4); + cache1.put(5, 4); + cache1.put(1, 9); + cache1.put(7, 1); + cache1.put(4, 2); + System.out.println(cache1.get(1)); + System.out.println(cache1.get(4)); + System.out.println(cache1.get(7)); + // System.out.println(cache1.get(3)); + // System.out.println(cache1.get(4)); + } + + public LFUCache(int capacity) { + currentSize = 0; + this.capacity = capacity; + cache = new HashMap<>(); + fMap = new HashMap<>(); + } + + /** + * Remove node and delink + * + * @param node Node + */ + private void popNode(Node node) { + if (node.prev != null && node.next != null) { + node.prev.next = node.next; + node.next.prev = node.prev; + } else if (node.prev == null) { + node.next.prev = null; + node.next = null; + } else { + node.prev.next = null; + node.prev = null; + } + } + + /** + * Get value + * + * @param key key + * @return value + */ + public int get(int key) { + if (!cache.containsKey(key)) return -1; + fMap.put(key, update(key)); + return cache.get(key); + } + + /** + * Update fMap + * + * @param key key + */ + private Node update(int key) { + Node node = fMap.get(key); + node.hashSet.remove(key); + Node newNode; + if (node.next == null) { + newNode = makeNewNode(key, node.frequency + 1); + node.next = newNode; + newNode.prev = node; + } else if (node.next.frequency == node.frequency + 1) { + node.next.hashSet.add(key); + newNode = node.next; + } else { + newNode = makeNewNode(key, node.frequency + 1); + node.next.prev = newNode; + newNode.next = node.next; + newNode.prev = node; + node.next = newNode; + } + if (node.equals(head)) incrementHead(); + else if (node.hashSet.isEmpty()) popNode(node); + return newNode; + } + + /** + * Make new node + * + * @param key key + * @param frequency frequency + * @return Node + */ + private Node makeNewNode(int key, int frequency) { + LinkedHashSet linkedHashSet = new LinkedHashSet<>(); + linkedHashSet.add(key); + return new Node(frequency, linkedHashSet); + } + + /** + * Add new head + * + * @param key key + * @param frequency frequency + */ + private Node addHead(int key, int frequency) { + if (head == null) head = makeNewNode(key, frequency); + else if (head.frequency > frequency) { + Node node = makeNewNode(key, frequency); + node.next = head; + head.prev = node; + head = node; + } else head.hashSet.add(key); + return head; + } + + /** Increment head */ + private void incrementHead() { + if (head.hashSet.isEmpty()) { + head = head.next; + if (head != null) { + head.prev.next = null; + head.prev = null; + } + } + } + + /** + * Put key value pair + * + * @param key key + * @param value value + */ + public void put(int key, int value) { + if (capacity != 0) { + if (cache.containsKey(key)) { + fMap.put(key, update(key)); // update existing + cache.put(key, value); + } else { + if (currentSize == capacity) { + evict(); + cache.put(key, value); + fMap.put(key, addHead(key, 1)); + } else { + fMap.put(key, addHead(key, 1)); // add new head + cache.put(key, value); + currentSize++; + } + } + } + } + + /** Evict the node with least frequency */ + private void evict() { + int key = head.hashSet.iterator().next(); + head.hashSet.remove(key); + cache.remove(key); + fMap.remove(key); + incrementHead(); + } +} diff --git a/src/main/java/design/LRUCache.java b/src/main/java/design/LRUCache.java new file mode 100644 index 00000000..9f02b5c1 --- /dev/null +++ b/src/main/java/design/LRUCache.java @@ -0,0 +1,154 @@ +/* (C) 2024 YourCompanyName */ +package design; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 18/03/2017. Design and implement a data structure for Least + * Recently Used (LRU) cache. It should support the following operations: get and put. + * + *

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, + * otherwise return -1. put(key, value) - Set or insert the value if the key is not already present. + * When the cache reached its capacity, it should invalidate the least recently used item before + * inserting a new item. + * + *

Follow up: Could you do both operations in O(1) time complexity? + * + *

Example: + * + *

LRUCache cache = new LRUCache( 2 /* capacity + */ +/*); + +cache.put(1, 1); +cache.put(2, 2); +cache.get(1); // returns 1 +cache.put(3, 3); // evicts key 2 +cache.get(2); // returns -1 (not found) +cache.put(4, 4); // evicts key 1 +cache.get(1); // returns -1 (not found) +cache.get(3); // returns 3 +cache.get(4); // returns 4 +Show Company Tags +Show Tags +Show Similar Problems + +*/ +public class LRUCache { + public static class DLinkList { + int key, value; + DLinkList left; + DLinkList right; + + DLinkList(int key, int value) { + this.key = key; + this.value = value; + left = null; + right = null; + } + } + + private Map cache; + private DLinkList head, tail; + private int capacity, currentSize; + + /** + * Pop head node + * + * @return + */ + private DLinkList popHead() { + if (!head.right.equals(tail)) { + DLinkList node = head.right; + head.right = node.right; + node.right.left = head; + node.right = null; + node.left = null; + return node; + } + return null; + } + + /** + * Push to tail + * + * @param node + */ + private void offer(DLinkList node) { + tail.left.right = node; + node.left = tail.left; + node.right = tail; + tail.left = node; + } + + /** + * Move node to tail + * + * @param node + */ + private void moveToTail(DLinkList node) { + node.left.right = node.right; + node.right.left = node.left; + offer(node); + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + LRUCache cache = new LRUCache(2); + cache.put(1, 1); + cache.put(2, 2); + System.out.println(cache.get(1)); + cache.put(3, 3); + System.out.println(cache.get(2)); + cache.put(4, 4); + System.out.println(cache.get(1)); + System.out.println(cache.get(3)); + System.out.println(cache.get(4)); + } + + public LRUCache(int capacity) { + this.capacity = capacity; + this.currentSize = 0; + cache = new HashMap<>(); + head = new DLinkList(-1, -1); + tail = new DLinkList(-1, -1); + head.right = tail; + tail.left = head; + } + + public int get(int key) { + if (cache.get(key) == null) return -1; + DLinkList node = cache.get(key); + moveToTail(node); + return node.value; + } + + public void put(int key, int value) { + if (cache.containsKey(key)) { + DLinkList node = cache.get(key); + node.value = value; + moveToTail(node); + } else { + if (capacity == currentSize) { + DLinkList head = popHead(); + if (head != null) { + cache.remove(head.key); + DLinkList node = new DLinkList(key, value); + offer(node); + cache.put(key, node); + } + } else { + DLinkList node = new DLinkList(key, value); + offer(node); + cache.put(key, node); + ++currentSize; + } + } + } +} diff --git a/src/main/java/design/NestedIterator.java b/src/main/java/design/NestedIterator.java new file mode 100644 index 00000000..54ffa9c0 --- /dev/null +++ b/src/main/java/design/NestedIterator.java @@ -0,0 +1,77 @@ +/* (C) 2024 YourCompanyName */ +package design; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 30/11/2017. + * + *

Given a nested list of integers, implement an iterator to flatten it. + * + *

Each element is either an integer, or a list -- whose elements may also be integers or other + * lists. + * + *

Example 1: Given the list [[1,1],2,[1,1]], + * + *

By calling next repeatedly until hasNext returns false, the order of elements returned by next + * should be: [1,1,2,1,1]. + * + *

Example 2: Given the list [1,[4,[6]]], + * + *

By calling next repeatedly until hasNext returns false, the order of elements returned by next + * should be: [1,4,6]. + */ +public class NestedIterator implements Iterator { + + private List result; + private int curr, size; + + // This is the interface that allows for creating nested lists. + // You should not implement it, or speculate about its implementation + public interface NestedInteger { + // @return true if this NestedInteger holds a single integer, rather than a nested list. + public boolean isInteger(); + + // @return the single integer that this NestedInteger holds, if it holds a single integer + // Return null if this NestedInteger holds a nested list + public Integer getInteger(); + + // @return the nested list that this NestedInteger holds, if it holds a nested list + // Return null if this NestedInteger holds a single integer + public List getList(); + } + + public NestedIterator(List nestedList) { + this.result = new ArrayList<>(); + curr = 0; + flatten(result, nestedList); + size = result.size(); + } + + @Override + public Integer next() { + if (curr < size) { + return result.get(curr++); + } + return -1; + } + + @Override + public boolean hasNext() { + return curr < size; + } + + public static void main(String[] args) {} + + private void flatten(List flatList, List nestedList) { + for (NestedInteger n : nestedList) { + if (n.isInteger()) { + flatList.add(n.getInteger()); + } else { + flatten(flatList, n.getList()); + } + } + } +} diff --git a/src/main/java/design/RandomizedCollection.java b/src/main/java/design/RandomizedCollection.java new file mode 100644 index 00000000..9d3abb76 --- /dev/null +++ b/src/main/java/design/RandomizedCollection.java @@ -0,0 +1,118 @@ +/* (C) 2024 YourCompanyName */ +package design; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 14/04/2018. Design a data structure that supports all following + * operations in average O(1) time. + * + *

Note: Duplicate elements are allowed. insert(val): Inserts an item val to the collection. + * remove(val): Removes an item val from the collection if present. getRandom: Returns a random + * element from current collection of elements. The probability of each element being returned is + * linearly related to the number of same value the collection contains. Example: + * + *

// Init an empty collection. RandomizedCollection collection = new RandomizedCollection(); + * + *

// Inserts 1 to the collection. Returns true as the collection did not contain 1. + * collection.insert(1); + * + *

// Inserts another 1 to the collection. Returns false as the collection contained 1. + * Collection now contains [1,1]. collection.insert(1); + * + *

// Inserts 2 to the collection, returns true. Collection now contains [1,1,2]. + * collection.insert(2); + * + *

// getRandom should return 1 with the probability 2/3, and returns 2 with the probability 1/3. + * collection.getRandom(); + * + *

// Removes 1 from the collection, returns true. Collection now contains [1,2]. + * collection.remove(1); + * + *

// getRandom should return 1 and 2 both equally likely. collection.getRandom(); + * + *

Solution O(1) for each operation. Maintain a hashmap of value -> {set of indices}; Set of + * indices are indices of array containing the value. Insert: Insert a element in end of array and + * add the index of array as the set of values in hashmap. Remove: If the hashmap contains value + * remove a random element from the set and replace the element at that index with the last element + * from array and remove the last element from the array. Since we are removing the last element + * from array this operation requires only O(1) time getRandom(): Generate a random number between 0 + * and size of array and return the element at that position. + */ +public class RandomizedCollection { + + private Map> map; + private List list; + + /** Initialize your data structure here. */ + public RandomizedCollection() { + map = new HashMap<>(); + list = new ArrayList<>(); + } + + /** + * Inserts a value to the collection. Returns true if the collection did not already contain the + * specified element. + */ + public boolean insert(int val) { + boolean status = map.containsKey(val); + Set set = map.get(val); + if (set == null) { + set = new HashSet<>(); + map.put(val, set); + } + list.add(val); + set.add(list.size() - 1); + return !status; + } + + /** + * Removes a value from the collection. Returns true if the collection contained the specified + * element. + */ + public boolean remove(int val) { + if (map.containsKey(val)) { + Set set = map.get(val); + int valIndex = set.iterator().next(); + set.remove(valIndex); + if (set.isEmpty()) { + map.remove(val); + } + if (valIndex == list.size() - 1) { // if this is the last index then simply remove it + list.remove(list.size() - 1); + } else { + int lastEle = list.get(list.size() - 1); + map.get(lastEle).remove(list.size() - 1); + map.get(lastEle).add(valIndex); + list.set(valIndex, lastEle); + list.remove(list.size() - 1); + } + return true; + } else return false; + } + + /** Get a random element from the collection. */ + public int getRandom() { + Random random = new Random(); + return list.get(random.nextInt(list.size())); + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + RandomizedCollection collection = new RandomizedCollection(); + System.out.println(collection.insert(1)); + System.out.println(collection.insert(1)); + System.out.println(collection.insert(2)); + System.out.println(collection.getRandom()); + System.out.println(collection.remove(2)); + System.out.println(collection.getRandom()); + System.out.println(collection.remove(1)); + System.out.println(collection.getRandom()); + System.out.println(collection.remove(1)); + } +} diff --git a/src/main/java/design/RandomizedSet.java b/src/main/java/design/RandomizedSet.java new file mode 100644 index 00000000..5d52197e --- /dev/null +++ b/src/main/java/design/RandomizedSet.java @@ -0,0 +1,104 @@ +/* (C) 2024 YourCompanyName */ +package design; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 23/03/2017. Design a data structure that supports all following + * operations in average O(1) time. + * + *

insert(val): Inserts an item val to the set if not already present. remove(val): Removes an + * item val from the set if present. getRandom: Returns a random element from current set of + * elements. Each element must have the same probability of being returned. Example: + * + *

// Init an empty set. RandomizedSet randomSet = new RandomizedSet(); + * + *

// Inserts 1 to the set. Returns true as 1 was inserted successfully. randomSet.insert(1); + * + *

// Returns false as 2 does not exist in the set. randomSet.remove(2); + * + *

// Inserts 2 to the set, returns true. Set now contains [1,2]. randomSet.insert(2); + * + *

// getRandom should return either 1 or 2 randomly. randomSet.getRandom(); + * + *

// Removes 1 from the set, returns true. Set now contains [2]. randomSet.remove(1); + * + *

// 2 was already in the set, so return false. randomSet.insert(2); + * + *

// Since 2 is the only number in the set, getRandom always return 2. randomSet.getRandom(); + */ +public class RandomizedSet { + private Map map; + private List list; + private Random random; + + /** Initialize your data structure here. */ + public RandomizedSet() { + map = new HashMap<>(); + list = new ArrayList<>(); + random = new Random(); + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + RandomizedSet rSet = new RandomizedSet(); + System.out.println(rSet.getRandom()); + System.out.println(rSet.insert(1)); + System.out.println(rSet.insert(2)); + System.out.println(rSet.insert(2)); + System.out.println(rSet.insert(3)); + System.out.println(rSet.remove(2)); + System.out.println(rSet.insert(2)); + System.out.println(rSet.getRandom()); + System.out.println(rSet.insert(234)); + System.out.println(rSet.insert(23)); + System.out.println(rSet.insert(22)); + System.out.println(rSet.getRandom()); + System.out.println(rSet.remove(245)); + System.out.println(rSet.remove(234)); + System.out.println(rSet.getRandom()); + } + + /** + * Inserts a value to the set. Returns true if the set did not already contain the specified + * element. + */ + public boolean insert(int val) { + if (!map.keySet().contains(val)) { + int pos = list.size(); + map.put(val, pos); + list.add(val); + return true; + } + return false; + } + + /** Removes a value from the set. Returns true if the set contained the specified element. */ + public boolean remove(int val) { + if (map.containsKey(val)) { + int size = list.size(); + int posVal = map.get(val); + if (posVal < (size - 1)) { + int last = list.get(size - 1); + map.put(last, posVal); + list.set(posVal, last); + } + map.remove(val); + list.remove(size - 1); + return true; + } + return false; + } + + /** Get a random element from the set. */ + public int getRandom() { + /*if(list.size() == 0) return 0; + else if (list.size() == 1) return list.get(0);*/ + return list.get(random.nextInt(list.size() - 1)); + } +} diff --git a/src/main/java/design/SerializeDeserializeBinaryTree.java b/src/main/java/design/SerializeDeserializeBinaryTree.java new file mode 100644 index 00000000..cdb5a640 --- /dev/null +++ b/src/main/java/design/SerializeDeserializeBinaryTree.java @@ -0,0 +1,108 @@ +/* (C) 2024 YourCompanyName */ +package design; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 11/03/2017. Serialization is the process of converting a data + * structure or object into a sequence of bits so that it can be stored in a file or memory buffer, + * or transmitted across a network connection link to be reconstructed later in the same or another + * computer environment. + * + *

Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how + * your serialization/deserialization algorithm should work. You just need to ensure that a binary + * tree can be serialized to a string and this string can be deserialized to the original tree + * structure. + * + *

For example, you may serialize the following tree + * + *

1 / \ 2 3 / \ 4 5 as "[1,2,3,null,null,4,5]", just the same as how LeetCode OJ serializes a + * binary tree. You do not necessarily need to follow this format, so please be creative and come up + * with different approaches yourself. Note: Do not use class member/global/static variables to + * store states. Your serialize and deserialize algorithms should be stateless. + */ +public class SerializeDeserializeBinaryTree { + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + private static final String NULL = "X"; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(1); + TreeNode two = new TreeNode(2); + TreeNode three = new TreeNode(3); + TreeNode four = new TreeNode(4); + TreeNode five = new TreeNode(5); + TreeNode six = new TreeNode(6); + TreeNode seven = new TreeNode(7); + TreeNode eight = new TreeNode(8); + TreeNode nine = new TreeNode(9); + TreeNode ten = new TreeNode(10); + root.left = null; + root.right = two; + two.left = three; + three.left = four; + four.right = five; + five.right = six; + six.left = seven; + seven.left = eight; + eight.right = nine; + nine.right = ten; + String serializedStr = new SerializeDeserializeBinaryTree().serialize(root); + + TreeNode result = new SerializeDeserializeBinaryTree().deserialize(serializedStr); + } + + // Encodes a tree to a single string. + public String serialize(TreeNode root) { + if (root == null) return null; + List list = new ArrayList<>(); + encode(root, list); + StringBuilder sb = new StringBuilder(); + sb.append(list.get(0)); + for (int i = 1, l = list.size(); i < l; i++) { + sb.append(",").append(list.get(i)); + } + return sb.toString(); + } + + private void encode(TreeNode root, List list) { + if (root == null) list.add(NULL); + else { + list.add(String.valueOf(root.val)); + encode(root.left, list); + encode(root.right, list); + } + } + + // Decodes your encoded data to tree. + public TreeNode deserialize(String data) { + if (data == null || data.isEmpty()) return null; + StringTokenizer st = new StringTokenizer(data, ","); + Queue queue = new ArrayDeque<>(); + while (st.hasMoreTokens()) queue.offer(st.nextToken()); + return decode(queue); + } + + private TreeNode decode(Queue queue) { + String node = queue.poll(); + if (node.equals(NULL)) return null; + TreeNode root = new TreeNode(Integer.parseInt(node)); + root.left = decode(queue); + root.right = decode(queue); + return root; + } +} diff --git a/src/main/java/design/TicTacToe.java b/src/main/java/design/TicTacToe.java new file mode 100644 index 00000000..2f356a77 --- /dev/null +++ b/src/main/java/design/TicTacToe.java @@ -0,0 +1,124 @@ +/* (C) 2024 YourCompanyName */ +package design; + +/** + * Created by gouthamvidyapradhan on 13/05/2017. + * + *

Design a Tic-tac-toe game that is played between two players on a n x n grid. + * + *

You may assume the following rules: + * + *

A move is guaranteed to be valid and is placed on an empty block. Once a winning condition is + * reached, no more moves is allowed. A player who succeeds in placing n of their marks in a + * horizontal, vertical, or diagonal row wins the game. Example: Given n = 3, assume that player 1 + * is "X" and player 2 is "O" in the board. + * + *

TicTacToe toe = new TicTacToe(3); + * + *

toe.move(0, 0, 1); -> Returns 0 (no one wins) |X| | | | | | | // Player 1 makes a move at (0, + * 0). | | | | + * + *

toe.move(0, 2, 2); -> Returns 0 (no one wins) |X| |O| | | | | // Player 2 makes a move at (0, + * 2). | | | | + * + *

toe.move(2, 2, 1); -> Returns 0 (no one wins) |X| |O| | | | | // Player 1 makes a move at (2, + * 2). | | |X| + * + *

toe.move(1, 1, 2); -> Returns 0 (no one wins) |X| |O| | |O| | // Player 2 makes a move at (1, + * 1). | | |X| + * + *

toe.move(2, 0, 1); -> Returns 0 (no one wins) |X| |O| | |O| | // Player 1 makes a move at (2, + * 0). |X| |X| + * + *

toe.move(1, 0, 2); -> Returns 0 (no one wins) |X| |O| |O|O| | // Player 2 makes a move at (1, + * 0). |X| |X| + * + *

toe.move(2, 1, 1); -> Returns 1 (player 1 wins) |X| |O| |O|O| | // Player 1 makes a move at + * (2, 1). |X|X|X| + * + *

Follow up: Could you do better than O(n2) per move() operation? + * + *

Solution: The below solution works in O(1) time complexity. 1. For each player move, keep + * track of count of selection for each row and each column. 2. To keep track of counts in each + * diagonals we need to first know if the move is made on either one of the diagonals. The move is + * made in either of the diagonals if and only if (row = col) AND/OR (col + row = N - 1) 3. As soon + * as the count in any of column, row or diagonal reach N then return the current player as the + * winner, else return 0. + */ +public class TicTacToe { + /** Cell class to keep track of first player and second player row/column count */ + private class Cell { + int player1 = 0, player2 = 0; + } + + Cell[] rows, columns; // Array of row and column cells + private int N, fPD1 = 0, fPD2 = 0, sPD1 = 0, sPD2 = 0; // fPD1 -> first_player_diagonal1 + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + TicTacToe toe = new TicTacToe(3); + System.out.println(toe.move(0, 0, 1)); + System.out.println(toe.move(0, 2, 2)); + System.out.println(toe.move(1, 0, 1)); + System.out.println(toe.move(1, 1, 2)); + System.out.println(toe.move(2, 0, 1)); + } + + /** Initialize your data structure here. */ + public TicTacToe(int n) { + N = n; + rows = new Cell[N]; + columns = new Cell[N]; + } + + /** + * Move and check who wins. + * + * @param row row + * @param col col + * @param player player + * @return integer indicating the winner + */ + public int move(int row, int col, int player) { + switch (player) { + case 1: + increment(rows, row, 1); + increment(columns, col, 1); + if ((col + row) == (N - 1)) fPD2++; + if (row == col) fPD1++; + if (rows[row].player1 == N || columns[col].player1 == N || fPD1 == N || fPD2 == N) return 1; + break; + + case 2: + increment(rows, row, 2); + increment(columns, col, 2); + if ((col + row) == (N - 1)) sPD2++; + if (row == col) sPD1++; + if (rows[row].player2 == N || columns[col].player2 == N || sPD1 == N || sPD2 == N) return 2; + break; + } + return 0; + } + + /** + * Increment row / col count + * + * @param cells array of cells + * @param key row / col key + * @param player Player object + */ + private void increment(Cell[] cells, int key, int player) { + Cell p = cells[key]; + if (p == null) { + p = new Cell(); + cells[key] = p; + } + if (player == 1) p.player1++; + else p.player2++; + } +} diff --git a/src/main/java/design/Trie.java b/src/main/java/design/Trie.java new file mode 100644 index 00000000..e896bb0a --- /dev/null +++ b/src/main/java/design/Trie.java @@ -0,0 +1,90 @@ +/* (C) 2024 YourCompanyName */ +package design; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by Goutham Vidya Pradhan on 7/3/2017. Implement a trie with insert, search, and + * startsWith methods. + * + *

Note: You may assume that all inputs are consist of lowercase letters a-z. + */ +public class Trie { + + private Map map; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + Trie trie = new Trie(); + trie.insert("boxing"); + trie.insert("box"); + System.out.println(trie.search("boxing")); + System.out.println(trie.startsWith("box")); + System.out.println(trie.search("box")); + } + + /** Initialize your data structure here. */ + public Trie() { + map = new HashMap<>(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + if (word != null) { + add(0, word, word.length()); + } + } + + private void add(int i, String word, int length) { + if (i < length) { + char c = word.charAt(i); + Trie subTrie = map.get(c); + if (subTrie == null) { + subTrie = new Trie(); + map.put(c, subTrie); + } + subTrie.add(i + 1, word, length); + } else map.put(null, new Trie()); // use null to indicate end of string + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + if (word != null) { + return search(0, word, word.length()); + } + return false; + } + + private boolean search(int i, String word, int length) { + if (i < length) { + char c = word.charAt(i); + Trie subTrie = map.get(c); + if (subTrie == null) return false; + return subTrie.search(i + 1, word, length); + } + return map.containsKey(null); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + if (prefix != null) { + return startsWith(0, prefix, prefix.length()); + } + return false; + } + + private boolean startsWith(int i, String prefix, int length) { + if (i < length) { + char c = prefix.charAt(i); + Trie subTrie = map.get(c); + if (subTrie == null) return false; + return subTrie.startsWith(i + 1, prefix, length); + } else return true; + } +} diff --git a/src/main/java/design/Twitter.java b/src/main/java/design/Twitter.java new file mode 100644 index 00000000..f5c0e622 --- /dev/null +++ b/src/main/java/design/Twitter.java @@ -0,0 +1,184 @@ +/* (C) 2024 YourCompanyName */ +package design; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 18/03/2017. Design a simplified version of Twitter where users + * can post tweets, follow/unfollow another user and is able to see the 10 most recent tweets in the + * user's news feed. Your design should support the following methods: + * + *

postTweet(userId, tweetId): Compose a new tweet. getNewsFeed(userId): Retrieve the 10 most + * recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who + * the user followed or by the user herself. Tweets must be ordered from most recent to least + * recent. follow(followerId, followeeId): Follower follows a followee. unfollow(followerId, + * followeeId): Follower unfollows a followee. Example: + * + *

Twitter twitter = new Twitter(); + * + *

// User 1 posts a new tweet (id = 5). twitter.postTweet(1, 5); + * + *

// User 1's news feed should return a list with 1 tweet id -> [5]. twitter.getNewsFeed(1); + * + *

// User 1 follows user 2. twitter.follow(1, 2); + * + *

// User 2 posts a new tweet (id = 6). twitter.postTweet(2, 6); + * + *

// User 1's news feed should return a list with 2 tweet ids -> [6, 5]. // Tweet id 6 should + * precede tweet id 5 because it is posted after tweet id 5. twitter.getNewsFeed(1); + * + *

// User 1 unfollows user 2. twitter.unfollow(1, 2); + * + *

// User 1's news feed should return a list with 1 tweet id -> [5], // since user 1 is no + * longer following user 2. twitter.getNewsFeed(1); + */ +public class Twitter { + class User { + int id; + Set follow = new HashSet<>(); + Queue tweets = new ArrayDeque<>(); + + User(int id) { + this.id = id; + } + + public void follow(int id) { + follow.add(id); + } + + public void addTweet(Tweet t) { + if (tweets.size() == 10) { + tweets.poll(); + } + tweets.offer(t); + } + + public void unFollow(int id) { + follow.remove(id); + } + + public Set getFollow() { + return follow; + } + + public Queue getTweets() { + return tweets; + } + } + + class Tweet { + int id; + long time; + + Tweet(int id, long time) { + this.id = id; + this.time = time; + } + } + + private Map userMap; + private Map tweetMap; + private static long tweetCount = 0L; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + Twitter twitter = new Twitter(); + twitter.postTweet(1, 5); + twitter.follow(1, 1); + System.out.println(twitter.getNewsFeed(1)); + /*twitter.follow(2, 1); + System.out.println(twitter.getNewsFeed(2)); + //twitter.unfollow(2, 1); + twitter.postTweet(2, 3); + System.out.println(twitter.getNewsFeed(1)); + System.out.println(twitter.getNewsFeed(2)); + twitter.follow(1, 2); + System.out.println(twitter.getNewsFeed(1)); + twitter.unfollow(2, 1); + System.out.println(twitter.getNewsFeed(2)); + System.out.println(twitter.getNewsFeed(1)); + //twitter.getNewsFeed(2); + */ + } + + /** Initialize your data structure here. */ + public Twitter() { + userMap = new HashMap<>(); + tweetMap = new HashMap<>(); + } + + /** Compose a new tweet. */ + public void postTweet(int userId, int tweetId) { + User user = userMap.get(userId); + if (user == null) { + user = new User(userId); + userMap.put(userId, user); + } + user.addTweet(new Tweet(tweetId, tweetCount++)); + } + + /** + * Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must + * be posted by users who the user followed or by the user herself. Tweets must be ordered from + * most recent to least recent. + */ + public List getNewsFeed(int userId) { + User user = userMap.get(userId); + List result = new ArrayList<>(); + if (user == null) return result; + Set follwers = user.getFollow(); + if (follwers != null) { + List tweets = new ArrayList<>(); + tweets.addAll(user.getTweets()); + for (Integer i : follwers) { + User f = userMap.get(i); + if (f != null) { + tweets.addAll(f.getTweets()); + } + } + Comparator comparator = + new Comparator() { + @Override + public int compare(Tweet o1, Tweet o2) { + return Long.compare(o2.time, o1.time); + } + }; + + Collections.sort(tweets, comparator); + + for (int i = 0; i < 10; i++) { + if (i >= tweets.size()) break; + result.add(tweets.get(i).id); + } + } + return result; + } + + /** Follower follows a followee. If the operation is invalid, it should be a no-op. */ + public void follow(int followerId, int followeeId) { + if (followerId == followeeId) return; + User user = userMap.get(followerId); + if (user == null) user = new User(followerId); + userMap.put(followerId, user); + if (userMap.get(followeeId) != null) { + user.follow(userMap.get(followeeId).id); + } else { + User newUser = new User(followeeId); + userMap.put(followeeId, newUser); + user.follow(userMap.get(followeeId).id); + } + } + + /** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */ + public void unfollow(int followerId, int followeeId) { + User user = userMap.get(followerId); + if (user != null) { + user.unFollow(followeeId); + } + } +} diff --git a/src/main/java/design/WordDictionary.java b/src/main/java/design/WordDictionary.java new file mode 100644 index 00000000..b24468ca --- /dev/null +++ b/src/main/java/design/WordDictionary.java @@ -0,0 +1,117 @@ +/* (C) 2024 YourCompanyName */ +package design; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 09/12/2017. + * + *

Design a data structure that supports the following two operations: + * + *

void addWord(word) bool search(word) search(word) can search a literal word or a regular + * expression string containing only letters a-z or .. A . means it can represent any one letter. + * + *

For example: + * + *

addWord("bad") addWord("dad") addWord("mad") search("pad") -> false search("bad") -> true + * search(".ad") -> true search("b..") -> true Note: You may assume that all words are consist of + * lowercase letters a-z. + * + *

Solution: Implement a simple Trie and perform a search. + */ +public class WordDictionary { + + private Trie trie; + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + WordDictionary wd = new WordDictionary(); + wd.addWord("bad"); + wd.addWord("dad"); + wd.addWord("mad"); + System.out.println(wd.search("pad")); + System.out.println(wd.search("bad")); + System.out.println(wd.search(".ad")); + System.out.println(wd.search("...")); + } + + /** Initialize your data structure here. */ + public WordDictionary() { + this.trie = new Trie(); + } + + /** Adds a word into the data structure. */ + public void addWord(String word) { + this.trie.insert(word); + } + + /** + * Returns if the word is in the data structure. A word could contain the dot character '.' to + * represent any one letter. + */ + public boolean search(String word) { + return this.trie.search(word); + } + + private class Trie { + + private Map map; + + /** Initialize your data structure here. */ + private Trie() { + map = new HashMap<>(); + } + + /** Inserts a word into the trie. */ + private void insert(String word) { + if (word != null) { + add(0, word, word.length()); + } + } + + private void add(int i, String word, int length) { + if (i < length) { + char c = word.charAt(i); + Trie subTrie = map.get(c); + if (subTrie == null) { + subTrie = new Trie(); + map.put(c, subTrie); + } + subTrie.add(i + 1, word, length); + } else map.put(null, new Trie()); // use null to indicate end of string + } + + /** Returns if the word is in the trie. */ + private boolean search(String word) { + if (word != null) { + return search(0, word, word.length()); + } + return false; + } + + private boolean search(int i, String word, int length) { + if (i < length) { + char c = word.charAt(i); + if (c == '.') { + for (Character child : map.keySet()) { + if (child != null) { + Trie subTrie = map.get(child); + if (subTrie.search(i + 1, word, length)) return true; + } + } + return false; + } else { + Trie subTrie = map.get(c); + if (subTrie == null) return false; + return subTrie.search(i + 1, word, length); + } + } + return map.containsKey(null); + } + } +} diff --git a/src/main/java/design/WordFilter.java b/src/main/java/design/WordFilter.java new file mode 100644 index 00000000..23e21b71 --- /dev/null +++ b/src/main/java/design/WordFilter.java @@ -0,0 +1,111 @@ +/* (C) 2024 YourCompanyName */ +package design; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 25/12/2017. Given many words, words[i] has weight i. + * + *

Design a class WordFilter that supports one function, WordFilter.f(String prefix, String + * suffix). It will return the word with given prefix and suffix with maximum weight. If no word + * exists, return -1. + * + *

Examples: Input: WordFilter(["apple"]) WordFilter.f("a", "e") // returns 0 WordFilter.f("b", + * "") // returns -1 Note: words has length in range [1, 15000]. For each test case, up to + * words.length queries WordFilter.f may be made. words[i] has length in range [1, 10]. prefix, + * suffix have lengths in range [0, 10]. words[i] and prefix, suffix queries consist of lowercase + * letters only. + * + *

Solution: Implement a trie to store the dictionary of words. For every word insert all the + * possible suffixes into the trie. Additionally overwrite weight each time a word is inserted. + * Example for a word 'cat' all the possible trie insertions are -> #cat, t#cat, at#cat, cat#cat + * Search for 'suffix#prefix' in the trie and return its weight + */ +public class WordFilter { + + private Trie trie; + private int maxWeight; // max weight possible + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + String[] words = {"apple", "cat", "mat", "mars", "abxcd", "abycd", "apple"}; + WordFilter wf = new WordFilter(words); + System.out.println(wf.f("abx", "")); + } + + public WordFilter(String[] words) { + trie = new Trie(); + trie.weight = -1; + maxWeight = words.length - 1; + for (int i = 0; i < words.length; i++) { + String word = words[i]; + trie.insert("#" + word, i); + for (int j = 0, l = word.length(); j < l; j++) { + trie.insert(word.substring(j, l) + "#" + word, i); + } + } + } + + public int f(String prefix, String suffix) { + if ((suffix == null || suffix.isEmpty()) && (prefix == null || prefix.isEmpty())) { + return maxWeight; + } else if (prefix == null || prefix.isEmpty()) { + return trie.search(suffix + "#"); + } else if (suffix == null || suffix.isEmpty()) { + return trie.search("#" + prefix); + } else { + return trie.search(suffix + "#" + prefix); + } + } + + public static class Trie { + + private Map map; + int weight; + + /** Initialize your data structure here. */ + public Trie() { + map = new HashMap<>(); + } + + /** Inserts a word into the trie. */ + public void insert(String word, int weight) { + if (word != null) { + add(0, word, word.length(), weight); + } + } + + private void add(int i, String word, int length, int weight) { + if (i < length) { + char c = word.charAt(i); + map.putIfAbsent(c, new Trie()); + Trie subTrie = map.get(c); + subTrie.weight = weight; + subTrie.add(i + 1, word, length, weight); + } + } + + /** Returns if the word is in the trie. */ + public int search(String word) { + if (word != null) { + return search(0, word, word.length()); + } + return -1; + } + + private int search(int i, String word, int length) { + if (i < length) { + char c = word.charAt(i); + Trie subTrie = map.get(c); + if (subTrie == null) return -1; + return subTrie.search(i + 1, word, length); + } + return this.weight; + } + } +} diff --git a/src/main/java/divide_and_conquer/KthLargestElementInAnArray.java b/src/main/java/divide_and_conquer/KthLargestElementInAnArray.java new file mode 100644 index 00000000..d87be858 --- /dev/null +++ b/src/main/java/divide_and_conquer/KthLargestElementInAnArray.java @@ -0,0 +1,53 @@ +/* (C) 2024 YourCompanyName */ +package divide_and_conquer; + +/** + * Created by gouthamvidyapradhan on 09/03/2017. Find the kth largest element in an unsorted array. + * Note that it is the kth largest element in the sorted order, not the kth distinct element. + * + *

For example, Given [3,2,1,5,6,4] and k = 2, return 5. + * + *

Note: You may assume k is always valid, 1 ≤ k ≤ array's length. + */ +public class KthLargestElementInAnArray { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] nums = {3, 2, 1, 5, 6, 4}; + + System.out.println(new KthLargestElementInAnArray().findKthLargest(nums, 6)); + } + + private int findKthLargest(int[] nums, int k) { + return solve(nums, 0, nums.length - 1, k); + } + + private int solve(int[] nums, int pIndex, int end, int k) { + int pivot = nums[end]; + int temp; + int start = pIndex; + for (int i = pIndex; i < end; i++) { + if (nums[i] <= pivot) { + temp = nums[i]; + nums[i] = nums[pIndex]; + nums[pIndex] = temp; + pIndex += 1; + } + } + temp = nums[pIndex]; + nums[pIndex] = nums[end]; + nums[end] = temp; + + int pos = (end - pIndex) + 1; + if (pos == k) return nums[pIndex]; + else if (pos > k) { + return solve(nums, pIndex + 1, end, k); + } else { + return solve(nums, start, pIndex - 1, k - pos); + } + } +} diff --git a/src/main/java/divide_and_conquer/MyCalendarII.java b/src/main/java/divide_and_conquer/MyCalendarII.java new file mode 100644 index 00000000..45462d50 --- /dev/null +++ b/src/main/java/divide_and_conquer/MyCalendarII.java @@ -0,0 +1,99 @@ +/* (C) 2024 YourCompanyName */ +package divide_and_conquer; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 02/11/2019 Implement a MyCalendarTwo class to store your + * events. A new event can be added if adding the event will not cause a triple booking. + * + *

Your class will have one method, book(int start, int end). Formally, this represents a booking + * on the half open interval [start, end), the range of real numbers x such that start <= x < end. + * + *

A triple booking happens when three events have some non-empty intersection (ie., there is + * some time that is common to all 3 events.) + * + *

For each call to the method MyCalendar.book, return true if the event can be added to the + * calendar successfully without causing a triple booking. Otherwise, return false and do not add + * the event to the calendar. + * + *

Your class will be called like this: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, + * end) Example 1: + * + *

MyCalendar(); MyCalendar.book(10, 20); // returns true MyCalendar.book(50, 60); // returns + * true MyCalendar.book(10, 40); // returns true MyCalendar.book(5, 15); // returns false + * MyCalendar.book(5, 10); // returns true MyCalendar.book(25, 55); // returns true Explanation: The + * first two events can be booked. The third event can be double booked. The fourth event (5, 15) + * can't be booked, because it would result in a triple booking. The fifth event (5, 10) can be + * booked, as it does not use time 10 which is already double booked. The sixth event (25, 55) can + * be booked, as the time in [25, 40) will be double booked with the third event; the time [40, 50) + * will be single booked, and the time [50, 55) will be double booked with the second event. + * + *

Note: + * + *

The number of calls to MyCalendar.book per test case will be at most 1000. In calls to + * MyCalendar.book(start, end), start and end are integers in the range [0, 10^9]. + */ +public class MyCalendarII { + public static void main(String[] args) { + MyCalendarII t = new MyCalendarII(); + System.out.println(t.book(20, 27)); + System.out.println(t.book(27, 36)); + System.out.println(t.book(27, 36)); + System.out.println(t.book(24, 33)); + } + + private class Pair { + int a, b, index; + + Pair(int a, int b, int index) { + this.a = a; + this.b = b; + this.index = index; + } + } + + TreeSet treeSet; + int count; + + public MyCalendarII() { + count = 0; + treeSet = + new TreeSet<>( + (o1, o2) -> { + int r = Integer.compare(o1.a, o2.a); + if (r == 0) { + int r2 = Integer.compare(o1.b, o2.b); + if (r2 == 0) { + return Integer.compare(o1.index, o2.index); + } else return r2; + } + return r; + }); + } + + public boolean book(int start, int end) { + Pair range = new Pair(start, end, count++); + Iterator ascending = treeSet.iterator(); + Pair prev = null; + while (ascending.hasNext()) { + Pair cur = ascending.next(); + if (prev != null) { + if ((range.a >= prev.a && range.a < prev.b) && (range.a >= cur.a && range.a < cur.b)) { + return false; + } else if ((prev.a >= range.a && prev.a < range.b) + && (cur.a >= prev.a && cur.a < Math.min(prev.b, range.b))) { + return false; + } else if ((range.a >= prev.a && range.a < range.b) + && (cur.a >= range.a && cur.a < Math.min(prev.b, range.b))) { + return false; + } + } + if ((range.a >= cur.a && range.a < cur.b) || (cur.a >= range.a && cur.a < range.b)) { + prev = cur; + } + } + treeSet.add(range); + return true; + } +} diff --git a/src/main/java/divide_and_conquer/ReversePairs.java b/src/main/java/divide_and_conquer/ReversePairs.java new file mode 100644 index 00000000..0706ccf8 --- /dev/null +++ b/src/main/java/divide_and_conquer/ReversePairs.java @@ -0,0 +1,118 @@ +/* (C) 2024 YourCompanyName */ +package divide_and_conquer; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 30/06/2018. Given an array nums, we call (i, j) an important + * reverse pair if i < j and nums[i] > 2*nums[j]. + * + *

You need to return the number of important reverse pairs in the given array. + * + *

Example1: + * + *

Input: [1,3,2,3,1] Output: 2 Example2: + * + *

Input: [2,4,3,5,1] Output: 3 Note: The length of the given array will not exceed 50,000. All + * the numbers in the input array are in the range of 32-bit integer. + * + *

Solution: O(n log n): Example: 1,3,2,3,1 1. Sort the array in non-increasing order (if there + * is a collision, sort by lower index). So the sorted array will be (3, 3, 2, 1, 1) having indexes + * (1, 3, 2, 0, 4) 2. Maintain a prefix sum of index (starting from 1) for the sorted array. So, + * prefix sum for the above sorted array is (1, 2, 3, 4, 5) Now, the basic idea is to iterate from + * index n - 1 to 0 in the original array and for each element calculate the element p (num[i] x 2) + * and find the upper bound of the element p in sorted array which is 3 at index 1 in this case and + * add prefix sum of the index 1 to the result. So the result now becomes 2. + * + *

To maintain a prefix sum and update it efficiently we have to use a BIT or Fenwick tree. + */ +public class ReversePairs { + + class Pair { + int i, n; + + Pair(int i, int n) { + this.i = i; + this.n = n; + } + + int getN() { + return n; + } + + int getI() { + return i; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {2, 4, 3, 5, 1}; + System.out.println(new ReversePairs().reversePairs(A)); + } + + public int reversePairs(int[] nums) { + List list = new ArrayList<>(); + Ftree ft = new Ftree(nums.length); + for (int i = 0; i < nums.length; i++) { + list.add(new Pair(i, nums[i])); + ft.update(i, 1); + } + Collections.sort(list, (Comparator.comparing(Pair::getN).reversed().thenComparing(Pair::getI))); + int[] indexMap = new int[nums.length]; + for (int i = 0, l = list.size(); i < l; i++) { + indexMap[list.get(i).getI()] = i; + } + int ans = 0; + for (int i = nums.length - 1; i >= 0; i--) { + ft.update(indexMap[i], -1); + int index = binarySearch(list, (long) nums[i] * 2); + if (index > -1) { + ans += ft.getRangeSum(index); + } + } + return ans; + } + + private int binarySearch(List list, long n) { + int l = 0, h = list.size() - 1; + int ans = -1; + while (l <= h) { + int m = l + (h - l) / 2; + if (list.get(m).n > n) { + ans = m; + l = m + 1; + } else { + h = m - 1; + } + } + return ans; + } + + private class Ftree { + private int[] a; + + Ftree(int n) { + a = new int[n + 1]; + } + + void update(int p, int v) { + for (int i = p + 1; i < a.length; i += (i & (-i))) { + a[i] += v; + } + } + + int getRangeSum(int p) { + int sum = 0; + for (int i = p + 1; i > 0; i -= (i & (-i))) { + sum += a[i]; + } + return sum; + } + } +} diff --git a/src/main/java/divide_and_conquer/ReversePairsII.java b/src/main/java/divide_and_conquer/ReversePairsII.java new file mode 100644 index 00000000..fb79020b --- /dev/null +++ b/src/main/java/divide_and_conquer/ReversePairsII.java @@ -0,0 +1,87 @@ +/* (C) 2024 YourCompanyName */ +package divide_and_conquer; + +/** + * Created by gouthamvidyapradhan on 01/08/2019 Given an array nums, we call (i, j) an important + * reverse pair if i < j and nums[i] > 2*nums[j]. + * + *

You need to return the number of important reverse pairs in the given array. + * + *

Example1: + * + *

Input: [1,3,2,3,1] Output: 2 Example2: + * + *

Input: [2,4,3,5,1] Output: 3 Note: The length of the given array will not exceed 50,000. All + * the numbers in the input array are in the range of 32-bit integer. + * + *

Solution: O(N log N) Given two sorted arrays A[] and B[] it is quite easy to see for every + * element i in A, how many elements in A have a value > 2 * B[j] using binary search (also possible + * using two pointers) - using this idea we can implement standard merge sort algorithm and for + * every sorted pairs A[] and B[] before we merge we can total number of elements in A which are > 2 + * x B[i] + */ +public class ReversePairsII { + public static void main(String[] args) { + int[] A = {2, 4, 3, 5, 1}; + System.out.println(new ReversePairsII().reversePairs(A)); + } + + int answer = 0; + + public int reversePairs(int[] nums) { + mergeSort(nums, 0, nums.length - 1); + return answer; + } + + private int[] mergeSort(int[] num, int l, int h) { + if (l < h) { + int m = l + (h - l) / 2; + int[] left = mergeSort(num, l, m); + int[] right = mergeSort(num, m + 1, h); + return merge(left, right); + } else if (l == h) { + return new int[] {num[l]}; + } else { + return new int[] {}; + } + } + + private int[] merge(int[] A, int[] B) { + for (int i = 0; i < B.length; i++) { + int num = B[i]; + int l = 0, h = A.length; + int index = -1; + while (l < h) { + int m = l + (h - l) / 2; + if ((long) A[m] > (2 * (long) num)) { + index = m; + h = m; + } else { + l = m + 1; + } + } + if (index > -1) { + answer += ((A.length - index)); + } + } + int[] C = new int[A.length + B.length]; + int k = 0; + int i = 0, j = 0; + for (; i < A.length && j < B.length; ) { + if (A[i] < B[j]) { + C[k++] = A[i]; + i++; + } else { + C[k++] = B[j]; + j++; + } + } + while (i < A.length) { + C[k++] = A[i++]; + } + while (j < B.length) { + C[k++] = B[j++]; + } + return C; + } +} diff --git a/src/main/java/divide_and_conquer/SearchA2DMatrix.java b/src/main/java/divide_and_conquer/SearchA2DMatrix.java new file mode 100644 index 00000000..5234afae --- /dev/null +++ b/src/main/java/divide_and_conquer/SearchA2DMatrix.java @@ -0,0 +1,49 @@ +/* (C) 2024 YourCompanyName */ +package divide_and_conquer; + +/** + * Created by gouthamvidyapradhan on 09/03/2017. Write an efficient algorithm that searches for a + * value in an m x n matrix. This matrix has the following properties: + * + *

Integers in each row are sorted in ascending from left to right. Integers in each column are + * sorted in ascending from top to bottom. For example, + * + *

Consider the following matrix: + * + *

[ [1, 4, 7, 11, 15], [2, 5, 8, 12, 19], [3, 6, 9, 16, 22], [10, 13, 14, 17, 24], [18, 21, 23, + * 26, 30] ] Given target = 5, return true. + * + *

Given target = 20, return false. + */ +public class SearchA2DMatrix { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] matrix = { + {1, 3, 5, 7, 9}, // 1, 3, 5, 7, 9 + {2, 4, 6, 8, 10}, // 2, 4, 6, 8, 10 + {11, 13, 15, 17, 19}, // 11, 15, 17, 18, 19 + {12, 14, 16, 18, 20}, // 13, 20, 21, 22, 23 + {21, 22, 23, 24, 25} // 14, 25, 26, 27, 28 + }; + + System.out.println(new SearchA2DMatrix().searchMatrix(matrix, 11)); + } + + private boolean searchMatrix(int[][] matrix, int target) { + if (matrix.length == 0) return false; + int M = matrix.length; + int N = matrix[0].length; + int r = 0, c = N - 1; + while (r < M && c >= 0) { + if (matrix[r][c] == target) return true; + else if (target < matrix[r][c]) --c; + else if (target > matrix[r][c]) r++; + } + return false; + } +} diff --git a/src/main/java/divide_and_conquer/TwentyFourGame.java b/src/main/java/divide_and_conquer/TwentyFourGame.java new file mode 100644 index 00000000..a9c5535a --- /dev/null +++ b/src/main/java/divide_and_conquer/TwentyFourGame.java @@ -0,0 +1,113 @@ +/* (C) 2024 YourCompanyName */ +package divide_and_conquer; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 18/05/2019 You have 4 cards each containing a number from 1 to + * 9. You need to judge whether they could operated through *, /, +, -, (, ) to get the value of 24. + * + *

Example 1: Input: [4, 1, 8, 7] Output: True Explanation: (8-4) * (7-1) = 24 Example 2: Input: + * [1, 2, 1, 2] Output: False Note: The division operator / represents real division, not integer + * division. For example, 4 / (1 - 2/3) = 12. Every operation done is between two numbers. In + * particular, we cannot use - as a unary operator. For example, with [1, 1, 1, 1] as input, the + * expression -1 - 1 - 1 - 1 is not allowed. You cannot concatenate numbers together. For example, + * if the input is [1, 2, 1, 2], we cannot write this as 12 + 12. + * + *

Solution O(1) Generate all permutation of a given 4 digit number and for each permutation + * split the number into two parts with left and right (at various possible split points). Now + * perform all possible operations(+, -, * and /) for each left and right and check if any of the + * operation results in 24 + */ +public class TwentyFourGame { + + public static void main(String[] args) { + int[] A = {4, 7, 7, 7}; + System.out.println(new TwentyFourGame().judgePoint24(A)); + } + + class Fraction { + int n, d; + + Fraction(int n, int d) { + this.n = n; + this.d = d; + } + } + + public boolean judgePoint24(int[] nums) { + List result = new ArrayList<>(); + permute(0, nums, result); + for (int[] A : result) { + List list = generate(0, 3, A); + for (Fraction f : list) { + if ((f.d != 0) && (f.n / f.d) == 24 && (f.n % f.d) == 0) return true; + } + } + return false; + } + + private void permute(int i, int[] nums, List result) { + if (i >= nums.length) { + result.add(Arrays.copyOf(nums, 4)); + } else { + for (int j = i; j < nums.length; j++) { + swap(i, j, nums); + permute(i + 1, nums, result); + swap(i, j, nums); + } + } + } + + private void swap(int i, int j, int[] nums) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } + + private List generate(int l, int r, int[] nums) { + if (l > r) { + return new ArrayList<>(); + } else if (l == r) { + return Arrays.asList(new Fraction(nums[l], 1)); + } else { + List result = new ArrayList<>(); + for (int i = l; i < r; i++) { + for (int j = l; j <= i; j++) { + List left = generate(l, j, nums); + List right = generate(j + 1, r, nums); + if (right.isEmpty()) { + result.addAll(left); + } else if (left.isEmpty()) { + result.addAll(right); + } else { + for (Fraction lF : left) { + for (Fraction rF : right) { + int n = (lF.n * rF.d + rF.n * lF.d); + int d = (lF.d * rF.d); + Fraction sum = new Fraction(n, d); + + n = (lF.n * rF.d - (rF.n * lF.d)); + d = (lF.d * rF.d); + Fraction diff = new Fraction(n, d); + + n = (lF.n * rF.n); + d = (lF.d * rF.d); + Fraction prod = new Fraction(n, d); + + n = (lF.n * rF.d); + d = (lF.d * rF.n); + Fraction div = new Fraction(n, d); + result.add(sum); + result.add(diff); + result.add(prod); + result.add(div); + } + } + } + } + } + return result; + } + } +} diff --git a/src/main/java/dynamic_programming/BestTimeToBuyAndSellStockIII.java b/src/main/java/dynamic_programming/BestTimeToBuyAndSellStockIII.java new file mode 100644 index 00000000..9e03a07e --- /dev/null +++ b/src/main/java/dynamic_programming/BestTimeToBuyAndSellStockIII.java @@ -0,0 +1,48 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 15/02/2018. Say you have an array for which the ith element is + * the price of a given stock on day i. + * + *

Design an algorithm to find the maximum profit. You may complete at most two transactions. + * + *

Note: You may not engage in multiple transactions at the same time (ie, you must sell the + * stock before you buy again). + * + *

Solution: O(n): In the first iteration calculate the max profit that can be made by one buy + * and sell by iterating from right to left and saving this in a dp array and maintaining a max + * value. In the second iteration starting from left to right maintain a min value and calculate the + * max profit that can be made by one buy and sell by taking the difference of current with min and + * calculate the total profit of two transactions by summing up the current profit made with the + * profit in dp array. + */ +public class BestTimeToBuyAndSellStockIII { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) throws Exception { + int[] A = {10, 9, 8, 7}; + System.out.println(new BestTimeToBuyAndSellStockIII().maxProfit(A)); + } + + public int maxProfit(int[] prices) { + if (prices.length == 0 || prices.length == 1) return 0; + int[] dp = new int[prices.length]; + int min = prices[0]; + int max = prices[prices.length - 1]; + for (int i = prices.length - 2; i >= 0; i--) { + dp[i] = Math.max(max - prices[i], dp[i + 1]); + max = Math.max(max, prices[i]); + } + max = Integer.MIN_VALUE; + for (int i = 0; i < prices.length; i++) { + max = Math.max(max, prices[i] - min + dp[i]); + min = Math.min(min, prices[i]); + } + return max; + } +} diff --git a/src/main/java/dynamic_programming/BestTimeToBuyAndSellStocks.java b/src/main/java/dynamic_programming/BestTimeToBuyAndSellStocks.java new file mode 100644 index 00000000..5945831f --- /dev/null +++ b/src/main/java/dynamic_programming/BestTimeToBuyAndSellStocks.java @@ -0,0 +1,43 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 17/03/2017. Say you have an array for which the ith element is + * the price of a given stock on day i. + * + *

If you were only permitted to complete at most one transaction (ie, buy one and sell one share + * of the stock), design an algorithm to find the maximum profit. + * + *

Example 1: Input: [7, 1, 5, 3, 6, 4] Output: 5 + * + *

max. difference = 6-1 = 5 (not 7-1 = 6, as selling price needs to be larger than buying price) + * Example 2: Input: [7, 6, 4, 3, 1] Output: 0 + * + *

In this case, no transaction is done, i.e. max profit = 0. + */ +public class BestTimeToBuyAndSellStocks { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] prices = {1, 1, 1, 1, 1}; + System.out.println(new BestTimeToBuyAndSellStocks().maxProfit(prices)); + } + + public int maxProfit(int[] prices) { + if (prices.length == 0) return 0; + int[] max = new int[prices.length]; + max[prices.length - 1] = prices[prices.length - 1]; + for (int i = prices.length - 2; i >= 0; i--) { + max[i] = Math.max(prices[i], max[i + 1]); + } + int result = Integer.MIN_VALUE; + for (int i = 0, l = max.length; i < l; i++) { + result = Math.max(result, max[i] - prices[i]); + } + return result; + } +} diff --git a/src/main/java/dynamic_programming/BestTimeToBuyAndSellStocksWithFee.java b/src/main/java/dynamic_programming/BestTimeToBuyAndSellStocksWithFee.java new file mode 100644 index 00000000..ba4b3100 --- /dev/null +++ b/src/main/java/dynamic_programming/BestTimeToBuyAndSellStocksWithFee.java @@ -0,0 +1,46 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 14/12/2017. Your are given an array of integers prices, for + * which the i-th element is the price of a given stock on day i; and a non-negative integer fee + * representing a transaction fee. + * + *

You may complete as many transactions as you like, but you need to pay the transaction fee for + * each transaction. You may not buy more than 1 share of a stock at a time (ie. you must sell the + * stock share before you buy again.) + * + *

Return the maximum profit you can make. + * + *

Example 1: Input: prices = [1, 3, 2, 8, 4, 9], fee = 2 Output: 8 Explanation: The maximum + * profit can be achieved by: Buying at prices[0] = 1 Selling at prices[3] = 8 Buying at prices[4] = + * 4 Selling at prices[5] = 9 The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8. Note: + * + *

0 < prices.length <= 50000. 0 < prices[i] < 50000. 0 <= fee < 50000. + * + *

Solution: O(n) for every step either you can buy stock or sell. Maintain two variables 'cash' + * to save max value if you had sold the stock at current price and 'stock' to save max value if you + * had purchased the stock at current price. Return max cash + */ +public class BestTimeToBuyAndSellStocksWithFee { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 3, 2, 8, 4, 9}; + System.out.println(new BestTimeToBuyAndSellStocksWithFee().maxProfit(A, 2)); + } + + public int maxProfit(int[] prices, int fee) { + int cash = 0, stock = -prices[0]; + for (int i = 1; i < prices.length; i++) { + cash = Math.max(cash, prices[i] + stock - fee); + stock = Math.max(stock, cash - prices[i]); + } + return cash; + } +} diff --git a/src/main/java/dynamic_programming/BombEnemy.java b/src/main/java/dynamic_programming/BombEnemy.java new file mode 100644 index 00000000..ece7d3d1 --- /dev/null +++ b/src/main/java/dynamic_programming/BombEnemy.java @@ -0,0 +1,73 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 25/01/2020 Given a 2D grid, each cell is either a wall 'W', an + * enemy 'E' or empty '0' (the number zero), return the maximum enemies you can kill using one bomb. + * The bomb kills all the enemies in the same row and column from the planted point until it hits + * the wall since the wall is too strong to be destroyed. Note: You can only put the bomb at an + * empty cell. + * + *

Example: + * + *

Input: [["0","E","0","0"],["E","0","W","E"],["0","E","0","0"]] Output: 3 Explanation: For the + * given grid, + * + *

0 E 0 0 E 0 W E 0 E 0 0 + * + *

Placing a bomb at (1,1) kills 3 enemies. + */ +public class BombEnemy { + public static void main(String[] args) { + char[][] grid = {{'0', 'E', '0', '0'}, {'E', '0', 'W', 'E'}, {'0', 'E', '0', '0'}}; + System.out.println(new BombEnemy().maxKilledEnemies(grid)); + } + + public int maxKilledEnemies(char[][] grid) { + int[][] DP1 = new int[grid.length][grid[0].length]; + int[][] DP2 = new int[grid.length][grid[0].length]; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 'E') { + DP1[i][j] = 1; + } + if (grid[i][j] != 'W') { + if (j - 1 >= 0) { + DP1[i][j] += DP1[i][j - 1]; + } + if (i - 1 >= 0) { + DP1[i][j] += DP1[i - 1][j]; + } + } + } + } + + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if (grid[i][j] == 'E') { + DP2[i][j] = 1; + } + if (grid[i][j] != 'W') { + if (j + 1 < grid[0].length) { + DP2[i][j] += DP2[i][j + 1]; + } + if (i + 1 < grid.length) { + DP2[i][j] += DP2[i + 1][j]; + } + } + } + } + + int max = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == '0') { + max = Math.max(max, DP1[i][j] + DP2[i][j]); + } + } + } + return max; + } +} diff --git a/src/main/java/dynamic_programming/BurstBalloons.java b/src/main/java/dynamic_programming/BurstBalloons.java new file mode 100644 index 00000000..7a7db0f3 --- /dev/null +++ b/src/main/java/dynamic_programming/BurstBalloons.java @@ -0,0 +1,88 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 02/01/2018. Given n balloons, indexed from 0 to n-1. Each + * balloon is painted with a number on it represented by array nums. You are asked to burst all the + * balloons. If the you burst balloon i you will get nums[left] * nums[i] * nums[right] coins. Here + * left and right are adjacent indices of i. After the burst, the left and right then becomes + * adjacent. + * + *

Find the maximum coins you can collect by bursting the balloons wisely. + * + *

Note: (1) You may imagine nums[-1] = nums[n] = 1. They are not real therefore you can not + * burst them. (2) 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100 + * + *

Example: + * + *

Given [3, 1, 5, 8] + * + *

Return 167 + * + *

nums = [3,1,5,8] --> [3,5,8] --> [3,8] --> [8] --> [] coins = 3*1*5 + 3*5*8 + 1*3*8 + 1*8*1 = + * 167 + * + *

Solution: O(N ^ 3) The recursive top-down dp memorization solution is based on the idea where + * each balloon is considered as the last balloon to be burst. For the above example 1,3,1,5,8,1 (1 + * included at either end to indicate boundary) each balloon starting from 3 until 8 is chosen each + * time as a the last balloon to be burst using the boundary 1 on either side. So, for the first + * iteration the result is calculated as 3*1(left boundary)*1(right boundary) + dp(1, 3) + * (left-sub-problem having 1 and 3 as the boundary) + dp(3, 1) (right-sub-problem having 3 and 1 as + * the boundary) + */ +public class BurstBalloons { + private int[][] dp; + private int[] N; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {3, 1, 5, 8}; + System.out.println(new BurstBalloons().maxCoins(A)); + } + + public int maxCoins(int[] nums) { + N = new int[nums.length + 2]; + N[0] = N[N.length - 1] = 1; // boundary + for (int i = 0; i < nums.length; i++) { + N[i + 1] = nums[i]; + } + int[][] DP = new int[N.length][N.length]; + for (int r = 2; r < N.length; r++) { + for (int i = 0; i < N.length; i++) { + int j = i + r; + if (j < N.length) { + int max = Integer.MIN_VALUE; + for (int t = i + 1; t < j; t++) { + max = Math.max(max, N[t] * N[i] * N[j] + DP[t][j] + DP[i][t]); + } + DP[i][j] = max; + } + } + } + return DP[0][N.length - 1]; + /* for (int i = 0; i < nums.length; i++) { + N[i + 1] = nums[i]; + } + dp = new int[N.length][N.length]; + for (int[] aDp : dp) { + Arrays.fill(aDp, -1); + }*/ + // return dp(0, N.length - 1); + } + + private int dp(int l, int r) { + if (l + 1 == r) return 0; + if (dp[l][r] != -1) return dp[l][r]; + int result = 0; + for (int i = l + 1; i < r; i++) { + result = Math.max(result, N[i] * N[l] * N[r] + dp(l, i) + dp(i, r)); + } + dp[l][r] = result; + return dp[l][r]; + } +} diff --git a/src/main/java/dynamic_programming/CanIWin.java b/src/main/java/dynamic_programming/CanIWin.java new file mode 100644 index 00000000..183b85aa --- /dev/null +++ b/src/main/java/dynamic_programming/CanIWin.java @@ -0,0 +1,78 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 04/07/2017. In the "100 game," two players take turns adding, + * to a running total, any integer from 1..10. The player who first causes the running total to + * reach or exceed 100 wins. + * + *

What if we change the game so that players cannot re-use integers? + * + *

For example, two players might take turns drawing from a common pool of numbers of 1..15 + * without replacement until they reach a total >= 100. + * + *

Given an integer maxChoosableInteger and another integer desiredTotal, determine if the first + * player to move can force a win, assuming both players play optimally. + * + *

You can always assume that maxChoosableInteger will not be larger than 20 and desiredTotal + * will not be larger than 300. + * + *

Example + * + *

Input: maxChoosableInteger = 10 desiredTotal = 11 + * + *

Output: false + * + *

Explanation: No matter which integer the first player choose, the first player will lose. The + * first player can choose an integer from 1 up to 10. If the first player choose 1, the second + * player can only choose integers from 2 up to 10. The second player will win by choosing 10 and + * get a total = 11, which is >= desiredTotal. Same with other integers chosen by the first player, + * the second player will always win. + */ +public class CanIWin { + + private Map> DP; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new CanIWin().canIWin(5, 15)); + } + + public boolean canIWin(int maxChoosableInteger, int desiredTotal) { + int sum = 0; + for (int i = 1; i <= maxChoosableInteger; i++) sum += i; + if (desiredTotal == 0) return true; + else if (desiredTotal > sum) + return false; // if the desiredTotal exceeds the max possible sum return false; + DP = new HashMap<>(); + DP.put(true, new HashMap<>()); + DP.put(false, new HashMap<>()); + return dp(0, maxChoosableInteger, desiredTotal, true, 0); + } + + private boolean dp(int state, int M, int D, boolean P, int sum) { + if (sum >= D) return false; + Map map = DP.get(P); + if (map.containsKey(state)) return map.get(state); + else { + map.put(state, false); + for (int i = 0; i < M; i++) { + if ((state & (1 << i)) == 0) { + if (!dp(state | (1 << i), M, D, !P, sum + i + 1)) { + map.put(state, true); + break; + } + } + } + } + return map.get(state); + } +} diff --git a/src/main/java/dynamic_programming/CatAndMouse.java b/src/main/java/dynamic_programming/CatAndMouse.java new file mode 100644 index 00000000..7d8e847d --- /dev/null +++ b/src/main/java/dynamic_programming/CatAndMouse.java @@ -0,0 +1,153 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 03/03/2019 + * + *

A game on an undirected graph is played by two players, Mouse and Cat, who alternate turns. + * + *

The graph is given as follows: graph[a] is a list of all nodes b such that ab is an edge of + * the graph. + * + *

Mouse starts at node 1 and goes first, Cat starts at node 2 and goes second, and there is a + * Hole at node 0. + * + *

During each player's turn, they must travel along one edge of the graph that meets where they + * are. For example, if the Mouse is at node 1, it must travel to any node in graph[1]. + * + *

Additionally, it is not allowed for the Cat to travel to the Hole (node 0.) + * + *

Then, the game can end in 3 ways: + * + *

If ever the Cat occupies the same node as the Mouse, the Cat wins. If ever the Mouse reaches + * the Hole, the Mouse wins. If ever a position is repeated (ie. the players are in the same + * position as a previous turn, and it is the same player's turn to move), the game is a draw. Given + * a graph, and assuming both players play optimally, return 1 if the game is won by Mouse, 2 if the + * game is won by Cat, and 0 if the game is a draw. + * + *

Example 1: + * + *

Input: [[2,5],[3],[0,4,5],[1,4,5],[2,3],[0,2,3]] Output: 0 Explanation: 4---3---1 | | 2---5 \ + * / 0 + * + *

Note: + * + *

3 <= graph.length <= 50 It is guaranteed that graph[1] is non-empty. It is guaranteed that + * graph[2] contains a non-zero element. + * + *

Solution: Each combination of mouse, cat and turn for a state (m, c, p). Transition between + * different states form a state graph - start to color each state with either MOUSE, CAT or a DRAW + * based on who wins this state. Perform a bottom up dp inorder to arrive at the answer. + */ +public class CatAndMouse { + + private final int CAT = 2, MOUSE = 1, DRAW = 0, PLAYER_CAT = 1, PLAYER_MOUSE = 0; + private Queue queue = new ArrayDeque<>(); + + class State { + int catPos, mPos, player, color; + + State(int mPos, int catPos, int player, int color) { + this.catPos = catPos; + this.mPos = mPos; + this.player = player; + this.color = color; + } + } + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[][] graph = {{2, 5}, {3}, {0, 4, 5}, {1, 4, 5}, {2, 3}, {0, 2, 3}}; + System.out.println(new CatAndMouse().catMouseGame(graph)); + } + + public int catMouseGame(int[][] graph) { + int[][][] color = new int[graph.length][graph.length][2]; + int[][][] degree = new int[graph.length][graph.length][2]; + + for (int i = 1; i < graph.length; i++) { + for (int p = 0; p < 2; p++) { + color[0][i][p] = MOUSE; + queue.offer(new State(0, i, p, MOUSE)); + color[i][i][p] = CAT; + queue.offer(new State(i, i, p, CAT)); + } + } + + for (int m = 0; m < graph.length; m++) { + for (int c = 1; c < graph.length; c++) { + degree[m][c][0] = graph[m].length; + degree[m][c][1] = graph[c].length; + for (int v : graph[c]) { + if (v == 0) { + degree[m][c][1]--; + break; + } + } + } + } + + while (!queue.isEmpty()) { + State current = queue.poll(); + List parents = getParents(graph, current, color); + if (color[current.mPos][current.catPos][current.player] == CAT) { + enqueue(queue, parents, PLAYER_CAT, CAT, color, degree); + } else { + enqueue(queue, parents, PLAYER_MOUSE, MOUSE, color, degree); + } + } + return color[1][2][0]; + } + + private void enqueue( + Queue queue, + List parents, + int player, + int col, + int[][][] color, + int[][][] degree) { + for (State parent : parents) { + if (color[parent.mPos][parent.catPos][parent.player] == DRAW) { + if (parent.player == player) { + color[parent.mPos][parent.catPos][parent.player] = col; + queue.offer(new State(parent.mPos, parent.catPos, parent.player, col)); + } else { + int currDegree = --degree[parent.mPos][parent.catPos][parent.player]; + if (currDegree == 0) { + color[parent.mPos][parent.catPos][parent.player] = col; + queue.offer(new State(parent.mPos, parent.catPos, parent.player, col)); + } + } + } + } + } + + private List getParents(int[][] graph, State current, int[][][] color) { + int player = current.player; + int[] positions; + List list = new ArrayList<>(); + if (player == PLAYER_MOUSE) { + positions = graph[current.catPos]; + for (int pos : positions) { + if (pos == 0) continue; + if (color[current.mPos][pos][PLAYER_CAT] == DRAW) { + list.add(new State(current.mPos, pos, PLAYER_CAT, DRAW)); + } + } + } else { + positions = graph[current.mPos]; + for (int pos : positions) { + if (color[pos][current.catPos][PLAYER_MOUSE] == DRAW) { + list.add(new State(pos, current.catPos, PLAYER_MOUSE, DRAW)); + } + } + } + return list; + } +} diff --git a/src/main/java/dynamic_programming/CherryPickup.java b/src/main/java/dynamic_programming/CherryPickup.java new file mode 100644 index 00000000..082c03a6 --- /dev/null +++ b/src/main/java/dynamic_programming/CherryPickup.java @@ -0,0 +1,80 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 27/01/2018. In a N x N grid representing a field of cherries, + * each cell is one of three possible integers. + * + *

0 means the cell is empty, so you can pass through; 1 means the cell contains a cherry, that + * you can pick up and pass through; -1 means the cell contains a thorn that blocks your way. Your + * task is to collect maximum number of cherries possible by following the rules below: + * + *

Starting at the position (0, 0) and reaching (N-1, N-1) by moving right or down through valid + * path cells (cells with value 0 or 1); After reaching (N-1, N-1), returning to (0, 0) by moving + * left or up through valid path cells; When passing through a path cell containing a cherry, you + * pick it up and the cell becomes an empty cell (0); If there is no valid path between (0, 0) and + * (N-1, N-1), then no cherries can be collected. Example 1: Input: grid = [[0, 1, -1], [1, 0, -1], + * [1, 1, 1]] Output: 5 Explanation: The player started at (0, 0) and went down, down, right right + * to reach (2, 2). 4 cherries were picked up during this single trip, and the matrix becomes + * [[0,1,-1],[0,0,-1],[0,0,0]]. Then, the player went left, up, up, left to return home, picking up + * one more cherry. The total number of cherries picked up is 5, and this is the maximum possible. + * Note: + * + *

grid is an N by N 2D array, with 1 <= N <= 50. Each grid[i][j] is an integer in the set {-1, + * 0, 1}. It is guaranteed that grid[0][0] and grid[N-1][N-1] are not -1. + * + *

Solution O(N ^ 3) time-complexity. Traversing from (0, 0) -> (n - 1, n - 1) or the other way + * around both are the same. The key point to note here is the traversal should be done by two + * person simultaneously starting from (0, 0). Notice after t steps, each position (r, c) we could + * be, is on the line r + c = t (along the diagonal). So if we have two people at positions (r1, c1) + * and (r2, c2), then r2 = r1 + c1 - c2. + */ +public class CherryPickup { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] A = {{0, 1, -1}, {1, 0, -1}, {1, 1, 1}}; + System.out.println(new CherryPickup().cherryPickup(A)); + } + + public int cherryPickup(int[][] grid) { + int[][][] DP = new int[grid.length][grid.length][grid.length]; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid.length; j++) { + Arrays.fill(DP[i][j], -1); + } + } + int result = dp(grid.length, 0, 0, 0, DP, grid); + if (result < 0) return 0; + else return result; + } + + private int dp(int N, int r1, int c1, int c2, int[][][] DP, int[][] grid) { + int r2 = r1 + (c1 - c2); + if (r1 >= N || c1 >= N || c2 >= N || r2 >= N || grid[r1][c1] == -1 || grid[r2][c2] == -1) + return Integer.MIN_VALUE; + else if (DP[r1][c1][c2] != -1) return DP[r1][c1][c2]; + else if (r1 == N - 1 && c1 == N - 1) return grid[N - 1][N - 1]; + else { + int max = (c1 == c2) ? grid[r1][c1] : (grid[r1][c1] + grid[r2][c2]); + // verify all the 4 possibilities. (P1 down + P2 right), (P1 right, P2 right), (P1 right + P2 + // down), + // (P1 down, P2 down) + max += + Math.max( + Math.max( + Math.max(dp(N, r1 + 1, c1, c2, DP, grid), dp(N, r1 + 1, c1, c2 + 1, DP, grid)), + dp(N, r1, c1 + 1, c2, DP, grid)), + dp(N, r1, c1 + 1, c2 + 1, DP, grid)); + DP[r1][c1][c2] = max; + return max; + } + } +} diff --git a/src/main/java/dynamic_programming/CherryPickupII.java b/src/main/java/dynamic_programming/CherryPickupII.java new file mode 100644 index 00000000..0118620b --- /dev/null +++ b/src/main/java/dynamic_programming/CherryPickupII.java @@ -0,0 +1,90 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 28/07/2020 Given a rows x cols matrix grid representing a field + * of cherries. Each cell in grid represents the number of cherries that you can collect. + * + *

You have two robots that can collect cherries for you, Robot #1 is located at the top-left + * corner (0,0) , and Robot #2 is located at the top-right corner (0, cols-1) of the grid. + * + *

Return the maximum number of cherries collection using both robots by following the rules + * below: + * + *

From a cell (i,j), robots can move to cell (i+1, j-1) , (i+1, j) or (i+1, j+1). When any robot + * is passing through a cell, It picks it up all cherries, and the cell becomes an empty cell (0). + * When both robots stay on the same cell, only one of them takes the cherries. Both robots cannot + * move outside of the grid at any moment. Both robots should reach the bottom row in the grid. + * + *

Example 1: + * + *

Input: grid = [[3,1,1],[2,5,1],[1,5,5],[2,1,1]] Output: 24 Explanation: Path of robot #1 and + * #2 are described in color green and blue respectively. Cherries taken by Robot #1, (3 + 2 + 5 + + * 2) = 12. Cherries taken by Robot #2, (1 + 5 + 5 + 1) = 12. Total of cherries: 12 + 12 = 24. + * Example 2: + * + *

Input: grid = + * [[1,0,0,0,0,0,1],[2,0,0,0,0,3,0],[2,0,9,0,0,0,0],[0,3,0,5,4,0,0],[1,0,2,3,0,0,6]] Output: 28 + * Explanation: Path of robot #1 and #2 are described in color green and blue respectively. Cherries + * taken by Robot #1, (1 + 9 + 5 + 2) = 17. Cherries taken by Robot #2, (1 + 3 + 4 + 3) = 11. Total + * of cherries: 17 + 11 = 28. Example 3: + * + *

Input: grid = [[1,0,0,3],[0,0,0,3],[0,0,3,3],[9,0,3,3]] Output: 22 Example 4: + * + *

Input: grid = [[1,1],[1,1]] Output: 4 + * + *

Constraints: + * + *

rows == grid.length cols == grid[i].length 2 <= rows, cols <= 70 0 <= grid[i][j] <= 100 + */ +public class CherryPickupII { + private final int[] R = {1, 1, 1}; + private final int[] C = {0, -1, 1}; + + public static void main(String[] args) { + int[][] A = { + {1, 0, 0, 3}, + {2, 0, 0, 0, 0, 3, 0}, + {2, 0, 9, 0, 0, 0, 0}, + {0, 3, 0, 5, 4, 0, 0}, + {1, 0, 2, 3, 0, 0, 6} + }; + System.out.println(new CherryPickupII().cherryPickup(A)); + } + + int[][][] DP; + + public int cherryPickup(int[][] grid) { + DP = new int[grid.length][grid[0].length][grid[0].length]; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + Arrays.fill(DP[i][j], -1); + } + } + return dp(0, 0, grid[0].length - 1, grid); + } + + private int dp(int r, int c1, int c2, int[][] grid) { + if (DP[r][c1][c2] != -1) return DP[r][c1][c2]; + else { + int count = (c1 == c2) ? grid[r][c1] : (grid[r][c1] + grid[r][c2]); + int max = count; + for (int i = 0; i < 3; i++) { + int newR = r + R[i]; + int newC1 = c1 + C[i]; + if (newR >= 0 && newR < grid.length && newC1 >= 0 && newC1 < grid[0].length) { + for (int j = 0; j < 3; j++) { + int newC2 = c2 + C[j]; + if (newC2 >= 0 && newC2 < grid[0].length) { + max = Math.max(max, count + dp(newR, newC1, newC2, grid)); + } + } + } + } + DP[r][c1][c2] = max; + return max; + } + } +} diff --git a/src/main/java/dynamic_programming/ClimbingStairs.java b/src/main/java/dynamic_programming/ClimbingStairs.java new file mode 100644 index 00000000..6d283ed8 --- /dev/null +++ b/src/main/java/dynamic_programming/ClimbingStairs.java @@ -0,0 +1,30 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 01/04/2017. You are climbing a stair case. It takes n steps to + * reach to the top. + * + *

Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the + * top? + * + *

Note: Given n will be a positive integer. + */ +public class ClimbingStairs { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception {} + + public int climbStairs(int n) { + if (n == 0 || n == 1) return 1; + int[] A = new int[n + 1]; + A[n] = 1; + A[n - 1] = 1; + for (int i = n - 2; i >= 0; i--) A[i] = A[i + 1] + A[i + 2]; + return A[0]; + } +} diff --git a/src/main/java/dynamic_programming/CoinChange.java b/src/main/java/dynamic_programming/CoinChange.java new file mode 100644 index 00000000..1233b457 --- /dev/null +++ b/src/main/java/dynamic_programming/CoinChange.java @@ -0,0 +1,58 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 23/06/2017. You are given coins of different denominations and + * a total amount of money amount. Write a function to compute the fewest number of coins that you + * need to make up that amount. If that amount of money cannot be made up by any combination of the + * coins, return -1. + * + *

Example 1: coins = [1, 2, 5], amount = 11 return 3 (11 = 5 + 5 + 1) + * + *

Example 2: coins = [2], amount = 3 return -1. + * + *

Note: You may assume that you have an infinite number of each kind of coin. + * + *

Solution: For example if you have N coins and amount equal to Q For every coin you have two + * options i) If you chose to include this coin then, total amount reduces by the sum equivalent to + * the value of this coin and you are left with N coins and Q = (Q - value of this coin) ii) If you + * chose not to include this coin then, you are left with N - 1 coins (since you chose to not to + * include this coin) and total amount is still equal to Q + * + *

Calculate recursively for each coin and possible amount Since there can be overlapping + * sub-problems you can save the state in a 2D matrix - a typical DP approach. + * + *

For each state minimum is calculated using -> Min(1 + fn(i, amount - v[i]), fn(i + 1, amount)) + * + *

Worst-case time complexity is O(N x Q) where N is the total number of coins and Q is the total + * amount + */ +public class CoinChange { + private int[][] DP; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] coins = {1, 2, 5}; + System.out.println(new CoinChange().coinChange(coins, 11)); + } + + public int coinChange(int[] coins, int amount) { + DP = new int[coins.length][amount + 1]; + int result = dp(amount, 0, coins); + if (result == Integer.MAX_VALUE - 1) return -1; + return result; + } + + private int dp(int amount, int i, int[] coins) { + if (amount == 0) return 0; + else if (i >= coins.length || amount < 0) return Integer.MAX_VALUE - 1; + if (DP[i][amount] != 0) return DP[i][amount]; + DP[i][amount] = Math.min(1 + dp(amount - coins[i], i, coins), dp(amount, i + 1, coins)); + return DP[i][amount]; + } +} diff --git a/src/main/java/dynamic_programming/CoinChange2.java b/src/main/java/dynamic_programming/CoinChange2.java new file mode 100644 index 00000000..86c5ff2f --- /dev/null +++ b/src/main/java/dynamic_programming/CoinChange2.java @@ -0,0 +1,50 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 22/03/2017. You are given coins of different denominations and + * a total amount of money. Write a function to compute the number of combinations that make up that + * amount. You may assume that you have infinite number of each kind of coin. + * + *

Note: You can assume that + * + *

0 <= amount <= 5000 1 <= coin <= 5000 the number of coins is less than 500 the answer is + * guaranteed to fit into signed 32-bit integer Example 1: + * + *

Input: amount = 5, coins = [1, 2, 5] Output: 4 Explanation: there are four ways to make up the + * amount: 5=5 5=2+2+1 5=2+1+1+1 5=1+1+1+1+1 Example 2: + * + *

Input: amount = 3, coins = [2] Output: 0 Explanation: the amount of 3 cannot be made up just + * with coins of 2. Example 3: + * + *

Input: amount = 10, coins = [10] Output: 1 + */ +public class CoinChange2 { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] coins = {1, 2, 5}; + System.out.println(new CoinChange2().change(5, coins)); + } + + public int change(int amount, int[] coins) { + int[][] dp = new int[coins.length][amount + 1]; + for (int i = 0, l = coins.length; i < l; i++) Arrays.fill(dp[i], -1); + return dp(dp, 0, coins, coins.length, amount); + } + + private int dp(int[][] dp, int i, int[] coins, int l, int n) { + if (n == 0) return 1; + else if (i >= l) return 0; + if (n < 0) return 0; + if (dp[i][n] != -1) return dp[i][n]; + dp[i][n] = dp(dp, i + 1, coins, l, n) + dp(dp, i, coins, l, n - coins[i]); + return dp[i][n]; + } +} diff --git a/src/main/java/dynamic_programming/CombinationSumIV.java b/src/main/java/dynamic_programming/CombinationSumIV.java new file mode 100644 index 00000000..f0d2e714 --- /dev/null +++ b/src/main/java/dynamic_programming/CombinationSumIV.java @@ -0,0 +1,58 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 17/12/2017. Given an integer array with all positive numbers + * and no duplicates, find the number of possible combinations that add up to a positive integer + * target. + * + *

Example: + * + *

nums = [1, 2, 3] target = 4 + * + *

The possible combination ways are: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) + * (3, 1) + * + *

Note that different sequences are counted as different combinations. + * + *

Therefore the output is 7. Follow up: What if negative numbers are allowed in the given array? + * How does it change the problem? What limitation we need to add to the question to allow negative + * numbers? + * + *

Solution: Backtrack and dp + */ +public class CombinationSumIV { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 2, 3}; + System.out.println(new CombinationSumIV().combinationSum4(A, 4)); + } + + public int combinationSum4(int[] nums, int target) { + int[] dp = new int[target + 1]; + Arrays.fill(dp, -1); + dp[0] = 1; + return backtrack(nums, dp, target); + } + + private int backtrack(int[] nums, int[] dp, int sum) { + int total = 0; + if (sum < 0) return 0; + if (dp[sum] != -1) return dp[sum]; + else { + for (int num : nums) { + total += backtrack(nums, dp, sum - num); + } + } + dp[sum] = total; + return dp[sum]; + } +} diff --git a/src/main/java/dynamic_programming/ConcatenatedWords.java b/src/main/java/dynamic_programming/ConcatenatedWords.java new file mode 100644 index 00000000..f462ac00 --- /dev/null +++ b/src/main/java/dynamic_programming/ConcatenatedWords.java @@ -0,0 +1,62 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Created by gouthamvidyapradhan on 12/06/2017. Accepted Given a list of words (without + * duplicates), please write a program that returns all concatenated words in the given list of + * words. + * + *

A concatenated word is defined as a string that is comprised entirely of at least two shorter + * words in the given array. + * + *

Example: Input: + * ["cat","cats","catsdogcats","dog","dogcatsdog","hippopotamuses","rat","ratcatdogcat"] + * + *

Output: ["catsdogcats","dogcatsdog","ratcatdogcat"] + * + *

Explanation: "catsdogcats" can be concatenated by "cats", "dog" and "cats"; "dogcatsdog" can + * be concatenated by "dog", "cats" and "dog"; "ratcatdogcat" can be concatenated by "rat", "cat", + * "dog" and "cat". + * + *

Note: The number of elements of the given array will not exceed 10,000 The length sum of + * elements in the given array will not exceed 600,000. All the input string will only include lower + * case letters. The returned elements order does not matter. + */ +public class ConcatenatedWords { + public static void main(String[] args) throws Exception { + String[] words = {""}; + System.out.println(new ConcatenatedWords().findAllConcatenatedWordsInADict(words)); + } + + public List findAllConcatenatedWordsInADict(String[] words) { + Set dictionary = new HashSet<>(); + for (String w : words) dictionary.add(w); + List result = new ArrayList<>(); + for (String w : words) { + if (!w.isEmpty() && concatenatedWordsPossible(w, dictionary)) result.add(w); + } + return result; + } + + private boolean concatenatedWordsPossible(String word, Set dictionary) { + boolean[] D = new boolean[word.length() + 1]; + D[word.length()] = true; + dictionary.remove(word); // remove current word from dictionary temporarily + for (int i = word.length() - 1; i >= 0; i--) { + for (int j = i, l = word.length(); j < l; j++) { + String subStr = word.substring(i, j + 1); + if (dictionary.contains(subStr) && D[j + 1]) { + D[i] = true; + break; + } + } + } + dictionary.add(word); // restore deleted word + return D[0]; + } +} diff --git a/src/main/java/dynamic_programming/ConstrainedSubsequenceSum.java b/src/main/java/dynamic_programming/ConstrainedSubsequenceSum.java new file mode 100644 index 00000000..5b1dcc06 --- /dev/null +++ b/src/main/java/dynamic_programming/ConstrainedSubsequenceSum.java @@ -0,0 +1,53 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** Created by gouthamvidyapradhan on 14/05/2020 */ +public class ConstrainedSubsequenceSum { + + public static void main(String[] args) { + int[] A = {10, -2, -10, -5, 20}; + System.out.println(new ConstrainedSubsequenceSum().constrainedSubsetSum(A, 2)); + } + + class Node { + int v, i; + + public int getV() { + return v; + } + + public int getI() { + return i; + } + + Node(int v, int i) { + this.v = v; + this.i = i; + } + } + + public int constrainedSubsetSum(int[] nums, int k) { + Queue pQ = + new PriorityQueue<>(Comparator.comparing(Node::getV).thenComparing(Node::getI).reversed()); + int max = Integer.MIN_VALUE; + for (int i = 0; i < nums.length; i++) { + int value = nums[i]; + while (!pQ.isEmpty() && (i - pQ.peek().i > k)) { + pQ.poll(); + } + if (pQ.isEmpty()) { + pQ.offer(new Node(value, i)); + } else { + if (pQ.peek().v + value > value) { + pQ.offer(new Node(pQ.peek().v + value, i)); + } else { + pQ.offer(new Node(value, i)); + } + } + max = Math.max(max, pQ.peek().v); + } + return max; + } +} diff --git a/src/main/java/dynamic_programming/ContinuousSubarraySum.java b/src/main/java/dynamic_programming/ContinuousSubarraySum.java new file mode 100644 index 00000000..4cdeb35d --- /dev/null +++ b/src/main/java/dynamic_programming/ContinuousSubarraySum.java @@ -0,0 +1,51 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 10/12/2017. Given a list of non-negative numbers and a target + * integer k, write a function to check if the array has a continuous subarray of size at least 2 + * that sums up to the multiple of k, that is, sums up to n*k where n is also an integer. + * + *

Example 1: Input: [23, 2, 4, 6, 7], k=6 Output: True Explanation: Because [2, 4] is a + * continuous subarray of size 2 and sums up to 6. Example 2: Input: [23, 2, 6, 4, 7], k=6 Output: + * True Explanation: Because [23, 2, 6, 4, 7] is an continuous subarray of size 5 and sums up to 42. + * Note: The length of the array won't exceed 10,000. You may assume the sum of all the numbers is + * in the range of a signed 32-bit integer. + * + *

Solution: O(n) sum the elements and maintain a hashmap of key value pair of (sum % k) -> + * index. If the key is already found in the hashmap and the difference in the current_index and + * hashmap index is > 1 then return true. + */ +public class ContinuousSubarraySum { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 3, 6, 12, 7}; + System.out.println(new ContinuousSubarraySum().checkSubarraySum(A, 6)); + } + + public boolean checkSubarraySum(int[] nums, int k) { + Map map = new HashMap<>(); + int sum = 0; + map.put(0, -1); + for (int i = 0; i < nums.length; i++) { + sum += nums[i]; + int mod = (k == 0) ? sum : sum % k; // this is to handle case where k is 0 + if (map.containsKey(mod)) { + if (i - map.get(mod) > 1) { + return true; + } + } else { + map.put(mod, i); + } + } + return false; + } +} diff --git a/src/main/java/dynamic_programming/CornerRectangles.java b/src/main/java/dynamic_programming/CornerRectangles.java new file mode 100644 index 00000000..649278dc --- /dev/null +++ b/src/main/java/dynamic_programming/CornerRectangles.java @@ -0,0 +1,54 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 26/12/2017. Given a grid where each entry is only 0 or 1, find + * the number of corner rectangles. + * + *

A corner rectangle is 4 distinct 1s on the grid that form an axis-aligned rectangle. Note that + * only the corners need to have the value 1. Also, all four 1s used must be distinct. + * + *

Example 1: Input: grid = [[1, 0, 0, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 1, 0], [1, 0, 1, 0, 1]] + * Output: 1 Explanation: There is only one corner rectangle, with corners grid[1][2], grid[1][4], + * grid[3][2], grid[3][4]. Example 2: Input: grid = [[1, 1, 1], [1, 1, 1], [1, 1, 1]] Output: 9 + * Explanation: There are four 2x2 rectangles, four 2x3 and 3x2 rectangles, and one 3x3 rectangle. + * Example 3: Input: grid = [[1, 1, 1, 1]] Output: 0 Explanation: Rectangles must have four distinct + * corners. Note: The number of rows and columns of grid will each be in the range [1, 200]. Each + * grid[i][j] will be either 0 or 1. The number of 1s in the grid will be at most 6000. + * + *

Solution O(n + m ^ 2): For every row, consider each pair of 1s (every column pairs) and sum up + * the previous occurrence of 1s for the same column. + */ +public class CornerRectangles { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] A = {{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}; + System.out.println(new CornerRectangles().countCornerRectangles(A)); + } + + public int countCornerRectangles(int[][] grid) { + int[][] count = new int[grid[0].length][grid[0].length]; + int result = 0; + for (int[] row : grid) { + for (int i = 0; i < row.length; i++) { + if (row[i] == 1) { + for (int j = i + 1; j < row.length; j++) { + if (row[j] == 1) { + if (count[i][j] > 0) { + result += count[i][j]; + } + count[i][j]++; + } + } + } + } + } + return result; + } +} diff --git a/src/main/java/dynamic_programming/CountDifferentPalindromicSubsequences.java b/src/main/java/dynamic_programming/CountDifferentPalindromicSubsequences.java new file mode 100644 index 00000000..6b0476d6 --- /dev/null +++ b/src/main/java/dynamic_programming/CountDifferentPalindromicSubsequences.java @@ -0,0 +1,84 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 10/04/2021 Given a string S, find the number of different + * non-empty palindromic subsequences in S, and return that number modulo 10^9 + 7. + * + *

A subsequence of a string S is obtained by deleting 0 or more characters from S. + * + *

A sequence is palindromic if it is equal to the sequence reversed. + * + *

Two sequences A_1, A_2, ... and B_1, B_2, ... are different if there is some i for which A_i + * != B_i. + * + *

Example 1: Input: S = 'bccb' Output: 6 Explanation: The 6 different non-empty palindromic + * subsequences are 'b', 'c', 'bb', 'cc', 'bcb', 'bccb'. Note that 'bcb' is counted only once, even + * though it occurs twice. Example 2: Input: S = + * 'abcdabcdabcdabcdabcdabcdabcdabcddcbadcbadcbadcbadcbadcbadcbadcba' Output: 104860361 Explanation: + * There are 3104860382 different non-empty palindromic subsequences, which is 104860361 modulo 10^9 + * + 7. Note: + * + *

The length of S will be in the range [1, 1000]. Each character S[i] will be in the set {'a', + * 'b', 'c', 'd'}. + * + *

Solution: O(N ^ 2) x 4 + */ +public class CountDifferentPalindromicSubsequences { + public static void main(String[] args) { + System.out.println( + new CountDifferentPalindromicSubsequences() + .countPalindromicSubsequences( + "abcdabcdabcdabcdabcdabcdabcdabcddcbadcbadcbadcbadcbadcbadcbadcba")); + } + + private long[][][] DP; + final char[] chars = {'a', 'b', 'c', 'd'}; + final int MOD = (int) 1e9 + 7; + + public int countPalindromicSubsequences(String S) { + DP = new long[S.length()][S.length()][4]; + for (int i = 0; i < S.length(); i++) { + for (int j = 0; j < S.length(); j++) { + Arrays.fill(DP[i][j], -1); + } + } + long result = 0L; + for (char c : chars) { + long r = dp(0, S.length() - 1, S, c); + result = ((result + r) % MOD); + } + return (int) result; + } + + private long dp(int i, int j, String s, char c) { + if (i > j) return 0; + else if (DP[i][j][c - 'a'] != -1) return DP[i][j][c - 'a']; + else if (s.charAt(i) == s.charAt(j) && s.charAt(i) == c) { + if (i == j) return 1; + else { + long sum = 0L; + for (char aChar : chars) { + long r = dp(i + 1, j - 1, s, aChar); + if (aChar == c) { + r = ((r + 2) % MOD); + } + sum = ((sum + r) % MOD); + } + DP[i][j][c - 'a'] = sum; + return DP[i][j][c - 'a']; + } + } else if (s.charAt(i) == c) { + DP[i][j][c - 'a'] = dp(i, j - 1, s, c); + return DP[i][j][c - 'a']; + } else if (s.charAt(j) == c) { + DP[i][j][c - 'a'] = dp(i + 1, j, s, c); + return DP[i][j][c - 'a']; + } else { + DP[i][j][c - 'a'] = dp(i + 1, j - 1, s, c); + return DP[i][j][c - 'a']; + } + } +} diff --git a/src/main/java/dynamic_programming/CountVowelsPermutation.java b/src/main/java/dynamic_programming/CountVowelsPermutation.java new file mode 100644 index 00000000..f0484020 --- /dev/null +++ b/src/main/java/dynamic_programming/CountVowelsPermutation.java @@ -0,0 +1,72 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 25/01/2020 Given an integer n, your task is to count how many + * strings of length n can be formed under the following rules: + * + *

Each character is a lower case vowel ('a', 'e', 'i', 'o', 'u') Each vowel 'a' may only be + * followed by an 'e'. Each vowel 'e' may only be followed by an 'a' or an 'i'. Each vowel 'i' may + * not be followed by another 'i'. Each vowel 'o' may only be followed by an 'i' or a 'u'. Each + * vowel 'u' may only be followed by an 'a'. Since the answer may be too large, return it modulo + * 10^9 + 7. + * + *

Example 1: + * + *

Input: n = 1 Output: 5 Explanation: All possible strings are: "a", "e", "i" , "o" and "u". + * Example 2: + * + *

Input: n = 2 Output: 10 Explanation: All possible strings are: "ae", "ea", "ei", "ia", "ie", + * "io", "iu", "oi", "ou" and "ua". Example 3: + * + *

Input: n = 5 Output: 68 + */ +public class CountVowelsPermutation { + public static void main(String[] args) {} + + public int countVowelPermutation(int n) { + if (n == 1) return 5; + Map> graph = new HashMap<>(); + List vowels = Arrays.asList('a', 'e', 'i', 'o', 'u'); + Map count = new HashMap<>(); + vowels.forEach(v -> graph.put(v, new ArrayList<>())); + graph.get('a').add('e'); + graph.get('e').add('a'); + graph.get('e').add('i'); + graph.get('i').add('a'); + graph.get('i').add('e'); + graph.get('i').add('o'); + graph.get('i').add('u'); + graph.get('u').add('a'); + graph.get('o').add('i'); + graph.get('o').add('u'); + count.put('a', 1); + count.put('e', 2); + count.put('i', 4); + count.put('o', 2); + count.put('u', 1); + int[] charCount = new int[5]; + for (int i = 2; i < n; i++) { + int j = 0; + Arrays.fill(charCount, 0); + for (char c : vowels) { + List children = graph.get(c); + for (char child : children) { + charCount[j] = ((charCount[j] + count.get(child)) % 1000000007); + } + j++; + } + j = 0; + for (char c : vowels) { + count.put(c, charCount[j++]); + } + } + int sum = 0; + for (char c : vowels) { + sum = ((sum + (count.get(c))) % 1000000007); + } + return sum; + } +} diff --git a/src/main/java/dynamic_programming/DecodeWays.java b/src/main/java/dynamic_programming/DecodeWays.java new file mode 100644 index 00000000..fb82e92d --- /dev/null +++ b/src/main/java/dynamic_programming/DecodeWays.java @@ -0,0 +1,46 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 01/04/2017. A message containing letters from A-Z is being + * encoded to numbers using the following mapping: + * + *

'A' -> 1 'B' -> 2 ... 'Z' -> 26 Given an encoded message containing digits, determine the + * total number of ways to decode it. + * + *

For example, Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12). + * + *

The number of ways decoding "12" is 2. + */ +public class DecodeWays { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new DecodeWays().numDecodings("3120")); + } + + public int numDecodings(String s) { + if (s == null || s.isEmpty()) return 0; + int[] dp = new int[s.length() + 2]; + dp[s.length()] = 1; + dp[s.length() + 1] = 1; + for (int i = s.length() - 1; i >= 0; i--) { + for (int j = i + 1; j < i + 3; j++) { + if (j <= s.length()) { + String subStr = s.substring(i, j); + if (!subStr.startsWith("0")) { + int intVal = Integer.parseInt(subStr); + if (intVal <= 26) { + dp[i] += dp[j]; + } + } + } + } + } + return dp[0]; + } +} diff --git a/src/main/java/dynamic_programming/DecodeWaysII.java b/src/main/java/dynamic_programming/DecodeWaysII.java new file mode 100644 index 00000000..25cc3f2f --- /dev/null +++ b/src/main/java/dynamic_programming/DecodeWaysII.java @@ -0,0 +1,105 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 11/12/2017. A message containing letters from A-Z is being + * encoded to numbers using the following mapping way: + * + *

'A' -> 1 'B' -> 2 ... 'Z' -> 26 Beyond that, now the encoded string can also contain the + * character '*', which can be treated as one of the numbers from 1 to 9. + * + *

Given the encoded message containing digits and the character '*', return the total number of + * ways to decode it. + * + *

Also, since the answer may be very large, you should return the output mod 109 + 7. + * + *

Example 1: Input: "*" Output: 9 Explanation: The encoded message can be decoded to the string: + * "A", "B", "C", "D", "E", "F", "G", "H", "I". Example 2: Input: "1*" Output: 9 + 9 = 18 Note: The + * length of the input string will fit in range [1, 105]. The input string will only contain the + * character '*' and digits '0' - '9'. + * + *

Solution: O(n) consider each digit and a pair of digits and perform a cartesian product to + * calculate the total number of ways. A pair of digits are to be considered only if their combined + * value does not exceed 26. Corner cases with combination of * and 0s can be tricky + */ +public class DecodeWaysII { + + private final int CONST = 1000000007; + private int[] dp; + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new DecodeWaysII().numDecodings("10")); + } + + public int numDecodings(String s) { + dp = new int[s.length() + 1]; + if (s.charAt(s.length() - 1) == '*') { + dp[s.length() - 1] = 9; + } else if (s.charAt(s.length() - 1) == '0') { + dp[s.length() - 1] = 0; + } else dp[s.length() - 1] = 1; + dp[s.length()] = 1; + + for (int i = s.length() - 2; i >= 0; i--) { + char curr = s.charAt(i); + char next = s.charAt(i + 1); + switch (curr) { + case '0': + dp[i] = 0; + break; + // number begins with a '*' + case '*': + dp[i] = (int) ((9 * (long) dp[i + 1]) % CONST); + switch (next) { + // The next char is a '*' + case '*': + dp[i] = + (int) + ((dp[i] + ((15 * (long) dp[i + 2]) % CONST)) + % CONST); // multiplication can be + // very large hence type casting to long is necessary + break; + + case '0': + dp[i] = (int) ((dp[i] + ((2 * (long) dp[i + 2]) % CONST)) % CONST); + break; + + default: + if ((next - '0') > 6) { + dp[i] = ((dp[i] + (dp[i + 2])) % CONST); + } else { + dp[i] = (int) ((dp[i] + ((2 * (long) dp[i + 2]) % CONST)) % CONST); + } + break; + } + break; + + default: + dp[i] = dp[i + 1]; + switch (next) { + case '*': + if ((curr - '0') == 1) { + dp[i] = (int) ((dp[i] + ((9 * (long) dp[i + 2]) % CONST)) % CONST); + } else if ((curr - '0') == 2) { + dp[i] = (int) ((dp[i] + ((6 * (long) dp[i + 2]) % CONST)) % CONST); + } + break; + + default: + if ((curr - '0') == 1) { + dp[i] = ((dp[i] + dp[i + 2]) % CONST); + } else if ((curr - '0') == 2 && (next - '0' <= 6)) { + dp[i] = ((dp[i] + dp[i + 2]) % CONST); + } + break; + } + } + } + return dp[0]; + } +} diff --git a/src/main/java/dynamic_programming/DeleteColumnsToMakeSortedIII.java b/src/main/java/dynamic_programming/DeleteColumnsToMakeSortedIII.java new file mode 100644 index 00000000..6b4a31e1 --- /dev/null +++ b/src/main/java/dynamic_programming/DeleteColumnsToMakeSortedIII.java @@ -0,0 +1,75 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 21/02/2020 We are given an array A of N lowercase letter + * strings, all of the same length. + * + *

Now, we may choose any set of deletion indices, and for each string, we delete all the + * characters in those indices. + * + *

For example, if we have an array A = ["babca","bbazb"] and deletion indices {0, 1, 4}, then + * the final array after deletions is ["bc","az"]. + * + *

Suppose we chose a set of deletion indices D such that after deletions, the final array has + * every element (row) in lexicographic order. + * + *

For clarity, A[0] is in lexicographic order (ie. A[0][0] <= A[0][1] <= ... <= A[0][A[0].length + * - 1]), A[1] is in lexicographic order (ie. A[1][0] <= A[1][1] <= ... <= A[1][A[1].length - 1]), + * and so on. + * + *

Return the minimum possible value of D.length. + * + *

Example 1: + * + *

Input: ["babca","bbazb"] Output: 3 Explanation: After deleting columns 0, 1, and 4, the final + * array is A = ["bc", "az"]. Both these rows are individually in lexicographic order (ie. A[0][0] + * <= A[0][1] and A[1][0] <= A[1][1]). Note that A[0] > A[1] - the array A isn't necessarily in + * lexicographic order. Example 2: + * + *

Input: ["edcba"] Output: 4 Explanation: If we delete less than 4 columns, the only row won't + * be lexicographically sorted. Example 3: + * + *

Input: ["ghi","def","abc"] Output: 0 Explanation: All rows are already lexicographically + * sorted. + * + *

Note: + * + *

1 <= A.length <= 100 1 <= A[i].length <= 100 + */ +public class DeleteColumnsToMakeSortedIII { + public static void main(String[] args) { + String[] A = {"ghi", "def", "abc"}; + System.out.println(new DeleteColumnsToMakeSortedIII().minDeletionSize(A)); + } + + int[] DP; + + public int minDeletionSize(String[] A) { + DP = new int[A[0].length()]; + int max = 0; + for (int i = 0; i < A[0].length(); i++) { + max = Math.max(max, dp(A, i)); + } + return A[0].length() - max; + } + + private int dp(String[] A, int i) { + if (i >= A[0].length()) return 0; + else if (DP[i] != 0) return DP[i]; + DP[i] = 1; + for (int j = i + 1; j < A[0].length(); j++) { + boolean possible = true; + for (String str : A) { + if (str.charAt(j) < str.charAt(i)) { + possible = false; + break; + } + } + if (possible) { + DP[i] = Math.max(DP[i], dp(A, j) + 1); + } + } + return DP[i]; + } +} diff --git a/src/main/java/dynamic_programming/DistinctSubsequences.java b/src/main/java/dynamic_programming/DistinctSubsequences.java new file mode 100644 index 00000000..24a6ebaa --- /dev/null +++ b/src/main/java/dynamic_programming/DistinctSubsequences.java @@ -0,0 +1,56 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 08/05/2020 Given a string S and a string T, count the number of + * distinct subsequences of S which equals T. + * + *

A subsequence of a string is a new string which is formed from the original string by deleting + * some (can be none) of the characters without disturbing the relative positions of the remaining + * characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not). + * + *

It's guaranteed the answer fits on a 32-bit signed integer. + * + *

Example 1: + * + *

Input: S = "rabbbit", T = "rabbit" Output: 3 Explanation: As shown below, there are 3 ways you + * can generate "rabbit" from S. (The caret symbol ^ means the chosen letters) + * + *

rabbbit ^^^^ ^^ rabbbit ^^ ^^^^ rabbbit ^^^ ^^^ Example 2: + * + *

Input: S = "babgbag", T = "bag" Output: 5 Explanation: As shown below, there are 5 ways you + * can generate "bag" from S. (The caret symbol ^ means the chosen letters) + * + *

babgbag ^^ ^ babgbag ^^ ^ babgbag ^ ^^ babgbag ^ ^^ babgbag ^^^ + */ +public class DistinctSubsequences { + int[][] DP; + + public static void main(String[] args) { + System.out.println(new DistinctSubsequences().numDistinct("babgbag", "bag")); + } + + public int numDistinct(String s, String t) { + DP = new int[s.length()][t.length()]; + for (int i = 0; i < s.length(); i++) { + Arrays.fill(DP[i], -1); + } + return dp(0, 0, s, t); + } + + private int dp(int i, int j, String s, String t) { + if (j >= t.length()) return 1; + else if (i >= s.length()) return 0; + else if (DP[i][j] != -1) return DP[i][j]; + else { + if (s.charAt(i) != t.charAt(j)) { + DP[i][j] = dp(i + 1, j, s, t); + } else { + DP[i][j] = dp(i + 1, j + 1, s, t) + dp(i + 1, j, s, t); + } + return DP[i][j]; + } + } +} diff --git a/src/main/java/dynamic_programming/DistinctSubsequencesII.java b/src/main/java/dynamic_programming/DistinctSubsequencesII.java new file mode 100644 index 00000000..54499fc4 --- /dev/null +++ b/src/main/java/dynamic_programming/DistinctSubsequencesII.java @@ -0,0 +1,49 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; +/** + * Created by gouthamvidyapradhan on 08/05/2020 Given a string S, count the number of distinct, + * non-empty subsequences of S . + * + *

Since the result may be large, return the answer modulo 10^9 + 7. + * + *

Example 1: + * + *

Input: "abc" Output: 7 Explanation: The 7 distinct subsequences are "a", "b", "c", "ab", "ac", + * "bc", and "abc". Example 2: + * + *

Input: "aba" Output: 6 Explanation: The 6 distinct subsequences are "a", "b", "ab", "ba", "aa" + * and "aba". Example 3: + * + *

Input: "aaa" Output: 3 Explanation: The 3 distinct subsequences are "a", "aa" and "aaa". + * + *

Note: + * + *

S contains only lowercase letters. 1 <= S.length <= 2000 + */ +public class DistinctSubsequencesII { + public static void main(String[] args) { + System.out.println(new DistinctSubsequencesII().distinctSubseqII("abac")); + } + + final int MOD = (int) 1e9 + 7; + + public int distinctSubseqII(String S) { + int[] DP = new int[S.length() + 1]; + DP[S.length()] = 1; + for (int i = S.length() - 1; i >= 0; i--) { + int sum = 0; + for (int j = i + 1; j <= S.length(); j++) { + sum = ((sum + DP[j]) % MOD); + if (j < S.length() && S.charAt(j) == S.charAt(i)) { + break; + } + } + DP[i] = sum; + } + int ans = 0; + for (int i : DP) { + ans = ((ans + i) % MOD); + } + return ans - 1; + } +} diff --git a/src/main/java/dynamic_programming/DungeonGame.java b/src/main/java/dynamic_programming/DungeonGame.java new file mode 100644 index 00000000..80b669cd --- /dev/null +++ b/src/main/java/dynamic_programming/DungeonGame.java @@ -0,0 +1,81 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 12/07/2017. The demons had captured the princess (P) and + * imprisoned her in the bottom-right corner of a dungeon. The dungeon consists of M x N rooms laid + * out in a 2D grid. Our valiant knight (K) was initially positioned in the top-left room and must + * fight his way through the dungeon to rescue the princess. + * + *

The knight has an initial health point represented by a positive integer. If at any point his + * health point drops to 0 or below, he dies immediately. + * + *

Some of the rooms are guarded by demons, so the knight loses health (negative integers) upon + * entering these rooms; other rooms are either empty (0's) or contain magic orbs that increase the + * knight's health (positive integers). + * + *

In order to reach the princess as quickly as possible, the knight decides to move only + * rightward or downward in each step. + * + *

+ * + *

Write a function to determine the knight's minimum initial health so that he is able to rescue + * the princess. + * + *

For example, given the dungeon below, the initial health of the knight must be at least 7 if + * he follows the optimal path RIGHT-> RIGHT -> DOWN -> DOWN. + * + *

-2 (K) -3 3 -5 -10 1 10 30 -5 (P) + * + *

Notes: + * + *

The knight's health has no upper bound. Any room can contain threats or power-ups, even the + * first room the knight enters and the bottom-right room where the princess is imprisoned. + * + *

Solution: O(MxN log Integer.MAX_VALUE) Binary search the suitable initial health value in the + * range (1, Integer.MAX_VALUE) and do a top down DP to check the balance health when he reaches + * princess. + */ +public class DungeonGame { + private final int[] R = {0, -1}; + private final int[] C = {-1, 0}; + private int DP[][]; + + public static void main(String[] args) throws Exception { + int[][] dungeon = {{200}}; + System.out.println(new DungeonGame().calculateMinimumHP(dungeon)); + } + + public int calculateMinimumHP(int[][] dungeon) { + DP = new int[dungeon.length][dungeon[0].length]; + int l = 0, h = Integer.MAX_VALUE, ans = 0; + while (l <= h) { + int m = l + (h - l) / 2; + for (int i = 0; i < dungeon.length; i++) Arrays.fill(DP[i], Integer.MIN_VALUE); + DP[0][0] = m + dungeon[0][0]; + if (dp(dungeon, dungeon.length - 1, dungeon[0].length - 1) > 0) { + ans = m; + h = m - 1; + } else { + l = m + 1; + } + } + return ans == 0 ? 1 : ans; + } + + private int dp(int[][] dungeon, int r, int c) { + if (DP[r][c] != Integer.MIN_VALUE) return DP[r][c]; + for (int i = 0; i < 2; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR >= 0 && newR < dungeon.length && newC >= 0 && newC < dungeon[0].length) { + int life = dp(dungeon, newR, newC); + if (life <= 0) DP[r][c] = Math.max(DP[r][c], 0); + else DP[r][c] = Math.max(DP[r][c], dungeon[r][c] + life); + } + } + return DP[r][c]; + } +} diff --git a/src/main/java/dynamic_programming/EncodeStringWithShortestLength.java b/src/main/java/dynamic_programming/EncodeStringWithShortestLength.java new file mode 100644 index 00000000..2520dde5 --- /dev/null +++ b/src/main/java/dynamic_programming/EncodeStringWithShortestLength.java @@ -0,0 +1,90 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; +/** + * Created by gouthamvidyapradhan on 15/09/2019 Given a non-empty string, encode the string such + * that its encoded length is the shortest. + * + *

The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets + * is being repeated exactly k times. + * + *

Note: + * + *

k will be a positive integer and encoded string will not be empty or have extra space. You may + * assume that the input string contains only lowercase English letters. The string's length is at + * most 160. If an encoding process does not make the string shorter, then do not encode it. If + * there are several solutions, return any of them is fine. + * + *

Example 1: + * + *

Input: "aaa" Output: "aaa" Explanation: There is no way to encode it such that it is shorter + * than the input string, so we do not encode it. + * + *

Example 2: + * + *

Input: "aaaaa" Output: "5[a]" Explanation: "5[a]" is shorter than "aaaaa" by 1 character. + * + *

Example 3: + * + *

Input: "aaaaaaaaaa" Output: "10[a]" Explanation: "a9[a]" or "9[a]a" are also valid solutions, + * both of them have the same length = 5, which is the same as "10[a]". + * + *

Example 4: + * + *

Input: "aabcaabcd" Output: "2[aabc]d" Explanation: "aabc" occurs twice, so one answer can be + * "2[aabc]d". + * + *

Example 5: + * + *

Input: "abbbabbbcabbbabbbc" Output: "2[2[abbb]c]" Explanation: "abbbabbbc" occurs twice, but + * "abbbabbbc" can also be encoded to "2[abbb]c", so one answer can be "2[2[abbb]c]". + * + *

Solution: O(N ^ 4) Maintain a 2d String array of minimum substring and split each substring + * and combine the minimum substrings So, the answer could be either DP[i][j] = min(DP[i][k] + DP[k + * + 1][j]) or split (i, j) at every index k and check if a new minimum substring can be formed + * which is lesser than the current minimum. + */ +public class EncodeStringWithShortestLength { + + private String[][] DP; + + public static void main(String[] args) { + System.out.println( + new EncodeStringWithShortestLength() + .encode( + "xabcabcabcxxabcabcabcxxabcabcabcxxabcdabcabcxxabcabcabcxxabcabcabcxxabcabcabcxxabcabcabcx")); + } + + public String encode(String s) { + DP = new String[s.length()][s.length()]; + return encodeStr(s, 0, s.length() - 1); + } + + private String encodeStr(String s, int i, int j) { + if (i == j) { + DP[i][j] = String.valueOf(s.charAt(i)); + return DP[i][j]; + } else if (DP[i][j] != null) return DP[i][j]; + String currSubStr = s.substring(i, j + 1); + DP[i][j] = currSubStr; + for (int k = i + 1; k < j + 1; k++) { + String left = encodeStr(s, i, k - 1); + String right = encodeStr(s, k, j); + if (left.length() + right.length() < DP[i][j].length()) { + DP[i][j] = left + right; + } + } + for (int k = i + 1; k < j + 1; k++) { + if (currSubStr.length() % (k - i) == 0) { + String subStr = s.substring(i, k); + if (currSubStr.replaceAll(subStr, "").trim().isEmpty()) { + String candidate = + (currSubStr.length() / subStr.length()) + "[" + encodeStr(s, i, k - 1) + "]"; + if (candidate.length() < DP[i][j].length()) { + DP[i][j] = candidate; + } + } + } + } + return DP[i][j]; + } +} diff --git a/src/main/java/dynamic_programming/FreedomTrail.java b/src/main/java/dynamic_programming/FreedomTrail.java new file mode 100644 index 00000000..69cd9e1c --- /dev/null +++ b/src/main/java/dynamic_programming/FreedomTrail.java @@ -0,0 +1,67 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 15/02/2020 In the video game Fallout 4, the quest "Road to + * Freedom" requires players to reach a metal dial called the "Freedom Trail Ring", and use the dial + * to spell a specific keyword in order to open the door. + * + *

Given a string ring, which represents the code engraved on the outer ring and another string + * key, which represents the keyword needs to be spelled. You need to find the minimum number of + * steps in order to spell all the characters in the keyword. + * + *

Initially, the first character of the ring is aligned at 12:00 direction. You need to spell + * all the characters in the string key one by one by rotating the ring clockwise or anticlockwise + * to make each character of the string key aligned at 12:00 direction and then by pressing the + * center button. + * + *

At the stage of rotating the ring to spell the key character key[i]: + * + *

You can rotate the ring clockwise or anticlockwise one place, which counts as 1 step. The + * final purpose of the rotation is to align one of the string ring's characters at the 12:00 + * direction, where this character must equal to the character key[i]. If the character key[i] has + * been aligned at the 12:00 direction, you need to press the center button to spell, which also + * counts as 1 step. After the pressing, you could begin to spell the next character in the key + * (next stage), otherwise, you've finished all the spelling. Example: + * + *

Input: ring = "godding", key = "gd" Output: 4 Explanation: For the first key character 'g', + * since it is already in place, we just need 1 step to spell this character. For the second key + * character 'd', we need to rotate the ring "godding" anticlockwise by two steps to make it become + * "ddinggo". Also, we need 1 more step for spelling. So the final output is 4. Note: + * + *

Length of both ring and key will be in range 1 to 100. There are only lowercase letters in + * both strings and might be some duplcate characters in both strings. It's guaranteed that string + * key could always be spelled by rotating the string ring. + */ +public class FreedomTrail { + public static void main(String[] args) { + System.out.println(new FreedomTrail().findRotateSteps("godding", "gd")); + } + + int[][] DP; + + public int findRotateSteps(String ring, String key) { + DP = new int[ring.length()][key.length()]; + return dp(0, ring, key, 0) + key.length(); + } + + private int dp(int i, String ring, String key, int k) { + if (k == key.length()) return 0; + else { + if (DP[i][k] != 0) return DP[i][k]; + char c = key.charAt(k); + int min = Integer.MAX_VALUE; + for (int j = 0; j < ring.length(); j++) { + if (ring.charAt(j) == c) { + min = + Math.min( + min, + Math.min(Math.abs(i - j), ring.length() - Math.abs(i - j)) + + dp(j, ring, key, k + 1)); + } + } + DP[i][k] = min; + return min; + } + } +} diff --git a/src/main/java/dynamic_programming/HandshakesThatDontCross.java b/src/main/java/dynamic_programming/HandshakesThatDontCross.java new file mode 100644 index 00000000..1450b29e --- /dev/null +++ b/src/main/java/dynamic_programming/HandshakesThatDontCross.java @@ -0,0 +1,64 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 19/02/2020 You are given an even number of people num_people + * that stand around a circle and each person shakes hands with someone else, so that there are + * num_people / 2 handshakes total. + * + *

Return the number of ways these handshakes could occur such that none of the handshakes cross. + * + *

Since this number could be very big, return the answer mod 10^9 + 7 + * + *

Example 1: + * + *

Input: num_people = 2 Output: 1 Example 2: + * + *

Input: num_people = 4 Output: 2 Explanation: There are two ways to do it, the first way is + * [(1,2),(3,4)] and the second one is [(2,3),(4,1)]. Example 3: + * + *

Input: num_people = 6 Output: 5 Example 4: + * + *

Input: num_people = 8 Output: 14 + * + *

Constraints: + * + *

2 <= num_people <= 1000 num_people % 2 == 0 + */ +public class HandshakesThatDontCross { + public static void main(String[] args) { + System.out.println(new HandshakesThatDontCross().numberOfWays(20)); + } + + int[] DP; + final int MOD = 1000000007; + + public int numberOfWays(int N) { + // DP = new int[N + 1][N + 1]; + DP = new int[N + 1]; + Arrays.fill(DP, -1); + // + // for(int i = 0; i <= N; i ++){ + // Arrays.fill(DP[i], -1); + // } + return dp(0, N - 1); + } + + private int dp(int i, int j) { + if (i > j) return 1; + else if ((j - i + 1) % 2 != 0) return 0; + else if (DP[j - i + 1] != -1) return DP[j - i + 1]; + else { + int sum = 0; + for (int k = i; k <= j; k++) { + int left = (dp(i + 1, k - 1) % MOD); + int right = (dp(k + 1, j) % MOD); + sum = ((sum + ((left * right) % MOD)) % MOD); + } + DP[j - i + 1] = sum; + return sum; + } + } +} diff --git a/src/main/java/dynamic_programming/HouseRobber.java b/src/main/java/dynamic_programming/HouseRobber.java new file mode 100644 index 00000000..8d6c0762 --- /dev/null +++ b/src/main/java/dynamic_programming/HouseRobber.java @@ -0,0 +1,35 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by pradhang on 4/3/2017. You are a professional robber planning to rob houses along a + * street. Each house has a certain amount of money stashed, the only constraint stopping you from + * robbing each of them is that adjacent houses have security system connected and it will + * automatically contact the police if two adjacent houses were broken into on the same night. + * + *

Given a list of non-negative integers representing the amount of money of each house, + * determine the maximum amount of money you can rob tonight without alerting the police. + */ +public class HouseRobber { + private int[] max; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception {} + + public int rob(int[] nums) { + if (nums.length == 0) return 0; + max = new int[nums.length]; + if (nums.length == 1) return nums[0]; + max[nums.length - 1] = nums[nums.length - 1]; + max[nums.length - 2] = Math.max(nums[nums.length - 1], nums[nums.length - 2]); + for (int i = nums.length - 3; i >= 0; i--) { + max[i] = Math.max(max[i + 1], nums[i] + max[i + 2]); + } + return max[0]; + } +} diff --git a/src/main/java/dynamic_programming/HouseRobberII.java b/src/main/java/dynamic_programming/HouseRobberII.java new file mode 100644 index 00000000..23b67131 --- /dev/null +++ b/src/main/java/dynamic_programming/HouseRobberII.java @@ -0,0 +1,45 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by pradhang on 7/11/2017. After robbing those houses on that street, the thief has found + * himself a new place for his thievery so that he will not get too much attention. This time, all + * houses at this place are arranged in a circle. That means the first house is the neighbor of the + * last one. Meanwhile, the security system for these houses remain the same as for those in the + * previous street. + * + *

Given a list of non-negative integers representing the amount of money of each house, + * determine the maximum amount of money you can rob tonight without alerting the police. + */ +public class HouseRobberII { + public static void main(String[] args) throws Exception { + int[] nums = {6, 3, 10, 8, 2, 10, 3, 5, 10, 5, 3}; + System.out.println(new HouseRobberII().rob(nums)); + } + + public int rob(int[] nums) { + if (nums.length == 0) return 0; + if (nums.length == 1) return nums[0]; + else if (nums.length == 2) { + if (nums[0] > nums[1]) return nums[0]; + return nums[1]; + } else if (nums.length == 3) return Math.max(Math.max(nums[0], nums[1]), nums[2]); + int[] DP = new int[nums.length]; + for (int i = nums.length - 1; i > 0; i--) { + if (i + 3 < nums.length) DP[i] = Math.max(nums[i] + DP[i + 2], nums[i] + DP[i + 3]); + else if (i + 2 < nums.length) DP[i] = nums[i] + DP[i + 2]; + else DP[i] = nums[i]; + } + int max = Math.max(DP[1], DP[2]); + Arrays.fill(DP, 0); // reset + for (int i = nums.length - 2; i >= 0; i--) { + if (i + 3 < nums.length) DP[i] = Math.max(nums[i] + DP[i + 2], nums[i] + DP[i + 3]); + else if (i + 2 < nums.length) DP[i] = nums[i] + DP[i + 2]; + else DP[i] = nums[i]; + } + max = Math.max(max, Math.max(DP[0], DP[1])); + return max; + } +} diff --git a/src/main/java/dynamic_programming/InterleavingString.java b/src/main/java/dynamic_programming/InterleavingString.java new file mode 100644 index 00000000..defcddd3 --- /dev/null +++ b/src/main/java/dynamic_programming/InterleavingString.java @@ -0,0 +1,40 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; +/** + * Created by gouthamvidyapradhan on 30/01/2020 Given s1, s2, s3, find whether s3 is formed by the + * interleaving of s1 and s2. + * + *

Example 1: + * + *

Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac" Output: true Example 2: + * + *

Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc" Output: false + */ +public class InterleavingString { + public static void main(String[] args) { + System.out.println(new InterleavingString().isInterleave("aabcc", "aabcc", "aabcaabccc")); + } + + public boolean isInterleave(String s1, String s2, String s3) { + boolean[][] DP = new boolean[s1.length() + 1][s2.length() + 1]; + DP[0][0] = true; + if (s3.length() != (s2.length() + s1.length())) return false; + for (int i = 0; i <= s1.length(); i++) { + for (int j = 0; j <= s2.length(); j++) { + if (i == 0 && j == 0) continue; + int index = (i + j); + if (j > 0) { + if (s3.charAt(index - 1) == s2.charAt(j - 1) && DP[i][j - 1]) { + DP[i][j] = true; + } + } + if (i > 0) { + if (s3.charAt(index - 1) == s1.charAt(i - 1) && DP[i - 1][j]) { + DP[i][j] = true; + } + } + } + } + return DP[s1.length()][s2.length()]; + } +} diff --git a/src/main/java/dynamic_programming/JumpGameV.java b/src/main/java/dynamic_programming/JumpGameV.java new file mode 100644 index 00000000..142c49d2 --- /dev/null +++ b/src/main/java/dynamic_programming/JumpGameV.java @@ -0,0 +1,71 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 18/02/2020 Given an array of integers arr and an integer d. In + * one step you can jump from index i to index: + * + *

i + x where: i + x < arr.length and 0 < x <= d. i - x where: i - x >= 0 and 0 < x <= d. In + * addition, you can only jump from index i to index j if arr[i] > arr[j] and arr[i] > arr[k] for + * all indices k between i and j (More formally min(i, j) < k < max(i, j)). + * + *

You can choose any index of the array and start jumping. Return the maximum number of indices + * you can visit. + * + *

Notice that you can not jump outside of the array at any time. + * + *

Example 1: + * + *

Input: arr = [6,4,14,6,8,13,9,7,10,6,12], d = 2 Output: 4 Explanation: You can start at index + * 10. You can jump 10 --> 8 --> 6 --> 7 as shown. Note that if you start at index 6 you can only + * jump to index 7. You cannot jump to index 5 because 13 > 9. You cannot jump to index 4 because + * index 5 is between index 4 and 6 and 13 > 9. Similarly You cannot jump from index 3 to index 2 or + * index 1. Example 2: + * + *

Input: arr = [3,3,3,3,3], d = 3 Output: 1 Explanation: You can start at any index. You always + * cannot jump to any index. Example 3: + * + *

Input: arr = [7,6,5,4,3,2,1], d = 1 Output: 7 Explanation: Start at index 0. You can visit all + * the indicies. Example 4: + * + *

Input: arr = [7,1,7,1,7,1], d = 2 Output: 2 Example 5: + * + *

Input: arr = [66], d = 1 Output: 1 + * + *

Constraints: + * + *

1 <= arr.length <= 1000 1 <= arr[i] <= 10^5 1 <= d <= arr.length + */ +public class JumpGameV { + public static void main(String[] args) { + int[] A = {7, 1, 7, 1, 7, 1}; + System.out.println(new JumpGameV().maxJumps(A, 2)); + } + + int[] DP; + + public int maxJumps(int[] arr, int d) { + DP = new int[arr.length]; + // Arrays.fill(DP, -1); + int max = 0; + for (int i = 0; i < arr.length; i++) { + max = Math.max(max, dp(arr, d, i)); + } + return max; + } + + private int dp(int[] A, int d, int i) { + if (DP[i] != 0) return DP[i]; + int max = 1; + for (int j = i - 1; j >= (i - d); j--) { + if (j < 0 || A[j] >= A[i]) break; + max = Math.max(max, dp(A, d, j) + 1); + } + for (int j = i + 1; j <= (i + d); j++) { + if (j >= A.length || A[j] >= A[i]) break; + max = Math.max(max, dp(A, d, j) + 1); + } + DP[i] = max; + return max; + } +} diff --git a/src/main/java/dynamic_programming/KnightDialer.java b/src/main/java/dynamic_programming/KnightDialer.java new file mode 100644 index 00000000..0424ecc7 --- /dev/null +++ b/src/main/java/dynamic_programming/KnightDialer.java @@ -0,0 +1,82 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 24/09/2019 A chess knight can move as indicated in the chess + * diagram below: + * + *

. + * + *

This time, we place our chess knight on any numbered key of a phone pad (indicated above), and + * the knight makes N-1 hops. Each hop must be from one key to another numbered key. + * + *

Each time it lands on a key (including the initial placement of the knight), it presses the + * number of that key, pressing N digits total. + * + *

How many distinct numbers can you dial in this manner? + * + *

Since the answer may be large, output the answer modulo 10^9 + 7. + * + *

Example 1: + * + *

Input: 1 Output: 10 Example 2: + * + *

Input: 2 Output: 20 Example 3: + * + *

Input: 3 Output: 46 + * + *

Note: + * + *

1 <= N <= 5000 + * + *

Solution: O(N x 4 x 3) Visit all different possible states and sum up the total possible + * moves. Cache the states to avoid recalculating. + */ +public class KnightDialer { + + final int[] R = {-1, -1, -2, -2, 1, 1, 2, 2}; + final int[] C = {2, -2, -1, 1, 2, -2, 1, -1}; + + public static void main(String[] args) { + System.out.println(new KnightDialer().knightDialer(2)); + } + + int[][][] DP; + + public int knightDialer(int N) { + DP = new int[4][3][N + 1]; + int ans = 0; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 3; j++) { + if ((i == 3 && j == 0) || (i == 3 && j == 2)) continue; + DP[i][j][0] = 1; + } + } + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 3; j++) { + if ((i == 3 && j == 0) || (i == 3 && j == 2)) continue; + ans += (dp(N - 1, i, j) % 10e9 + 7); + ans %= 10e9 + 7; + } + } + return ans; + } + + private int dp(int N, int r, int c) { + if (N < 0) return 0; + if (r == 3 && c == 0) return 0; + if (r == 3 && c == 2) return 0; + if (DP[r][c][N] != 0) return DP[r][c][N]; + int sum = 0; + for (int i = 0; i < 8; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR >= 0 && newC >= 0 && newR < 4 && newC < 3) { + sum += (dp(N - 1, newR, newC) % 10e9 + 7); + sum %= 10e9 + 7; + } + } + DP[r][c][N] = sum; + return sum; + } +} diff --git a/src/main/java/dynamic_programming/KnightProbabilityInChessboard.java b/src/main/java/dynamic_programming/KnightProbabilityInChessboard.java new file mode 100644 index 00000000..5674e4cb --- /dev/null +++ b/src/main/java/dynamic_programming/KnightProbabilityInChessboard.java @@ -0,0 +1,73 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 13/02/2018. On an NxN chessboard, a knight starts at the r-th + * row and c-th column and attempts to make exactly K moves. The rows and columns are 0 indexed, so + * the top-left square is (0, 0), and the bottom-right square is (N-1, N-1). + * + *

A chess knight has 8 possible moves it can make, as illustrated below. Each move is two + * squares in a cardinal direction, then one square in an orthogonal direction. + * + *

Each time the knight is to move, it chooses one of eight possible moves uniformly at random + * (even if the piece would go off the chessboard) and moves there. + * + *

The knight continues moving until it has made exactly K moves or has moved off the chessboard. + * Return the probability that the knight remains on the board after it has stopped moving. + * + *

Example: Input: 3, 2, 0, 0 Output: 0.0625 Explanation: There are two moves (to (1,2), (2,1)) + * that will keep the knight on the board. From each of those positions, there are also two moves + * that will keep the knight on the board. The total probability the knight stays on the board is + * 0.0625. Note: N will be between 1 and 25. K will be between 0 and 100. The knight always + * initially starts on the board. + * + *

Solution: Solution O(N ^ 2 x K) DP top down memoization for each different states. + */ +public class KnightProbabilityInChessboard { + + int[] R = {1, -1, 2, -2, -1, -2, 2, 1}; + int[] C = {2, 2, 1, 1, -2, -1, -1, -2}; + + double[][][] dp; + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new KnightProbabilityInChessboard().knightProbability(3, 2, 0, 0)); + } + + public double knightProbability(int N, int K, int r, int c) { + dp = new double[N][N][K + 1]; + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + Arrays.fill(dp[i][j], -1.0D); + } + } + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + dp[i][j][0] = 1.0D; + } + } + return dp(dp, r, c, K, N); + } + + private double dp(double[][][] dp, int r, int c, int K, int N) { + if (r < 0 || r >= N || c < 0 || c >= N) return 0.0D; + if (dp[r][c][K] != -1.0D) return dp[r][c][K]; + double sum = 0.0D; + for (int i = 0; i < 8; i++) { + int newR = r + R[i]; + int newC = c + C[i]; + if (newR >= 0 && newR < N && newC >= 0 && newC < N) { + sum += dp(dp, newR, newC, K - 1, N); + } + } + dp[r][c][K] = (sum / 8.0); + return dp[r][c][K]; + } +} diff --git a/src/main/java/dynamic_programming/LargestMultipleOfThree.java b/src/main/java/dynamic_programming/LargestMultipleOfThree.java new file mode 100644 index 00000000..1042aca3 --- /dev/null +++ b/src/main/java/dynamic_programming/LargestMultipleOfThree.java @@ -0,0 +1,81 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 29/05/2020 Given an integer array of digits, return the largest + * multiple of three that can be formed by concatenating some of the given digits in any order. + * + *

Since the answer may not fit in an integer data type, return the answer as a string. + * + *

If there is no answer return an empty string. + * + *

Example 1: + * + *

Input: digits = [8,1,9] Output: "981" Example 2: + * + *

Input: digits = [8,6,7,1,0] Output: "8760" Example 3: + * + *

Input: digits = [1] Output: "" Example 4: + * + *

Input: digits = [0,0,0,0,0,0] Output: "0" + * + *

Constraints: + * + *

1 <= digits.length <= 10^4 0 <= digits[i] <= 9 The returning answer must not contain + * unnecessary leading zeros. + */ +public class LargestMultipleOfThree { + public static void main(String[] args) { + int[] A = {8, 4, 1, 7}; + System.out.println(new LargestMultipleOfThree().largestMultipleOfThree(A)); + } + + int[][][] DP; + + public String largestMultipleOfThree(int[] digits) { + Arrays.sort(digits); + for (int i = 0, j = digits.length - 1; i < j; i++, j--) { + int t = digits[i]; + digits[i] = digits[j]; + digits[j] = t; + } + DP = new int[digits.length][3][2]; + for (int i = 0; i < digits.length; i++) { + for (int j = 0; j < 3; j++) { + Arrays.fill(DP[i][j], -2); + } + } + dp(0, 0, digits); + StringBuilder sb = new StringBuilder(); + int r = 0; + for (int i = 0; i < digits.length; i++) { + if (DP[i][r][1] >= DP[i][r][0]) { + if (sb.length() != 1 || sb.charAt(0) != '0') { + sb.append(digits[i]); + } + r = (Integer.parseInt(String.valueOf(r + "" + digits[i])) % 3); + } + } + return sb.toString(); + } + + private int dp(int i, int r, int[] A) { + if (i == A.length) { + return r == 0 ? 0 : -1; + } else if (DP[i][r][0] != -2) { + return Math.max(DP[i][r][0], DP[i][r][1]); + } else { + int d = A[i]; + int newR = (Integer.parseInt(String.valueOf(r + "" + d)) % 3); + int result = dp(i + 1, newR, A); + if (result >= 0) { + result = result + 1; + } + DP[i][r][1] = result; + DP[i][r][0] = dp(i + 1, r, A); + return Math.max(DP[i][r][0], DP[i][r][1]); + } + } +} diff --git a/src/main/java/dynamic_programming/LargestPlusSign.java b/src/main/java/dynamic_programming/LargestPlusSign.java new file mode 100644 index 00000000..19310d26 --- /dev/null +++ b/src/main/java/dynamic_programming/LargestPlusSign.java @@ -0,0 +1,131 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 20/01/2018. In a 2D grid from (0, 0) to (N-1, N-1), every cell + * contains a 1, except those cells in the given list mines which are 0. What is the largest + * axis-aligned plus sign of 1s contained in the grid? Return the order of the plus sign. If there + * is none, return 0. + * + *

An "axis-aligned plus sign of 1s of order k" has some center grid[x][y] = 1 along with 4 arms + * of length k-1 going up, down, left, and right, and made of 1s. This is demonstrated in the + * diagrams below. Note that there could be 0s or 1s beyond the arms of the plus sign, only the + * relevant area of the plus sign is checked for 1s. + * + *

Examples of Axis-Aligned Plus Signs of Order k: + * + *

Order 1: 000 010 000 + * + *

Order 2: 00000 00100 01110 00100 00000 + * + *

Order 3: 0000000 0001000 0001000 0111110 0001000 0001000 0000000 Example 1: + * + *

Input: N = 5, mines = [[4, 2]] Output: 2 Explanation: 11111 11111 11111 11111 11011 In the + * above grid, the largest plus sign can only be order 2. One of them is marked in bold. Example 2: + * + *

Input: N = 2, mines = [] Output: 1 Explanation: There is no plus sign of order 2, but there is + * of order 1. Example 3: + * + *

Input: N = 1, mines = [[0, 0]] Output: 0 Explanation: There is no plus sign, so return 0. + * Note: + * + *

N will be an integer in the range [1, 500]. mines will have length at most 5000. mines[i] will + * be length 2 and consist of integers in the range [0, N-1]. (Additionally, programs submitted in + * C, C++, or C# will be judged with a slightly smaller time limit.) + * + *

Solution O(N x N) for each cell containing 1 find the nearest cell containing 0 in both + * vertical and horizontal direction - save this value in a 2d array for each cell. The answer is + * max value saved in 2d array. + */ +public class LargestPlusSign { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] M = {{4, 2}}; + System.out.println(new LargestPlusSign().orderOfLargestPlusSign(5, M)); + } + + public int orderOfLargestPlusSign(int N, int[][] mines) { + int[][] A = new int[N][N]; // array to save the mines information. + int[][] B = new int[N][N]; // array to save the minimum distance to the cell containing 0 + for (int[] row : mines) { + int r = row[0]; + int c = row[1]; + A[r][c] = 1; + } + for (int i = 0; i < A.length; i++) { + for (int j = 0; j < A[0].length; j++) { + if (A[i][j] == 0) { + A[i][j] = 1; + } else { + A[i][j] = 0; + } + B[i][j] = Integer.MAX_VALUE; + } + } + // For each rwo + for (int i = 0; i < A.length; i++) { + int prev = 0; + // forward direction + for (int j = 0; j < A[0].length; j++) { + if (A[i][j] == 0) { + prev = 0; + B[i][j] = 0; + } else { + prev++; + B[i][j] = Math.min(B[i][j], prev); + } + } + prev = 0; + // backward direction + for (int j = N - 1; j >= 0; j--) { + if (A[i][j] == 0) { + prev = 0; + B[i][j] = 0; + } else { + prev++; + B[i][j] = Math.min(B[i][j], prev); + } + } + } + + // for each column + for (int j = 0; j < B[0].length; j++) { + int prev = 0; + // downward direction + for (int i = 0; i < B.length; i++) { + if (A[i][j] == 0) { + prev = 0; + B[i][j] = 0; + } else { + prev++; + B[i][j] = Math.min(B[i][j], prev); + } + } + prev = 0; + // upward direction + for (int i = N - 1; i >= 0; i--) { + if (A[i][j] == 0) { + prev = 0; + B[i][j] = 0; + } else { + prev++; + B[i][j] = Math.min(B[i][j], prev); + } + } + } + + int result = 0; + for (int i = 0; i < B.length; i++) { + for (int j = 0; j < B[0].length; j++) { + result = Math.max(result, B[i][j]); + } + } + return result; + } +} diff --git a/src/main/java/dynamic_programming/LargestSumOfAverages.java b/src/main/java/dynamic_programming/LargestSumOfAverages.java new file mode 100644 index 00000000..11377ce4 --- /dev/null +++ b/src/main/java/dynamic_programming/LargestSumOfAverages.java @@ -0,0 +1,58 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; +/** + * Created by gouthamvidyapradhan on 04/05/2018. We partition a row of numbers A into at most K + * adjacent (non-empty) groups, then our score is the sum of the average of each group. What is the + * largest score we can achieve? + * + *

Note that our partition must use every number in A, and that scores are not necessarily + * integers. + * + *

Example: Input: A = [9,1,2,3,9] K = 3 Output: 20 Explanation: The best choice is to partition + * A into [9], [1, 2, 3], [9]. The answer is 9 + (1 + 2 + 3) / 3 + 9 = 20. We could have also + * partitioned A into [9, 1], [2], [3, 9], for example. That partition would lead to a score of 5 + + * 2 + 6 = 13, which is worse. + * + *

Note: + * + *

1 <= A.length <= 100. 1 <= A[i] <= 10000. 1 <= K <= A.length. Answers within 10^-6 of the + * correct answer will be accepted as correct. + * + *

Solution: O(N x N x K): Calculate average for each sub-array starting from the right. + */ +public class LargestSumOfAverages { + + public static void main(String[] args) { + int[] A = {9, 1, 2, 3, 9}; + System.out.println(new LargestSumOfAverages().largestSumOfAverages(A, 3)); + } + + public double largestSumOfAverages(int[] A, int K) { + double[][] dp = new double[K][A.length]; + for (int i = dp[0].length - 1; i >= 0; i--) { + dp[0][i] = A[i]; + if (i + 1 < dp[0].length) { + dp[0][i] += dp[0][i + 1]; + } + } + + for (int i = dp[0].length - 1, j = 1; i >= 0; i--, j++) { + dp[0][i] = dp[0][i] / j; + } + + for (int i = dp[0].length - 1; i >= 0; i--) { + for (int j = 1; j < dp.length; j++) { + double sum = 0.0D; + for (int k = i, c = 1; k < dp[0].length; k++, c++) { + sum += A[k]; + if (k + 1 < dp[0].length) { + double avg = sum / c; + avg += dp[j - 1][k + 1]; + dp[j][i] = Math.max(dp[j][i], avg); + } + } + } + } + return dp[K - 1][0]; + } +} diff --git a/src/main/java/dynamic_programming/LengthofLongestFibonacciSubsequence.java b/src/main/java/dynamic_programming/LengthofLongestFibonacciSubsequence.java new file mode 100644 index 00000000..d7966bee --- /dev/null +++ b/src/main/java/dynamic_programming/LengthofLongestFibonacciSubsequence.java @@ -0,0 +1,63 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 23/08/2019 A sequence X_1, X_2, ..., X_n is fibonacci-like if: + * + *

n >= 3 X_i + X_{i+1} = X_{i+2} for all i + 2 <= n Given a strictly increasing array A of + * positive integers forming a sequence, find the length of the longest fibonacci-like subsequence + * of A. If one does not exist, return 0. + * + *

(Recall that a subsequence is derived from another sequence A by deleting any number of + * elements (including none) from A, without changing the order of the remaining elements. For + * example, [3, 5, 8] is a subsequence of [3, 4, 5, 6, 7, 8].) + * + *

Example 1: + * + *

Input: [1,2,3,4,5,6,7,8] Output: 5 Explanation: The longest subsequence that is + * fibonacci-like: [1,2,3,5,8]. Example 2: + * + *

Input: [1,3,7,11,12,14,18] Output: 3 Explanation: The longest subsequence that is + * fibonacci-like: [1,11,12], [3,11,14] or [7,11,18]. + * + *

Note: + * + *

3 <= A.length <= 1000 1 <= A[0] < A[1] < ... < A[A.length - 1] <= 10^9 (The time limit has + * been reduced by 50% for submissions in Java, C, and C++.) + * + *

Solution O(N ^ 2) For every value at index i sum up with every value at index j and check if + * this sum is already known if known then increment the sub-sequence length by 1, continue this + * process until max length is found. + */ +public class LengthofLongestFibonacciSubsequence { + public static void main(String[] args) { + int[] A = {1, 2, 4, 7, 12, 20}; + System.out.println(new LengthofLongestFibonacciSubsequence().lenLongestFibSubseq(A)); + } + + public int lenLongestFibSubseq(int[] A) { + if (A.length < 3) return 0; + Map> indexMap = new HashMap<>(); + int max = 0; + for (int i = A.length - 1; i >= 0; i--) { + Map subHashMap = new HashMap<>(); + for (int j = 0; j < i; j++) { + int sum = A[i] + A[j]; + if (indexMap.containsKey(sum)) { + if (indexMap.get(sum).containsKey(A[i])) { + int value = 1 + indexMap.get(sum).get(A[i]); + subHashMap.put(A[j], value); + max = Math.max(max, value); + } else { + subHashMap.put(A[j], 1); + max = Math.max(max, 1); + } + } + } + indexMap.put(A[i], subHashMap); + } + return max == 0 ? 0 : max + 2; + } +} diff --git a/src/main/java/dynamic_programming/LongestChunkedPalindromeDecomposition.java b/src/main/java/dynamic_programming/LongestChunkedPalindromeDecomposition.java new file mode 100644 index 00000000..2d2ed539 --- /dev/null +++ b/src/main/java/dynamic_programming/LongestChunkedPalindromeDecomposition.java @@ -0,0 +1,57 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 17/04/2020 Return the largest possible k such that there exists + * a_1, a_2, ..., a_k such that: + * + *

Each a_i is a non-empty string; Their concatenation a_1 + a_2 + ... + a_k is equal to text; + * For all 1 <= i <= k, a_i = a_{k+1 - i}. + * + *

Example 1: + * + *

Input: text = "ghiabcdefhelloadamhelloabcdefghi" Output: 7 Explanation: We can split the + * string on "(ghi)(abcdef)(hello)(adam)(hello)(abcdef)(ghi)". Example 2: + * + *

Input: text = "merchant" Output: 1 Explanation: We can split the string on "(merchant)". + * Example 3: + * + *

Input: text = "antaprezatepzapreanta" Output: 11 Explanation: We can split the string on + * "(a)(nt)(a)(pre)(za)(tpe)(za)(pre)(a)(nt)(a)". Example 4: + * + *

Input: text = "aaa" Output: 3 Explanation: We can split the string on "(a)(a)(a)". + * + *

Constraints: + * + *

text consists only of lowercase English characters. 1 <= text.length <= 1000 + */ +public class LongestChunkedPalindromeDecomposition { + public static void main(String[] args) { + System.out.println( + new LongestChunkedPalindromeDecomposition().longestDecomposition("merchant")); + } + + private int[] DP; + + public int longestDecomposition(String text) { + DP = new int[text.length()]; + return dp(0, text.length() - 1, text); + } + + private int dp(int i, int e, String text) { + if (i > e) return 0; + else if (i == e) return 1; + else if (DP[i] > 0) return DP[i]; + else { + for (int j = e; j > i; j--) { + if (text.charAt(j) == text.charAt(i)) { + if (text.substring(j, e + 1).equals(text.substring(i, i + (e - j + 1)))) { + DP[i] = Math.max(DP[i], dp(i + (e - j + 1), j - 1, text) + 2); + } + } + } + DP[i] = DP[i] == 0 ? 1 : DP[i]; + return DP[i]; + } + } +} diff --git a/src/main/java/dynamic_programming/LongestIncreasingSubsequence.java b/src/main/java/dynamic_programming/LongestIncreasingSubsequence.java new file mode 100644 index 00000000..1550be7d --- /dev/null +++ b/src/main/java/dynamic_programming/LongestIncreasingSubsequence.java @@ -0,0 +1,42 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 02/04/2017. Given an unsorted array of integers, find the + * length of longest increasing subsequence. + * + *

For example, Given [10, 9, 2, 5, 3, 7, 101, 18], The longest increasing subsequence is [2, 3, + * 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is + * only necessary for you to return the length. + * + *

Your algorithm should run in O(n2) complexity. + * + *

Follow up: Could you improve it to O(n log n) time complexity? + */ +public class LongestIncreasingSubsequence { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] nums = {9, 8, 7, 6}; + System.out.println(new LongestIncreasingSubsequence().lengthOfLIS(nums)); + } + + public int lengthOfLIS(int[] nums) { + if (nums.length == 0) return 0; + int[] A = new int[nums.length]; + int max = Integer.MIN_VALUE; + for (int i = 0, l = nums.length; i < l; i++) { + int lis = 1; + for (int j = 0; j < i; j++) { + if (nums[i] > nums[j]) lis = Math.max(lis, A[j] + 1); + } + A[i] = lis; + max = Math.max(max, A[i]); + } + return max; + } +} diff --git a/src/main/java/dynamic_programming/LongestPaliandromicSubstring.java b/src/main/java/dynamic_programming/LongestPaliandromicSubstring.java new file mode 100644 index 00000000..30b34e83 --- /dev/null +++ b/src/main/java/dynamic_programming/LongestPaliandromicSubstring.java @@ -0,0 +1,62 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 24/02/2017. Given a string s, find the longest palindromic + * substring in s. You may assume that the maximum length of s is 1000. + * + *

Example: + * + *

Input: "babad" + * + *

Output: "bab" + * + *

Note: "aba" is also a valid answer. Example: + * + *

Input: "cbbd" + * + *

Output: "bb" + */ +public class LongestPaliandromicSubstring { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new LongestPaliandromicSubstring().longestPalindrome("forgeeksskeegfor")); + } + + public String longestPalindrome(String s) { + int l = s.length(); + int startIndex = 0; + int maxLen = 1; + boolean[][] A = new boolean[l][l]; + for (int i = 0, j = 0; i < l; i++, j++) A[i][j] = true; + + for (int i = 0, j = i + 1; j < l; i++, j++) { + if (s.charAt(i) == s.charAt(j)) { + A[i][j] = true; + startIndex = i; + maxLen = 2; + } + } + + for (int k = 3; k <= l; k++) { + for (int i = 0, j = k - 1; j < l; i++, j++) { + if (s.charAt(i) == s.charAt(j)) { + A[i][j] = A[i + 1][j - 1]; + if (A[i][j]) { + if (k > maxLen) { + startIndex = i; + maxLen = k; + } + } + } + } + } + + return s.substring(startIndex, startIndex + maxLen); + } +} diff --git a/src/main/java/dynamic_programming/LongestPalindromicSubsequence.java b/src/main/java/dynamic_programming/LongestPalindromicSubsequence.java new file mode 100644 index 00000000..ce06e81a --- /dev/null +++ b/src/main/java/dynamic_programming/LongestPalindromicSubsequence.java @@ -0,0 +1,40 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 27/03/2017. Given an unsorted array of integers, find the + * length of longest increasing subsequence. + * + *

For example, Given [10, 9, 2, 5, 3, 7, 101, 18], The longest increasing subsequence is [2, 3, + * 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is + * only necessary for you to return the length. + * + *

Your algorithm should run in O(n2) complexity. + * + *

Follow up: Could you improve it to O(n log n) time complexity? + */ +public class LongestPalindromicSubsequence { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new LongestPalindromicSubsequence().longestPalindromeSubseq("bbbab")); + } + + public int longestPalindromeSubseq(String s) { + int[][] dp = new int[s.length() + 1][s.length() + 1]; + String sI = new StringBuilder(s).reverse().toString(); + for (int i = 1, l = s.length(); i <= l; i++) + for (int j = 1; j <= l; j++) { + dp[i][j] = + (s.charAt(i - 1) == sI.charAt(j - 1)) + ? dp[i - 1][j - 1] + 1 + : Math.max(dp[i - 1][j], dp[i][j - 1]); + } + + return dp[s.length()][s.length()]; + } +} diff --git a/src/main/java/dynamic_programming/MakeArrayStrictlyIncreasing.java b/src/main/java/dynamic_programming/MakeArrayStrictlyIncreasing.java new file mode 100644 index 00000000..1a403009 --- /dev/null +++ b/src/main/java/dynamic_programming/MakeArrayStrictlyIncreasing.java @@ -0,0 +1,82 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 28/02/2020 Given two integer arrays arr1 and arr2, return the + * minimum number of operations (possibly zero) needed to make arr1 strictly increasing. + * + *

In one operation, you can choose two indices 0 <= i < arr1.length and 0 <= j < arr2.length and + * do the assignment arr1[i] = arr2[j]. + * + *

If there is no way to make arr1 strictly increasing, return -1. + * + *

Example 1: + * + *

Input: arr1 = [1,5,3,6,7], arr2 = [1,3,2,4] Output: 1 Explanation: Replace 5 with 2, then arr1 + * = [1, 2, 3, 6, 7]. Example 2: + * + *

Input: arr1 = [1,5,3,6,7], arr2 = [4,3,1] Output: 2 Explanation: Replace 5 with 3 and then + * replace 3 with 4. arr1 = [1, 3, 4, 6, 7]. Example 3: + * + *

Input: arr1 = [1,5,3,6,7], arr2 = [1,6,3,3] Output: -1 Explanation: You can't make arr1 + * strictly increasing. + * + *

Constraints: + * + *

1 <= arr1.length, arr2.length <= 2000 0 <= arr1[i], arr2[i] <= 10^9 + */ +public class MakeArrayStrictlyIncreasing { + public static void main(String[] args) { + int[] A = {1, 5, 3, 6, 7}; + int[] B = {4, 3, 1}; + System.out.println(new MakeArrayStrictlyIncreasing().makeArrayIncreasing(A, B)); + } + + private int[][] DP; + + public int makeArrayIncreasing(int[] arr1, int[] arr2) { + DP = new int[arr1.length][arr2.length + 1]; + Arrays.sort(arr2); + for (int i = 0; i < arr1.length; i++) { + Arrays.fill(DP[i], -1); + } + int min = dp(1, 0, arr1, arr2); + for (int i = 0; i < arr2.length; i++) { + min = Math.min(min, dp(1, i + 1, arr1, arr2) + 1); + } + return min == 2000 ? -1 : min; + } + + private int dp(int i, int j, int[] arr1, int[] arr2) { + if (i >= arr1.length) return 0; + else if (DP[i][j] != -1) return DP[i][j]; + else { + int curr = (j == 0 ? arr1[i - 1] : arr2[j - 1]); + int min = 2000; + if (arr1[i] > curr) { + min = dp(i + 1, 0, arr1, arr2); + } + int k = binarySearch(arr2, curr); + if (k != -1) { + min = Math.min(min, dp(i + 1, k + 1, arr1, arr2) + 1); + } + DP[i][j] = min; + return min; + } + } + + private int binarySearch(int[] A, int k) { + int l = 0, h = A.length; + int ans = -1; + while (l < h) { + int m = l + (h - l) / 2; + if (A[m] > k) { + ans = m; + h = m; + } else l = m + 1; + } + return ans; + } +} diff --git a/src/main/java/dynamic_programming/MaxSum3SubArray.java b/src/main/java/dynamic_programming/MaxSum3SubArray.java new file mode 100644 index 00000000..ce9cfe6e --- /dev/null +++ b/src/main/java/dynamic_programming/MaxSum3SubArray.java @@ -0,0 +1,122 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; +/** + * Created by gouthamvidyapradhan on 22/11/2017. + * + *

In a given array nums of positive integers, find three non-overlapping subarrays with maximum + * sum. + * + *

Each subarray will be of size k, and we want to maximize the sum of all 3*k entries. + * + *

Return the result as a list of indices representing the starting position of each interval + * (0-indexed). If there are multiple answers, return the lexicographically smallest one. + * + *

Example: Input: [1,2,1,2,6,7,5,1], 2 Output: [0, 3, 5] Explanation: Subarrays [1, 2], [2, 6], + * [7, 5] correspond to the starting indices [0, 3, 5]. We could have also taken [2, 1], but an + * answer of [1, 3, 5] would be lexicographically larger. Note: nums.length will be between 1 and + * 20000. nums[i] will be between 1 and 65535. k will be between 1 and floor(nums.length / 3). + * + *

Solution: O(N) solution by prefix and reverse-prefix sum First calculate max index for array + * index k, then use this to calculate max index for two array indices j and k and again use this + * result to calculate the final max index for i, j and k for the 3 arrays. + */ +public class MaxSum3SubArray { + + class Max { + int i, j, k, max; + + Max(int i, int max) { + this.i = i; + this.max = max; + } + + Max(int i, int j, int max) { + this.i = i; + this.j = j; + this.max = max; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 2, 1, 2, 6}; + int[] result = new MaxSum3SubArray().maxSumOfThreeSubarrays(A, 1); + for (int i = 0; i < result.length; i++) System.out.print(result[i] + " "); + } + + public int[] maxSumOfThreeSubarrays(int[] nums, int k) { + int[] fPrefix = new int[nums.length]; // forward prefix sum + int[] rPrefix = new int[nums.length]; // reverse prefix sum + + // calculate forward prefix sum + for (int i = 0; i < k; i++) { + fPrefix[0] += nums[i]; + } + for (int i = 1; i < nums.length; i++) { + if (i + k - 1 < nums.length) { + fPrefix[i] = fPrefix[i - 1] - nums[i - 1] + nums[i + k - 1]; + } + } + int sum = 0; + for (int i = nums.length - 1; i >= nums.length - k; i--) { + sum += nums[i]; + } + Max[] max1 = new Max[nums.length]; + max1[nums.length - k] = new Max(nums.length - k, sum); + + // calculate reverse prefix sum + rPrefix[nums.length - k] = sum; + for (int i = nums.length - 1; i >= 0; i--) { + if (i + k >= nums.length) continue; + rPrefix[i] = rPrefix[i + 1] - nums[i + k] + nums[i]; + } + + // calculate max for k index + for (int i = nums.length - 1; i >= 0; i--) { + if (i + k >= nums.length) continue; + max1[i] = new Max(i, rPrefix[i]); + if (max1[i + 1] != null) { + if (max1[i].max < max1[i + 1].max) { + max1[i] = new Max(max1[i + 1].i, max1[i + 1].max); + } + } + } + + // calculate max for j and k index + Max[] max2 = new Max[nums.length]; + for (int i = nums.length - 1; i >= 0; i--) { + if (i + k < nums.length && max1[i + k] != null) { + max2[i] = new Max(i, max1[i + k].i, fPrefix[i] + max1[i + k].max); + } + } + for (int i = nums.length - 1; i >= 0; i--) { + if (i + 1 > nums.length - 1 || max2[i + 1] == null) continue; + if (max2[i].max < max2[i + 1].max) { + max2[i].max = max2[i + 1].max; + max2[i].i = max2[i + 1].i; + max2[i].j = max2[i + 1].j; + } + } + + // calculate max for i, j and k index + int[] result = new int[3]; + int max = 0; + for (int i = 0; i < nums.length; i++) { + if ((i + k) < nums.length - 1 && max2[i + k] != null) { + int temp = fPrefix[i] + max2[i + k].max; + if (temp > max) { + max = temp; + result[0] = i; + result[1] = max2[i + k].i; + result[2] = max2[i + k].j; + } + } + } + return result; + } +} diff --git a/src/main/java/dynamic_programming/MaximalSquare.java b/src/main/java/dynamic_programming/MaximalSquare.java new file mode 100644 index 00000000..c2ec8835 --- /dev/null +++ b/src/main/java/dynamic_programming/MaximalSquare.java @@ -0,0 +1,54 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 28/11/2017. Given a 2D binary matrix filled with 0's and 1's, + * find the largest square containing only 1's and return its area. + * + *

For example, given the following matrix: + * + *

1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0 Return 4. + * + *

Solution: O(n * m) time and space complexity. Calculate the max length of a square using DP(i, + * j) = min(DP[i - 1][j], DP[i][j - 1], DP[i - 1][j - 1]) + 1 Return the square of the answer. + */ +public class MaximalSquare { + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + char[][] A = { + {'1', '0', '1', '0', '0'}, + {'1', '0', '1', '1', '1'}, + {'1', '1', '1', '1', '1'}, + {'1', '0', '0', '1', '0'} + }; + System.out.println(new MaximalSquare().maximalSquare(A)); + } + + public int maximalSquare(char[][] matrix) { + if (matrix.length == 0) return 0; + int[][] dp = new int[matrix.length][matrix[0].length]; + for (int i = 0; i < matrix.length; i++) { + for (int j = 0; j < matrix[0].length; j++) { + if (j - 1 >= 0 && i - 1 >= 0) { + if (matrix[i][j] == '1') { + dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]); + dp[i][j] = Math.min(dp[i][j], dp[i - 1][j - 1]) + 1; + } + } else { + dp[i][j] = matrix[i][j] == '1' ? 1 : 0; + } + } + } + int max = 0; + for (int i = 0; i < dp.length; i++) { + for (int j = 0; j < dp[0].length; j++) { + max = Math.max(max, dp[i][j]); + } + } + return max * max; + } +} diff --git a/src/main/java/dynamic_programming/MaximumProductSubarray.java b/src/main/java/dynamic_programming/MaximumProductSubarray.java new file mode 100644 index 00000000..b669a656 --- /dev/null +++ b/src/main/java/dynamic_programming/MaximumProductSubarray.java @@ -0,0 +1,36 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 02/04/2017. Find the contiguous subarray within an array + * (containing at least one number) which has the largest product. + * + *

For example, given the array [2,3,-2,4], the contiguous subarray [2,3] has the largest product + * = 6. + */ +public class MaximumProductSubarray { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {2, 3, -2, 4}; + System.out.println(new MaximumProductSubarray().maxProduct(A)); + } + + public int maxProduct(int[] nums) { + if (nums.length == 1) return nums[0]; + int min = nums[0]; + int max = nums[0]; + int result = max; + for (int i = 1; i < nums.length; i++) { + int prevMin = min, prevMax = max; + min = Math.min(nums[i], Math.min(nums[i] * prevMin, nums[i] * prevMax)); + max = Math.max(nums[i], Math.max(nums[i] * prevMin, nums[i] * prevMax)); + result = Math.max(result, max); + } + return result; + } +} diff --git a/src/main/java/dynamic_programming/MaximumProfitInJobScheduling.java b/src/main/java/dynamic_programming/MaximumProfitInJobScheduling.java new file mode 100644 index 00000000..3495aec1 --- /dev/null +++ b/src/main/java/dynamic_programming/MaximumProfitInJobScheduling.java @@ -0,0 +1,81 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 18/06/2020 We have n jobs, where every job is scheduled to be + * done from startTime[i] to endTime[i], obtaining a profit of profit[i]. + * + *

You're given the startTime, endTime and profit arrays, return the maximum profit you can take + * such that there are no two jobs in the subset with overlapping time range. + * + *

If you choose a job that ends at time X you will be able to start another job that starts at + * time X. + * + *

Example 1: + * + *

Input: startTime = [1,2,3,3], endTime = [3,4,5,6], profit = [50,10,40,70] Output: 120 + * Explanation: The subset chosen is the first and fourth job. Time range [1-3]+[3-6] , we get + * profit of 120 = 50 + 70. Example 2: + * + *

Input: startTime = [1,2,3,4,6], endTime = [3,5,10,6,9], profit = [20,20,100,70,60] Output: 150 + * Explanation: The subset chosen is the first, fourth and fifth job. Profit obtained 150 = 20 + 70 + * + 60. Example 3: + * + *

Input: startTime = [1,1,1], endTime = [2,3,4], profit = [5,6,4] Output: 6 + * + *

Constraints: + * + *

1 <= startTime.length == endTime.length == profit.length <= 5 * 104 1 <= startTime[i] < + * endTime[i] <= 109 1 <= profit[i] <= 104 + */ +public class MaximumProfitInJobScheduling { + private class Pair { + int a, b; + + Pair(int a, int b) { + this.a = a; + this.b = b; + } + } + + public static void main(String[] args) { + int[] st = {4, 2, 4, 8, 2}; + int[] et = {5, 5, 5, 10, 8}; + int[] p = {1, 2, 8, 10, 4}; + System.out.println(new MaximumProfitInJobScheduling().jobScheduling(st, et, p)); + } + + Map DP; + TreeMap> graph; + + public int jobScheduling(int[] startTime, int[] endTime, int[] profit) { + DP = new HashMap<>(); + graph = new TreeMap<>(); + int start = 0; + for (int i = 0; i < startTime.length; i++) { + List children = graph.getOrDefault(startTime[i], new ArrayList<>()); + children.add(new Pair(endTime[i], profit[i])); + graph.putIfAbsent(startTime[i], children); + start = Math.min(start, startTime[i]); + } + return dp(start); + } + + private int dp(int i) { + Integer current = graph.ceilingKey(i); + if (current == null) return 0; + else if (DP.containsKey(current)) return DP.get(current); + else { + List children = graph.get(current); + int profit = 0; + for (Pair c : children) { + profit = Math.max(profit, dp(c.a) + c.b); + } + profit = Math.max(profit, dp(current + 1)); + DP.put(current, profit); + return profit; + } + } +} diff --git a/src/main/java/dynamic_programming/MaximumSubarray.java b/src/main/java/dynamic_programming/MaximumSubarray.java new file mode 100644 index 00000000..82ed2628 --- /dev/null +++ b/src/main/java/dynamic_programming/MaximumSubarray.java @@ -0,0 +1,26 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 07/07/2017. Find the contiguous subarray within an array + * (containing at least one number) which has the largest sum. + * + *

For example, given the array [-2,1,-3,4,-1,2,1,-5,4], the contiguous subarray [4,-1,2,1] has + * the largest sum = 6. + */ +public class MaximumSubarray { + public static void main(String[] args) throws Exception { + int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4}; + System.out.println(new MaximumSubarray().maxSubArray(nums)); + } + + public int maxSubArray(int[] nums) { + if (nums.length == 1) return nums[0]; + int max = nums[nums.length - 1]; + for (int i = nums.length - 2; i >= 0; i--) { + nums[i] = Math.max(nums[i], nums[i] + nums[i + 1]); + max = Math.max(max, nums[i]); + } + return max; + } +} diff --git a/src/main/java/dynamic_programming/MaximumVacationDays.java b/src/main/java/dynamic_programming/MaximumVacationDays.java new file mode 100644 index 00000000..a530a7a8 --- /dev/null +++ b/src/main/java/dynamic_programming/MaximumVacationDays.java @@ -0,0 +1,95 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 13/04/2019 + * + *

LeetCode wants to give one of its best employees the option to travel among N cities to + * collect algorithm problems. But all work and no play makes Jack a dull boy, you could take + * vacations in some particular cities and weeks. Your job is to schedule the traveling to maximize + * the number of vacation days you could take, but there are certain rules and restrictions you need + * to follow. + * + *

Rules and restrictions: You can only travel among N cities, represented by indexes from 0 to + * N-1. Initially, you are in the city indexed 0 on Monday. The cities are connected by flights. The + * flights are represented as a N*N matrix (not necessary symmetrical), called flights representing + * the airline status from the city i to the city j. If there is no flight from the city i to the + * city j, flights[i][j] = 0; Otherwise, flights[i][j] = 1. Also, flights[i][i] = 0 for all i. You + * totally have K weeks (each week has 7 days) to travel. You can only take flights at most once per + * day and can only take flights on each week's Monday morning. Since flight time is so short, we + * don't consider the impact of flight time. For each city, you can only have restricted vacation + * days in different weeks, given an N*K matrix called days representing this relationship. For the + * value of days[i][j], it represents the maximum days you could take vacation in the city i in the + * week j. You're given the flights matrix and days matrix, and you need to output the maximum + * vacation days you could take during K weeks. + * + *

Example 1: Input:flights = [[0,1,1],[1,0,1],[1,1,0]], days = [[1,3,1],[6,0,3],[3,3,3]] Output: + * 12 Explanation: Ans = 6 + 3 + 3 = 12. + * + *

One of the best strategies is: 1st week : fly from city 0 to city 1 on Monday, and play 6 days + * and work 1 day. (Although you start at city 0, we could also fly to and start at other cities + * since it is Monday.) 2nd week : fly from city 1 to city 2 on Monday, and play 3 days and work 4 + * days. 3rd week : stay at city 2, and play 3 days and work 4 days. Example 2: Input:flights = + * [[0,0,0],[0,0,0],[0,0,0]], days = [[1,1,1],[7,7,7],[7,7,7]] Output: 3 Explanation: Ans = 1 + 1 + + * 1 = 3. + * + *

Since there is no flights enable you to move to another city, you have to stay at city 0 for + * the whole 3 weeks. For each week, you only have one day to play and six days to work. So the + * maximum number of vacation days is 3. Example 3: Input:flights = [[0,1,1],[1,0,1],[1,1,0]], days + * = [[7,0,0],[0,7,0],[0,0,7]] Output: 21 Explanation: Ans = 7 + 7 + 7 = 21 + * + *

One of the best strategies is: 1st week : stay at city 0, and play 7 days. 2nd week : fly from + * city 0 to city 1 on Monday, and play 7 days. 3rd week : fly from city 1 to city 2 on Monday, and + * play 7 days. Note: N and K are positive integers, which are in the range of [1, 100]. In the + * matrix flights, all the values are integers in the range of [0, 1]. In the matrix days, all the + * values are integers in the range [0, 7]. You could stay at a city beyond the number of vacation + * days, but you should work on the extra days, which won't be counted as vacation days. If you fly + * from the city A to the city B and take the vacation on that day, the deduction towards vacation + * days will count towards the vacation days of city B in that week. We don't consider the impact of + * flight hours towards the calculation of vacation days. + * + *

Solution: O(N x N x K) Start from the last week K; Calculate for the last week maximum + * vacation days for all possible cities. Now, iteratively calculate backwards for each week K - 1 + * and for each city and for each available connection from the city memoize the maximum vacation + * days possible for this city Return the answer for city 0 and week 0 + */ +public class MaximumVacationDays { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[][] flights = { + {0, 1, 0, 1, 1}, {1, 0, 0, 1, 1}, {1, 0, 0, 1, 0}, {0, 1, 0, 0, 0}, {0, 0, 0, 1, 0} + }; + int[][] days = { + {0, 4, 1, 6, 6}, {4, 3, 3, 0, 1}, {3, 6, 6, 5, 0}, {1, 3, 1, 1, 4}, {5, 3, 3, 3, 4} + }; + System.out.println(new MaximumVacationDays().maxVacationDays(flights, days)); + } + + public int maxVacationDays(int[][] flights, int[][] days) { + int N = days.length; + int W = days[0].length; + int[][] DP = new int[N][W + 1]; + for (int w = W - 1; w >= 0; w--) { + for (int n = 0; n < N; n++) { + DP[n][w] = days[n][w] + DP[n][w + 1]; + } + + for (int n = 0; n < N; n++) { + int max = Integer.MIN_VALUE; + int[] F = flights[n]; + for (int i = 0; i < F.length; i++) { + if (F[i] == 1) { + max = Math.max(max, days[i][w] + DP[i][w + 1]); + } + } + DP[n][w] = Math.max(DP[n][w], max); + } + } + return DP[0][0]; + } +} diff --git a/src/main/java/dynamic_programming/MinCostClimbingStairs.java b/src/main/java/dynamic_programming/MinCostClimbingStairs.java new file mode 100644 index 00000000..d316b922 --- /dev/null +++ b/src/main/java/dynamic_programming/MinCostClimbingStairs.java @@ -0,0 +1,32 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 30/04/2018. On a staircase, the i-th step has some non-negative + * cost cost[i] assigned (0 indexed). + * + *

Once you pay the cost, you can either climb one or two steps. You need to find minimum cost to + * reach the top of the floor, and you can either start from the step with index 0, or the step with + * index 1. + * + *

Example 1: Input: cost = [10, 15, 20] Output: 15 Explanation: Cheapest is start on cost[1], + * pay that cost and go to the top. Example 2: Input: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] + * Output: 6 Explanation: Cheapest is start on cost[0], and only step on 1s, skipping cost[3]. Note: + * cost will have a length in the range [2, 1000]. Every cost[i] will be an integer in the range [0, + * 999]. + * + *

Solution: O(N) At every step there are two options, either cost[i] + cost[i + 1] or cost[i] + + * cost[i + 2] + */ +public class MinCostClimbingStairs { + public static void main(String[] args) throws Exception {} + + public int minCostClimbingStairs(int[] cost) { + for (int i = cost.length - 1; i >= 0; i--) { + if (i + 1 < cost.length && i + 2 < cost.length) { + cost[i] = Math.min(cost[i] + cost[i + 1], cost[i] + cost[i + 2]); + } + } + return Math.min(cost[0], cost[1]); + } +} diff --git a/src/main/java/dynamic_programming/MinimumCostForTickets.java b/src/main/java/dynamic_programming/MinimumCostForTickets.java new file mode 100644 index 00000000..e1477c5c --- /dev/null +++ b/src/main/java/dynamic_programming/MinimumCostForTickets.java @@ -0,0 +1,85 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 05/05/2019 In a country popular for train travel, you have + * planned some train travelling one year in advance. The days of the year that you will travel is + * given as an array days. Each day is an integer from 1 to 365. + * + *

Train tickets are sold in 3 different ways: + * + *

a 1-day pass is sold for costs[0] dollars; a 7-day pass is sold for costs[1] dollars; a 30-day + * pass is sold for costs[2] dollars. The passes allow that many days of consecutive travel. For + * example, if we get a 7-day pass on day 2, then we can travel for 7 days: day 2, 3, 4, 5, 6, 7, + * and 8. + * + *

Return the minimum number of dollars you need to travel every day in the given list of days. + * + *

Example 1: + * + *

Input: days = [1,4,6,7,8,20], costs = [2,7,15] Output: 11 Explanation: For example, here is + * one way to buy passes that lets you travel your travel plan: On day 1, you bought a 1-day pass + * for costs[0] = $2, which covered day 1. On day 3, you bought a 7-day pass for costs[1] = $7, + * which covered days 3, 4, ..., 9. On day 20, you bought a 1-day pass for costs[0] = $2, which + * covered day 20. In total you spent $11 and covered all the days of your travel. Example 2: + * + *

Input: days = [1,2,3,4,5,6,7,8,9,10,30,31], costs = [2,7,15] Output: 17 Explanation: For + * example, here is one way to buy passes that lets you travel your travel plan: On day 1, you + * bought a 30-day pass for costs[2] = $15 which covered days 1, 2, ..., 30. On day 31, you bought a + * 1-day pass for costs[0] = $2 which covered day 31. In total you spent $17 and covered all the + * days of your travel. + * + *

Note: + * + *

1 <= days.length <= 365 1 <= days[i] <= 365 days is in strictly increasing order. costs.length + * == 3 1 <= costs[i] <= 1000 + * + *

Solution: O(N ^ 2 x 3) + */ +public class MinimumCostForTickets { + + public static void main(String[] args) { + int[] days = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 30, 31}; + int[] costs = {2, 7, 15}; + System.out.println(new MinimumCostForTickets().mincostTickets(days, costs)); + } + /** + * Main method + * + * @param days + * @param costs + * @return + */ + public int mincostTickets(int[] days, int[] costs) { + int[] min = new int[days.length]; + Arrays.fill(min, Integer.MAX_VALUE); + for (int i = days.length - 1; i >= 0; i--) { + for (int j = 0; j < costs.length; j++) { + if (j == 0) { + min[i] = Math.min(min[i], costs[j] + ((i + 1 >= min.length) ? 0 : min[i + 1])); + } else if (j == 1) { + int c = 0; + for (int k = i + 1; k < days.length; k++) { + if (days[k] >= (days[i] + 7)) { + c = min[k]; + break; + } + } + min[i] = Math.min(min[i], costs[j] + c); + } else { + int c = 0; + for (int k = i + 1; k < days.length; k++) { + if (days[k] >= (days[i] + 30)) { + c = min[k]; + break; + } + } + min[i] = Math.min(min[i], costs[j] + c); + } + } + } + return min[0]; + } +} diff --git a/src/main/java/dynamic_programming/MinimumCostToMergeStones.java b/src/main/java/dynamic_programming/MinimumCostToMergeStones.java new file mode 100644 index 00000000..8e0a1c80 --- /dev/null +++ b/src/main/java/dynamic_programming/MinimumCostToMergeStones.java @@ -0,0 +1,97 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 02/02/2020 There are N piles of stones arranged in a row. The + * i-th pile has stones[i] stones. + * + *

A move consists of merging exactly K consecutive piles into one pile, and the cost of this + * move is equal to the total number of stones in these K piles. + * + *

Find the minimum cost to merge all piles of stones into one pile. If it is impossible, return + * -1. + * + *

Example 1: + * + *

Input: stones = [3,2,4,1], K = 2 Output: 20 Explanation: We start with [3, 2, 4, 1]. We merge + * [3, 2] for a cost of 5, and we are left with [5, 4, 1]. We merge [4, 1] for a cost of 5, and we + * are left with [5, 5]. We merge [5, 5] for a cost of 10, and we are left with [10]. The total cost + * was 20, and this is the minimum possible. Example 2: + * + *

Input: stones = [3,2,4,1], K = 3 Output: -1 Explanation: After any merge operation, there are + * 2 piles left, and we can't merge anymore. So the task is impossible. Example 3: + * + *

Input: stones = [3,5,1,2,6], K = 3 Output: 25 Explanation: We start with [3, 5, 1, 2, 6]. We + * merge [5, 1, 2] for a cost of 8, and we are left with [3, 8, 6]. We merge [3, 8, 6] for a cost of + * 17, and we are left with [17]. The total cost was 25, and this is the minimum possible. + * + *

Note: + * + *

1 <= stones.length <= 30 2 <= K <= 30 1 <= stones[i] <= 100 + */ +public class MinimumCostToMergeStones { + public static void main(String[] args) { + int[] A = {3, 5, 1, 2, 6}; + System.out.println(new MinimumCostToMergeStones().mergeStones(A, 2)); + } + + private int[][][] DP; + private int K; + private int[] sum; + + public int mergeStones(int[] stones, int K) { + if (((stones.length - 1) % (K - 1)) != 0) return -1; + DP = new int[stones.length][stones.length][K + 1]; + this.K = K; + sum = new int[stones.length]; + sum[0] = stones[0]; + for (int i = 1; i < stones.length; i++) { + sum[i] = (sum[i - 1] + stones[i]); + } + for (int i = 0; i < stones.length; i++) { + for (int j = 0; j < stones.length; j++) { + for (int k = 1; k <= K; k++) { + if (k == 1 && i == j) { + DP[i][j][k] = 0; + } else DP[i][j][k] = 999999; + } + } + } + for (int r = 2; r <= stones.length; r++) { + for (int i = 0; i < stones.length; i++) { + int j = i + r - 1; + if (j < stones.length) { + for (int k = 2; k <= K; k++) { + int min = Integer.MAX_VALUE; + for (int t = i; t < j; t++) { + min = Math.min(min, DP[i][t][k - 1] + DP[t + 1][j][1]); + } + DP[i][j][k] = min; + } + DP[i][j][1] = DP[i][j][K] + (sum[j] - ((i - 1) >= 0 ? sum[i - 1] : 0)); + } + } + } + return DP[0][stones.length - 1][1]; + // return dp(0, stones.length - 1, 1); + } + + private int dp(int s, int e, int X) { + if (s == e) { + if (X == 1) return 0; + else return 999999; + } + if (DP[s][e][X] != 0) return DP[s][e][X]; + if (X == 1) { + DP[s][e][X] = dp(s, e, K) + sum[e] - ((s - 1) >= 0 ? sum[s - 1] : 0); + return DP[s][e][X]; + } else { + int min = Integer.MAX_VALUE; + for (int t = s; t < e; t++) { + min = Math.min(min, dp(s, t, X - 1) + dp(t + 1, e, 1)); + } + DP[s][e][X] = min; + return DP[s][e][X]; + } + } +} diff --git a/src/main/java/dynamic_programming/MinimumDifficultyOfAJobSchedule.java b/src/main/java/dynamic_programming/MinimumDifficultyOfAJobSchedule.java new file mode 100644 index 00000000..16015802 --- /dev/null +++ b/src/main/java/dynamic_programming/MinimumDifficultyOfAJobSchedule.java @@ -0,0 +1,66 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 19/02/2020 You want to schedule a list of jobs in d days. Jobs + * are dependent (i.e To work on the i-th job, you have to finish all the jobs j where 0 <= j < i). + * + *

You have to finish at least one task every day. The difficulty of a job schedule is the sum of + * difficulties of each day of the d days. The difficulty of a day is the maximum difficulty of a + * job done in that day. + * + *

Given an array of integers jobDifficulty and an integer d. The difficulty of the i-th job is + * jobDifficulty[i]. + * + *

Return the minimum difficulty of a job schedule. If you cannot find a schedule for the jobs + * return -1. + * + *

Example 1: + * + *

Input: jobDifficulty = [6,5,4,3,2,1], d = 2 Output: 7 Explanation: First day you can finish + * the first 5 jobs, total difficulty = 6. Second day you can finish the last job, total difficulty + * = 1. The difficulty of the schedule = 6 + 1 = 7 Example 2: + * + *

Input: jobDifficulty = [9,9,9], d = 4 Output: -1 Explanation: If you finish a job per day you + * will still have a free day. you cannot find a schedule for the given jobs. Example 3: + * + *

Input: jobDifficulty = [1,1,1], d = 3 Output: 3 Explanation: The schedule is one job per day. + * total difficulty will be 3. Example 4: + * + *

Input: jobDifficulty = [7,1,7,1,7,1], d = 3 Output: 15 Example 5: + * + *

Input: jobDifficulty = [11,111,22,222,33,333,44,444], d = 6 Output: 843 + * + *

Constraints: + * + *

1 <= jobDifficulty.length <= 300 0 <= jobDifficulty[i] <= 1000 1 <= d <= 10 + */ +public class MinimumDifficultyOfAJobSchedule { + public static void main(String[] args) { + int[] A = {11, 111, 22, 222, 33, 333, 44, 444}; + System.out.println(new MinimumDifficultyOfAJobSchedule().minDifficulty(A, 6)); + } + + int[][] DP; + + public int minDifficulty(int[] jobDifficulty, int d) { + DP = new int[jobDifficulty.length][d + 1]; + int result = dp(0, d, jobDifficulty); + if (result == 50000) return -1; + else return result; + } + + private int dp(int i, int d, int[] J) { + if (i >= J.length && d == 0) return 0; + else if (J.length - i < d || d <= 0) return 50000; + else if (DP[i][d] != 0) return DP[i][d]; + int max = J[i]; + int min = Integer.MAX_VALUE; + for (int k = i; k <= J.length - 1; k++) { + max = Math.max(max, J[k]); + min = Math.min(min, max + dp(k + 1, d - 1, J)); + } + DP[i][d] = min; + return min; + } +} diff --git a/src/main/java/dynamic_programming/MinimumDistanceToTypeAWordUsingTwoFingers.java b/src/main/java/dynamic_programming/MinimumDistanceToTypeAWordUsingTwoFingers.java new file mode 100644 index 00000000..a0e3198f --- /dev/null +++ b/src/main/java/dynamic_programming/MinimumDistanceToTypeAWordUsingTwoFingers.java @@ -0,0 +1,99 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 26/04/2020 + * + *

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z + * + *

You have a keyboard layout as shown above in the XY plane, where each English uppercase letter + * is located at some coordinate, for example, the letter A is located at coordinate (0,0), the + * letter B is located at coordinate (0,1), the letter P is located at coordinate (2,3) and the + * letter Z is located at coordinate (4,1). + * + *

Given the string word, return the minimum total distance to type such string using only two + * fingers. The distance between coordinates (x1,y1) and (x2,y2) is |x1 - x2| + |y1 - y2|. + * + *

Note that the initial positions of your two fingers are considered free so don't count towards + * your total distance, also your two fingers do not have to start at the first letter or the first + * two letters. + * + *

Example 1: + * + *

Input: word = "CAKE" Output: 3 Explanation: Using two fingers, one optimal way to type "CAKE" + * is: Finger 1 on letter 'C' -> cost = 0 Finger 1 on letter 'A' -> cost = Distance from letter 'C' + * to letter 'A' = 2 Finger 2 on letter 'K' -> cost = 0 Finger 2 on letter 'E' -> cost = Distance + * from letter 'K' to letter 'E' = 1 Total distance = 3 Example 2: + * + *

Input: word = "HAPPY" Output: 6 Explanation: Using two fingers, one optimal way to type + * "HAPPY" is: Finger 1 on letter 'H' -> cost = 0 Finger 1 on letter 'A' -> cost = Distance from + * letter 'H' to letter 'A' = 2 Finger 2 on letter 'P' -> cost = 0 Finger 2 on letter 'P' -> cost = + * Distance from letter 'P' to letter 'P' = 0 Finger 1 on letter 'Y' -> cost = Distance from letter + * 'A' to letter 'Y' = 4 Total distance = 6 Example 3: + * + *

Input: word = "NEW" Output: 3 Example 4: + * + *

Input: word = "YEAR" Output: 7 + * + *

Constraints: + * + *

2 <= word.length <= 300 Each word[i] is an English uppercase letter. + */ +public class MinimumDistanceToTypeAWordUsingTwoFingers { + int[][] DP; + int[][] dist; + + public static void main(String[] args) { + System.out.println(new MinimumDistanceToTypeAWordUsingTwoFingers().minimumDistance("YEAR")); + } + + public int minimumDistance(String word) { + DP = new int[word.length()][word.length()]; + dist = new int[26][26]; + char[][] chars = { + {'A', 'B', 'C', 'D', 'E', 'F'}, + {'G', 'H', 'I', 'J', 'K', 'L'}, + {'M', 'N', 'O', 'P', 'Q', 'R'}, + {'S', 'T', 'U', 'V', 'W', 'X'}, + {'Y', 'Z', ' ', ' ', ' ', ' '} + }; + for (int i = 0; i < chars.length; i++) { + for (int j = 0; j < chars[0].length; j++) { + char from = chars[i][j]; + if (from == ' ') break; + for (int k = 0; k < chars.length; k++) { + for (int l = 0; l < chars[0].length; l++) { + char to = chars[k][l]; + if (to == ' ') break; + dist[from - 'A'][to - 'A'] = Math.abs(k - i) + Math.abs(l - j); + } + } + } + } + for (int i = 0; i < word.length(); i++) { + for (int j = 0; j < word.length(); j++) { + DP[i][j] = -1; + } + } + int min = Integer.MAX_VALUE; + for (int i = 1; i < word.length(); i++) { + min = Math.min(min, dp(0, i, word)); + } + return min; + } + + private int dp(int p, int i, String S) { + if (DP[p][i] != -1) return DP[p][i]; + else { + int left = Integer.MAX_VALUE, right; + int min = Integer.MAX_VALUE; + if (p + 1 == S.length()) return 0; + if (p + 1 != i) { + left = dp(p + 1, i, S) + dist[S.charAt(p) - 'A'][S.charAt(p + 1) - 'A']; + } + right = dp(p + 1, p, S) + dist[S.charAt(i) - 'A'][S.charAt(p + 1) - 'A']; + DP[p][i] = Math.min(min, Math.min(left, right)); + return DP[p][i]; + } + } +} diff --git a/src/main/java/dynamic_programming/MinimumNumberOfRefuelingStops.java b/src/main/java/dynamic_programming/MinimumNumberOfRefuelingStops.java new file mode 100644 index 00000000..d2185f69 --- /dev/null +++ b/src/main/java/dynamic_programming/MinimumNumberOfRefuelingStops.java @@ -0,0 +1,79 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 24/07/2018. A car travels from a starting position to a + * destination which is target miles east of the starting position. + * + *

Along the way, there are gas stations. Each station[i] represents a gas station that is + * station[i][0] miles east of the starting position, and has station[i][1] liters of gas. + * + *

The car starts with an infinite tank of gas, which initially has startFuel liters of fuel in + * it. It uses 1 liter of gas per 1 mile that it drives. + * + *

When the car reaches a gas station, it may stop and refuel, transferring all the gas from the + * station into the car. + * + *

What is the least number of refueling stops the car must make in order to reach its + * destination? If it cannot reach the destination, return -1. + * + *

Note that if the car reaches a gas station with 0 fuel left, the car can still refuel there. + * If the car reaches the destination with 0 fuel left, it is still considered to have arrived. + * + *

Example 1: + * + *

Input: target = 1, startFuel = 1, stations = [] Output: 0 Explanation: We can reach the target + * without refueling. Example 2: + * + *

Input: target = 100, startFuel = 1, stations = [[10,100]] Output: -1 Explanation: We can't + * reach the target (or even the first gas station). Example 3: + * + *

Input: target = 100, startFuel = 10, stations = [[10,60],[20,30],[30,30],[60,40]] Output: 2 + * Explanation: We start with 10 liters of fuel. We drive to position 10, expending 10 liters of + * fuel. We refuel from 0 liters to 60 liters of gas. Then, we drive from position 10 to position 60 + * (expending 50 liters of fuel), and refuel from 10 liters to 50 liters of gas. We then drive to + * and reach the target. We made 2 refueling stops along the way, so we return 2. + * + *

Note: + * + *

1 <= target, startFuel, stations[i][1] <= 10^9 0 <= stations.length <= 500 0 < stations[0][0] + * < stations[1][0] < ... < stations[stations.length-1][0] < target + * + *

Solution O(N ^ 2): Maintain a DP array with maximum distance that can be travelled with i + * stops. DP[i] is the max distance that can be travelled with exactly i stops. The minimum i where + * the target can be achieved (dp[i] >= target) will be the answer. + */ +public class MinimumNumberOfRefuelingStops { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int target = 100, startFuel = 10; + int[][] stations = {{10, 60}, {20, 30}, {30, 30}, {60, 40}}; + System.out.println( + new MinimumNumberOfRefuelingStops().minRefuelStops(target, startFuel, stations)); + } + + public int minRefuelStops(int target, int startFuel, int[][] stations) { + long[] dp = new long[stations.length + 1]; + dp[0] = startFuel; + for (int i = 0; i < stations.length; i++) { + int d = stations[i][0]; + int f = stations[i][1]; + for (int j = i; j >= 0; j--) { + if (dp[j] >= d) { + dp[j + 1] = Math.max(dp[j + 1], dp[j] + f); + } + } + } + for (int i = 0; i < dp.length; i++) { + if (dp[i] >= target) { + return i; + } + } + return -1; + } +} diff --git a/src/main/java/dynamic_programming/MinimumNumberOfTaps.java b/src/main/java/dynamic_programming/MinimumNumberOfTaps.java new file mode 100644 index 00000000..45b1de6e --- /dev/null +++ b/src/main/java/dynamic_programming/MinimumNumberOfTaps.java @@ -0,0 +1,71 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 01/03/2020 There is a one-dimensional garden on the x-axis. The + * garden starts at the point 0 and ends at the point n. (i.e The length of the garden is n). + * + *

There are n + 1 taps located at points [0, 1, ..., n] in the garden. + * + *

Given an integer n and an integer array ranges of length n + 1 where ranges[i] (0-indexed) + * means the i-th tap can water the area [i - ranges[i], i + ranges[i]] if it was open. + * + *

Return the minimum number of taps that should be open to water the whole garden, If the garden + * cannot be watered return -1. + * + *

Example 1: + * + *

Input: n = 5, ranges = [3,4,1,1,0,0] Output: 1 Explanation: The tap at point 0 can cover the + * interval [-3,3] The tap at point 1 can cover the interval [-3,5] The tap at point 2 can cover the + * interval [1,3] The tap at point 3 can cover the interval [2,4] The tap at point 4 can cover the + * interval [4,4] The tap at point 5 can cover the interval [5,5] Opening Only the second tap will + * water the whole garden [0,5] Example 2: + * + *

Input: n = 3, ranges = [0,0,0,0] Output: -1 Explanation: Even if you activate all the four + * taps you cannot water the whole garden. Example 3: + * + *

Input: n = 7, ranges = [1,2,1,0,2,1,0,1] Output: 3 Example 4: + * + *

Input: n = 8, ranges = [4,0,0,0,0,0,0,0,4] Output: 2 Example 5: + * + *

Input: n = 8, ranges = [4,0,0,0,4,0,0,0,4] Output: 1 + * + *

Constraints: + * + *

1 <= n <= 10^4 ranges.length == n + 1 0 <= ranges[i] <= 100 + */ +public class MinimumNumberOfTaps { + public static void main(String[] args) { + int[] A = {0, 1, 2, 0, 0, 1, 1, 0}; + System.out.println(new MinimumNumberOfTaps().minTaps(7, A)); + } + + int[] DP; + + public int minTaps(int n, int[] ranges) { + DP = new int[n + 1]; + Arrays.fill(DP, -2); + return dp(0, 0, ranges, n); + } + + private int dp(int i, int prev, int[] R, int n) { + if (i > n) return 0; + else if (DP[i] != -2) return DP[i]; + else { + int min = Integer.MAX_VALUE; + int start = R[prev] > 0 ? prev : i; + for (int j = start; j < start + 100 && j <= n; j++) { + if (j - R[j] <= prev) { + int result = dp(j + R[j] + 1, j + R[j], R, n); + if (result >= 0) { + min = Math.min(min, result + 1); + } + } + } + DP[i] = (min == Integer.MAX_VALUE ? -1 : min); + return DP[i]; + } + } +} diff --git a/src/main/java/dynamic_programming/NonNegativeIntegersWithoutConsecutiveOnes.java b/src/main/java/dynamic_programming/NonNegativeIntegersWithoutConsecutiveOnes.java new file mode 100644 index 00000000..e4fa996d --- /dev/null +++ b/src/main/java/dynamic_programming/NonNegativeIntegersWithoutConsecutiveOnes.java @@ -0,0 +1,85 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 20/10/2019 Given a positive integer n, find the number of + * non-negative integers less than or equal to n, whose binary representations do NOT contain + * consecutive ones. + * + *

Example 1: Input: 5 Output: 5 Explanation: Here are the non-negative integers <= 5 with their + * corresponding binary representations: 0 : 0 1 : 1 2 : 10 3 : 11 4 : 100 5 : 101 Among them, only + * integer 3 disobeys the rule (two consecutive ones) and the other 5 satisfy the rule. Note: 1 <= n + * <= 109 + * + *

Solution: O(1) (30 ^ 2) For each bit we can set either '0' or '1' starting from index i to 0, + * if we set 0 then the next bit i + 1 can be either set to 0 or 1 but, if we set it to 1 then the + * next bit at position i + 1 can only be 0 because two consecutive 1s are invalid. This gives us a + * general dp formula DP[0][i] = DP[0][i + 1] + DP[1][i + 1] for bit 0 and similarly DP[1][i] = + * DP[0][i + 1]. + * + *

Lets consider an example with number = 4 (binary representation is 100). Now, the above + * approach would calculate all possible number ranging from 0 (000) -> 7 (111), lets say the count + * is x. But, we actually want to restrict until only 100. Therefore we have to calculate all valid + * states starting from 100 until 111 and lets say this is y. Now, the answer would be x - y + 1. + * Adding 1 here because the state 100 (which is a valid state) would be counted twice in x and also + * in y. For cases where a binary representation of given N is like 1100 we have to find a max + * possible valid state which occurs just before 1100 which in this case is 1010 and now calculate y + * starting from 1010 to 1111. + */ +public class NonNegativeIntegersWithoutConsecutiveOnes { + public static void main(String[] args) { + System.out.println(new NonNegativeIntegersWithoutConsecutiveOnes().findIntegers(1000000000)); + } + + public int findIntegers(int num) { + int msbIndex = 0; + for (int i = 0; i < 31; i++) { + if (((1 << i) & num) > 0) { + msbIndex = i; + } + } + int[][] DP1 = new int[2][msbIndex + 1]; // count from 0 until all possible value. + int[][] DP2 = new int[2][msbIndex + 2]; // count from given N until max possible value + for (int i = msbIndex; i >= 0; i--) { + if (i == msbIndex) { + DP1[0][msbIndex] = 1; + DP1[1][msbIndex] = 1; + } else { + DP1[0][i] = DP1[0][i + 1] + DP1[1][i + 1]; + DP1[1][i] = DP1[0][i + 1]; + } + } + // find valid state just before given num + int[] bits = new int[msbIndex + 1]; + boolean bitFlipped = false; + for (int i = msbIndex, j = 0; i >= 0; i--, j++) { + if (j == 0) { + bits[j] = 1; + } else { + if (bitFlipped) { + bits[j] = bits[j - 1] == 0 ? 1 : 0; + } else { + if (((1 << i) & num) > 0) { + if (bits[j - 1] > 0) { + bits[j] = 0; + bitFlipped = true; + } else bits[j] = 1; + } + } + } + } + DP2[0][msbIndex + 1] = 1; + for (int i = bits.length - 1; i >= 0; i--) { + if (bits[i] == 0) { + DP2[0][i] = DP2[0][i + 1] + DP2[1][i + 1]; + // if the curr bit is 0 then, we can make this 1 provided the previous bit was not 1 + if (bits[i - 1] == 0) { + DP2[1][i] = (i == bits.length - 1) ? 1 : DP1[0][i + 1]; + } + } else { + DP2[1][i] = DP2[0][i + 1]; + } + } + return (DP1[0][0] + DP1[1][0]) - (DP2[0][0] + DP2[1][0]) + 1; + } +} diff --git a/src/main/java/dynamic_programming/NumberOfDiceRollsWithTargetSum.java b/src/main/java/dynamic_programming/NumberOfDiceRollsWithTargetSum.java new file mode 100644 index 00000000..3922b23f --- /dev/null +++ b/src/main/java/dynamic_programming/NumberOfDiceRollsWithTargetSum.java @@ -0,0 +1,53 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 29/11/2019 You have d dice, and each die has f faces numbered + * 1, 2, ..., f. + * + *

Return the number of possible ways (out of fd total ways) modulo 10^9 + 7 to roll the dice so + * the sum of the face up numbers equals target. + * + *

Example 1: + * + *

Input: d = 1, f = 6, target = 3 Output: 1 Explanation: You throw one die with 6 faces. There + * is only one way to get a sum of 3. Example 2: + * + *

Input: d = 2, f = 6, target = 7 Output: 6 Explanation: You throw two dice, each with 6 faces. + * There are 6 ways to get a sum of 7: 1+6, 2+5, 3+4, 4+3, 5+2, 6+1. Example 3: + * + *

Input: d = 2, f = 5, target = 10 Output: 1 Explanation: You throw two dice, each with 5 faces. + * There is only one way to get a sum of 10: 5+5. Example 4: + * + *

Input: d = 1, f = 2, target = 3 Output: 0 Explanation: You throw one die with 2 faces. There + * is no way to get a sum of 3. Example 5: + * + *

Input: d = 30, f = 30, target = 500 Output: 222616187 Explanation: The answer must be returned + * modulo 10^9 + 7. + * + *

Constraints: + * + *

1 <= d, f <= 30 1 <= target <= 1000 + */ +public class NumberOfDiceRollsWithTargetSum { + public static void main(String[] args) { + System.out.println(new NumberOfDiceRollsWithTargetSum().numRollsToTarget(3, 3, 3)); + } + + private final int MOD = 1000000007; + + public int numRollsToTarget(int d, int f, int target) { + int[][] DP = new int[d + 1][target + 1]; + for (int i = 1; i <= Math.min(f, target); i++) { + DP[1][i] = 1; + } + for (int i = 2; i <= d; i++) { + for (int j = 1; j <= target; j++) { + for (int k = 1; k <= Math.min(f, j); k++) { + DP[i][j] = (DP[i - 1][j - k]) == 0 ? DP[i][j] : ((DP[i][j] + (DP[i - 1][j - k])) % MOD); + } + } + } + return DP[d][target]; + } +} diff --git a/src/main/java/dynamic_programming/NumberOfLIS.java b/src/main/java/dynamic_programming/NumberOfLIS.java new file mode 100644 index 00000000..a6dd2ce6 --- /dev/null +++ b/src/main/java/dynamic_programming/NumberOfLIS.java @@ -0,0 +1,70 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 13/12/2017. Given an unsorted array of integers, find the + * number of longest increasing subsequence. + * + *

Example 1: Input: [1,3,5,4,7] Output: 2 Explanation: The two longest increasing subsequence + * are [1, 3, 4, 7] and [1, 3, 5, 7]. Example 2: Input: [2,2,2,2,2] Output: 5 Explanation: The + * length of longest continuous increasing subsequence is 1, and there are 5 subsequences' length is + * 1, so output 5. Note: Length of the given array will be not exceed 2000 and the answer is + * guaranteed to be fit in 32-bit signed int. + * + *

Solution O(n ^ 2) compute the LIS and save the results in length also save the max length of + * LIS in maxVal. Calculate the count as below + * + *

For every pair of (i, j) count[i] = count[i] + count[j] where length[i] == length[j] + 1 and + * nums[j] < nums[i] + * + *

sum-up the count for every length where length[i] == maxVal + */ +public class NumberOfLIS { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 12, 11, 1, 1, 1, 12}; + System.out.println(new NumberOfLIS().findNumberOfLIS(A)); + } + + public int findNumberOfLIS(int[] nums) { + if (nums.length == 0) return 0; + int[] length = new int[nums.length]; + length[0] = 1; + int maxVal = 1; + for (int i = 1; i < nums.length; i++) { + int max = 1; + for (int j = 0; j < i; j++) { + if (nums[i] > nums[j]) { + max = Math.max(max, length[j] + 1); + maxVal = Math.max(maxVal, max); + } + } + length[i] = max; + } + int[] count = new int[nums.length]; + count[0] = 1; + for (int i = 1; i < length.length; i++) { + for (int j = 0; j < i; j++) { + if ((length[j] + 1 == length[i]) && (nums[j] < nums[i])) { + count[i] += count[j]; + } + } + if (count[i] == 0) { + count[i] = 1; // default is just 1 + } + } + int ans = 0; + for (int i = 0; i < length.length; i++) { + if (length[i] == maxVal) { + ans += count[i]; + } + } + return ans; + } +} diff --git a/src/main/java/dynamic_programming/NumberOfMusicPlaylists.java b/src/main/java/dynamic_programming/NumberOfMusicPlaylists.java new file mode 100644 index 00000000..e81aae24 --- /dev/null +++ b/src/main/java/dynamic_programming/NumberOfMusicPlaylists.java @@ -0,0 +1,36 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** Created by gouthamvidyapradhan on 13/06/2020 */ +public class NumberOfMusicPlaylists { + public static void main(String[] args) { + // + } + + int[][] DP; + final int MOD = (int) 1e9 + 7; + + public int numMusicPlaylists(int N, int L, int K) { + DP = new int[L + 1][N + 1]; + for (int i = 0; i <= L; i++) { + Arrays.fill(DP[i], -1); + } + DP[0][0] = 1; + return (int) dp(L, N, K, N); + } + + private long dp(int i, int j, int K, int N) { + if (i < j) return 0; + else if (i < 0 || j < 0) return 0; + else if (DP[i][j] != -1) return DP[i][j]; + else { + long sum = 0L; + sum += ((dp(i - 1, j - 1, K, N) * (N - (j - 1))) % MOD); + sum += (dp(i - 1, j, K, N) * (Math.max(j - K, 0)) % MOD); + DP[i][j] = (int) (sum % MOD); + return DP[i][j]; + } + } +} diff --git a/src/main/java/dynamic_programming/NumberOfPathsWithMaxScore.java b/src/main/java/dynamic_programming/NumberOfPathsWithMaxScore.java new file mode 100644 index 00000000..09d2fcee --- /dev/null +++ b/src/main/java/dynamic_programming/NumberOfPathsWithMaxScore.java @@ -0,0 +1,84 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Created by gouthamvidyapradhan on 13/04/2021 You are given a square board of characters. You can + * move on the board starting at the bottom right square marked with the character 'S'. + * + *

You need to reach the top left square marked with the character 'E'. The rest of the squares + * are labeled either with a numeric character 1, 2, ..., 9 or with an obstacle 'X'. In one move you + * can go up, left or up-left (diagonally) only if there is no obstacle there. + * + *

Return a list of two integers: the first integer is the maximum sum of numeric characters you + * can collect, and the second is the number of such paths that you can take to get that maximum + * sum, taken modulo 10^9 + 7. + * + *

In case there is no path, return [0, 0]. + * + *

Example 1: + * + *

Input: board = ["E23","2X2","12S"] Output: [7,1] Example 2: + * + *

Input: board = ["E12","1X1","21S"] Output: [4,2] Example 3: + * + *

Input: board = ["E11","XXX","11S"] Output: [0,0] + * + *

Constraints: + * + *

2 <= board.length == board[i].length <= 100 Solution: O(N x N) where N is the length of board. + */ +public class NumberOfPathsWithMaxScore { + public static void main(String[] args) { + String[] board = {"E11", "XXX", "11S"}; + List input = Arrays.stream(board).collect(Collectors.toList()); + int[] r = new NumberOfPathsWithMaxScore().pathsWithMaxScore(input); + System.out.println(r[0] + " " + r[1]); + } + + long[][] M, N; + final int[] R = {0, 1, 1}; + final int[] C = {1, 1, 0}; + int MOD = (int) 1e9 + 7; + + public int[] pathsWithMaxScore(List board) { + M = new long[board.size()][board.get(0).length()]; + N = new long[board.size()][board.get(0).length()]; + N[board.size() - 1][board.get(0).length() - 1] = 1; + for (int i = board.size() - 1; i >= 0; i--) { + for (int j = board.get(i).length() - 1; j >= 0; j--) { + char curr = board.get(i).charAt(j); + if (curr != 'X') { + int currInt = 0; + if (curr != 'S' && curr != 'E') { + currInt = Integer.parseInt(String.valueOf(curr)); + } + long currMax = -1; + for (int k = 0; k < 3; k++) { + int newR = i + R[k]; + int newC = j + C[k]; + if (newR < board.size() + && newC < board.get(0).length() + && board.get(newR).charAt(newC) != 'X' + && N[newR][newC] != 0) { + M[i][j] = Math.max(M[i][j], ((currInt + M[newR][newC]) % MOD)); + long newMax = ((currInt + M[newR][newC]) % MOD); + if (newMax > currMax) { + currMax = newMax; + N[i][j] = N[newR][newC]; + } else if (newMax == currMax) { + N[i][j] = ((N[newR][newC] + N[i][j]) % MOD); + } + } + } + } + } + } + int[] res = new int[2]; + res[0] = (int) M[0][0]; + res[1] = (int) N[0][0]; + return res; + } +} diff --git a/src/main/java/dynamic_programming/NumberOfWaysToStayInTheSamePlace.java b/src/main/java/dynamic_programming/NumberOfWaysToStayInTheSamePlace.java new file mode 100644 index 00000000..9da8381b --- /dev/null +++ b/src/main/java/dynamic_programming/NumberOfWaysToStayInTheSamePlace.java @@ -0,0 +1,68 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 05/04/2020 You have a pointer at index 0 in an array of size + * arrLen. At each step, you can move 1 position to the left, 1 position to the right in the array + * or stay in the same place (The pointer should not be placed outside the array at any time). + * + *

Given two integers steps and arrLen, return the number of ways such that your pointer still at + * index 0 after exactly steps steps. + * + *

Since the answer may be too large, return it modulo 10^9 + 7. + * + *

Example 1: + * + *

Input: steps = 3, arrLen = 2 Output: 4 Explanation: There are 4 differents ways to stay at + * index 0 after 3 steps. Right, Left, Stay Stay, Right, Left Right, Stay, Left Stay, Stay, Stay + * Example 2: + * + *

Input: steps = 2, arrLen = 4 Output: 2 Explanation: There are 2 differents ways to stay at + * index 0 after 2 steps Right, Left Stay, Stay Example 3: + * + *

Input: steps = 4, arrLen = 2 Output: 8 + * + *

Constraints: + * + *

1 <= steps <= 500 1 <= arrLen <= 10^6 + * + *

Solution O(S x S) where S is number of steps. This is quite a straight forward problem. Every + * state is a combination of position in the array and the number of steps. From every state we can + * traverse in three direction remain in the same position i.e (i, n - 1), move right (i + 1, n - 1) + * and move left (i - 1, n - 1). The base state will be (0, 0) which is equal to count of 1, memoize + * each state and do a dop down dp staring from state (0, N). + */ +public class NumberOfWaysToStayInTheSamePlace { + + private static final int MOD = (int) (1e9 + 7); + + public static void main(String[] args) { + System.out.println(new NumberOfWaysToStayInTheSamePlace().numWays(500, 1000000)); + } + + int[][] DP; + + public int numWays(int steps, int arrLen) { + int colLimit = arrLen < steps ? arrLen : steps; + DP = new int[colLimit + 1][steps + 1]; + for (int i = 0; i <= colLimit; i++) { + Arrays.fill(DP[i], -1); + } + DP[0][0] = 1; + return (int) dp(0, steps, arrLen); + } + + private long dp(int i, int n, int A) { + if (i < 0 || i >= A) return 0; + else if (n < 0) return 0; + if (DP[i][n] != -1) return DP[i][n]; + DP[i][n] = + (int) + (((((dp(i, n - 1, A) % MOD) + (dp(i - 1, n - 1, A) % MOD)) % MOD) + + (dp(i + 1, n - 1, A) % MOD)) + % MOD); + return DP[i][n]; + } +} diff --git a/src/main/java/dynamic_programming/OddEvenJump.java b/src/main/java/dynamic_programming/OddEvenJump.java new file mode 100644 index 00000000..f7238aed --- /dev/null +++ b/src/main/java/dynamic_programming/OddEvenJump.java @@ -0,0 +1,138 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 17/03/2019 You are given an integer array A. From some starting + * index, you can make a series of jumps. The (1st, 3rd, 5th, ...) jumps in the series are called + * odd numbered jumps, and the (2nd, 4th, 6th, ...) jumps in the series are called even numbered + * jumps. + * + *

You may from index i jump forward to index j (with i < j) in the following way: + * + *

During odd numbered jumps (ie. jumps 1, 3, 5, ...), you jump to the index j such that A[i] <= + * A[j] and A[j] is the smallest possible value. If there are multiple such indexes j, you can only + * jump to the smallest such index j. During even numbered jumps (ie. jumps 2, 4, 6, ...), you jump + * to the index j such that A[i] >= A[j] and A[j] is the largest possible value. If there are + * multiple such indexes j, you can only jump to the smallest such index j. (It may be the case that + * for some index i, there are no legal jumps.) A starting index is good if, starting from that + * index, you can reach the end of the array (index A.length - 1) by jumping some number of times + * (possibly 0 or more than once.) + * + *

Return the number of good starting indexes. + * + *

Example 1: + * + *

Input: [10,13,12,14,15] Output: 2 Explanation: From starting index i = 0, we can jump to i = 2 + * (since A[2] is the smallest among A[1], A[2], A[3], A[4] that is greater or equal to A[0]), then + * we can't jump any more. From starting index i = 1 and i = 2, we can jump to i = 3, then we can't + * jump any more. From starting index i = 3, we can jump to i = 4, so we've reached the end. From + * starting index i = 4, we've reached the end already. In total, there are 2 different starting + * indexes (i = 3, i = 4) where we can reach the end with some number of jumps. Example 2: + * + *

Input: [2,3,1,1,4] Output: 3 Explanation: From starting index i = 0, we make jumps to i = 1, i + * = 2, i = 3: + * + *

During our 1st jump (odd numbered), we first jump to i = 1 because A[1] is the smallest value + * in (A[1], A[2], A[3], A[4]) that is greater than or equal to A[0]. + * + *

During our 2nd jump (even numbered), we jump from i = 1 to i = 2 because A[2] is the largest + * value in (A[2], A[3], A[4]) that is less than or equal to A[1]. A[3] is also the largest value, + * but 2 is a smaller index, so we can only jump to i = 2 and not i = 3. + * + *

During our 3rd jump (odd numbered), we jump from i = 2 to i = 3 because A[3] is the smallest + * value in (A[3], A[4]) that is greater than or equal to A[2]. + * + *

We can't jump from i = 3 to i = 4, so the starting index i = 0 is not good. + * + *

In a similar manner, we can deduce that: From starting index i = 1, we jump to i = 4, so we + * reach the end. From starting index i = 2, we jump to i = 3, and then we can't jump anymore. From + * starting index i = 3, we jump to i = 4, so we reach the end. From starting index i = 4, we are + * already at the end. In total, there are 3 different starting indexes (i = 1, i = 3, i = 4) where + * we can reach the end with some number of jumps. Example 3: + * + *

Input: [5,1,3,4,2] Output: 3 Explanation: We can reach the end from starting indexes 1, 2, and + * 4. + * + *

Note: + * + *

1 <= A.length <= 20000 0 <= A[i] < 100000 + * + *

Solution: O(N log N) For each array index and for each odd/even turn pre-calculate the next + * jump index - this can be achieved in O(n log n) by using a balanced tree. Check for each array + * index if we can reach end of the array by using the pre-calculated values for next jump - cache + * the values to avoid recalculating. Sum up total number of such start indices and that will be the + * answer. + */ +public class OddEvenJump { + + private class Node { + int num, pos; + + Node(int num, int pos) { + this.num = num; + this.pos = pos; + } + } + + TreeSet treeSet; + int[][] next; + int[][] possible; + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[] A = {10, 13, 12, 14, 15}; + System.out.println(new OddEvenJump().oddEvenJumps(A)); + } + + public int oddEvenJumps(int[] A) { + treeSet = new TreeSet<>(Comparator.comparingInt(o -> o.num)); + next = new int[2][A.length]; + possible = new int[2][A.length]; + Arrays.fill(next[0], -1); + Arrays.fill(next[1], -1); + Arrays.fill(possible[0], -1); + Arrays.fill(possible[1], -1); + for (int i = A.length - 1; i >= 0; i--) { + int num = A[i]; + // odd case + Node curr = new Node(num, i); + Node ceil = treeSet.ceiling(new Node(num, i)); + if (ceil != null) { + next[0][i] = ceil.pos; + } + // even case + Node floor = treeSet.floor(new Node(num, i)); + if (floor != null) { + next[1][i] = floor.pos; + } + treeSet.remove(curr); + treeSet.add(curr); + } + int count = 0; + for (int i = 0; i < A.length; i++) { + count += dp(A, i, next, possible, 0) == 1 ? 1 : 0; + } + return count; + } + + private int dp(int[] A, int i, int[][] next, int[][] possible, int oddOrEven) { + if (i == A.length - 1) return 1; + else if (possible[oddOrEven][i] == 1 || possible[oddOrEven][i] == 0) { + return possible[oddOrEven][i]; + } else { + int nextPos = oddOrEven == 0 ? next[0][i] : next[1][i]; + if (nextPos == -1) { + possible[oddOrEven][i] = 0; + return possible[oddOrEven][i]; + } else { + possible[oddOrEven][i] = dp(A, nextPos, next, possible, ((oddOrEven + 1) % 2)); + return possible[oddOrEven][i]; + } + } + } +} diff --git a/src/main/java/dynamic_programming/OnesAndZeroes.java b/src/main/java/dynamic_programming/OnesAndZeroes.java new file mode 100644 index 00000000..7f260040 --- /dev/null +++ b/src/main/java/dynamic_programming/OnesAndZeroes.java @@ -0,0 +1,65 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 01/08/2019 In the computer world, use restricted resource you + * have to generate maximum benefit is what we always want to pursue. + * + *

For now, suppose you are a dominator of m 0s and n 1s respectively. On the other hand, there + * is an array with strings consisting of only 0s and 1s. + * + *

Now your task is to find the maximum number of strings that you can form with given m 0s and n + * 1s. Each 0 and 1 can be used at most once. + * + *

Note: + * + *

The given numbers of 0s and 1s will both not exceed 100 The size of given string array won't + * exceed 600. + * + *

Example 1: + * + *

Input: Array = {"10", "0001", "111001", "1", "0"}, m = 5, n = 3 Output: 4 + * + *

Explanation: This are totally 4 strings can be formed by the using of 5 0s and 3 1s, which are + * “10,”0001”,”1”,”0” + * + *

Example 2: + * + *

Input: Array = {"10", "0", "1"}, m = 1, n = 1 Output: 2 + * + *

Explanation: You could form "10", but then you'd have nothing left. Better form "0" and "1". + * + *

Solution: O(S x m x n) For every string array position we have two choices i. pick this value + * or ii. not pick this value. Evaluate both these cases and cache the result in a dp array. + */ +public class OnesAndZeroes { + public static void main(String[] args) { + String[] str = {"10", "0", "1"}; + System.out.println(new OnesAndZeroes().findMaxForm(str, 1, 1)); + } + + public int findMaxForm(String[] strs, int m, int n) { + int[][][] dp = new int[strs.length + 1][m + 1][n + 1]; + for (int i = strs.length - 1; i >= 0; i--) { + String string = strs[i]; + int zero = 0; + int one = 0; + for (char c : string.toCharArray()) { + if (c == '0') { + zero++; + } else { + one++; + } + } + for (int p = m; p >= 0; p--) { + for (int q = n; q >= 0; q--) { + dp[i][p][q] = dp[i + 1][p][q]; + if (p - zero >= 0 && q - one >= 0) { + dp[i][p][q] = Math.max(dp[i][p][q], dp[i + 1][p - zero][q - one] + 1); + } + } + } + } + return dp[0][m][n]; + } +} diff --git a/src/main/java/dynamic_programming/OutOfBoundaryPaths.java b/src/main/java/dynamic_programming/OutOfBoundaryPaths.java new file mode 100644 index 00000000..3bf44810 --- /dev/null +++ b/src/main/java/dynamic_programming/OutOfBoundaryPaths.java @@ -0,0 +1,49 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 15/05/2019 There is an m by n grid with a ball. Given the start + * coordinate (i,j) of the ball, you can move the ball to adjacent cell or cross the grid boundary + * in four directions (up, down, left, right). However, you can at most move N times. Find out the + * number of paths to move the ball out of grid boundary. The answer may be very large, return it + * after mod 10 ^ 9 + 7. + * + *

Solution: O(m x n x N x 4) Move in all possible directions from the starting position (i, j) + * and keep track of distance traversed and ensure the distance traversed does not exceed N. Keep + * the count of number of possibilities to go out of the boundary for each cell reached. Return the + * sum in cell (a, b) + */ +public class OutOfBoundaryPaths { + + final int[] R = {1, -1, 0, 0}; + final int[] C = {0, 0, 1, -1}; + int[][][] DP; + int mod = 1000000007; + + public static void main(String[] args) { + System.out.println(new OutOfBoundaryPaths().findPaths(2, 2, 2, 0, 0)); + } + + public int findPaths(int m, int n, int N, int a, int b) { + if (N == 0) return 0; + DP = new int[m][n][N + 1]; + + for (int k = 1; k <= N; k++) { + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + for (int p = 0; p < 4; p++) { + int newR = i + R[p]; + int newC = j + C[p]; + if (newR < 0 || newC < 0 || newR >= m || newC >= n) { + DP[i][j][k] = ((DP[i][j][k] + 1) % mod); + } else { + DP[i][j][k] = (((DP[i][j][k] + DP[newR][newC][k - 1])) % mod); + } + } + } + } + } + + return DP[a][b][N]; + } +} diff --git a/src/main/java/dynamic_programming/PaintHouseII.java b/src/main/java/dynamic_programming/PaintHouseII.java new file mode 100644 index 00000000..b22086be --- /dev/null +++ b/src/main/java/dynamic_programming/PaintHouseII.java @@ -0,0 +1,67 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 23/12/2017. There are a row of n houses, each house can be + * painted with one of the k colors. The cost of painting each house with a certain color is + * different. You have to paint all the houses such that no two adjacent houses have the same color. + * + *

The cost of painting each house with a certain color is represented by a n x k cost matrix. + * For example, costs[0][0] is the cost of painting house 0 with color 0; costs[1][2] is the cost of + * painting house 1 with color 2, and so on... Find the minimum cost to paint all houses. + * + *

Note: All costs are positive integers. + * + *

Follow up: Could you solve it in O(nk) runtime? + * + *

Solution: Worst case run-time complexity of O(n x k) : Perform a prefix and postfix sum and + * maintain a auxiliary array to keep track of prefix and post-fix sum. Perform a bottom-up dp to + * calculate the final result. DP[i][j] = DP[i][j] + Min(LeftPrefixSum[i + 1][j], RightPrefixSum[i + + * 1][j]) + */ +public class PaintHouseII { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] A = {{1, 2, 3}, {1, 2, 3}, {1, 2, 3}}; + System.out.println(new PaintHouseII().minCostII(A)); + } + + public int minCostII(int[][] costs) { + if (costs.length == 0) return 0; + int[][] lMin = new int[costs.length][costs[0].length]; + int[][] rMin = new int[costs.length][costs[0].length]; + for (int i = costs.length - 2; i >= 0; i--) { + int min = Integer.MAX_VALUE; + for (int j = 0; j < costs[0].length; j++) { + lMin[i + 1][j] = min; + min = Math.min(min, costs[i + 1][j]); + } + min = Integer.MAX_VALUE; + for (int j = costs[0].length - 1; j >= 0; j--) { + rMin[i + 1][j] = min; + min = Math.min(min, costs[i + 1][j]); + } + + for (int j = 0; j < costs[0].length; j++) { + if (j == 0) { + costs[i][j] = costs[i][j] + rMin[i + 1][j]; + } else if (j == costs[0].length - 1) { + costs[i][j] = costs[i][j] + lMin[i + 1][j]; + } else { + costs[i][j] = costs[i][j] + Math.min(lMin[i + 1][j], rMin[i + 1][j]); + } + } + } + int min = Integer.MAX_VALUE; + for (int i = 0; i < costs[0].length; i++) { + min = Math.min(min, costs[0][i]); + } + return min; + } +} diff --git a/src/main/java/dynamic_programming/PaintHouseIII.java b/src/main/java/dynamic_programming/PaintHouseIII.java new file mode 100644 index 00000000..7b981013 --- /dev/null +++ b/src/main/java/dynamic_programming/PaintHouseIII.java @@ -0,0 +1,105 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 22/10/2020 There is a row of m houses in a small city, each + * house must be painted with one of the n colors (labeled from 1 to n), some houses that has been + * painted last summer should not be painted again. + * + *

A neighborhood is a maximal group of continuous houses that are painted with the same color. + * (For example: houses = [1,2,2,3,3,2,1,1] contains 5 neighborhoods [{1}, {2,2}, {3,3}, {2}, + * {1,1}]). + * + *

Given an array houses, an m * n matrix cost and an integer target where: + * + *

houses[i]: is the color of the house i, 0 if the house is not painted yet. cost[i][j]: is the + * cost of paint the house i with the color j+1. Return the minimum cost of painting all the + * remaining houses in such a way that there are exactly target neighborhoods, if not possible + * return -1. + * + *

Example 1: + * + *

Input: houses = [0,0,0,0,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], m = 5, n = 2, target + * = 3 Output: 9 Explanation: Paint houses of this way [1,2,2,1,1] This array contains target = 3 + * neighborhoods, [{1}, {2,2}, {1,1}]. Cost of paint all houses (1 + 1 + 1 + 1 + 5) = 9. Example 2: + * + *

Input: houses = [0,2,1,2,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], m = 5, n = 2, target + * = 3 Output: 11 Explanation: Some houses are already painted, Paint the houses of this way + * [2,2,1,2,2] This array contains target = 3 neighborhoods, [{2,2}, {1}, {2,2}]. Cost of paint the + * first and last house (10 + 1) = 11. Example 3: + * + *

Input: houses = [0,0,0,0,0], cost = [[1,10],[10,1],[1,10],[10,1],[1,10]], m = 5, n = 2, target + * = 5 Output: 5 Example 4: + * + *

Input: houses = [3,1,2,3], cost = [[1,1,1],[1,1,1],[1,1,1],[1,1,1]], m = 4, n = 3, target = 3 + * Output: -1 Explanation: Houses are already painted with a total of 4 neighborhoods + * [{3},{1},{2},{3}] different of target = 3. + * + *

Constraints: + * + *

m == houses.length == cost.length n == cost[i].length 1 <= m <= 100 1 <= n <= 20 1 <= target + * <= m 0 <= houses[i] <= n 1 <= cost[i][j] <= 10^4 + */ +public class PaintHouseIII { + public static void main(String[] args) { + // int[] h = {0,0}; + // int[][] cost = {{1,2}, {1,2}}; + int[] h = {3, 1, 2, 3}; + int[][] cost = {{1, 10}, {10, 1}, {1, 10}, {10, 1}, {1, 10}}; + int m = 5; + int n = 2; + int target = 5; + System.out.println(new PaintHouseIII().minCost(h, cost, m, n, target)); + } + + int[][][] DP; + + public int minCost(int[] houses, int[][] cost, int m, int n, int target) { + DP = new int[houses.length][target + 1][n + 1]; + for (int i = 0; i < houses.length; i++) { + for (int j = 0; j < target + 1; j++) { + Arrays.fill(DP[i][j], -2); + } + } + int result = dp(0, 0, target, cost, houses); + return result; + } + + private int dp(int i, int c, int t, int[][] cost, int[] houses) { + if (t == 0 && i == houses.length) return 0; + else if (t == -1 || i == houses.length) return -1; + else if (DP[i][t][c] != -2) return DP[i][t][c]; + else { + int min = Integer.MAX_VALUE; + if (houses[i] != 0) { + int result; + if (houses[i] == c) { + result = dp(i + 1, c, t, cost, houses); + } else { + result = dp(i + 1, houses[i], t - 1, cost, houses); + } + if (result != -1) { + if (c != 0) { + min = Math.min(min, result); + } else min = result; + } + } else { + for (int co = 1; co < cost[0].length + 1; co++) { + int result; + if (co != c) { + result = dp(i + 1, co, t - 1, cost, houses); + } else { + result = dp(i + 1, co, t, cost, houses); + } + if (result != -1) { + min = Math.min(min, cost[i][co - 1] + result); + } + } + } + DP[i][t][c] = (min == Integer.MAX_VALUE ? -1 : min); + return DP[i][t][c]; + } + } +} diff --git a/src/main/java/dynamic_programming/PalindromePairs.java b/src/main/java/dynamic_programming/PalindromePairs.java new file mode 100644 index 00000000..1ca89e4d --- /dev/null +++ b/src/main/java/dynamic_programming/PalindromePairs.java @@ -0,0 +1,154 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 25/01/2018. Given a list of unique words, find all pairs of + * distinct indices (i, j) in the given list, so that the concatenation of the two words, i.e. + * words[i] + words[j] is a palindrome. + * + *

Example 1: Given words = ["bat", "tab", "cat"] Return [[0, 1], [1, 0]] The palindromes are + * ["battab", "tabbat"] Example 2: Given words = ["abcd", "dcba", "lls", "s", "sssll"] Return [[0, + * 1], [1, 0], [3, 2], [2, 4]] The palindromes are ["dcbaabcd", "abcddcba", "slls", "llssssll"] + * + *

Solution O(n x m ^ 2) where m is the average length of each string and n is the number of + * strings. + */ +public class PalindromePairs { + + public class Trie { + + private Map map; + private int index; + + /** Initialize your data structure here. */ + public Trie() { + map = new HashMap<>(); + } + + /** Inserts a word into the trie. */ + public void insert(String word, int pos) { + if (word != null) { + add(0, word, word.length(), pos); + } + } + + private void add(int i, String word, int length, int pos) { + if (i < length) { + char c = word.charAt(i); + Trie subTrie = map.get(c); + if (subTrie == null) { + subTrie = new Trie(); + map.put(c, subTrie); + } + subTrie.add(i + 1, word, length, pos); + } else { + Trie t = new Trie(); + t.index = pos; + map.put(null, t); // use null to indicate end of string + } + } + + public Trie getSubTrie(Character c) { + return this.map.get(c); + } + + public int getIndex() { + return index; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + String[] words = {"", "aa"}; + List> result = new PalindromePairs().palindromePairs(words); + result.stream().map(x -> (x.get(0) + " " + x.get(1))).forEach(System.out::println); + } + + public List> palindromePairs(String[] words) { + Trie forwardTrie = new Trie(); // maintain a forward and backward trie + Trie backwardTrie = new Trie(); + Map> links = new HashMap<>(); // maintain links to avoid duplicates + for (int i = 0; i < words.length; i++) { + forwardTrie.insert(words[i], i); + backwardTrie.insert(new StringBuilder(words[i]).reverse().toString(), i); + } + List> result = new ArrayList<>(); + for (int i = 0; i < words.length; i++) { + String word = words[i]; + boolean[][] T = new boolean[word.length()][word.length()]; + for (int j = 0, l = word.length(); j < l; j++) { + T[j][j] = true; + int k = j + 1; + if (k < l) { + if (word.charAt(j) == word.charAt(k)) { + T[j][k] = true; + } + } + } + for (int m = 2, l = word.length(); m < l; m++) { + for (int j = 0, k = m; j < l && k < l; j++, k++) { + if (word.charAt(j) == word.charAt(k) && T[j + 1][k - 1]) { + T[j][k] = true; + } + } + } + Trie subTrie = backwardTrie; + if (subTrie.getSubTrie(null) != null && !word.isEmpty() && T[0][word.length() - 1]) { + Trie emptySubTrie = subTrie.getSubTrie(null); + result.add(Arrays.asList(i, emptySubTrie.getIndex())); + result.add(Arrays.asList(emptySubTrie.getIndex(), i)); + } + for (int j = 0, l = word.length(); j < l; j++) { + char c = word.charAt(j); + subTrie = subTrie.getSubTrie(c); + if (subTrie == null) break; + Trie indexNode = subTrie.getSubTrie(null); + if (indexNode != null) { + if ((j == l - 1) || (T[j + 1][l - 1])) { + if (indexNode.getIndex() != i) { // ignore same index + Set linkedTo = links.get(i); + if (linkedTo == null) { + linkedTo = new HashSet<>(); + links.put(i, linkedTo); + } + if (!linkedTo.contains(indexNode.getIndex())) { + linkedTo.add(indexNode.getIndex()); + result.add(Arrays.asList(i, indexNode.getIndex())); + } + } + } + } + } + subTrie = forwardTrie; + for (int j = word.length() - 1; j >= 0; j--) { + char c = word.charAt(j); + subTrie = subTrie.getSubTrie(c); + if (subTrie == null) break; + Trie indexNode = subTrie.getSubTrie(null); + if (indexNode != null) { + if ((j == 0) || (T[0][j - 1])) { + if (indexNode.getIndex() != i) { // ignore same index + Set linkedTo = links.get(indexNode.getIndex()); + if (linkedTo == null) { + linkedTo = new HashSet<>(); + links.put(indexNode.getIndex(), linkedTo); + } + if (!linkedTo.contains(i)) { + linkedTo.add(i); + result.add(Arrays.asList(indexNode.getIndex(), i)); + } + } + } + } + } + } + return result; + } +} diff --git a/src/main/java/dynamic_programming/PalindromePartitioningII.java b/src/main/java/dynamic_programming/PalindromePartitioningII.java new file mode 100644 index 00000000..6dedd2c3 --- /dev/null +++ b/src/main/java/dynamic_programming/PalindromePartitioningII.java @@ -0,0 +1,55 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by pradhang on 4/3/2017. Given a string s, partition s such that every substring of the + * partition is a palindrome. + * + *

Return the minimum cuts needed for a palindrome partitioning of s. + * + *

For example, given s = "aab", Return 1 since the palindrome partitioning ["aa","b"] could be + * produced using 1 cut. + */ +public class PalindromePartitioningII { + private int A[]; + private boolean[][] paliandrome; + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + System.out.println( + new PalindromePartitioningII() + .minCut( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); + } + + public int minCut(String s) { + if (s == null || s.isEmpty()) return 0; + A = new int[s.length()]; + Arrays.fill(A, Integer.MAX_VALUE); + char[] charArr = s.toCharArray(); + paliandrome = new boolean[charArr.length][charArr.length]; + return doNext(charArr, 0) - 1; + } + + private int doNext(char[] s, int p) { + if (p >= s.length) return 0; + if (A[p] < Integer.MAX_VALUE) return A[p]; + for (int i = p, l = s.length; i < l; i++) { + if (p + 1 <= i - 1) { + paliandrome[p][i] = (paliandrome[p + 1][i - 1] && (s[p] == s[i])); + } else { + paliandrome[p][i] = (i == p) || (s[i] == s[p]); + } + if (paliandrome[p][i]) { + A[p] = Math.min(doNext(s, i + 1) + 1, A[p]); + } + } + return A[p]; + } +} diff --git a/src/main/java/dynamic_programming/PalindromePartitioningIII.java b/src/main/java/dynamic_programming/PalindromePartitioningIII.java new file mode 100644 index 00000000..be678971 --- /dev/null +++ b/src/main/java/dynamic_programming/PalindromePartitioningIII.java @@ -0,0 +1,80 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 22/04/2020 You are given a string s containing lowercase + * letters and an integer k. You need to : + * + *

First, change some characters of s to other lowercase English letters. Then divide s into k + * non-empty disjoint substrings such that each substring is palindrome. Return the minimal number + * of characters that you need to change to divide the string. + * + *

Example 1: + * + *

Input: s = "abc", k = 2 Output: 1 Explanation: You can split the string into "ab" and "c", and + * change 1 character in "ab" to make it palindrome. Example 2: + * + *

Input: s = "aabbc", k = 3 Output: 0 Explanation: You can split the string into "aa", "bb" and + * "c", all of them are palindrome. Example 3: + * + *

Input: s = "leetcode", k = 8 Output: 0 + * + *

Constraints: + * + *

1 <= k <= s.length <= 100. s only contains lowercase English letters. + */ +public class PalindromePartitioningIII { + + public static void main(String[] args) { + System.out.println(new PalindromePartitioningIII().palindromePartition("leetcode", 8)); + } + + int[][][] DP; + + public int palindromePartition(String s, int k) { + DP = new int[s.length()][s.length()][k + 1]; + for (int i = 0; i < s.length(); i++) { + for (int j = 0; j < s.length(); j++) { + Arrays.fill(DP[i][j], -1); + } + } + return dp(0, s.length() - 1, k, s); + } + + private int dp(int i, int j, int n, String s) { + if (i == j && n == 1) return 0; + else if ((j - i + 1 < n) || (n <= 0)) return -1; + else if (DP[i][j][n] != -1) return DP[i][j][n]; + else if (n == 1) { + int result = count(s.substring(i, j + 1)); + DP[i][j][n] = result; + return result; + } else { + int min = Integer.MAX_VALUE; + for (int k = i; k < j; k++) { + int left = dp(i, k, 1, s); + int right = dp(k + 1, j, n - 1, s); + if (right != -1) { + min = Math.min(min, left + right); + } + } + if (min != Integer.MAX_VALUE) { + DP[i][j][n] = min; + return min; + } + return -1; + } + } + + private int count(String s) { + int cnt = 0; + for (int i = 0, j = s.length() - 1; i < j; i++, j--) { + if (s.charAt(i) != s.charAt(j)) { + cnt++; + } + } + return cnt; + } +} diff --git a/src/main/java/dynamic_programming/PalindromeRemoval.java b/src/main/java/dynamic_programming/PalindromeRemoval.java new file mode 100644 index 00000000..3c81a1fb --- /dev/null +++ b/src/main/java/dynamic_programming/PalindromeRemoval.java @@ -0,0 +1,50 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 12/05/2020 Given an integer array arr, in one move you can + * select a palindromic subarray arr[i], arr[i+1], ..., arr[j] where i <= j, and remove that + * subarray from the given array. Note that after removing a subarray, the elements on the left and + * on the right of that subarray move to fill the gap left by the removal. + * + *

Return the minimum number of moves needed to remove all numbers from the array. + * + *

Example 1: + * + *

Input: arr = [1,2] Output: 2 Example 2: + * + *

Input: arr = [1,3,4,1,5] Output: 3 Explanation: Remove [4] then remove [1,3,1] then remove + * [5]. + * + *

Constraints: + * + *

1 <= arr.length <= 100 1 <= arr[i] <= 20 + */ +public class PalindromeRemoval { + public static void main(String[] args) { + int[] A = {1, 3, 1, 2, 4, 2}; + System.out.println(new PalindromeRemoval().minimumMoves(A)); + } + + int[][] DP; + + public int minimumMoves(int[] arr) { + DP = new int[arr.length][arr.length]; + return dp(0, arr.length - 1, arr); + } + + private int dp(int i, int j, int[] arr) { + if (i > j) return 1; + else if (DP[i][j] != 0) return DP[i][j]; + else { + int min = Integer.MAX_VALUE; + for (int t = j; t >= i; t--) { + if (arr[i] == arr[t]) { + min = Math.min(min, dp(i + 1, t - 1, arr) + ((t + 1 > j) ? 0 : dp(t + 1, j, arr))); + } + } + DP[i][j] = min; + return min; + } + } +} diff --git a/src/main/java/dynamic_programming/PalindromicSubstrings.java b/src/main/java/dynamic_programming/PalindromicSubstrings.java new file mode 100644 index 00000000..d8dcf944 --- /dev/null +++ b/src/main/java/dynamic_programming/PalindromicSubstrings.java @@ -0,0 +1,55 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 13/12/2017. + * + *

Given a string, your task is to count how many palindromic substrings in this string. + * + *

The substrings with different start indexes or end indexes are counted as different substrings + * even they consist of same characters. + * + *

Example 1: Input: "abc" Output: 3 Explanation: Three palindromic strings: "a", "b", "c". + * Example 2: Input: "aaa" Output: 6 Explanation: Six palindromic strings: "a", "a", "a", "aa", + * "aa", "aaa". Note: The input string length won't exceed 1000. + * + *

Solution O(n ^ 2): Example abcba: Compare char at two indices each time for example if char at + * index 0 and index 4 are equal and if substring 1 and 3 is a palindrome then, sub-string 0 and 4 + * is also a palindrome + */ +public class PalindromicSubstrings { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + System.out.println(new PalindromicSubstrings().countSubstrings("aaa")); + } + + public int countSubstrings(String s) { + boolean[][] T = new boolean[s.length()][s.length()]; + int count = s.length(); + for (int i = 0, j = 0; i < T.length; i++, j++) { + T[i][j] = true; + } + + for (int k = 1, col = s.length(); k < col; k++) { + for (int i = 0, j = k; i < col && j < col; i++, j++) { + if (k == 1) { + if (s.charAt(i) == s.charAt(j)) { + T[i][j] = true; + count++; + } + } else { + if (s.charAt(i) == s.charAt(j) && T[i + 1][j - 1]) { + T[i][j] = true; + count++; + } + } + } + } + return count; + } +} diff --git a/src/main/java/dynamic_programming/ProfitableSchemes.java b/src/main/java/dynamic_programming/ProfitableSchemes.java new file mode 100644 index 00000000..b6f3becc --- /dev/null +++ b/src/main/java/dynamic_programming/ProfitableSchemes.java @@ -0,0 +1,70 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; +/** + * Created by gouthamvidyapradhan on 26/03/2019 There are G people in a gang, and a list of various + * crimes they could commit. + * + *

The i-th crime generates a profit[i] and requires group[i] gang members to participate. + * + *

If a gang member participates in one crime, that member can't participate in another crime. + * + *

Let's call a profitable scheme any subset of these crimes that generates at least P profit, + * and the total number of gang members participating in that subset of crimes is at most G. + * + *

How many schemes can be chosen? Since the answer may be very large, return it modulo 10^9 + 7. + * + *

Example 1: + * + *

Input: G = 5, P = 3, group = [2,2], profit = [2,3] Output: 2 Explanation: To make a profit of + * at least 3, the gang could either commit crimes 0 and 1, or just crime 1. In total, there are 2 + * schemes. Example 2: + * + *

Input: G = 10, P = 5, group = [2,3,5], profit = [6,7,8] Output: 7 Explanation: To make a + * profit of at least 5, the gang could commit any crimes, as long as they commit one. There are 7 + * possible schemes: (0), (1), (2), (0,1), (0,2), (1,2), and (0,1,2). + * + *

Note: + * + *

1 <= G <= 100 0 <= P <= 100 1 <= group[i] <= 100 0 <= profit[i] <= 100 1 <= group.length = + * profit.length <= 100 + * + *

Solution: O(G x P) Time and Space complexity. The problem is similar to the standard Knapsack + * DP problem. For every group value (ranging from 0 - 100) if a minimum of profit can be achieved + * then add this to the total count. Sum up the count (profitable schemes) for every group value + * ranging from 0 - G and return this as your answer. + */ +public class ProfitableSchemes { + + private final int MOD = 1000000007; + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[] group = {2, 3}; + int[] profit = {2, 5}; + System.out.println(new ProfitableSchemes().profitableSchemes(5, 2, group, profit)); + } + + public int profitableSchemes(int G, int P, int[] group, int[] profit) { + int[][] DP = new int[G + 1][P + 1]; + int ans = 0; + DP[0][0] = 1; + for (int k = group.length - 1; k >= 0; k--) { + int g = group[k]; + int p = profit[k]; + for (int i = DP.length - 1; i >= 0; i--) { + for (int j = DP[0].length - 1; j >= 0; j--) { + int r1 = (i - g < 0) ? 0 : DP[i - g][Math.max(0, j - p)]; + int r2 = DP[i][j]; + DP[i][j] = ((r1 % MOD) + (r2 % MOD)) % MOD; + } + } + } + for (int i = 0; i < DP.length; i++) { + ans = (ans + DP[i][P]) % MOD; + } + return ans; + } +} diff --git a/src/main/java/dynamic_programming/RemoveBoxes.java b/src/main/java/dynamic_programming/RemoveBoxes.java new file mode 100644 index 00000000..094f9497 --- /dev/null +++ b/src/main/java/dynamic_programming/RemoveBoxes.java @@ -0,0 +1,50 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; +/** + * Created by gouthamvidyapradhan on 28/05/2019 Given several boxes with different colors + * represented by different positive numbers. You may experience several rounds to remove boxes + * until there is no box left. Each time you can choose some continuous boxes with the same color + * (composed of k boxes, k >= 1), remove them and get k*k points. Find the maximum points you can + * get. + * + *

Example 1: Input: + * + *

[1, 3, 2, 2, 2, 3, 4, 3, 1] Output: 23 Explanation: [1, 3, 2, 2, 2, 3, 4, 3, 1] ----> [1, 3, + * 3, 4, 3, 1] (3*3=9 points) ----> [1, 3, 3, 3, 1] (1*1=1 points) ----> [1, 1] (3*3=9 points) ----> + * [] (2*2=4 points) Note: The number of boxes n would not exceed 100. + * + *

Solution O(N ^ 4) For each sub-array [l, r] make a dp cache and calculate maximum of [l, i][1] + * + [i + 1, r][1] or maximum of [l + 1, i - 1][n] + [i, r][1] where boxes[l] == boxes[i] where n is + * the count of repetitions + */ +public class RemoveBoxes { + + int[][][] dp; + + public static void main(String[] args) { + int[] boxes = {3, 3, 3}; + System.out.println(new RemoveBoxes().removeBoxes(boxes)); + } + + public int removeBoxes(int[] boxes) { + dp = new int[boxes.length][boxes.length][boxes.length + 1]; + return calculate(0, boxes.length - 1, 1, boxes); + } + + int calculate(int l, int r, int n, int[] boxes) { + if (l > r) return 0; + else { + if (dp[l][r][n] != 0) return dp[l][r][n]; + dp[l][r][n] = (n * n) + calculate(l + 1, r, 1, boxes); + for (int i = l + 1; i <= r; i++) { + int center = 0, next = 0; + if (boxes[l] == boxes[i]) { + center = calculate(l + 1, i - 1, 1, boxes); + next = calculate(i, r, n + 1, boxes); + } + dp[l][r][n] = Math.max(dp[l][r][n], center + next); + } + } + return dp[l][r][n]; + } +} diff --git a/src/main/java/dynamic_programming/RestoreTheArray.java b/src/main/java/dynamic_programming/RestoreTheArray.java new file mode 100644 index 00000000..abae42d0 --- /dev/null +++ b/src/main/java/dynamic_programming/RestoreTheArray.java @@ -0,0 +1,72 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 28/05/2020 + * + *

A program was supposed to print an array of integers. The program forgot to print whitespaces + * and the array is printed as a string of digits and all we know is that all integers in the array + * were in the range [1, k] and there are no leading zeros in the array. + * + *

Given the string s and the integer k. There can be multiple ways to restore the array. + * + *

Return the number of possible array that can be printed as a string s using the mentioned + * program. + * + *

The number of ways could be very large so return it modulo 10^9 + 7 + * + *

Example 1: + * + *

Input: s = "1000", k = 10000 Output: 1 Explanation: The only possible array is [1000] Example + * 2: + * + *

Input: s = "1000", k = 10 Output: 0 Explanation: There cannot be an array that was printed + * this way and has all integer >= 1 and <= 10. Example 3: + * + *

Input: s = "1317", k = 2000 Output: 8 Explanation: Possible arrays are + * [1317],[131,7],[13,17],[1,317],[13,1,7],[1,31,7],[1,3,17],[1,3,1,7] Example 4: + * + *

Input: s = "2020", k = 30 Output: 1 Explanation: The only possible array is [20,20]. [2020] is + * invalid because 2020 > 30. [2,020] is ivalid because 020 contains leading zeros. Example 5: + * + *

Input: s = "1234567890", k = 90 Output: 34 + * + *

Constraints: + * + *

1 <= s.length <= 10^5. s consists of only digits and doesn't contain leading zeros. 1 <= k <= + * 10^9. + */ +public class RestoreTheArray { + public static void main(String[] args) { + System.out.println(new RestoreTheArray().numberOfArrays("19284738192", 90)); + } + + int[] DP; + int MOD = (int) 1e9 + 7; + + public int numberOfArrays(String s, int k) { + DP = new int[s.length() + 1]; + Arrays.fill(DP, -1); + return dp(0, s, k); + } + + private int dp(int i, String s, int k) { + if (i == s.length()) return 1; + else if (DP[i] != -1) return DP[i]; + else if (s.charAt(i) == '0') return 0; + else { + long sum = 0L; + String num = ""; + for (int j = i; j < (i + 10) && j < s.length(); j++) { + num = num + s.charAt(j); + if (Long.parseLong(num) <= k) { + sum = ((sum + dp(j + 1, s, k)) % MOD); + } + } + DP[i] = (int) sum; + return DP[i]; + } + } +} diff --git a/src/main/java/dynamic_programming/RussianDollEnvelopes.java b/src/main/java/dynamic_programming/RussianDollEnvelopes.java new file mode 100644 index 00000000..2b454d20 --- /dev/null +++ b/src/main/java/dynamic_programming/RussianDollEnvelopes.java @@ -0,0 +1,72 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 05/05/2019 You have a number of envelopes with widths and + * heights given as a pair of integers (w, h). One envelope can fit into another if and only if both + * the width and height of one envelope is greater than the width and height of the other envelope. + * + *

What is the maximum number of envelopes can you Russian doll? (put one inside other) + * + *

Note: Rotation is not allowed. + * + *

Example: + * + *

Input: [[5,4],[6,4],[6,7],[2,3]] Output: 3 Explanation: The maximum number of envelopes you + * can Russian doll is 3 ([2,3] => [5,4] => [6,7]). + * + *

Solution: O(N ^ 2) Sort the envelopes based on increasing order of area and for each envelope + * iterate through all the possible envelopes which are smaller than that the current envelope and + * check the maximum possible envelopes which an be russian dolled. + */ +public class RussianDollEnvelopes { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[][] A = {{5, 4}, {6, 4}, {6, 7}, {2, 3}}; + System.out.println(new RussianDollEnvelopes().maxEnvelopes(A)); + } + + class Envelope { + int l, b; + + Envelope(int l, int b) { + this.l = l; + this.b = b; + } + } + /** + * @param envelopes + * @return + */ + public int maxEnvelopes(int[][] envelopes) { + if (envelopes.length == 0) return 0; + List list = new ArrayList<>(); + for (int[] row : envelopes) { + list.add(new Envelope(row[0], row[1])); + } + list.sort(((o1, o2) -> Integer.compare(o2.l * o2.b, o1.l * o1.b))); + int[] DP = new int[envelopes.length]; + Arrays.fill(DP, 1); + for (int i = list.size() - 1; i >= 0; i--) { + Envelope env = list.get(i); + for (int j = i + 1, l = list.size(); j < l; j++) { + Envelope childEnv = list.get(j); + if (env.l > childEnv.l && env.b > childEnv.b) { + DP[i] = Math.max(DP[i], DP[j] + 1); + } + } + } + int ans = 1; + for (int i : DP) { + ans = Math.max(ans, i); + } + return ans; + } +} diff --git a/src/main/java/dynamic_programming/ShortestPathVisitingAllNodes.java b/src/main/java/dynamic_programming/ShortestPathVisitingAllNodes.java new file mode 100644 index 00000000..c56069de --- /dev/null +++ b/src/main/java/dynamic_programming/ShortestPathVisitingAllNodes.java @@ -0,0 +1,105 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 16/10/2020 + * + *

An undirected, connected graph of N nodes (labeled 0, 1, 2, ..., N-1) is given as graph. + * + *

graph.length = N, and j != i is in the list graph[i] exactly once, if and only if nodes i and + * j are connected. + * + *

Return the length of the shortest path that visits every node. You may start and stop at any + * node, you may revisit nodes multiple times, and you may reuse edges. + * + *

Example 1: + * + *

Input: [[1,2,3],[0],[0],[0]] Output: 4 Explanation: One possible path is [1,0,2,0,3] Example + * 2: + * + *

Input: [[1],[0,2,4],[1,3,4],[2],[1,2]] Output: 4 Explanation: One possible path is [0,1,4,2,3] + * + *

Note: + * + *

1 <= graph.length <= 12 0 <= graph[i].length < graph.length + */ +public class ShortestPathVisitingAllNodes { + public static void main(String[] args) { + int[][] graph = {{2, 3, 4, 8}, {8}, {0}, {0, 8}, {0, 5, 6}, {4, 7}, {4}, {5}, {0, 3, 1}}; + System.out.println(new ShortestPathVisitingAllNodes().shortestPathLength(graph)); + } + + Stack stack; + Set done; + + class Node { + int v, s; + + Node(int v, int s) { + this.v = v; + this.s = s; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Node)) return false; + Node node = (Node) o; + return v == node.v && s == node.s; + } + + @Override + public int hashCode() { + return Objects.hash(v, s); + } + } + + public int shortestPathLength(int[][] G) { + int dest = (int) Math.pow(2, G.length) - 1; + int[][] DP = new int[G.length][dest + 1]; + done = new HashSet<>(); + stack = new Stack<>(); + for (int i = 0; i < G.length; i++) { + Node n = new Node(i, 1 << i); + if (!done.contains(n)) { + dfs(n, G); + } + } + for (int i = 0; i < G.length; i++) { + Arrays.fill(DP[i], Integer.MAX_VALUE); + } + while (!stack.isEmpty()) { + Node node = stack.pop(); + int[] children = G[node.v]; + int currDist = DP[node.v][node.s] == Integer.MAX_VALUE ? 0 : DP[node.v][node.s]; + for (int c : children) { + if (DP[c][node.s | (1 << c)] < Integer.MAX_VALUE + && ((currDist + 1) < DP[c][node.s | (1 << c)])) { + stack.push(new Node(c, node.s | (1 << c))); + } + DP[c][node.s | (1 << c)] = Math.min(DP[c][node.s | (1 << c)], currDist + 1); + } + } + int min = Integer.MAX_VALUE; + for (int i = 0; i < G.length; i++) { + min = Math.min(min, DP[i][dest]); + } + return min == Integer.MAX_VALUE ? 0 : min; + } + + private void dfs(Node n, int[][] graph) { + done.add(n); + int[] children = graph[n.v]; + if (children != null) { + for (int c : children) { + Node child = new Node(c, (n.s | (1 << c))); + if (!done.contains(child)) { + dfs(child, graph); + } + } + } + stack.push(n); + } +} diff --git a/src/main/java/dynamic_programming/SmallestSufficientTeam.java b/src/main/java/dynamic_programming/SmallestSufficientTeam.java new file mode 100644 index 00000000..c91247c0 --- /dev/null +++ b/src/main/java/dynamic_programming/SmallestSufficientTeam.java @@ -0,0 +1,123 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 04/06/2020 In a project, you have a list of required skills + * req_skills, and a list of people. The i-th person people[i] contains a list of skills that person + * has. + * + *

Consider a sufficient team: a set of people such that for every required skill in req_skills, + * there is at least one person in the team who has that skill. We can represent these teams by the + * index of each person: for example, team = [0, 1, 3] represents the people with skills people[0], + * people[1], and people[3]. + * + *

Return any sufficient team of the smallest possible size, represented by the index of each + * person. + * + *

You may return the answer in any order. It is guaranteed an answer exists. + * + *

Example 1: + * + *

Input: req_skills = ["java","nodejs","reactjs"], people = + * [["java"],["nodejs"],["nodejs","reactjs"]] Output: [0,2] Example 2: + * + *

Input: req_skills = ["algorithms","math","java","reactjs","csharp","aws"], people = + * [["algorithms","math","java"],["algorithms","math","reactjs"],["java","csharp","aws"],["reactjs","csharp"],["csharp","math"],["aws","java"]] + * Output: [1,2] + * + *

Constraints: + * + *

1 <= req_skills.length <= 16 1 <= people.length <= 60 1 <= people[i].length, + * req_skills[i].length, people[i][j].length <= 16 Elements of req_skills and people[i] are + * (respectively) distinct. req_skills[i][j], people[i][j][k] are lowercase English letters. Every + * skill in people[i] is a skill in req_skills. It is guaranteed a sufficient team exists. + */ +public class SmallestSufficientTeam { + + public static void main(String[] args) { + String[] req = {"java", "nodejs", "reactjs"}; + List> people = new ArrayList<>(); + people.add(Arrays.asList("java")); + people.add(Arrays.asList("nodejs")); + people.add(Arrays.asList("nodejs", "reactjs")); + int[] R = new SmallestSufficientTeam().smallestSufficientTeam(req, people); + for (int r : R) { + System.out.print(r + " "); + } + System.out.println(); + } + + private int allSkills; + Map peopleSkillSet; + Map skillMap; + final int MAX_SKILLS = 63; + final int CHOOSE_PEOPLE = 64; + + public int[] smallestSufficientTeam(String[] reqSkills, List> people) { + skillMap = new HashMap<>(); + peopleSkillSet = new HashMap<>(); + int i = 0; + for (String s : reqSkills) { + skillMap.put(s, i++); + } + for (i = 0; i < people.size(); i++) { + for (String s : people.get(i)) { + int skillIndex = skillMap.get(s); + int skills = peopleSkillSet.getOrDefault(i, 0); + skills = (skills | (1 << skillIndex)); + peopleSkillSet.put(i, skills); + } + } + int S = ((int) (Math.pow(2, reqSkills.length)) + 1); + int[][] DP = new int[S][people.size()]; + allSkills = (1 << reqSkills.length) - 1; + for (i = 0; i < DP.length; i++) { + for (int j = 0; j < DP[0].length; j++) { + DP[i][j] = -1; + } + } + int n = dp(0, 0, DP); + n &= MAX_SKILLS; + if (n == Integer.MAX_VALUE) return new int[0]; + List answer = new ArrayList<>(); + i = 0; + for (int j = 0; j < people.size(); j++) { + if (((DP[i][j] & MAX_SKILLS) == n) && (DP[i][j] & CHOOSE_PEOPLE) > 0) { + i |= (peopleSkillSet.getOrDefault(j, 0)); + answer.add(j); + n--; + } + if (n == 0) break; + } + int[] result = new int[answer.size()]; + for (int a = 0; a < result.length; a++) { + result[a] = answer.get(a); + } + return result; + } + + private int dp(int i, int skill, int[][] DP) { + if (i >= DP[0].length) { + if (skill >= allSkills) { + return 0; + } else return Integer.MAX_VALUE; + } + if (skill == allSkills) return 0; + else if (DP[skill][i] != -1) return DP[skill][i]; + else { + int withOut = dp(i + 1, skill, DP); + int with = dp(i + 1, (skill | peopleSkillSet.getOrDefault(i, 0)), DP); + with += with != Integer.MAX_VALUE ? 1 : 0; + if (Math.min(with, withOut) == Integer.MAX_VALUE) { + DP[skill][i] = Integer.MAX_VALUE; + } else + DP[skill][i] = + ((with & MAX_SKILLS) < (withOut & MAX_SKILLS)) + ? ((with & MAX_SKILLS) | CHOOSE_PEOPLE) + : (withOut & MAX_SKILLS); + return DP[skill][i]; + } + } +} diff --git a/src/main/java/dynamic_programming/SplitArrayLargestSum.java b/src/main/java/dynamic_programming/SplitArrayLargestSum.java new file mode 100644 index 00000000..4e33b849 --- /dev/null +++ b/src/main/java/dynamic_programming/SplitArrayLargestSum.java @@ -0,0 +1,53 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 24/12/2017. Given an array which consists of non-negative + * integers and an integer m, you can split the array into m non-empty continuous subarrays. Write + * an algorithm to minimize the largest sum among these m subarrays. + * + *

Note: If n is the length of array, assume the following constraints are satisfied: + * + *

1 ≤ n ≤ 1000 1 ≤ m ≤ min(50, n) Examples: + * + *

Input: nums = [7,2,5,10,8] m = 2 + * + *

Output: 18 + * + *

Explanation: There are four ways to split nums into two subarrays. The best way is to split it + * into [7,2,5] and [10,8], where the largest sum among the two subarrays is only 18. + * + *

Solution O(n ^ 2 * k) Build a bottom up min-max dp table for each sub-array ranging from n -> + * 0 + */ +public class SplitArrayLargestSum { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {7, 2, 5, 10, 8}; + System.out.println(new SplitArrayLargestSum().splitArray(A, 2)); + } + + public int splitArray(int[] nums, int m) { + int[][] dp = new int[m][nums.length]; + for (int i = nums.length - 1; i >= 0; i--) { + int sum = 0; + for (int j = i; j < nums.length; j++) { + sum += nums[j]; + if (j + 1 >= nums.length) break; + for (int k = 0; k < m - 1; k++) { + dp[k + 1][i] = (dp[k + 1][i] == 0) ? Integer.MAX_VALUE : dp[k + 1][i]; + int temp = Math.max(sum, dp[k][j + 1]); + dp[k + 1][i] = Math.min(dp[k + 1][i], temp); + } + } + dp[0][i] = sum; + } + return dp[m - 1][0]; + } +} diff --git a/src/main/java/dynamic_programming/StickersToSpellWord.java b/src/main/java/dynamic_programming/StickersToSpellWord.java new file mode 100644 index 00000000..994dc62e --- /dev/null +++ b/src/main/java/dynamic_programming/StickersToSpellWord.java @@ -0,0 +1,106 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 14/07/2019 We are given N different types of stickers. Each + * sticker has a lowercase English word on it. + * + *

You would like to spell out the given target string by cutting individual letters from your + * collection of stickers and rearranging them. + * + *

You can use each sticker more than once if you want, and you have infinite quantities of each + * sticker. + * + *

What is the minimum number of stickers that you need to spell out the target? If the task is + * impossible, return -1. + * + *

Example 1: + * + *

Input: + * + *

["with", "example", "science"], "thehat" Output: + * + *

3 Explanation: + * + *

We can use 2 "with" stickers, and 1 "example" sticker. After cutting and rearrange the letters + * of those stickers, we can form the target "thehat". Also, this is the minimum number of stickers + * necessary to form the target string. Example 2: + * + *

Input: + * + *

["notice", "possible"], "basicbasic" Output: + * + *

-1 Explanation: + * + *

We can't form the target "basicbasic" from cutting letters from the given stickers. Note: + * + *

stickers has length in the range [1, 50]. stickers consists of lowercase English words + * (without apostrophes). target has length in the range [1, 15], and consists of lowercase English + * letters. In all test cases, all words were chosen randomly from the 1000 most common US English + * words, and the target was chosen as a concatenation of two random words. The time limit may be + * more challenging than usual. It is expected that a 50 sticker test case can be solved within 35ms + * on average. + * + *

Solution: O(2 ^ T x T x S) where T is the length of target and S is length of sticker array. + * Each state is a combination of characters selected in the target sticker plus the total count of + * stickers used. Cache the minimum count in each state and explore all the different possible + * states. + */ +public class StickersToSpellWord { + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + String[] stickers = {"bright", "neighbor", "capital"}; + + System.out.println(new StickersToSpellWord().minStickers(stickers, "originalchair")); + } + + private int destination = 0; + private int min = Integer.MAX_VALUE; + private int[][] DP; + + public int minStickers(String[] stickers, String target) { + for (int i = 0; i < target.length(); i++) { + destination |= (1 << i); + } + DP = new int[destination][target.length() + 1]; + int answer = dp(stickers, target, 0, 0); + return answer == Integer.MAX_VALUE ? -1 : answer; + } + + private int dp(String[] stickers, String target, int curr, int count) { + if (curr == destination) { + return count; + } else { + if (count > min) return Integer.MAX_VALUE; + if (DP[curr][count] != 0) return DP[curr][count]; + DP[curr][count] = Integer.MAX_VALUE; + for (String s : stickers) { + int temp = 0; + char[] arr = s.toCharArray(); + for (int i = 0, l = target.length(); i < l; i++) { + if ((curr & (1 << i)) == 0) { + char targetChar = target.charAt(i); + for (int j = 0; j < arr.length; j++) { + if (arr[j] == targetChar) { + arr[j] = '0'; + temp |= (1 << i); + break; + } + } + } + } + if (temp > 0) { + int child = (curr | temp); + int retValue = dp(stickers, target, child, count + 1); + DP[curr][count] = Math.min(DP[curr][count], retValue); + min = Math.min(min, DP[curr][count]); + } + } + return DP[curr][count]; + } + } +} diff --git a/src/main/java/dynamic_programming/StoneGame.java b/src/main/java/dynamic_programming/StoneGame.java new file mode 100644 index 00000000..b3869d5c --- /dev/null +++ b/src/main/java/dynamic_programming/StoneGame.java @@ -0,0 +1,97 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 22/03/2019 Alex and Lee play a game with piles of stones. There + * are an even number of piles arranged in a row, and each pile has a positive integer number of + * stones piles[i]. + * + *

The objective of the game is to end with the most stones. The total number of stones is odd, + * so there are no ties. + * + *

Alex and Lee take turns, with Alex starting first. Each turn, a player takes the entire pile + * of stones from either the beginning or the end of the row. This continues until there are no more + * piles left, at which point the person with the most stones wins. + * + *

Assuming Alex and Lee play optimally, return True if and only if Alex wins the game. + * + *

Example 1: + * + *

Input: [5,3,4,5] Output: true Explanation: Alex starts first, and can only take the first 5 or + * the last 5. Say he takes the first 5, so that the row becomes [3, 4, 5]. If Lee takes 3, then the + * board is [4, 5], and Alex takes 5 to win with 10 points. If Lee takes the last 5, then the board + * is [3, 4], and Alex takes 4 to win with 9 points. This demonstrated that taking the first 5 was a + * winning move for Alex, so we return true. + * + *

Note: + * + *

2 <= piles.length <= 500 piles.length is even. 1 <= piles[i] <= 500 sum(piles) is odd. + * + *

Solution: O(N ^ 2) Each state can be considered as State = (total stones left, player's turn). + * Do a dfs on each state and memoize the result in order not to recalculate. When all the stones + * are exhausted - Alex wins if the total collected stones by her is greater than total collected by + * Lee + */ +public class StoneGame { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[] A = {5, 3, 4, 5}; + System.out.println(new StoneGame().stoneGame(A)); + } + + public boolean stoneGame(int[] piles) { + int sum = 0; + for (int i = 0; i < piles.length; i++) { + sum += piles[i]; + } + int[][] A = new int[2][sum + 1]; + Arrays.fill(A[0], -1); + Arrays.fill(A[1], -1); + int result = dp(A, piles, 0, piles.length - 1, sum, 0, 0, 0); + return result == 1; + } + + private int dp(int[][] A, int[] piles, int i, int j, int sum, int p, int sumA, int sumB) { + if (A[p][sum] != -1) return A[p][sum]; + else { + if (p == 0) { + if (i <= j) { + int result = dp(A, piles, i + 1, j, sum - piles[i], (p + 1) % 2, sumA + piles[i], sumB); + if (result == 0) { + A[p][sum] = 1; + return 1; + } else { + result = dp(A, piles, i, j - 1, sum - piles[j], (p + 1) % 2, sumA + piles[j], sumB); + A[p][sum] = result; + return result; + } + } else { + if (sumA > sumB) return 1; + else return 0; + } + } else { + if (i <= j) { + int result = dp(A, piles, i + 1, j, sum - piles[i], (p + 1) % 2, sumA, sumB + piles[i]); + if (result == 0) { + A[p][sum] = 1; + return 1; + } else { + result = dp(A, piles, i, j - 1, sum - piles[j], (p + 1) % 2, sumA, sumB + piles[j]); + A[p][sum] = result; + return result; + } + } else { + if (sumB > sumA) return 1; + else return 0; + } + } + } + } +} diff --git a/src/main/java/dynamic_programming/StoneGameIII.java b/src/main/java/dynamic_programming/StoneGameIII.java new file mode 100644 index 00000000..8b4ba08d --- /dev/null +++ b/src/main/java/dynamic_programming/StoneGameIII.java @@ -0,0 +1,98 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 16/04/2020 Alice and Bob continue their games with piles of + * stones. There are several stones arranged in a row, and each stone has an associated value which + * is an integer given in the array stoneValue. + * + *

Alice and Bob take turns, with Alice starting first. On each player's turn, that player can + * take 1, 2 or 3 stones from the first remaining stones in the row. + * + *

The score of each player is the sum of values of the stones taken. The score of each player is + * 0 initially. + * + *

The objective of the game is to end with the highest score, and the winner is the player with + * the highest score and there could be a tie. The game continues until all the stones have been + * taken. + * + *

Assume Alice and Bob play optimally. + * + *

Return "Alice" if Alice will win, "Bob" if Bob will win or "Tie" if they end the game with the + * same score. + * + *

Example 1: + * + *

Input: values = [1,2,3,7] Output: "Bob" Explanation: Alice will always lose. Her best move + * will be to take three piles and the score become 6. Now the score of Bob is 7 and Bob wins. + * Example 2: + * + *

Input: values = [1,2,3,-9] Output: "Alice" Explanation: Alice must choose all the three piles + * at the first move to win and leave Bob with negative score. If Alice chooses one pile her score + * will be 1 and the next move Bob's score becomes 5. The next move Alice will take the pile with + * value = -9 and lose. If Alice chooses two piles her score will be 3 and the next move Bob's score + * becomes 3. The next move Alice will take the pile with value = -9 and also lose. Remember that + * both play optimally so here Alice will choose the scenario that makes her win. Example 3: + * + *

Input: values = [1,2,3,6] Output: "Tie" Explanation: Alice cannot win this game. She can end + * the game in a draw if she decided to choose all the first three piles, otherwise she will lose. + * Example 4: + * + *

Input: values = [1,2,3,-1,-2,-3,7] Output: "Alice" Example 5: + * + *

Input: values = [-1,-2,-3] Output: "Tie" + * + *

Constraints: + * + *

1 <= values.length <= 50000 -1000 <= values[i] <= 1000 + */ +public class StoneGameIII { + private class State { + int a, b; + + State(int a, int b) { + this.a = a; + this.b = b; + } + } + + public static void main(String[] args) { + int[] V = {-1, -2, -3}; + System.out.println(new StoneGameIII().stoneGameIII(V)); + } + + private State[][] DP; + + public String stoneGameIII(int[] stoneValue) { + DP = new State[2][stoneValue.length]; + State result = dp(0, 0, stoneValue); + return (result.a > result.b) ? "Alice" : (result.b > result.a) ? "Bob" : "Tie"; + } + + private State dp(int i, int p, int[] stoneValue) { + if (i >= stoneValue.length) return new State(0, 0); + else if (DP[p][i] != null) return DP[p][i]; + else { + int sum = 0; + for (int j = 0; j < 3; j++) { + if (i + j >= stoneValue.length) break; + sum += (stoneValue[i + j]); + State result = dp(i + j + 1, (p + 1) % 2, stoneValue); + if (p == 0) { + if (DP[p][i] == null) { + DP[p][i] = new State((sum + result.a), result.b); + } else if (DP[p][i].a < (sum + result.a)) { + DP[p][i] = new State((sum + result.a), result.b); + } + } else { + if (DP[p][i] == null) { + DP[p][i] = new State(result.a, (sum + result.b)); + } else if (DP[p][i].b < (sum + result.b)) { + DP[p][i] = new State(result.a, (sum + result.b)); + } + } + } + return DP[p][i]; + } + } +} diff --git a/src/main/java/dynamic_programming/StoneGameIV.java b/src/main/java/dynamic_programming/StoneGameIV.java new file mode 100644 index 00000000..70060906 --- /dev/null +++ b/src/main/java/dynamic_programming/StoneGameIV.java @@ -0,0 +1,89 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 03/12/2020 Alice and Bob take turns playing a game, with Alice + * starting first. + * + *

Initially, there are n stones in a pile. On each player's turn, that player makes a move + * consisting of removing any non-zero square number of stones in the pile. + * + *

Also, if a player cannot make a move, he/she loses the game. + * + *

Given a positive integer n. Return True if and only if Alice wins the game otherwise return + * False, assuming both players play optimally. + * + *

Example 1: + * + *

Input: n = 1 Output: true Explanation: Alice can remove 1 stone winning the game because Bob + * doesn't have any moves. Example 2: + * + *

Input: n = 2 Output: false Explanation: Alice can only remove 1 stone, after that Bob removes + * the last one winning the game (2 -> 1 -> 0). Example 3: + * + *

Input: n = 4 Output: true Explanation: n is already a perfect square, Alice can win with one + * move, removing 4 stones (4 -> 0). Example 4: + * + *

Input: n = 7 Output: false Explanation: Alice can't win the game if Bob plays optimally. If + * Alice starts removing 4 stones, Bob will remove 1 stone then Alice should remove only 1 stone and + * finally Bob removes the last one (7 -> 3 -> 2 -> 1 -> 0). If Alice starts removing 1 stone, Bob + * will remove 4 stones then Alice only can remove 1 stone and finally Bob removes the last one (7 + * -> 6 -> 2 -> 1 -> 0). Example 5: + * + *

Input: n = 17 Output: false Explanation: Alice can't win the game if Bob plays optimally. + * + *

Constraints: + * + *

1 <= n <= 10^5 + */ +public class StoneGameIV { + public static void main(String[] args) { + System.out.println(new StoneGameIV().winnerSquareGame(1000)); + } + + public boolean winnerSquareGame(int n) { + Set perfectSquare = new HashSet<>(); + perfectSquare.add(1); + for (int i = 2; (long) (i * i) <= n; i++) { + genSquare(i * i, n, perfectSquare); + } + int[] pq = new int[perfectSquare.size()]; + int i = 0; + for (int s : perfectSquare) { + pq[i++] = s; + } + Arrays.sort(pq); + int[] DP = new int[n + 1]; + int status = dp(n, 0, pq, DP); + return status != 1; + } + + private int dp(int n, int p, int[] perfectSquares, int[] DP) { + if (n == 0) return 1; + else if (DP[n] != 0) return DP[n]; + else { + int result = 1; + for (int sq : perfectSquares) { + if (n < sq) break; + int r = dp(n - sq, ((p + 1) % 2), perfectSquares, DP); + if (r == 1) { + result = 2; + break; + } + } + DP[n] = result; + return result; + } + } + + private void genSquare(int sq, int limit, Set perfectSquare) { + if (!perfectSquare.contains(sq)) { + perfectSquare.add(sq); + if (((long) sq * sq) <= limit) { + genSquare(sq * sq, limit, perfectSquare); + } + } + } +} diff --git a/src/main/java/dynamic_programming/StrangePrinter.java b/src/main/java/dynamic_programming/StrangePrinter.java new file mode 100644 index 00000000..9db36a72 --- /dev/null +++ b/src/main/java/dynamic_programming/StrangePrinter.java @@ -0,0 +1,46 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 11/02/2020 There is a strange printer with the following two + * special requirements: + * + *

The printer can only print a sequence of the same character each time. At each turn, the + * printer can print new characters starting from and ending at any places, and will cover the + * original existing characters. Given a string consists of lower English letters only, your job is + * to count the minimum number of turns the printer needed in order to print it. + * + *

Example 1: Input: "aaabbb" Output: 2 Explanation: Print "aaa" first and then print "bbb". + * Example 2: Input: "aba" Output: 2 Explanation: Print "aaa" first and then print "b" from the + * second place of the string, which will cover the existing character 'a'. Hint: Length of the + * given string will not exceed 100. + */ +public class StrangePrinter { + public static void main(String[] args) { + String A = "aaaaaaa"; + System.out.println(new StrangePrinter().strangePrinter(A)); + } + + int DP[][]; + + public int strangePrinter(String s) { + DP = new int[s.length() + 1][s.length() + 1]; + return calculate(0, s.length() - 1, s); + } + + private int calculate(int i, int j, String s) { + if (i > j) return 0; + else if (DP[i][j] != 0) return DP[i][j]; + else { + DP[i][j] = calculate(i, j - 1, s) + 1; + int min = DP[i][j]; + for (int m = i; m < j; m++) { + if (s.charAt(m) == s.charAt(j)) { + min = Math.min(min, calculate(i, m, s) + calculate(m + 1, j - 1, s)); + } + } + DP[i][j] = min; + return DP[i][j]; + } + } +} diff --git a/src/main/java/dynamic_programming/TallestBillboard.java b/src/main/java/dynamic_programming/TallestBillboard.java new file mode 100644 index 00000000..fcd356c9 --- /dev/null +++ b/src/main/java/dynamic_programming/TallestBillboard.java @@ -0,0 +1,92 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 19/05/2020 + * + *

You are installing a billboard and want it to have the largest height. The billboard will have + * two steel supports, one on each side. Each steel support must be an equal height. + * + *

You are given a collection of rods that can be welded together. For example, if you have rods + * of lengths 1, 2, and 3, you can weld them together to make a support of length 6. + * + *

Return the largest possible height of your billboard installation. If you cannot support the + * billboard, return 0. + * + *

Example 1: + * + *

Input: rods = [1,2,3,6] Output: 6 Explanation: We have two disjoint subsets {1,2,3} and {6}, + * which have the same sum = 6. Example 2: + * + *

Input: rods = [1,2,3,4,5,6] Output: 10 Explanation: We have two disjoint subsets {2,3,5} and + * {4,6}, which have the same sum = 10. Example 3: + * + *

Input: rods = [1,2] Output: 0 Explanation: The billboard cannot be supported, so we return 0. + * + *

Constraints: + * + *

1 <= rods.length <= 20 1 <= rods[i] <= 1000 sum(rods[i]) <= 5000 + */ +public class TallestBillboard { + + public static void main(String[] args) { + int[] A = {1, 2, 3, 4, 5, 6}; + System.out.println(new TallestBillboard().tallestBillboard(A)); + } + + public int tallestBillboard(int[] rods) { + if (rods.length == 0) return 0; + Map leftMap = partition(rods, 0, rods.length / 2); + Map rightMap = partition(rods, (rods.length / 2) + 1, rods.length - 1); + int max = 0; + for (int d : leftMap.keySet()) { + if (rightMap.containsKey(d)) { + int m1 = leftMap.get(d); + int m2 = rightMap.get(d); + max = Math.max(max, m1 + (m2 - d)); + max = Math.max(max, m2 + (m1 - d)); + } + } + return max; + } + + private Map partition(int[] rods, int i, int j) { + if (i > j) { + Map map = new HashMap<>(); + map.put(0, 0); + return map; + } else if (i == j) { + Map map = new HashMap<>(); + map.put(rods[i], rods[i]); + map.put(0, 0); + return map; + } else { + int m = (i + (j - i) / 2); + Map left = partition(rods, i, m); + Map right = partition(rods, m + 1, j); + Map newMap = new HashMap<>(); + for (int lDiff : left.keySet()) { + int lMax = left.get(lDiff); + for (int rDiff : right.keySet()) { + int rMax = right.get(rDiff); + int r1, r2, r3, r4; + r1 = lMax; + r2 = lMax - lDiff; + r3 = rMax; + r4 = rMax - rDiff; + update(newMap, Math.abs(((r1 + r3) - (r2 + r4))), r1 + r3, r2 + r4); + update(newMap, Math.abs(((r1 + r4) - (r2 + r3))), r1 + r4, r2 + r3); + } + } + return newMap; + } + } + + private void update(Map map, int diff, int rod1, int rod2) { + if (map.getOrDefault(diff, 0) < Math.max(rod1, rod2)) { + map.put(diff, Math.max(rod1, rod2)); + } + } +} diff --git a/src/main/java/dynamic_programming/TilingARectangle.java b/src/main/java/dynamic_programming/TilingARectangle.java new file mode 100644 index 00000000..9fbf1aa7 --- /dev/null +++ b/src/main/java/dynamic_programming/TilingARectangle.java @@ -0,0 +1,101 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 18/04/2020 + * + *

Given a rectangle of size n x m, find the minimum number of integer-sided squares that tile + * the rectangle. + * + *

Example 1: + * + *

Input: n = 2, m = 3 Output: 3 Explanation: 3 squares are necessary to cover the rectangle. 2 + * (squares of 1x1) 1 (square of 2x2) Example 2: + * + *

Input: n = 5, m = 8 Output: 5 Example 3: + * + *

Input: n = 11, m = 13 Output: 6 + * + *

Constraints: + * + *

1 <= n <= 13 1 <= m <= 13 + */ +public class TilingARectangle { + + public static void main(String[] args) { + System.out.println(new TilingARectangle().tilingRectangle(11, 13)); + } + + Map DP; + + public int tilingRectangle(int n, int m) { + DP = new HashMap<>(); + boolean[][] state = new boolean[n][m]; + return dp(state, 0, n, m); + } + + private int dp(boolean[][] state, int r, int n, int m) { + if (r >= n) return 0; + int[] A = new int[m]; + for (int i = r; i < n; i++) { + for (int j = 0; j < m; j++) { + if (state[i][j]) { + A[j]++; + } + } + } + long hashCode = 1; + for (int i = 0; i < A.length; i++) { + A[i] += r; + hashCode = (hashCode * 31) + A[i]; + } + if (DP.containsKey(hashCode)) return DP.get(hashCode); + else { + int min = Integer.MAX_VALUE; + int c = m; + for (int j = 0; j < m; j++) { + if (!state[r][j]) { + c = j; + break; + } + } + int k = 1; + for (; k <= Math.min(n, m); k++) { + if (r + k > n || c + k > m) break; + else if (state[r][c + k - 1] || state[r + k - 1][c]) break; + for (int a = r; a < (r + k); a++) { + for (int b = c; b < (c + k); b++) { + state[a][b] = true; + A[b]++; + } + } + int next = n; + int j = c + k; + for (int i = r; i < n; i++) { + for (; j < m; j++) { + if (!state[i][j]) { + next = i; + break; + } + } + if (next != n) break; + j = 0; + } + int result = dp(state, next, n, m); + if (result > -1) { + min = Math.min(min, result + 1); + } + } + k--; + for (int a = r; a < (r + k); a++) { + for (int b = c; b < (c + k); b++) { + state[a][b] = false; + } + } + DP.put(hashCode, min == Integer.MAX_VALUE ? -1 : min); + return DP.get(hashCode); + } + } +} diff --git a/src/main/java/dynamic_programming/TossStrangeCoins.java b/src/main/java/dynamic_programming/TossStrangeCoins.java new file mode 100644 index 00000000..c36fba82 --- /dev/null +++ b/src/main/java/dynamic_programming/TossStrangeCoins.java @@ -0,0 +1,35 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 19/11/2019 You have some coins. The i-th coin has a probability + * prob[i] of facing heads when tossed. + * + *

Return the probability that the number of coins facing heads equals target if you toss every + * coin exactly once. + * + *

Example 1: + * + *

Input: prob = [0.4], target = 1 Output: 0.40000 Example 2: + * + *

Input: prob = [0.5,0.5,0.5,0.5,0.5], target = 0 Output: 0.03125 + */ +public class TossStrangeCoins { + public static void main(String[] args) { + double[] A = {0.4, 0.4}; + System.out.println(new TossStrangeCoins().probabilityOfHeads(A, 1)); + } + + public double probabilityOfHeads(double[] prob, int target) { + double[][] DP = new double[target + 1][prob.length]; + DP[0][0] = 1 - prob[0]; + DP[1][0] = prob[0]; + for (int c = 1; c < prob.length; c++) { + for (int t = 0; t <= target; t++) { + if (t == 0) DP[t][c] = DP[t][c - 1] * (1 - prob[c]); + else DP[t][c] = DP[t][c - 1] * (1 - prob[c]) + DP[t - 1][c - 1] * (prob[c]); + } + } + return DP[target][prob.length - 1]; + } +} diff --git a/src/main/java/dynamic_programming/TwoKeysKeyboard.java b/src/main/java/dynamic_programming/TwoKeysKeyboard.java new file mode 100644 index 00000000..fe790f4c --- /dev/null +++ b/src/main/java/dynamic_programming/TwoKeysKeyboard.java @@ -0,0 +1,42 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 19/08/2017. Initially on a notepad only one character 'A' is + * present. You can perform two operations on this notepad for each step: + * + *

Copy All: You can copy all the characters present on the notepad (partial copy is not + * allowed). Paste: You can paste the characters which are copied last time. Given a number n. You + * have to get exactly n 'A' on the notepad by performing the minimum number of steps permitted. + * Output the minimum number of steps to get n 'A'. + * + *

Example 1: Input: 3 Output: 3 Explanation: Intitally, we have one character 'A'. In step 1, we + * use Copy All operation. In step 2, we use Paste operation to get 'AA'. In step 3, we use Paste + * operation to get 'AAA'. + * + *

Note: The n will be in the range [1, 1000]. + */ +public class TwoKeysKeyboard { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new TwoKeysKeyboard().minSteps(8)); + } + + public int minSteps(int n) { + int[] DP = new int[n + 1]; + for (int i = 2; i <= n; i++) { + DP[i] = i; + for (int j = 2; j < i; j++) { + if ((i % j) == 0) { + DP[i] = Math.min(DP[i], DP[j] + (i / j)); + } + } + } + return DP[n]; + } +} diff --git a/src/main/java/dynamic_programming/UniqueBinarySearchTrees.java b/src/main/java/dynamic_programming/UniqueBinarySearchTrees.java new file mode 100644 index 00000000..d2080f20 --- /dev/null +++ b/src/main/java/dynamic_programming/UniqueBinarySearchTrees.java @@ -0,0 +1,37 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +/** + * Created by gouthamvidyapradhan on 31/03/2017. Given n, how many structurally unique BST's (binary + * search trees) that store values 1...n? + * + *

For example, Given n = 3, there are a total of 5 unique BST's. + * + *

1 3 3 2 1 \ / / / \ \ 3 2 1 1 3 2 / / \ \ 2 1 2 3 + */ +public class UniqueBinarySearchTrees { + int[] dp; + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) throws Exception { + System.out.println(new UniqueBinarySearchTrees().numTrees(5)); + } + + public int numTrees(int n) { + dp = new int[n + 1]; + dp[0] = 1; + return dp(n); + } + + private int dp(int n) { + if (dp[n] != 0) return dp[n]; + for (int i = 1; i <= n; i++) { + dp[n] += dp(n - i) * dp(n - (n - i) - 1); + } + return dp[n]; + } +} diff --git a/src/main/java/dynamic_programming/UniqueBinarySearchTreesII.java b/src/main/java/dynamic_programming/UniqueBinarySearchTreesII.java new file mode 100644 index 00000000..1036c7ca --- /dev/null +++ b/src/main/java/dynamic_programming/UniqueBinarySearchTreesII.java @@ -0,0 +1,88 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 31/03/2017. Given an integer n, generate all structurally + * unique BST's (binary search trees) that store values 1...n. + * + *

For example, Given n = 3, your program should return all 5 unique BST's shown below. + * + *

1 3 3 2 1 \ / / / \ \ 3 2 1 1 3 2 / / \ \ 2 1 2 3 + */ +public class UniqueBinarySearchTreesII { + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + List list = new UniqueBinarySearchTreesII().generateTrees(3); + } + + class Pair { + int l, r; + + Pair(int l, int r) { + this.l = l; + this.r = r; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Pair)) return false; + Pair pair = (Pair) o; + return l == pair.l && r == pair.r; + } + + @Override + public int hashCode() { + return Objects.hash(l, r); + } + } + + Map> dp; + + public List generateTrees(int n) { + dp = new HashMap<>(); + if (n == 0) return new ArrayList<>(); + return generate(new Pair(1, n)); + } + + private List generate(Pair p) { + if (dp.containsKey(p)) { + return dp.get(p); + } else if (p.l > p.r) return Arrays.asList(new TreeNode(-1)); + else if (p.l == p.r) return Arrays.asList(new TreeNode(p.l)); + List list = new ArrayList<>(); + for (int i = p.l; i <= p.r; i++) { + Pair left = new Pair(p.l, i - 1); + Pair right = new Pair(i + 1, p.r); + List leftList = generate(left); + List rightList = generate(right); + for (TreeNode lNode : leftList) { + for (TreeNode rNode : rightList) { + TreeNode root = new TreeNode(i); + root.left = lNode.val == -1 ? null : lNode; + root.right = rNode.val == -1 ? null : rNode; + list.add(root); + } + } + } + dp.put(p, list); + return list; + } +} diff --git a/src/main/java/dynamic_programming/ValidPalindromeIII.java b/src/main/java/dynamic_programming/ValidPalindromeIII.java new file mode 100644 index 00000000..e3be5fad --- /dev/null +++ b/src/main/java/dynamic_programming/ValidPalindromeIII.java @@ -0,0 +1,51 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 23/04/2020 Given a string s and an integer k, find out if the + * given string is a K-Palindrome or not. + * + *

A string is K-Palindrome if it can be transformed into a palindrome by removing at most k + * characters from it. + * + *

Example 1: + * + *

Input: s = "abcdeca", k = 2 Output: true Explanation: Remove 'b' and 'e' characters. + * + *

Constraints: + * + *

1 <= s.length <= 1000 s has only lowercase English letters. 1 <= k <= s.length + */ +public class ValidPalindromeIII { + public static void main(String[] args) { + System.out.println(new ValidPalindromeIII().isValidPalindrome("abc", 0)); + } + + int[][] DP; + + public boolean isValidPalindrome(String s, int k) { + DP = new int[s.length()][s.length()]; + for (int i = 0; i < s.length(); i++) { + Arrays.fill(DP[i], -1); + } + return dp(0, s.length() - 1, s) <= k; + } + + private int dp(int i, int j, String S) { + if (i == j) return 0; + else if (i > j) return 0; + else if (DP[i][j] != -1) return DP[i][j]; + else { + int min = Integer.MAX_VALUE; + if (S.charAt(i) != S.charAt(j)) { + min = Math.min(min, Math.min(dp(i + 1, j, S), dp(i, j - 1, S)) + 1); + } else { + min = dp(i + 1, j - 1, S); + } + DP[i][j] = min; + return min; + } + } +} diff --git a/src/main/java/dynamic_programming/WordBreak.java b/src/main/java/dynamic_programming/WordBreak.java new file mode 100644 index 00000000..7b54b113 --- /dev/null +++ b/src/main/java/dynamic_programming/WordBreak.java @@ -0,0 +1,61 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 16/03/2017. Given a non-empty string s and a dictionary + * wordDict containing a list of non-empty words, determine if s can be segmented into a + * space-separated sequence of one or more dictionary words. You may assume the dictionary does not + * contain duplicate words. + * + *

For example, given s = "leetcode", dict = ["leet", "code"]. + * + *

Return true because "leetcode" can be segmented as "leet code". + */ +public class WordBreak { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + List dic = new ArrayList<>(); + String[] arr = { + "a", "aa", "aaa", "aaaa", "aaaaa", "aaaaaa", "aaaaaaa", "aaaaaaaa", "aaaaaaaaa", "aaaaaaaaaa" + }; + for (String s : arr) dic.add(s); + System.out.println( + new WordBreak() + .wordBreak( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + dic)); + } + + public boolean wordBreak(String s, List wordDict) { + Set dictionary = new HashSet<>(); + dictionary.addAll(wordDict); + Map dic = new HashMap<>(); + for (int i = s.length() - 1; i >= 0; i--) dp(i, s, dic, dictionary); + return dic.get(0); + } + + private boolean dp(int i, String s, Map dic, Set dictionary) { + if (i == s.length()) return true; + else if (dic.containsKey(i)) return dic.get(i); + else { + for (int j = i, l = s.length(); j < l; j++) { + String subStr = s.substring(i, j + 1); + if (dictionary.contains(subStr)) { + if (dp(j + 1, s, dic, dictionary)) { + dic.put(i, true); + break; + } + } + } + } + if (!dic.containsKey(i)) dic.put(i, false); + return dic.get(i); + } +} diff --git a/src/main/java/dynamic_programming/WordBreakII.java b/src/main/java/dynamic_programming/WordBreakII.java new file mode 100644 index 00000000..b4e7a682 --- /dev/null +++ b/src/main/java/dynamic_programming/WordBreakII.java @@ -0,0 +1,62 @@ +/* (C) 2024 YourCompanyName */ +package dynamic_programming; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 07/04/2017. Given a non-empty string s and a dictionary + * wordDict containing a list of non-empty words, add spaces in s to construct a sentence where each + * word is a valid dictionary word. You may assume the dictionary does not contain duplicate words. + * + *

Return all such possible sentences. + * + *

For example, given s = "catsanddog", dict = ["cat", "cats", "and", "sand", "dog"]. + * + *

A solution is ["cats and dog", "cat sand dog"]. + */ +public class WordBreakII { + private Map> map; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + List wordList = new ArrayList<>(); + wordList.add("cat"); + wordList.add("cats"); + wordList.add("and"); + wordList.add("sand"); + wordList.add("dog"); + System.out.println(new WordBreakII().wordBreak("catsanddog", wordList)); + } + + public List wordBreak(String s, List wordDict) { + if (s == null) return new ArrayList<>(); + map = new HashMap<>(); + Set dictionary = new HashSet<>(); + dictionary.addAll(wordDict); + return dp(0, s, s.length(), dictionary); + } + + private List dp(int p, String s, int l, Set dictionary) { + List result = new ArrayList<>(); + if (p >= s.length()) { + result.add(""); + return result; + } else if (map.containsKey(p)) { + return map.get(p); + } + for (int i = p; i < l; i++) { + String subStr = s.substring(p, i + 1); + if (dictionary.contains(subStr)) { + List subList = dp(i + 1, s, l, dictionary); + for (String se : subList) result.add((subStr + " " + se).trim()); + } + } + map.put(p, result); + return result; + } +} diff --git a/src/main/java/greedy/BoatsToSavePeople.java b/src/main/java/greedy/BoatsToSavePeople.java new file mode 100644 index 00000000..73736e0c --- /dev/null +++ b/src/main/java/greedy/BoatsToSavePeople.java @@ -0,0 +1,66 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 09/05/2019 The i-th person has weight people[i], and each boat + * can carry a maximum weight of limit. + * + *

Each boat carries at most 2 people at the same time, provided the sum of the weight of those + * people is at most limit. + * + *

Return the minimum number of boats to carry every given person. (It is guaranteed each person + * can be carried by a boat.) + * + *

Example 1: + * + *

Input: people = [1,2], limit = 3 Output: 1 Explanation: 1 boat (1, 2) Example 2: + * + *

Input: people = [3,2,2,1], limit = 3 Output: 3 Explanation: 3 boats (1, 2), (2) and (3) + * Example 3: + * + *

Input: people = [3,5,3,4], limit = 5 Output: 4 Explanation: 4 boats (3), (3), (4), (5) Note: + * + *

1 <= people.length <= 50000 1 <= people[i] <= limit <= 30000 + * + *

Solution O N log N Simple strategy is to greedy try to put in maximum possible people in a + * boat and increment the boat counter. Use TreeMap and sorting to achieve this easily + */ +public class BoatsToSavePeople { + public static void main(String[] args) { + int[] A = {3, 5, 3, 4}; + System.out.println(new BoatsToSavePeople().numRescueBoats(A, 8)); + } + + public int numRescueBoats(int[] people, int limit) { + TreeMap treeMap = new TreeMap<>(); + int boats = 0; + for (int p : people) { + treeMap.putIfAbsent(p, 0); + treeMap.put(p, treeMap.get(p) + 1); + } + Arrays.sort(people); + for (int p : people) { + if (treeMap.containsKey(p)) { + int count = treeMap.remove(p); + --count; + if (count != 0) { + treeMap.put(p, count); + } + int balance = limit - p; + Map.Entry floor = treeMap.floorEntry(balance); + if (floor != null) { + int c = floor.getValue(); + --c; + treeMap.remove(floor.getKey()); + if (c != 0) { + treeMap.put(floor.getKey(), c); + } + } + boats++; + } + } + return boats; + } +} diff --git a/src/main/java/greedy/BrokenCalculator.java b/src/main/java/greedy/BrokenCalculator.java new file mode 100644 index 00000000..24f1c25e --- /dev/null +++ b/src/main/java/greedy/BrokenCalculator.java @@ -0,0 +1,61 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 25/07/2019 On a broken calculator that has a number showing on + * its display, we can perform two operations: + * + *

Double: Multiply the number on the display by 2, or; Decrement: Subtract 1 from the number on + * the display. Initially, the calculator is displaying the number X. + * + *

Return the minimum number of operations needed to display the number Y. + * + *

Example 1: + * + *

Input: X = 2, Y = 3 Output: 2 Explanation: Use double operation and then decrement operation + * {2 -> 4 -> 3}. Example 2: + * + *

Input: X = 5, Y = 8 Output: 2 Explanation: Use decrement and then double {5 -> 4 -> 8}. + * Example 3: + * + *

Input: X = 3, Y = 10 Output: 3 Explanation: Use double, decrement and double {3 -> 6 -> 5 -> + * 10}. Example 4: + * + *

Input: X = 1024, Y = 1 Output: 1023 Explanation: Use decrement operations 1023 times. + * + *

Note: + * + *

1 <= X <= 10^9 1 <= Y <= 10^9 + * + *

Solution: O(log Y) Arrive at the solution by working backwards starting from Y. General idea + * is as follows. If Y is even then find the minimum steps required to arrive at Y by finding the + * quotient after dividing by 2. If Y is odd then find the minimum steps required to arrive at Y + 1 + * (even number) + 1 (to move backwards) + */ +public class BrokenCalculator { + public static void main(String[] args) { + // + } + + public int brokenCalc(int X, int Y) { + if (X == Y) return 0; + else if (Y < X) return X - Y; + else { + int count = 0; + while (Y > X) { + if (Y % 2 == 0) { + Y /= 2; + count++; + } else { + Y += 1; + Y /= 2; + count += 2; + } + } + if (X == Y) return count; + else return count + (X - Y); + } + } +} diff --git a/src/main/java/greedy/BurstBalloons.java b/src/main/java/greedy/BurstBalloons.java new file mode 100644 index 00000000..b0795e09 --- /dev/null +++ b/src/main/java/greedy/BurstBalloons.java @@ -0,0 +1,53 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 28/06/2017. + * + *

There are a number of spherical balloons spread in two-dimensional space. For each balloon, + * provided input is the start and end coordinates of the horizontal diameter. Since it's + * horizontal, y-coordinates don't matter and hence the x-coordinates of start and end of the + * diameter suffice. Start is always smaller than end. There will be at most 104 balloons. + * + *

An arrow can be shot up exactly vertically from different points along the x-axis. A balloon + * with xstart and xend bursts by an arrow shot at x if xstart ≤ x ≤ xend. There is no limit to the + * number of arrows that can be shot. An arrow once shot keeps travelling up infinitely. The problem + * is to find the minimum number of arrows that must be shot to burst all balloons. + * + *

Example: + * + *

Input: [[10,16], [2,8], [1,6], [7,12]] + * + *

Output: 2 + * + *

Explanation: One way is to shoot one arrow for example at x = 6 (bursting the balloons [2,8] + * and [1,6]) and another arrow at x + */ +public class BurstBalloons { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] baloons = {{10, 16}, {2, 8}, {1, 6}, {7, 12}}; + System.out.println(new BurstBalloons().findMinArrowShots(baloons)); + } + + public int findMinArrowShots(int[][] points) { + if (points.length == 0) return 0; + Arrays.sort(points, ((o1, o2) -> o1[1] - o2[1])); + int count = 0; + int leftMost = points[0][1]; + for (int i = 1; i < points.length; i++) { + if (leftMost < points[i][0]) { + count++; + leftMost = points[i][1]; + } + } + return count + 1; + } +} diff --git a/src/main/java/greedy/CourseScheduleIII.java b/src/main/java/greedy/CourseScheduleIII.java new file mode 100644 index 00000000..0ce37550 --- /dev/null +++ b/src/main/java/greedy/CourseScheduleIII.java @@ -0,0 +1,51 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +import java.util.Arrays; +import java.util.PriorityQueue; +import java.util.Queue; + +/** + * Created by gouthamvidyapradhan on 27/06/2017. + * + *

There are n different online courses numbered from 1 to n. Each course has some + * duration(course length) t and closed on dth day. A course should be taken continuously for t days + * and must be finished before or on the dth day. You will start at the 1st day. + * + *

Given n online courses represented by pairs (t,d), your task is to find the maximal number of + * courses that can be taken. + * + *

Example: Input: [[100, 200], [200, 1300], [1000, 1250], [2000, 3200]] Output: 3 Explanation: + * There're totally 4 courses, but you can take 3 courses at most: First, take the 1st course, it + * costs 100 days so you will finish it on the 100th day, and ready to take the next course on the + * 101st day. Second, take the 3rd course, it costs 1000 days so you will finish it on the 1100th + * day, and ready to take the next course on the 1101st day. Third, take the 2nd course, it costs + * 200 days so you will finish it on the 1300th day. The 4th course cannot be taken now, since you + * will finish it on the 3300th day, which exceeds the closed date. + * + *

Note: The integer 1 <= d, t, n <= 10,000. You can't take two courses simultaneously. + * + *

Solution: O(N log N) 1. Sort the courses with earliest deadline time (Greedy sort) 2. Maintain + * a max-heap of course duration. 3. Iterate through each course and increment the total time by + * current course time and include this in the max-heap created in step 2. 4. If the total time + * exceeds the current course deadline then, remove the course with max duration from max-heap + * inorder to accommodate the new course. + */ +public class CourseScheduleIII { + public static void main(String[] args) throws Exception { + int[][] course = {{5, 5}, {2, 6}, {4, 6}}; + System.out.println(new CourseScheduleIII().scheduleCourse(course)); + } + + public int scheduleCourse(int[][] courses) { + Arrays.sort(courses, (a, b) -> a[1] - b[1]); + Queue pq = new PriorityQueue<>((a, b) -> b - a); + int time = 0; + for (int[] course : courses) { + time += course[0]; + pq.add(course[0]); + if (time > course[1]) time -= pq.poll(); + } + return pq.size(); + } +} diff --git a/src/main/java/greedy/GasStation.java b/src/main/java/greedy/GasStation.java new file mode 100644 index 00000000..62a2d396 --- /dev/null +++ b/src/main/java/greedy/GasStation.java @@ -0,0 +1,46 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +/** + * Created by gouthamvidyapradhan on 28/06/2017. There are N gas stations along a circular route, + * where the amount of gas at station i is gas[i]. + * + *

You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i + * to its next station (i+1). You begin the journey with an empty tank at one of the gas stations. + * + *

Return the starting gas station's index if you can travel around the circuit once, otherwise + * return -1. + * + *

Note: The solution is guaranteed to be unique. + * + *

Solution: O(N) If point B cant be reached from point A then all the intermediate points + * between A and B cant be the starting point. Therefore reset the starting point to the new + * starting point. + */ +public class GasStation { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] gas = {10, 20, 30, 10}; + int[] cost = {5, 30, 10, 10}; + System.out.println(new GasStation().canCompleteCircuit(gas, cost)); + } + + public int canCompleteCircuit(int[] gas, int[] cost) { + int debt = 0, sum = 0, start = 0; + for (int i = 0; i < gas.length; i++) { + sum += gas[i] - cost[i]; + if (sum < 0) { + debt += sum; + sum = 0; + start = i + 1; + } + } + debt += sum; + return debt >= 0 ? start : -1; + } +} diff --git a/src/main/java/greedy/IPO.java b/src/main/java/greedy/IPO.java new file mode 100644 index 00000000..049cbf93 --- /dev/null +++ b/src/main/java/greedy/IPO.java @@ -0,0 +1,104 @@ +/* (C) 2024 YourCompanyName */ +package greedy; +/** + * Created by gouthamvidyapradhan on 09/04/2019 Suppose LeetCode will start its IPO soon. In order + * to sell a good price of its shares to Venture Capital, LeetCode would like to work on some + * projects to increase its capital before the IPO. Since it has limited resources, it can only + * finish at most k distinct projects before the IPO. Help LeetCode design the best way to maximize + * its total capital after finishing at most k distinct projects. + * + *

You are given several projects. For each project i, it has a pure profit Pi and a minimum + * capital of Ci is needed to start the corresponding project. Initially, you have W capital. When + * you finish a project, you will obtain its pure profit and the profit will be added to your total + * capital. + * + *

To sum up, pick a list of at most k distinct projects from given projects to maximize your + * final capital, and output your final maximized capital. + * + *

Example 1: Input: k=2, W=0, Profits=[1,2,3], Capital=[0,1,1]. + * + *

Output: 4 + * + *

Explanation: Since your initial capital is 0, you can only start the project indexed 0. After + * finishing it you will obtain profit 1 and your capital becomes 1. With capital 1, you can either + * start the project indexed 1 or the project indexed 2. Since you can choose at most 2 projects, + * you need to finish the project indexed 2 to get the maximum capital. Therefore, output the final + * maximized capital, which is 0 + 1 + 3 = 4. Note: You may assume all numbers in the input are + * non-negative integers. The length of Profits array and Capital array will not exceed 50,000. The + * answer is guaranteed to fit in a 32-bit signed integer. + * + *

Solution: O(N log N) where N is the size of Capital/Profit array. General intuition is to pick + * a project which gives maximum profit for the available capital. Sum the profit with the original + * capital and this becomes the new available capital now, again pick the project which gives + * maximum profit. Continue this until K projects are picked. Maintain a priority queue to pick the + * project which gives maximum profit. + */ +import java.util.*; + +public class IPO { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[] P = {1, 2, 3}; + int[] C = {1, 1, 2}; + System.out.println(new IPO().findMaximizedCapital(1, 0, P, C)); + } + + class Pair { + int p, c; + + Pair(int p, int c) { + this.p = p; + this.c = c; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Pair)) return false; + Pair pair = (Pair) o; + return p == pair.p && c == pair.c; + } + + public int getP() { + return p; + } + + public int getC() { + return c; + } + + @Override + public int hashCode() { + return Objects.hash(p, c); + } + } + + public int findMaximizedCapital(int k, int W, int[] Profits, int[] Capital) { + PriorityQueue profits = + new PriorityQueue<>(Comparator.comparing(Pair::getP).reversed().thenComparing(Pair::getC)); + PriorityQueue capitals = new PriorityQueue<>(Comparator.comparing(Pair::getC)); + for (int i = 0; i < Profits.length; i++) { + capitals.offer(new Pair(Profits[i], Capital[i])); + } + while (true) { + while (!capitals.isEmpty() && capitals.peek().getC() <= W) { + profits.offer(capitals.poll()); + } + if (!profits.isEmpty() && profits.peek().getC() <= W && k > 0) { + W += profits.poll().getP(); + k--; + } + if (capitals.isEmpty() || capitals.peek().getC() > W || k == 0) break; + } + while (k > 0 && !profits.isEmpty()) { + W += profits.poll().getP(); + k--; + } + return W; + } +} diff --git a/src/main/java/greedy/JumpGame.java b/src/main/java/greedy/JumpGame.java new file mode 100644 index 00000000..dcb916e4 --- /dev/null +++ b/src/main/java/greedy/JumpGame.java @@ -0,0 +1,36 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +/** + * Created by gouthamvidyapradhan on 17/03/2017. Given an array of non-negative integers, you are + * initially positioned at the first index of the array. + * + *

Each element in the array represents your maximum jump length at that position. + * + *

Determine if you are able to reach the last index. + * + *

For example: A = [2,3,1,1,4], return true. + * + *

A = [3,2,1,0,4], return false. + */ +public class JumpGame { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] nums = {1, 2, 1, 0, 4}; + System.out.println(new JumpGame().canJump(nums)); + } + + public boolean canJump(int[] nums) { + if (nums.length == 0) return false; + int min = nums.length - 1, max = nums.length - 1; + for (int i = nums.length - 2; i >= 0; i--) { + if ((nums[i] + i) >= min) min = i; + } + return (min == 0); + } +} diff --git a/src/main/java/greedy/JumpGameII.java b/src/main/java/greedy/JumpGameII.java new file mode 100644 index 00000000..5ffd6dd1 --- /dev/null +++ b/src/main/java/greedy/JumpGameII.java @@ -0,0 +1,40 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +/** + * Created by gouthamvidyapradhan on 02/04/2017. Given an array of non-negative integers, you are + * initially positioned at the first index of the array. + * + *

Each element in the array represents your maximum jump length at that position. + * + *

Your goal is to reach the last index in the minimum number of jumps. + * + *

For example: Given array A = [2,3,1,1,4] + * + *

The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then + * 3 steps to the last index.) + * + *

Note: You can assume that you can always reach the last index. + */ +public class JumpGameII { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception {} + + public int jump(int[] nums) { + int step = 0; + int e = 0, max = 0; + for (int i = 0; i < nums.length - 1; i++) { + max = Math.max(max, i + nums[i]); + if (i == e) { + step++; + e = max; + } + } + return step; + } +} diff --git a/src/main/java/greedy/LemonadeChange.java b/src/main/java/greedy/LemonadeChange.java new file mode 100644 index 00000000..43d4fa2c --- /dev/null +++ b/src/main/java/greedy/LemonadeChange.java @@ -0,0 +1,78 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +/** + * Created by gouthamvidyapradhan on 26/04/2019 + * + *

At a lemonade stand, each lemonade costs $5. + * + *

Customers are standing in a queue to buy from you, and order one at a time (in the order + * specified by bills). + * + *

Each customer will only buy one lemonade and pay with either a $5, $10, or $20 bill. You must + * provide the correct change to each customer, so that the net transaction is that the customer + * pays $5. + * + *

Note that you don't have any change in hand at first. + * + *

Return true if and only if you can provide every customer with correct change. + * + *

Example 1: + * + *

Input: [5,5,5,10,20] Output: true Explanation: From the first 3 customers, we collect three $5 + * bills in order. From the fourth customer, we collect a $10 bill and give back a $5. From the + * fifth customer, we give a $10 bill and a $5 bill. Since all customers got correct change, we + * output true. Example 2: + * + *

Input: [5,5,10] Output: true Example 3: + * + *

Input: [10,10] Output: false Example 4: + * + *

Input: [5,5,10,10,20] Output: false Explanation: From the first two customers in order, we + * collect two $5 bills. For the next two customers in order, we collect a $10 bill and give back a + * $5 bill. For the last customer, we can't give change of $15 back because we only have two $10 + * bills. Since not every customer received correct change, the answer is false. + * + *

Note: + * + *

0 <= bills.length <= 10000 bills[i] will be either 5, 10, or 20. + * + *

Solution: Store the count of number of five's and tens's. In case of change 15 return a 10 + 5 + * (if 10 is not available then, return 5 + 5 + 5 if three fives are available) Since we are + * choosing a 10 + 5 instead of 5 + 5 + 5, this problem holds a greedy property + */ +public class LemonadeChange { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) {} + + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int b : bills) { + if (b == 5) { + five++; + } else if (b == 10) { + ten++; + if (five > 0) { + five--; + } else { + return false; + } + } else { + if (ten > 0 && five > 0) { + ten--; + five--; + } else if (five > 2) { + five -= 3; + } else { + return false; + } + } + } + return true; + } +} diff --git a/src/main/java/greedy/MaximumLengthOfPairChain.java b/src/main/java/greedy/MaximumLengthOfPairChain.java new file mode 100644 index 00000000..8e363bcd --- /dev/null +++ b/src/main/java/greedy/MaximumLengthOfPairChain.java @@ -0,0 +1,50 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 01/05/2018. You are given n pairs of numbers. In every pair, + * the first number is always smaller than the second number. + * + *

Now, we define a pair (c, d) can follow another pair (a, b) if and only if b < c. Chain of + * pairs can be formed in this fashion. + * + *

Given a set of pairs, find the length longest chain which can be formed. You needn't use up + * all the given pairs. You can select pairs in any order. + * + *

Example 1: Input: [[1,2], [2,3], [3,4]] Output: 2 Explanation: The longest chain is [1,2] -> + * [3,4] Note: The number of given pairs will be in the range [1, 1000]. + * + *

Solution: O(N log N) sort the pairs with ending interval (greedy sort) and try to accommodate + * as many pairs as possible. If any current pair violates the chaining condition (b < c) then, + * ignore that particular pair. + */ +public class MaximumLengthOfPairChain { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] A = {{1, 2}, {2, 3}, {3, 4}}; + System.out.println(new MaximumLengthOfPairChain().findLongestChain(A)); + } + + public int findLongestChain(int[][] pairs) { + Arrays.sort( + pairs, + (o1, o2) -> o1[1] == o2[1] ? Integer.compare(o1[0], o2[0]) : Integer.compare(o1[1], o2[1])); + int count = 1; + int[] curr = pairs[0]; + for (int i = 1; i < pairs.length; i++) { + if (pairs[i][0] > curr[1]) { + count++; + curr = pairs[i]; + } + } + return count; + } +} diff --git a/src/main/java/greedy/MinimumTimeToBuildBlocks.java b/src/main/java/greedy/MinimumTimeToBuildBlocks.java new file mode 100644 index 00000000..68a9f445 --- /dev/null +++ b/src/main/java/greedy/MinimumTimeToBuildBlocks.java @@ -0,0 +1,53 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +import java.util.PriorityQueue; + +/** + * Created by gouthamvidyapradhan on 05/05/2020 You are given a list of blocks, where blocks[i] = t + * means that the i-th block needs t units of time to be built. A block can only be built by exactly + * one worker. + * + *

A worker can either split into two workers (number of workers increases by one) or build a + * block then go home. Both decisions cost some time. + * + *

The time cost of spliting one worker into two workers is given as an integer split. Note that + * if two workers split at the same time, they split in parallel so the cost would be split. + * + *

Output the minimum time needed to build all blocks. + * + *

Initially, there is only one worker. + * + *

Example 1: + * + *

Input: blocks = [1], split = 1 Output: 1 Explanation: We use 1 worker to build 1 block in 1 + * time unit. Example 2: + * + *

Input: blocks = [1,2], split = 5 Output: 7 Explanation: We split the worker into 2 workers in + * 5 time units then assign each of them to a block so the cost is 5 + max(1, 2) = 7. Example 3: + * + *

Input: blocks = [1,2,3], split = 1 Output: 4 Explanation: Split 1 worker into 2, then assign + * the first worker to the last block and split the second worker into 2. Then, use the two + * unassigned workers to build the first two blocks. The cost is 1 + max(3, 1 + max(1, 2)) = 4. + * + *

Constraints: + * + *

1 <= blocks.length <= 1000 1 <= blocks[i] <= 10^5 1 <= split <= 100 + */ +public class MinimumTimeToBuildBlocks { + public static void main(String[] args) { + int[] A = {1, 2, 3}; + System.out.println(new MinimumTimeToBuildBlocks().minBuildTime(A, 2)); + } + + public int minBuildTime(int[] blocks, int split) { + PriorityQueue queue = new PriorityQueue<>(); + for (int b : blocks) queue.offer(b); + while (queue.size() != 1) { + int a = queue.poll(); + int b = queue.poll(); + queue.offer(Math.max(a, b) + split); + } + return queue.poll(); + } +} diff --git a/src/main/java/greedy/NonOverlappingIntervals.java b/src/main/java/greedy/NonOverlappingIntervals.java new file mode 100644 index 00000000..93bec062 --- /dev/null +++ b/src/main/java/greedy/NonOverlappingIntervals.java @@ -0,0 +1,75 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 28/06/2017. Given a collection of intervals, find the minimum + * number of intervals you need to remove to make the rest of the intervals non-overlapping. + * + *

Note: You may assume the interval's end point is always bigger than its start point. Intervals + * like [1,2] and [2,3] have borders "touching" but they don't overlap each other. Example 1: Input: + * [ [1,2], [2,3], [3,4], [1,3] ] + * + *

Output: 1 + * + *

Explanation: [1,3] can be removed and the rest of intervals are non-overlapping. Example 2: + * Input: [ [1,2], [1,2], [1,2] ] + * + *

Output: 2 + * + *

Explanation: You need to remove two [1,2] to make the rest of intervals non-overlapping. + * Example 3: Input: [ [1,2], [2,3] ] + * + *

Output: 0 + * + *

Explanation: You don't need to remove any of the intervals since they're already + * non-overlapping. + */ +public class NonOverlappingIntervals { + + public static class Interval { + int start; + int end; + + Interval() { + start = 0; + end = 0; + } + + Interval(int s, int e) { + start = s; + end = e; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + Interval i1 = new Interval(1, 4); + Interval i2 = new Interval(5, 9); + Interval i3 = new Interval(3, 12); + // Interval i4 = new Interval(1, 3); + Interval[] intervals = {i1, i2, i3}; + System.out.println(new NonOverlappingIntervals().eraseOverlapIntervals(intervals)); + } + + public int eraseOverlapIntervals(Interval[] intervals) { + if (intervals.length == 0) return 0; + Arrays.sort(intervals, ((o1, o2) -> o1.end - o2.end)); + int count = 0; + Interval prev = intervals[0]; + for (int i = 1; i < intervals.length; i++) { + if (intervals[i].start < prev.end) { + count++; + } else { + prev = intervals[i]; + } + } + return count; + } +} diff --git a/src/main/java/greedy/PartitionLabels.java b/src/main/java/greedy/PartitionLabels.java new file mode 100644 index 00000000..f33c929b --- /dev/null +++ b/src/main/java/greedy/PartitionLabels.java @@ -0,0 +1,44 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +import java.util.*; + +/** Created by gouthamvidyapradhan on 30/11/2019 */ +public class PartitionLabels { + public static void main(String[] args) { + System.out.println(new PartitionLabels().partitionLabels("ababcbacadefegdehijhklij")); + } + + public List partitionLabels(String S) { + Map map = new HashMap<>(); + for (int i = 0; i < S.length(); i++) { + char c = S.charAt(i); + map.putIfAbsent(c, i); + map.remove(c); + map.put(c, i); + } + char start = S.charAt(0); + int currMax = map.get(start); + int startIndex = 0; + List list = new ArrayList<>(); + while (true) { + int i = startIndex; + for (; i <= currMax; i++) { + char c = S.charAt(i); + int pos = map.get(c); + currMax = Math.max(currMax, pos); + } + if (i > currMax && i < S.length()) { + list.add(i - startIndex); + startIndex = i; + currMax = map.get(S.charAt(i)); + } else { + if (i == S.length()) { + list.add(i - startIndex); + break; + } + } + } + return list; + } +} diff --git a/src/main/java/greedy/QueueReconstructionByHeight.java b/src/main/java/greedy/QueueReconstructionByHeight.java new file mode 100644 index 00000000..2e04f6dc --- /dev/null +++ b/src/main/java/greedy/QueueReconstructionByHeight.java @@ -0,0 +1,38 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +import java.util.Arrays; +import java.util.LinkedList; + +/** + * Created by gouthamvidyapradhan on 29/06/2017. Suppose you have a random list of people standing + * in a queue. Each person is described by a pair of integers (h, k), where h is the height of the + * person and k is the number of people in front of this person who have a height greater than or + * equal to h. Write an algorithm to reconstruct the queue. + * + *

Note: The number of people is less than 1,100. + * + *

Example + * + *

Input: [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]] + * + *

Output: [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]] + */ +public class QueueReconstructionByHeight { + public static void main(String[] args) throws Exception { + int[][] A = {{7, 0}, {4, 4}, {7, 1}, {5, 0}, {6, 1}, {5, 2}}; + int[][] r = new QueueReconstructionByHeight().reconstructQueue(A); + for (int[] i : r) { + System.out.println(i[0] + " " + i[1]); + } + } + + public int[][] reconstructQueue(int[][] people) { + Arrays.sort(people, ((o1, o2) -> (o2[0] - o1[0] == 0) ? o1[1] - o2[1] : o2[0] - o1[0])); + LinkedList list = new LinkedList<>(); + for (int[] p : people) list.add(p[1], p); + int[][] result = new int[people.length][2]; + for (int i = 0, l = list.size(); i < l; i++) result[i] = list.get(i); + return result; + } +} diff --git a/src/main/java/greedy/ReducingDishes.java b/src/main/java/greedy/ReducingDishes.java new file mode 100644 index 00000000..f21b0729 --- /dev/null +++ b/src/main/java/greedy/ReducingDishes.java @@ -0,0 +1,55 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 16/06/2020 A chef has collected data on the satisfaction level + * of his n dishes. Chef can cook any dish in 1 unit of time. + * + *

Like-time coefficient of a dish is defined as the time taken to cook that dish including + * previous dishes multiplied by its satisfaction level i.e. time[i]*satisfaction[i] + * + *

Return the maximum sum of Like-time coefficient that the chef can obtain after dishes + * preparation. + * + *

Dishes can be prepared in any order and the chef can discard some dishes to get this maximum + * value. + * + *

Example 1: + * + *

Input: satisfaction = [-1,-8,0,5,-9] Output: 14 Explanation: After Removing the second and + * last dish, the maximum total Like-time coefficient will be equal to (-1*1 + 0*2 + 5*3 = 14). Each + * dish is prepared in one unit of time. Example 2: + * + *

Input: satisfaction = [4,3,2] Output: 20 Explanation: Dishes can be prepared in any order, + * (2*1 + 3*2 + 4*3 = 20) Example 3: + * + *

Input: satisfaction = [-1,-4,-5] Output: 0 Explanation: People don't like the dishes. No dish + * is prepared. Example 4: + * + *

Input: satisfaction = [-2,5,-1,0,3,-3] Output: 35 + * + *

Constraints: + * + *

n == satisfaction.length 1 <= n <= 500 -10^3 <= satisfaction[i] <= 10^3 + */ +public class ReducingDishes { + public static void main(String[] args) { + int[] A = {4, 3, 2}; + System.out.println(new ReducingDishes().maxSatisfaction(A)); + } + + public int maxSatisfaction(int[] satisfaction) { + Queue pq = new PriorityQueue<>(((o1, o2) -> o2 - o1)); + Arrays.stream(satisfaction).forEach(pq::offer); + int max = 0, sum = 0; + while (!pq.isEmpty()) { + if ((max + sum) >= max) { + max += sum; + sum += pq.poll(); + } else break; + } + return max; + } +} diff --git a/src/main/java/greedy/ScoreAfterFlippingMatrix.java b/src/main/java/greedy/ScoreAfterFlippingMatrix.java new file mode 100644 index 00000000..fd7a9d1d --- /dev/null +++ b/src/main/java/greedy/ScoreAfterFlippingMatrix.java @@ -0,0 +1,94 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +/** + * Created by gouthamvidyapradhan on 26/04/2019 We have a two dimensional matrix A where each value + * is 0 or 1. + * + *

A move consists of choosing any row or column, and toggling each value in that row or column: + * changing all 0s to 1s, and all 1s to 0s. + * + *

After making any number of moves, every row of this matrix is interpreted as a binary number, + * and the score of the matrix is the sum of these numbers. + * + *

Return the highest possible score. + * + *

Example 1: + * + *

Input: [[0,0,1,1],[1,0,1,0],[1,1,0,0]] Output: 39 Explanation: Toggled to + * [[1,1,1,1],[1,0,0,1],[1,1,1,1]]. 0b1111 + 0b1001 + 0b1111 = 15 + 9 + 15 = 39 + * + *

Note: + * + *

1 <= A.length <= 20 1 <= A[0].length <= 20 A[i][j] is 0 or 1. + * + *

Solution: O(N x N) Select each row and greedily flip the row if it maximizes the value. Select + * each column and flip the column if the count of 1's in the column is smaller than count of 0's + * Sum up the final value from each column return the answer. + */ +public class ScoreAfterFlippingMatrix { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[][] A = {{1, 0}, {1, 0}, {1, 0}, {1, 1}}; + System.out.println(new ScoreAfterFlippingMatrix().matrixScore(A)); + } + + public int matrixScore(int[][] A) { + for (int[] a : A) { + int temp1 = makeNum(a); + flip(a); + int temp2 = makeNum(a); + if (temp1 > temp2) { + // revert + flip(a); + } + } + for (int i = 0; i < A[0].length; i++) { + int count = 0; + for (int j = 0; j < A.length; j++) { + if (A[j][i] == 1) { + count++; + } + } + if (count < (A.length - count)) { + for (int j = 0; j < A.length; j++) { + if (A[j][i] == 0) { + A[j][i] = 1; + } else { + A[j][i] = 0; + } + } + } + } + int sum = 0; + for (int[] a : A) { + sum += makeNum(a); + } + return sum; + } + + private int makeNum(int[] a) { + int n = 0; + for (int i = 0; i < a.length; i++) { + if (a[i] == 1) { + n |= (1 << (a.length - i - 1)); + } + } + return n; + } + + private void flip(int[] A) { + for (int i = 0; i < A.length; i++) { + if (A[i] == 1) { + A[i] = 0; + } else { + A[i] = 1; + } + } + } +} diff --git a/src/main/java/greedy/StringWithout3A3B.java b/src/main/java/greedy/StringWithout3A3B.java new file mode 100644 index 00000000..91c69416 --- /dev/null +++ b/src/main/java/greedy/StringWithout3A3B.java @@ -0,0 +1,61 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +/** + * Created by gouthamvidyapradhan on 07/05/2019 + * + *

Given two integers A and B, return any string S such that: + * + *

S has length A + B and contains exactly A 'a' letters, and exactly B 'b' letters; The + * substring 'aaa' does not occur in S; The substring 'bbb' does not occur in S. + * + *

Example 1: + * + *

Input: A = 1, B = 2 Output: "abb" Explanation: "abb", "bab" and "bba" are all correct answers. + * Example 2: + * + *

Input: A = 4, B = 1 Output: "aabaa" + * + *

Solution O(N) idea is to greedily try to put two a's if number of a's is > b and similarly for + * b + */ +public class StringWithout3A3B { + + public static void main(String[] args) { + System.out.println(new StringWithout3A3B().strWithout3a3b(4, 1)); + } + + public String strWithout3a3b(int A, int B) { + StringBuilder sb = new StringBuilder(); + while (A > 0 || B > 0) { + if (A > B && A > 1 && B > 0) { + sb.append("a").append("a"); + sb.append("b"); + A -= 2; + B -= 1; + } else if (B > A && B > 1 && A > 0) { + sb.append("b").append("b"); + sb.append("a"); + B -= 2; + A -= 1; + } else { + if (A > B && A > 1) { + sb.append("a"); + sb.append("a"); + A -= 2; + } else if (A > B && A > 0) { + sb.append("a"); + A -= 1; + } else if (B > A && B > 1) { + sb.append("b"); + sb.append("b"); + B -= 2; + } else { + sb.append("b"); + B -= 1; + } + } + } + return sb.toString(); + } +} diff --git a/src/main/java/greedy/TaskScheduler.java b/src/main/java/greedy/TaskScheduler.java new file mode 100644 index 00000000..d959cc10 --- /dev/null +++ b/src/main/java/greedy/TaskScheduler.java @@ -0,0 +1,95 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 26/11/2017. + * + *

Given a char array representing tasks CPU need to do. It contains capital letters A to Z where + * different letters represent different tasks.Tasks could be done without original order. Each task + * could be done in one interval. For each interval, CPU could finish one task or just be idle. + * + *

However, there is a non-negative cooling interval n that means between two same tasks, there + * must be at least n intervals that CPU are doing different tasks or just be idle. + * + *

You need to return the least number of intervals the CPU will take to finish all the given + * tasks. + * + *

Example 1: Input: tasks = ["A","A","A","B","B","B"], n = 2 Output: 8 Explanation: A -> B -> + * idle -> A -> B -> idle -> A -> B. Note: The number of tasks is in the range [1, 10000]. The + * integer n is in the range [0, 100]. + */ +public class TaskScheduler { + + class Task { + char t; + int count; + + Task(char t, int count) { + this.t = t; + this.count = count; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + } + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + char[] tasks = {'A', 'A', 'A', 'B', 'B', 'B'}; + System.out.println(new TaskScheduler().leastInterval(tasks, 2)); + } + + /** + * @param tasks + * @param n + * @return + */ + public int leastInterval(char[] tasks, int n) { + PriorityQueue queue = + new PriorityQueue<>(Comparator.comparing(Task::getCount).reversed()); + List waiting = new ArrayList<>(); + Map map = new HashMap<>(); + for (char c : tasks) { + if (map.get(c) == null) { + map.put(c, 1); + } else { + int v = map.get(c) + 1; + map.put(c, v); + } + } + for (char c : map.keySet()) { + Task task = new Task(c, map.get(c)); + queue.offer(task); + } + int count = 0; + while (!queue.isEmpty()) { + int i = 0; + while (i <= n) { + if (!queue.isEmpty()) { + Task task = queue.poll(); + task.count--; + if (task.count > 0) { + waiting.add(task); + } + } + count++; + if (queue.isEmpty() && waiting.isEmpty()) break; + i++; + } + queue.addAll(waiting); + waiting.clear(); + } + return count; + } +} diff --git a/src/main/java/greedy/TwoCityScheduling.java b/src/main/java/greedy/TwoCityScheduling.java new file mode 100644 index 00000000..495023fd --- /dev/null +++ b/src/main/java/greedy/TwoCityScheduling.java @@ -0,0 +1,67 @@ +/* (C) 2024 YourCompanyName */ +package greedy; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 15/08/2019 There are 2N people a company is planning to + * interview. The cost of flying the i-th person to city A is costs[i][0], and the cost of flying + * the i-th person to city B is costs[i][1]. + * + *

Return the minimum cost to fly every person to a city such that exactly N people arrive in + * each city. + * + *

Example 1: + * + *

Input: [[10,20],[30,200],[400,50],[30,20]] Output: 110 Explanation: The first person goes to + * city A for a cost of 10. The second person goes to city A for a cost of 30. The third person goes + * to city B for a cost of 50. The fourth person goes to city B for a cost of 20. + * + *

The total minimum cost is 10 + 30 + 50 + 20 = 110 to have half the people interviewing in each + * city. + * + *

Note: + * + *

1 <= costs.length <= 100 It is guaranteed that costs.length is even. 1 <= costs[i][0], + * costs[i][1] <= 1000 + * + *

Solution: O(N log N) The general idea is to first allocate all the candidates to city A and + * sum up the cost and mark this as MIN. Now, make pairs with (costA - CostB, i) and sort this list + * of pairs in descending order (this is a greedy way of getting to the minimum possible value) - + * take the first half of this sorted list and sum of their values and reduce this value from MIN to + * get the answer. + */ +public class TwoCityScheduling { + public static void main(String[] args) { + int[][] A = {{10, 20}, {30, 200}, {400, 50}, {30, 20}}; + System.out.println(new TwoCityScheduling().twoCitySchedCost(A)); + } + + class Pair { + int max, i; + + Pair(int max, int i) { + this.max = max; + this.i = i; + } + } + + public int twoCitySchedCost(int[][] costs) { + int min = 0; + + for (int i = 0; i < costs.length; i++) { + min += costs[i][0]; + } + + List list = new ArrayList<>(); + for (int i = 0; i < costs.length; i++) { + list.add(new Pair(costs[i][0] - costs[i][1], i)); + } + list.sort((o1, o2) -> Integer.compare(o2.max, o1.max)); + + for (int i = 0, N = (list.size() / 2); i < N; i++) { + min -= list.get(i).max; + } + return min; + } +} diff --git a/src/main/java/hashing/Anagrams.java b/src/main/java/hashing/Anagrams.java new file mode 100644 index 00000000..85684cc5 --- /dev/null +++ b/src/main/java/hashing/Anagrams.java @@ -0,0 +1,78 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 25/02/2017. Given a string s and a non-empty string p, find all + * the start indices of p's anagrams in s. + * + *

Strings consists of lowercase English letters only and the length of both strings s and p will + * not be larger than 20,100. + * + *

The order of output does not matter. + * + *

Example 1: + * + *

Input: s: "cbaebabacd" p: "abc" + * + *

Output: [0, 6] + * + *

Explanation: The substring with start index = 0 is "cba", which is an anagram of "abc". The + * substring with start index = 6 is "bac", which is an anagram of "abc". Example 2: + * + *

Input: s: "abab" p: "ab" + * + *

Output: [0, 1, 2] + * + *

Explanation: The substring with start index = 0 is "ab", which is an anagram of "ab". The + * substring with start index = 1 is "ba", which is an anagram of "ab". The substring with start + * index = 2 is "ab", which is an anagram of "ab". + */ +public class Anagrams { + int[] TC = new int[256]; + int[] PC = new int[256]; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + List result = new Anagrams().findAnagrams("abab", "ab"); + result.forEach(System.out::print); + } + + public List findAnagrams(String s, String p) { + List result = new ArrayList<>(); + int pLen = p.length(); + if (pLen > s.length()) return result; + Arrays.fill(TC, 0); + Arrays.fill(PC, 0); + for (int i = 0; i < pLen; i++) { + TC[s.charAt(i)]++; + PC[p.charAt(i)]++; + } + + int i = pLen; + for (int l = s.length(); i < l; i++) { + if (compare()) result.add(i - pLen); + + TC[s.charAt(i)]++; + TC[s.charAt(i - pLen)]--; + } + if (compare()) result.add(i - pLen); + + return result; + } + + private boolean compare() { + for (int i = 0; i < 256; i++) { + if (TC[i] != PC[i]) return false; + } + return true; + } +} diff --git a/src/main/java/hashing/AnalyzeUserWebsiteVisitPattern.java b/src/main/java/hashing/AnalyzeUserWebsiteVisitPattern.java new file mode 100644 index 00000000..1c128bf0 --- /dev/null +++ b/src/main/java/hashing/AnalyzeUserWebsiteVisitPattern.java @@ -0,0 +1,120 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 23/10/2019 We are given some website visits: the user with name + * username[i] visited the website website[i] at time timestamp[i]. + * + *

A 3-sequence is a list of websites of length 3 sorted in ascending order by the time of their + * visits. (The websites in a 3-sequence are not necessarily distinct.) + * + *

Find the 3-sequence visited by the largest number of users. If there is more than one + * solution, return the lexicographically smallest such 3-sequence. + * + *

Example 1: + * + *

Input: username = ["joe","joe","joe","james","james","james","james","mary","mary","mary"], + * timestamp = [1,2,3,4,5,6,7,8,9,10], website = + * ["home","about","career","home","cart","maps","home","home","about","career"] Output: + * ["home","about","career"] Explanation: The tuples in this example are: ["joe", 1, "home"] ["joe", + * 2, "about"] ["joe", 3, "career"] ["james", 4, "home"] ["james", 5, "cart"] ["james", 6, "maps"] + * ["james", 7, "home"] ["mary", 8, "home"] ["mary", 9, "about"] ["mary", 10, "career"] The + * 3-sequence ("home", "about", "career") was visited at least once by 2 users. The 3-sequence + * ("home", "cart", "maps") was visited at least once by 1 user. The 3-sequence ("home", "cart", + * "home") was visited at least once by 1 user. The 3-sequence ("home", "maps", "home") was visited + * at least once by 1 user. The 3-sequence ("cart", "maps", "home") was visited at least once by 1 + * user. + * + *

Note: + * + *

3 <= N = username.length = timestamp.length = website.length <= 50 1 <= username[i].length <= + * 10 0 <= timestamp[i] <= 10^9 1 <= website[i].length <= 10 Both username[i] and website[i] contain + * only lowercase characters. It is guaranteed that there is at least one user who visited at least + * 3 websites. No user visits two websites at the same time. + */ +public class AnalyzeUserWebsiteVisitPattern { + private class VisitCount { + String site; + int count; + + VisitCount(String site, int count) { + this.site = site; + this.count = count; + } + + public String getSite() { + return site; + } + + public int getCount() { + return count; + } + } + + private class WebsiteTime { + String website; + int time; + + WebsiteTime(String website, int time) { + this.website = website; + this.time = time; + } + + public int getTime() { + return time; + } + } + + Map> userVisitCount; + + public static void main(String[] args) { + String[] userName = { + "joe", "joe", "joe", "james", "james", "james", "james", "mary", "mary", "mary" + }; + int[] time = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + String[] website = { + "home", "about", "career", "home", "cart", "maps", "home", "home", "about", "career" + }; + List result = + new AnalyzeUserWebsiteVisitPattern().mostVisitedPattern(userName, time, website); + System.out.println(result); + } + + public List mostVisitedPattern(String[] username, int[] timestamp, String[] website) { + userVisitCount = new HashMap<>(); + for (int i = 0; i < username.length; i++) { + for (int j = i + 1; j < username.length; j++) { + if (username[i].equals(username[j])) { + for (int k = j + 1; k < username.length; k++) { + if (username[i].equals(username[j]) && username[j].equals(username[k])) { + List visits = + Arrays.asList( + new WebsiteTime(website[i], timestamp[i]), + new WebsiteTime(website[j], timestamp[j]), + new WebsiteTime(website[k], timestamp[k])); + visits.sort(Comparator.comparingInt(WebsiteTime::getTime)); + String concatinatedWebsite = + String.join( + "-", visits.get(0).website, visits.get(1).website, visits.get(2).website); + userVisitCount.putIfAbsent(concatinatedWebsite, new HashSet<>()); + userVisitCount.get(concatinatedWebsite).add(username[i]); + } + } + } + } + } + List visitCounts = new ArrayList<>(); + for (String k : userVisitCount.keySet()) { + visitCounts.add(new VisitCount(k, userVisitCount.get(k).size())); + } + visitCounts.sort( + Comparator.comparingInt(VisitCount::getCount) + .reversed() + .thenComparing(VisitCount::getSite)); + VisitCount visitCount = visitCounts.get(0); + String[] result = visitCount.getSite().split("-"); + return Arrays.asList(result[0], result[1], result[2]); + } +} diff --git a/src/main/java/hashing/BrickWall.java b/src/main/java/hashing/BrickWall.java new file mode 100644 index 00000000..33bca838 --- /dev/null +++ b/src/main/java/hashing/BrickWall.java @@ -0,0 +1,103 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 19/01/2018. There is a brick wall in front of you. The wall is + * rectangular and has several rows of bricks. The bricks have the same height but different width. + * You want to draw a vertical line from the top to the bottom and cross the least bricks. + * + *

The brick wall is represented by a list of rows. Each row is a list of integers representing + * the width of each brick in this row from left to right. + * + *

If your line go through the edge of a brick, then the brick is not considered as crossed. You + * need to find out how to draw the line to cross the least bricks and return the number of crossed + * bricks. + * + *

You cannot draw a line just along one of the two vertical edges of the wall, in which case the + * line will obviously cross no bricks. + * + *

Example: Input: [[1,2,2,1], [3,1,2], [1,3,2], [2,4], [3,1,2], [1,3,1,1]] Output: 2 + * Explanation: + * + *

Note: The width sum of bricks in different rows are the same and won't exceed INT_MAX. The + * number of bricks in each row is in range [1,10,000]. The height of wall is in range [1,10,000]. + * Total number of bricks of the wall won't exceed 20,000. + * + *

Solution: O(N) where N is the total number of bricks. Calculate the prefix sum for each row of + * bricks and keep a max_count of each occurrence of prefix. The answer is total number of rows of + * bricks - max_count + */ +public class BrickWall { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + List> wall = new ArrayList<>(); + List row1 = new ArrayList<>(); + List row2 = new ArrayList<>(); + List row3 = new ArrayList<>(); + List row4 = new ArrayList<>(); + List row5 = new ArrayList<>(); + List row6 = new ArrayList<>(); + row1.add(1); + row1.add(2); + row1.add(2); + row1.add(1); + row2.add(3); + row2.add(1); + row2.add(2); + row3.add(1); + row3.add(3); + row3.add(2); + row4.add(2); + row4.add(4); + row5.add(3); + row5.add(1); + row5.add(2); + row6.add(1); + row6.add(3); + row6.add(1); + row6.add(1); + wall.add(row1); + wall.add(row2); + wall.add(row3); + wall.add(row4); + wall.add(row5); + wall.add(row6); + System.out.println(new BrickWall().leastBricks(wall)); + } + + public int leastBricks(List> wall) { + for (List row : wall) { + int prefix = 0; + for (int i = 0, l = row.size(); i < l; i++) { + prefix += row.get(i); + row.set(i, prefix); + } + } + int result = Integer.MIN_VALUE; + Map map = new HashMap<>(); + for (List row : wall) { + for (int i = 0, l = row.size(); i < l - 1; i++) { + int prefix = row.get(i); + if (map.containsKey(prefix)) { + int plusOne = map.get(prefix) + 1; + map.put(prefix, plusOne); + result = Math.max(result, plusOne); + } else { + map.put(prefix, 1); + result = Math.max(result, 1); + } + } + } + return (result == Integer.MIN_VALUE) ? wall.size() : wall.size() - result; + } +} diff --git a/src/main/java/hashing/ContiguousArray.java b/src/main/java/hashing/ContiguousArray.java new file mode 100644 index 00000000..481408e2 --- /dev/null +++ b/src/main/java/hashing/ContiguousArray.java @@ -0,0 +1,54 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 16/12/2017. Given a binary array, find the maximum length of a + * contiguous subarray with equal number of 0 and 1. + * + *

Example 1: Input: [0,1] Output: 2 Explanation: [0, 1] is the longest contiguous subarray with + * equal number of 0 and 1. Example 2: Input: [0,1,0] Output: 2 Explanation: [0, 1] (or [1, 0]) is a + * longest contiguous subarray with equal number of 0 and 1. Note: The length of the given binary + * array will not exceed 50,000. + * + *

Solution: O(n) keep a count variable and increment count when a 1 is found and decrement count + * when a 0 is found. Maintain a map of count and its corresponding index. if the count repeats + * itself then take the difference of the current index and the index saved in the map. Max of the + * difference is the answer. + */ +public class ContiguousArray { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 1}; + System.out.println(new ContiguousArray().findMaxLength(A)); + } + + public int findMaxLength(int[] nums) { + Map map = new HashMap<>(); + int count = 0; + int max = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] == 0) { + count--; + } else count++; + if (count == 0) { + max = Math.max(max, i + 1); + } else { + if (map.containsKey(count)) { + int index = map.get(count); + max = Math.max(max, i - index); + } else { + map.put(count, i); + } + } + } + return max; + } +} diff --git a/src/main/java/hashing/CustomSortString.java b/src/main/java/hashing/CustomSortString.java new file mode 100644 index 00000000..a54cfe4c --- /dev/null +++ b/src/main/java/hashing/CustomSortString.java @@ -0,0 +1,65 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 01/05/2018. S and T are strings composed of lowercase letters. + * In S, no letter occurs more than once. + * + *

S was sorted in some custom order previously. We want to permute the characters of T so that + * they match the order that S was sorted. More specifically, if x occurs before y in S, then x + * should occur before y in the returned string. + * + *

Return any permutation of T (as a string) that satisfies this property. + * + *

Example : Input: S = "cba" T = "abcd" Output: "cbad" Explanation: "a", "b", "c" appear in S, + * so the order of "a", "b", "c" should be "c", "b", and "a". Since "d" does not appear in S, it can + * be at any position in T. "dcba", "cdba", "cbda" are also valid outputs. + * + *

Note: + * + *

S has length at most 26, and no character is repeated in S. T has length at most 200. S and T + * consist of lowercase letters only. + * + *

Solution: O(N) count occurrence of each character and write to the output string + */ +public class CustomSortString { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new CustomSortString().customSortString("cba", "abcd")); + } + + public String customSortString(String S, String T) { + Map map = new HashMap<>(); + for (int i = 0; i < T.length(); i++) { + if (!map.containsKey(T.charAt(i))) { + map.put(T.charAt(i), 1); + } else { + map.put(T.charAt(i), map.get(T.charAt(i)) + 1); + } + } + StringBuilder result = new StringBuilder(); + for (char c : S.toCharArray()) { + if (map.containsKey(c)) { + int count = map.remove(c); + for (int i = 0; i < count; i++) { + result.append(c); + } + } + } + for (char c : map.keySet()) { + int count = map.get(c); + for (int i = 0; i < count; i++) { + result.append(c); + } + } + return result.toString(); + } +} diff --git a/src/main/java/hashing/DistributeCandies.java b/src/main/java/hashing/DistributeCandies.java new file mode 100644 index 00000000..473888a7 --- /dev/null +++ b/src/main/java/hashing/DistributeCandies.java @@ -0,0 +1,36 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 25/04/2019 Given an integer array with even length, where + * different numbers in this array represent different kinds of candies. Each number means one candy + * of the corresponding kind. You need to distribute these candies equally in number to brother and + * sister. Return the maximum number of kinds of candies the sister could gain. Example 1: Input: + * candies = [1,1,2,2,3,3] Output: 3 Explanation: There are three different kinds of candies (1, 2 + * and 3), and two candies for each kind. Optimal distribution: The sister has candies [1,2,3] and + * the brother has candies [1,2,3], too. The sister has three different kinds of candies. Example 2: + * Input: candies = [1,1,2,3] Output: 2 Explanation: For example, the sister has candies [2,3] and + * the brother has candies [1,1]. The sister has two different kinds of candies, the brother has + * only one kind of candies. Note: + * + *

The length of the given array is in range [2, 10,000], and will be even. The number in given + * array is in range [-100,000, 100,000]. + * + *

Solution: O(N) Use a HashSet to identify all the different possible candies. The maximum types + * of candies sister can get is always Min(N/2, Number Of Unique Type of Candies) + */ +public class DistributeCandies { + public static void main(String[] args) {} + + public int distributeCandies(int[] candies) { + int N = candies.length; + Set set = new HashSet<>(); + for (int c : candies) { + set.add(c); + } + int n = set.size(); + return Math.min(N / 2, set.size()); + } +} diff --git a/src/main/java/hashing/GroupAnagrams.java b/src/main/java/hashing/GroupAnagrams.java new file mode 100644 index 00000000..be1b90e6 --- /dev/null +++ b/src/main/java/hashing/GroupAnagrams.java @@ -0,0 +1,57 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 10/03/2017. Given an array of strings, group anagrams together. + * + *

For example, given: ["eat", "tea", "tan", "ate", "nat", "bat"], Return: + * + *

[ ["ate", "eat","tea"], ["nat","tan"], ["bat"] ] Note: All inputs will be in lower-case. + */ +public class GroupAnagrams { + private int[] A = new int[256]; + private HashMap> hashMap = new HashMap<>(); + private List> result = new ArrayList<>(); + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + String[] strs = {"huh", "tit"}; + + List> result = new GroupAnagrams().groupAnagrams(strs); + for (List l : result) { + for (String s : l) System.out.println(s); + System.out.println("-----"); + } + } + + public List> groupAnagrams(String[] strs) { + for (int i = 0, l = strs.length; i < l; i++) { + Arrays.fill(A, 0); + String s = strs[i]; + for (int j = 0, sl = s.length(); j < sl; j++) A[s.charAt(j)]++; + + StringBuilder sb = new StringBuilder(); + for (int k = 0; k < 256; k++) { + if (A[k] != 0) sb.append(k).append("").append(A[k]); + } + List value = hashMap.get(sb.toString()); + if (value == null) value = new ArrayList<>(); + value.add(s); + hashMap.put(sb.toString(), value); + } + + for (String s : hashMap.keySet()) result.add(hashMap.get(s)); + + return result; + } +} diff --git a/src/main/java/hashing/GroupsOfSpecialEquivalentStrings.java b/src/main/java/hashing/GroupsOfSpecialEquivalentStrings.java new file mode 100644 index 00000000..958de35f --- /dev/null +++ b/src/main/java/hashing/GroupsOfSpecialEquivalentStrings.java @@ -0,0 +1,73 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 30/04/2019 You are given an array A of strings. + * + *

Two strings S and T are special-equivalent if after any number of moves, S == T. + * + *

A move consists of choosing two indices i and j with i % 2 == j % 2, and swapping S[i] with + * S[j]. + * + *

Now, a group of special-equivalent strings from A is a non-empty subset S of A such that any + * string not in S is not special-equivalent with any string in S. + * + *

Return the number of groups of special-equivalent strings from A. + * + *

Example 1: + * + *

Input: ["a","b","c","a","c","c"] Output: 3 Explanation: 3 groups ["a","a"], ["b"], + * ["c","c","c"] Example 2: + * + *

Input: ["aa","bb","ab","ba"] Output: 4 Explanation: 4 groups ["aa"], ["bb"], ["ab"], ["ba"] + * Example 3: + * + *

Input: ["abc","acb","bac","bca","cab","cba"] Output: 3 Explanation: 3 groups ["abc","cba"], + * ["acb","bca"], ["bac","cab"] Example 4: + * + *

Input: ["abcd","cdab","adcb","cbad"] Output: 1 Explanation: 1 group + * ["abcd","cdab","adcb","cbad"] + * + *

Note: + * + *

1 <= A.length <= 1000 1 <= A[i].length <= 20 All A[i] have the same length. All A[i] consist + * of only lowercase letters. + * + *

Solution: The character array of odd positions and even positions of two special-equivalent + * strings should be exactly equal after sorting. Use a hashset to count number of such groups. + */ +public class GroupsOfSpecialEquivalentStrings { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) {} + + public int numSpecialEquivGroups(String[] A) { + Set set = new HashSet<>(); + for (String s : A) { + StringBuilder temp1 = new StringBuilder(); + for (int i = 0, l = s.length(); i < l; i += 2) { + char c = s.charAt(i); + temp1.append(c); + } + StringBuilder temp2 = new StringBuilder(); + if (s.length() > 1) { + for (int i = 1, l = s.length(); i < l; i += 2) { + char c = s.charAt(i); + temp2.append(c); + } + } + char[] temp1Chars = temp1.toString().toCharArray(); + char[] temp2Chars = temp2.toString().toCharArray(); + Arrays.sort(temp1Chars); + Arrays.sort(temp2Chars); + set.add(String.valueOf(temp1Chars) + "+" + String.valueOf(temp2Chars)); + } + return set.size(); + } +} diff --git a/src/main/java/hashing/KdiffPairsInanArray.java b/src/main/java/hashing/KdiffPairsInanArray.java new file mode 100644 index 00000000..c724a8fe --- /dev/null +++ b/src/main/java/hashing/KdiffPairsInanArray.java @@ -0,0 +1,50 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 28/03/2017. Given an array of integers and an integer k, you + * need to find the number of unique k-diff pairs in the array. Here a k-diff pair is defined as an + * integer pair (i, j), where i and j are both numbers in the array and their absolute difference is + * k. + * + *

Example 1: Input: [3, 1, 4, 1, 5], k = 2 Output: 2 Explanation: There are two 2-diff pairs in + * the array, (1, 3) and (3, 5). Although we have two 1s in the input, we should only return the + * number of unique pairs. Example 2: Input:[1, 2, 3, 4, 5], k = 1 Output: 4 Explanation: There are + * four 1-diff pairs in the array, (1, 2), (2, 3), (3, 4) and (4, 5). Example 3: Input: [1, 3, 1, 5, + * 4], k = 0 Output: 1 Explanation: There is one 0-diff pair in the array, (1, 1). Note: The pairs + * (i, j) and (j, i) count as the same pair. The length of the array won't exceed 10,000. All the + * integers in the given input belong to the range: [-1e7, 1e7]. + */ +public class KdiffPairsInanArray { + private Map map = new HashMap<>(); + private int count = 0; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] nums = {1, 2, 3, 4, 5}; + System.out.println(new KdiffPairsInanArray().findPairs(nums, -1)); + } + + public int findPairs(int[] nums, int k) { + if (nums.length == 0 || k < 0) return 0; + for (int i : nums) { + map.put(i, map.getOrDefault(i, 0) + 1); + } + for (Map.Entry entry : map.entrySet()) { + if (k == 0) { + if (entry.getValue() > 1) count++; + } else { + if (map.containsKey(entry.getKey() + k)) count++; + } + } + return count; + } +} diff --git a/src/main/java/hashing/LargestUniqueNumber.java b/src/main/java/hashing/LargestUniqueNumber.java new file mode 100644 index 00000000..1d2fb3a0 --- /dev/null +++ b/src/main/java/hashing/LargestUniqueNumber.java @@ -0,0 +1,43 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 26/11/2019 Given an array of integers A, return the largest + * integer that only occurs once. + * + *

If no integer occurs once, return -1. + * + *

Example 1: + * + *

Input: [5,7,3,9,4,9,8,3,1] Output: 8 Explanation: The maximum integer in the array is 9 but it + * is repeated. The number 8 occurs only once, so it's the answer. Example 2: + * + *

Input: [9,9,8,8] Output: -1 Explanation: There is no number that occurs only once. + * + *

Note: + * + *

1 <= A.length <= 2000 0 <= A[i] <= 1000 + */ +public class LargestUniqueNumber { + public static void main(String[] args) { + // + } + + public int largestUniqueNumber(int[] A) { + Map map = new HashMap<>(); + for (int i : A) { + map.putIfAbsent(i, 0); + int v = map.get(i) + 1; + map.put(i, v); + } + int max = -1; + for (int k : map.keySet()) { + if (map.get(k) == 1) { + max = Math.max(max, k); + } + } + return max; + } +} diff --git a/src/main/java/hashing/MaximumSizeSubarraySumEqualsk.java b/src/main/java/hashing/MaximumSizeSubarraySumEqualsk.java new file mode 100644 index 00000000..219cd4a8 --- /dev/null +++ b/src/main/java/hashing/MaximumSizeSubarraySumEqualsk.java @@ -0,0 +1,60 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 18/10/2017. Given an array nums and a target value k, find the + * maximum length of a subarray that sums to k. If there isn't one, return 0 instead. + * + *

Note: The sum of the entire nums array is guaranteed to fit within the 32-bit signed integer + * range. + * + *

Example 1: Given nums = [1, -1, 5, -2, 3], k = 3, return 4. (because the subarray [1, -1, 5, + * -2] sums to 3 and is the longest) + * + *

Example 2: Given nums = [-2, -1, 2, 1], k = 1, return 2. (because the subarray [-1, 2] sums to + * 1 and is the longest) + * + *

Follow Up: Can you do it in O(n) time? + */ +public class MaximumSizeSubarraySumEqualsk { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, -1, 5, -2, 3}; + System.out.println(new MaximumSizeSubarraySumEqualsk().maxSubArrayLen(A, 10)); + } + + public int maxSubArrayLen(int[] nums, int k) { + Map index = new HashMap<>(); + int sum = 0; + for (int i = 0; i < nums.length; i++) { + sum += nums[i]; + index.putIfAbsent(sum, i); + } + sum = 0; + int ans = 0; + for (int i = 0; i < nums.length; i++) { + sum += nums[i]; + if (sum == k) { + ans = Math.max(ans, i + 1); + } else { + int exp = sum - k; + if (index.containsKey(exp)) { + int farLeft = index.get(exp); + if (farLeft < i) { + ans = Math.max(ans, i - index.get(exp)); + } + } + } + } + return ans; + } +} diff --git a/src/main/java/hashing/NumberOfAtoms.java b/src/main/java/hashing/NumberOfAtoms.java new file mode 100644 index 00000000..0fbdccbe --- /dev/null +++ b/src/main/java/hashing/NumberOfAtoms.java @@ -0,0 +1,149 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 06/08/2019 Given a chemical formula (given as a string), return + * the count of each atom. + * + *

An atomic element always starts with an uppercase character, then zero or more lowercase + * letters, representing the name. + * + *

1 or more digits representing the count of that element may follow if the count is greater + * than 1. If the count is 1, no digits will follow. For example, H2O and H2O2 are possible, but + * H1O2 is impossible. + * + *

Two formulas concatenated together produce another formula. For example, H2O2He3Mg4 is also a + * formula. + * + *

A formula placed in parentheses, and a count (optionally added) is also a formula. For + * example, (H2O2) and (H2O2)3 are formulas. + * + *

Given a formula, output the count of all elements as a string in the following form: the first + * name (in sorted order), followed by its count (if that count is more than 1), followed by the + * second name (in sorted order), followed by its count (if that count is more than 1), and so on. + * + *

Example 1: Input: formula = "H2O" Output: "H2O" Explanation: The count of elements are {'H': + * 2, 'O': 1}. Example 2: Input: formula = "Mg(OH)2" Output: "H2MgO2" Explanation: The count of + * elements are {'H': 2, 'Mg': 1, 'O': 2}. Example 3: Input: formula = "K4(ON(SO3)2)2" Output: + * "K4N2O14S4" Explanation: The count of elements are {'K': 4, 'N': 2, 'O': 14, 'S': 4}. Note: + * + *

All atom names consist of lowercase letters, except for the first character which is + * uppercase. The length of formula will be in the range [1, 1000]. formula will only consist of + * letters, digits, and round parentheses, and is a valid formula as defined in the problem. + * + *

Solution O(N ^ 2) Recursively solve each substring within round braces as subformula. Consider + * each subformula as right subformula and each each subformula before the round braces as left + * subformula - sum up value of both left and right subformula to get the answer. + */ +public class NumberOfAtoms { + public static void main(String[] args) { + String result = new NumberOfAtoms().countOfAtoms("K4(((K4)K4)2)2"); + System.out.println(result); + } + + public String countOfAtoms(String formula) { + Map atomCountResult = new NumberOfAtoms().countOfAtoms(formula, 0); + List sortedKeys = new ArrayList<>(atomCountResult.keySet()); + sortedKeys.sort(Comparator.naturalOrder()); + StringBuilder result = new StringBuilder(); + for (String k : sortedKeys) { + int count = atomCountResult.get(k); + if (count > 1) { + result.append(k).append(count); + } else result.append(k); + } + return result.toString(); + } + + private Map countOfAtoms(String formula, int startPos) { + Map left = new HashMap<>(); + StringBuilder atom = new StringBuilder(); + StringBuilder atomCount = new StringBuilder(); + for (int i = startPos; i < formula.length(); ) { + char c = formula.charAt(i); + if (c >= 'A' && c <= 'Z') { + if (atom.length() > 0) { + int count = 1; + if (atomCount.length() > 0) { + count = Integer.parseInt(atomCount.toString()); + } + String atomKey = atom.toString(); + if (left.containsKey(atomKey)) { + left.put(atomKey, left.get(atomKey) + count); + } else left.put(atom.toString(), count); + atom = new StringBuilder(); + atomCount = new StringBuilder(); + } + atom.append(c); + i++; + } else if (c >= 'a' && c <= 'z') { + atom.append(c); + i++; + } else if (c >= '0' && c <= '9') { + atomCount.append(c); + i++; + } else { + // this is equal to '(' + if (atom.length() > 0) { + int count = 1; + if (atomCount.length() > 0) { + count = Integer.parseInt(atomCount.toString()); + } + String atomKey = atom.toString(); + if (left.containsKey(atomKey)) { + left.put(atomKey, left.get(atomKey) + count); + } else left.put(atom.toString(), count); + atom = new StringBuilder(); + atomCount = new StringBuilder(); + } + int j = i, count = 0; + for (int l = formula.length(); j < l; j++) { + if (formula.charAt(j) == '(') { + count++; + } else if (formula.charAt(j) == ')') { + count--; + } + if (count == 0) break; + } + Map right = countOfAtoms(formula.substring(i + 1, j), 0); + j++; + StringBuilder rightAtomCount = new StringBuilder(); + for (int l = formula.length(); j < l; j++) { + if (formula.charAt(j) >= '0' && formula.charAt(j) <= '9') { + rightAtomCount.append(formula.charAt(j)); + } else break; + } + if (rightAtomCount.length() > 0) { + int mulFactor = Integer.parseInt(rightAtomCount.toString()); + for (String k : right.keySet()) { + right.put(k, right.get(k) * mulFactor); + } + } + left = merge(left, right); + i = j; + } + } + if (atom.length() > 0) { + int count = 1; + if (atomCount.length() > 0) { + count = Integer.parseInt(atomCount.toString()); + } + String atomKey = atom.toString(); + if (left.containsKey(atomKey)) { + left.put(atomKey, left.get(atomKey) + count); + } else left.put(atom.toString(), count); + } + return left; + } + + private Map merge(Map left, Map right) { + for (String k : left.keySet()) { + if (right.containsKey(k)) { + right.put(k, right.get(k) + left.get(k)); + } else right.put(k, left.get(k)); + } + return right; + } +} diff --git a/src/main/java/hashing/PartitionLabels.java b/src/main/java/hashing/PartitionLabels.java new file mode 100644 index 00000000..6b5bc435 --- /dev/null +++ b/src/main/java/hashing/PartitionLabels.java @@ -0,0 +1,60 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 10/04/2018. A string S of lowercase letters is given. We want + * to partition this string into as many parts as possible so that each letter appears in at most + * one part, and return a list of integers representing the size of these parts. + * + *

Example 1: Input: S = "ababcbacadefegdehijhklij" Output: [9,7,8] Explanation: The partition is + * "ababcbaca", "defegde", "hijhklij". This is a partition so that each letter appears in at most + * one part. A partition like "ababcbacadefegde", "hijhklij" is incorrect, because it splits S into + * less parts. Note: + * + *

S will have length in range [1, 500]. S will consist of lowercase letters ('a' to 'z') only. + * + *

Solution O(n): Maintain a hashmap index of last occurrence of a character and do a linear + * check for max index, get the length and add it to the result set. + */ +public class PartitionLabels { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new PartitionLabels().partitionLabels("abc")); + } + + public List partitionLabels(String S) { + if (S == null || S.trim().isEmpty()) return new ArrayList<>(); + Map map = new HashMap<>(); + for (int i = S.length() - 1; i >= 0; i--) { + char c = S.charAt(i); + map.putIfAbsent(c, i); + } + List result = new ArrayList<>(); + int start = 0; + int max = map.get(S.charAt(0)); + for (int i = 0; i < S.length(); i++) { + char c = S.charAt(i); + if (map.get(c) > max) { + max = map.get(c); + } else if (i == max) { + result.add(max - start + 1); + if (i < S.length() - 1) { + start = i + 1; + max = map.get(S.charAt(i + 1)); + } + } + } + return result; + } +} diff --git a/src/main/java/hashing/ShortEncodingOfWords.java b/src/main/java/hashing/ShortEncodingOfWords.java new file mode 100644 index 00000000..ada03526 --- /dev/null +++ b/src/main/java/hashing/ShortEncodingOfWords.java @@ -0,0 +1,63 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 04/05/2018. Given a list of words, we may encode it by writing + * a reference string S and a list of indexes A. + * + *

For example, if the list of words is ["time", "me", "bell"], we can write it as S = + * "time#bell#" and indexes = [0, 2, 5]. + * + *

Then for each index, we will recover the word by reading from the reference string from that + * index until we reach a "#" character. + * + *

What is the length of the shortest reference string S possible that encodes the given words? + * + *

Example: + * + *

Input: words = ["time", "me", "bell"] Output: 10 Explanation: S = "time#bell#" and indexes = + * [0, 2, 5]. Note: + * + *

1 <= words.length <= 2000. 1 <= words[i].length <= 7. Each word has only lowercase letters. + * + *

Solution: Sort the words by length and then use a hashmap to map each substring of a string + * with its position. + */ +public class ShortEncodingOfWords { + class Node { + String s; + int l; + + Node(String s, int l) { + this.s = s; + this.l = l; + } + } + + public static void main(String[] args) { + String[] A = {"memo", "me", "mo"}; + System.out.println(new ShortEncodingOfWords().minimumLengthEncoding(A)); + } + + public int minimumLengthEncoding(String[] words) { + List list = new ArrayList<>(); + for (String w : words) { + list.add(new Node(w, w.length())); + } + Collections.sort(list, (o1, o2) -> Integer.compare(o2.l, o1.l)); + Map map = new HashMap<>(); + int count = 0; + for (Node node : list) { + String str = node.s; + if (!map.containsKey(str)) { + for (int i = 0, l = str.length(); i < l; i++) { + map.put(str.substring(i, l), count + i); + } + count += (str.length() + 1); + } + } + return count; + } +} diff --git a/src/main/java/hashing/SortCharByFrequency.java b/src/main/java/hashing/SortCharByFrequency.java new file mode 100644 index 00000000..1f1aec8a --- /dev/null +++ b/src/main/java/hashing/SortCharByFrequency.java @@ -0,0 +1,81 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 25/03/2017. Given a string, sort it in decreasing order based + * on the frequency of characters. + * + *

Example 1: + * + *

Input: "tree" + * + *

Output: "eert" + * + *

Explanation: 'e' appears twice while 'r' and 't' both appear once. So 'e' must appear before + * both 'r' and 't'. Therefore "eetr" is also a valid answer. Example 2: + * + *

Input: "cccaaa" + * + *

Output: "cccaaa" + * + *

Explanation: Both 'c' and 'a' appear three times, so "aaaccc" is also a valid answer. Note + * that "cacaca" is incorrect, as the same characters must be together. + * + *

Example 3: + * + *

Input: "Aabb" + * + *

Output: "bbAa" + * + *

Explanation: "bbaA" is also a valid answer, but "Aabb" is incorrect. Note that 'A' and 'a' are + * treated as two different characters. + */ +public class SortCharByFrequency { + class Freq { + int i; + int c; + } + + private int[] buff = new int[256]; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new SortCharByFrequency().frequencySort("askdfkasdkfasdkljfklasdjfkl")); + } + + public String frequencySort(String s) { + if (s == null || s.isEmpty()) return s; + Arrays.fill(buff, 0); + StringBuilder sb = new StringBuilder(); + for (int i = 0, l = s.length(); i < l; i++) buff[s.charAt(i)]++; + + List fList = new ArrayList<>(); + for (int i = 0; i < 256; i++) { + if (buff[i] > 0) { + Freq f = new Freq(); + f.i = i; + f.c = buff[i]; + fList.add(f); + } + } + + Collections.sort(fList, (o1, o2) -> Integer.compare(o2.c, o1.c)); + + for (Freq f : fList) { + char c = (char) f.i; + int freq = f.c; + while (freq-- > 0) sb.append(c); + } + return sb.toString(); + } +} diff --git a/src/main/java/hashing/StringTransformsIntoAnotherString.java b/src/main/java/hashing/StringTransformsIntoAnotherString.java new file mode 100644 index 00000000..20932803 --- /dev/null +++ b/src/main/java/hashing/StringTransformsIntoAnotherString.java @@ -0,0 +1,52 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 23/10/2019 Given two strings str1 and str2 of the same length, + * determine whether you can transform str1 into str2 by doing zero or more conversions. + * + *

In one conversion you can convert all occurrences of one character in str1 to any other + * lowercase English character. + * + *

Return true if and only if you can transform str1 into str2. + * + *

Example 1: + * + *

Input: str1 = "aabcc", str2 = "ccdee" Output: true Explanation: Convert 'c' to 'e' then 'b' to + * 'd' then 'a' to 'c'. Note that the order of conversions matter. Example 2: + * + *

Input: str1 = "leetcode", str2 = "codeleet" Output: false Explanation: There is no way to + * transform str1 to str2. + * + *

Note: + * + *

1 <= str1.length == str2.length <= 10^4 Both str1 and str2 contain only lowercase English + * letters. + */ +public class StringTransformsIntoAnotherString { + public static void main(String[] args) { + System.out.println(new StringTransformsIntoAnotherString().canConvert("ab", "ba")); + } + + public boolean canConvert(String str1, String str2) { + if (str1.length() != str2.length()) return false; + if (str1.equals(str2)) return true; + Map mapping = new HashMap<>(); + for (int i = 0; i < str1.length(); i++) { + char c1 = str1.charAt(i); + char c2 = str2.charAt(i); + if (mapping.containsKey(c1)) { + if (mapping.get(c1) != c2) return false; + } else { + mapping.put(c1, c2); + } + } + Set set = new HashSet<>(); + for (char k : mapping.keySet()) { + set.add(mapping.get(k)); + } + return (set.size() < 26); + } +} diff --git a/src/main/java/hashing/SubstringConcatenationOfWords.java b/src/main/java/hashing/SubstringConcatenationOfWords.java new file mode 100644 index 00000000..73eceaf0 --- /dev/null +++ b/src/main/java/hashing/SubstringConcatenationOfWords.java @@ -0,0 +1,73 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 02/03/2019 You are given a string, s, and a list of words, + * words, that are all of the same length. Find all starting indices of substring(s) in s that is a + * concatenation of each word in words exactly once and without any intervening characters. + * + *

Example 1: + * + *

Input: s = "barfoothefoobarman", words = ["foo","bar"] Output: [0,9] Explanation: Substrings + * starting at index 0 and 9 are "barfoor" and "foobar" respectively. The output order does not + * matter, returning [9,0] is fine too. Example 2: + * + *

Input: s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"] Output: [] + * + *

Solution: General idea is to do the following 1. Calculate the word count for the given array + * of words and store this in a HashMap. 2. For every substring (substring of s) of length + * (words[0].length() * words.length) split this into words of length words[0].length and calculate + * the word frequency for the split words. If the word frequency matches the word frequency of the + * given original word list then add the starting index of this substring into the result array. + * + *

A small optimization is to break the substring match as soon as you find out that the word + * formed from the substring is not part of the original given word list or if the frequency of the + * word exceeds the frequency of the original word count. + */ +public class SubstringConcatenationOfWords { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + String[] words = {"word", "good", "best", "word"}; + System.out.println( + new SubstringConcatenationOfWords().findSubstring("wordgoodgoodgoodbestword", words)); + } + + public List findSubstring(String s, String[] words) { + if (words.length == 0) return new ArrayList<>(); + int wLen = words[0].length(); + int sLen = wLen * words.length; + List result = new ArrayList<>(); + if (sLen > s.length()) return result; + Map countMap = new HashMap<>(); + for (String w : words) { + countMap.putIfAbsent(w, 0); + countMap.put(w, countMap.get(w) + 1); + } + for (int k = 0; (s.length() - k) >= sLen; k++) { + Map subSMap = new HashMap<>(); + int i = k; + for (int j = i + wLen; (i - k) < sLen; i = j, j += wLen) { + String subS = s.substring(i, j); + subSMap.putIfAbsent(subS, 0); + subSMap.put(subS, subSMap.get(subS) + 1); + if (!countMap.containsKey(subS) || subSMap.get(subS) > countMap.get(subS)) { + break; + } + } + if ((i - k) >= sLen) { + result.add(k); + } + } + return result; + } +} diff --git a/src/main/java/hashing/TwoSum.java b/src/main/java/hashing/TwoSum.java new file mode 100644 index 00000000..0c321989 --- /dev/null +++ b/src/main/java/hashing/TwoSum.java @@ -0,0 +1,59 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +import java.util.HashMap; + +/** + * Created by gouthamvidyapradhan on 09/03/2017. Given an array of integers, return indices of the + * two numbers such that they add up to a specific target. + * + *

You may assume that each input would have exactly one solution, and you may not use the same + * element twice. + * + *

Example: Given nums = [2, 7, 11, 15], target = 9, + * + *

Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1]. + */ +public class TwoSum { + HashMap map = new HashMap<>(); + + public int[] twoSum(int[] nums, int target) { + int[] result = new int[2]; + + for (int i : nums) { + if (map.keySet().contains(i)) { + int count = map.get(i); + map.put(i, ++count); + } else { + map.put(i, 1); + } + } + + for (int i = 0, l = nums.length; i < l; i++) { + int ele = nums[i]; + int req = target - ele; + if (map.keySet().contains(req)) { + result[0] = i; + if (ele == req) { + int count = map.get(req); + if (count > 1) { + for (int j = i + 1; j < l; j++) { + if (nums[j] == req) { + result[1] = j; + return result; + } + } + } + } else { + for (int j = i + 1; j < l; j++) { + if (nums[j] == req) { + result[1] = j; + return result; + } + } + } + } + } + return result; + } +} diff --git a/src/main/java/hashing/ValidAnagram.java b/src/main/java/hashing/ValidAnagram.java new file mode 100644 index 00000000..97b51a97 --- /dev/null +++ b/src/main/java/hashing/ValidAnagram.java @@ -0,0 +1,46 @@ +/* (C) 2024 YourCompanyName */ +package hashing; + +/** + * Created by gouthamvidyapradhan on 10/03/2017. Given two strings s and t, write a function to + * determine if t is an anagram of s. + * + *

For example, s = "anagram", t = "nagaram", return true. s = "rat", t = "car", return false. + * + *

Note: You may assume the string contains only lowercase alphabets. + * + *

Follow up: What if the inputs contain unicode characters? How would you adapt your solution to + * such case? + */ +public class ValidAnagram { + private int[] S = new int[256]; + private int[] T = new int[256]; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new ValidAnagram().isAnagram("anagram", "nagaram")); + } + + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) return false; + + for (int i = 0, l = s.length(); i < l; i++) { + S[s.charAt(i)]++; + } + + for (int i = 0, l = t.length(); i < l; i++) { + T[t.charAt(i)]++; + } + + for (int i = 0; i < 256; i++) { + if (S[i] != T[i]) return false; + } + + return true; + } +} diff --git a/src/main/java/heap/Candy.java b/src/main/java/heap/Candy.java new file mode 100644 index 00000000..0f1b657c --- /dev/null +++ b/src/main/java/heap/Candy.java @@ -0,0 +1,92 @@ +/* (C) 2024 YourCompanyName */ +package heap; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 26/07/2018. There are N children standing in a line. Each child + * is assigned a rating value. + * + *

You are giving candies to these children subjected to the following requirements: + * + *

Each child must have at least one candy. Children with a higher rating get more candies than + * their neighbors. What is the minimum candies you must give? + * + *

Example 1: + * + *

Input: [1,0,2] Output: 5 Explanation: You can allocate to the first, second and third child + * with 2, 1, 2 candies respectively. Example 2: + * + *

Input: [1,2,2] Output: 4 Explanation: You can allocate to the first, second and third child + * with 1, 2, 1 candies respectively. The third child gets 1 candy because it satisfies the above + * two conditions. + * + *

Solution: O(N log N): Store the indexes in a heap, iterate through the heap one by one and + * assign candies one greater than its neighbours. Take care of edge cases. + */ +public class Candy { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] ratings = {29, 51, 87, 87, 72, 12}; + System.out.println(new Candy().candy(ratings)); + } + + public int candy(int[] ratings) { + if (ratings.length == 1) return 1; + PriorityQueue pq = + new PriorityQueue<>((o1, o2) -> Integer.compare(ratings[o1], ratings[o2])); + for (int i = 0; i < ratings.length; i++) { + pq.offer(i); + } + int[] count = new int[ratings.length]; + while (!pq.isEmpty()) { + int index = pq.poll(); + if (index - 1 < 0) { + if (ratings[index + 1] == ratings[index]) { + count[index] = 1; + } else { + count[index] = count[index + 1] + 1; + } + } else if (index + 1 >= ratings.length) { + if (ratings[index - 1] == ratings[index]) { + count[index] = 1; + } else { + count[index] = count[index - 1] + 1; + } + } else { + if ((ratings[index - 1] == ratings[index]) && (ratings[index + 1] == ratings[index])) { + count[index] = 1; + } else { + if (((ratings[index - 1] == ratings[index]) && (ratings[index + 1] > ratings[index])) + || ((ratings[index + 1] == ratings[index]) + && (ratings[index - 1] > ratings[index]))) { + count[index] = 1; + } else if (((ratings[index - 1] == ratings[index]) + && (ratings[index + 1] < ratings[index]))) { + count[index] = count[index + 1] + 1; + } else if (((ratings[index + 1] == ratings[index]) + && (ratings[index - 1] < ratings[index]))) { + count[index] = count[index - 1] + 1; + } else { + if (count[index - 1] > count[index + 1]) { + count[index] = count[index - 1] + 1; + } else { + count[index] = count[index + 1] + 1; + } + } + } + } + } + int result = 0; + for (int c : count) { + result += c; + } + return result; + } +} diff --git a/src/main/java/heap/DistantBarcodes.java b/src/main/java/heap/DistantBarcodes.java new file mode 100644 index 00000000..54ce859b --- /dev/null +++ b/src/main/java/heap/DistantBarcodes.java @@ -0,0 +1,81 @@ +/* (C) 2024 YourCompanyName */ +package heap; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 04/12/2019 In a warehouse, there is a row of barcodes, where + * the i-th barcode is barcodes[i]. + * + *

Rearrange the barcodes so that no two adjacent barcodes are equal. You may return any answer, + * and it is guaranteed an answer exists. + * + *

Example 1: + * + *

Input: [1,1,1,2,2,2] Output: [2,1,2,1,2,1] Example 2: + * + *

Input: [1,1,1,1,2,2,3,3] Output: [1,3,1,3,2,1,2,1] + * + *

Note: + * + *

1 <= barcodes.length <= 10000 1 <= barcodes[i] <= 10000 + */ +public class DistantBarcodes { + public static void main(String[] args) { + int[] barcode = {1, 1, 1, 2, 2, 2}; + int[] result = new DistantBarcodes().rearrangeBarcodes(barcode); + for (int i : result) { + System.out.print(i + " "); + } + System.out.println(); + } + + class Node { + int value, count, rank; + + Node(int value, int count, int rank) { + this.value = value; + this.count = count; + this.rank = rank; + } + } + + public int[] rearrangeBarcodes(int[] barcodes) { + PriorityQueue pq = + new PriorityQueue<>( + (o1, o2) -> { + int r = Integer.compare(o2.count, o1.count); + return r == 0 ? Integer.compare(o1.rank, o2.rank) : r; + }); + Map map = new HashMap<>(); + for (int b : barcodes) { + map.putIfAbsent(b, 0); + map.put(b, map.get(b) + 1); + } + for (int k : map.keySet()) { + pq.offer(new Node(k, map.get(k), -1)); + } + int[] result = new int[barcodes.length]; + int i = 0; + int rank = 0; + while (!pq.isEmpty()) { + Node node = pq.poll(); + result[i++] = node.value; + node.count -= 1; + node.rank = rank++; + if (!pq.isEmpty()) { + Node next = pq.poll(); + result[i++] = next.value; + next.count -= 1; + next.rank = rank++; + if (next.count > 0) { + pq.offer(next); + } + } + if (node.count > 0) { + pq.offer(node); + } + } + return result; + } +} diff --git a/src/main/java/heap/FreqStack.java b/src/main/java/heap/FreqStack.java new file mode 100644 index 00000000..78ca3dce --- /dev/null +++ b/src/main/java/heap/FreqStack.java @@ -0,0 +1,164 @@ +/* (C) 2024 YourCompanyName */ +package heap; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 30/04/2019 Implement FreqStack, a class which simulates the + * operation of a stack-like data structure. + * + *

FreqStack has two functions: + * + *

push(int x), which pushes an integer x onto the stack. pop(), which removes and returns the + * most frequent element in the stack. If there is a tie for most frequent element, the element + * closest to the top of the stack is removed and returned. + * + *

Example 1: + * + *

Input: ["FreqStack","push","push","push","push","push","push","pop","pop","pop","pop"], + * [[],[5],[7],[5],[7],[4],[5],[],[],[],[]] Output: [null,null,null,null,null,null,null,5,7,5,4] + * Explanation: After making six .push operations, the stack is [5,7,5,7,4,5] from bottom to top. + * Then: + * + *

pop() -> returns 5, as 5 is the most frequent. The stack becomes [5,7,5,7,4]. + * + *

pop() -> returns 7, as 5 and 7 is the most frequent, but 7 is closest to the top. The stack + * becomes [5,7,5,4]. + * + *

pop() -> returns 5. The stack becomes [5,7,4]. + * + *

pop() -> returns 4. The stack becomes [5,7]. + * + *

Note: + * + *

Calls to FreqStack.push(int x) will be such that 0 <= x <= 10^9. It is guaranteed that + * FreqStack.pop() won't be called if the stack has zero elements. The total number of + * FreqStack.push calls will not exceed 10000 in a single test case. The total number of + * FreqStack.pop calls will not exceed 10000 in a single test case. The total number of + * FreqStack.push and FreqStack.pop calls will not exceed 150000 across all test cases. + * + *

Solution: push O(log N) pop O(log N) Maintain a priority queue with a FreqNode where each + * FreqNode contains a frequency and a stack with (value and pushCount). Each stack in a priority + * queue contains same set of values. Every time when a value is to be added to the stack a new Node + * is created and pushed to stack which contains the push value and pushCount. + * + *

Example: For the below push operation push 5, push 5, push 5, push 6, push 6, push 7 the state + * of priority stack will be 3 : 5(0) -> 5(1) -> 5(2) 2 : 6(3) -> 6(4) 1 : 7(5) + * + *

When a push operation is invoked we have to identify in which stack the value has to go in + * therefore maintain a hashmap with push-value as key and value contains the reference to FreqNode + * in priority queue. Remove this FreqNode from priority queue and update the stack. + * + *

When a pop operation is invoked remove the FreqNode from the top of the priority queue and pop + * the value from top of its stack. + */ +public class FreqStack { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + FreqStack freqStack = new FreqStack(); + freqStack.push(5); + freqStack.push(5); + freqStack.push(5); + freqStack.push(5); + freqStack.push(6); + System.out.println(freqStack.pop()); + freqStack.push(7); + System.out.println(freqStack.pop()); + System.out.println(freqStack.pop()); + freqStack.push(1); + freqStack.push(2); + System.out.println(freqStack.pop()); + System.out.println(freqStack.pop()); + System.out.println(freqStack.pop()); + System.out.println(freqStack.pop()); + System.out.println(freqStack.pop()); + } + + class Node { + int val, pos; + + Node(int val, int pushCount) { + this.val = val; + this.pos = pushCount; + } + } + + class FreqNode { + int freq; + Stack stack; + + FreqNode(int freq, Stack stack) { + this.freq = freq; + this.stack = stack; + } + + public int getFreq() { + return freq; + } + + public int getTop() { + return !stack.isEmpty() ? stack.peek().pos : -1; + } + + public void push(Node e) { + freq++; + stack.push(e); + } + + public Node pop() { + freq--; + return stack.pop(); + } + } + + private PriorityQueue priorityQueue; + private Map map; + private int pushCount; + + public FreqStack() { + priorityQueue = + new PriorityQueue<>( + (o1, o2) -> { + if (o1.freq == o2.freq) { + return Integer.compare(o2.getTop(), o1.getTop()); + } else { + return Integer.compare(o2.freq, o1.freq); + } + }); + map = new HashMap<>(); + pushCount = 0; + } + + public void push(int x) { + pushCount++; + Node node = new Node(x, pushCount); + FreqNode freqNode; + if (map.containsKey(x)) { + freqNode = map.get(x); + priorityQueue.remove(freqNode); + freqNode.push(node); + } else { + Stack stack = new Stack<>(); + stack.push(node); + freqNode = new FreqNode(1, stack); + map.put(x, freqNode); + } + priorityQueue.offer(freqNode); + } + + public int pop() { + FreqNode freqNode = priorityQueue.poll(); + Node topNode = freqNode.pop(); + if (freqNode.freq == 0) { + map.remove(topNode.val); + } else { + priorityQueue.offer(freqNode); + } + return topNode.val; + } +} diff --git a/src/main/java/heap/KClosestPointsToOrigin.java b/src/main/java/heap/KClosestPointsToOrigin.java new file mode 100644 index 00000000..d15fe579 --- /dev/null +++ b/src/main/java/heap/KClosestPointsToOrigin.java @@ -0,0 +1,67 @@ +/* (C) 2024 YourCompanyName */ +package heap; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 30/11/2019 We have a list of points on the plane. Find the K + * closest points to the origin (0, 0). + * + *

(Here, the distance between two points on a plane is the Euclidean distance.) + * + *

You may return the answer in any order. The answer is guaranteed to be unique (except for the + * order that it is in.) + * + *

Example 1: + * + *

Input: points = [[1,3],[-2,2]], K = 1 Output: [[-2,2]] Explanation: The distance between (1, + * 3) and the origin is sqrt(10). The distance between (-2, 2) and the origin is sqrt(8). Since + * sqrt(8) < sqrt(10), (-2, 2) is closer to the origin. We only want the closest K = 1 points from + * the origin, so the answer is just [[-2,2]]. Example 2: + * + *

Input: points = [[3,3],[5,-1],[-2,4]], K = 2 Output: [[3,3],[-2,4]] (The answer [[-2,4],[3,3]] + * would also be accepted.) + * + *

Note: + * + *

1 <= K <= points.length <= 10000 -10000 < points[i][0] < 10000 -10000 < points[i][1] < 10000 + */ +public class KClosestPointsToOrigin { + public static void main(String[] args) { + int[][] A = {{3, 3}, {5, -1}, {-2, 4}}; + int[][] ans = new KClosestPointsToOrigin().kClosest(A, 2); + System.out.println(); + } + + class Point { + int a, b; + + Point(int a, int b) { + this.a = a; + this.b = b; + } + + public long distance() { + return (long) (a * a) + (long) (b * b); + } + } + + public int[][] kClosest(int[][] points, int K) { + PriorityQueue pq = + new PriorityQueue<>((o1, o2) -> Long.compare(o2.distance(), o1.distance())); + for (int[] p : points) { + pq.offer(new Point(p[0], p[1])); + if (pq.size() > K) { + pq.poll(); + } + } + int[][] ans = new int[K][2]; + int i = 0; + while (!pq.isEmpty()) { + Point point = pq.poll(); + ans[i][0] = point.a; + ans[i++][1] = point.b; + } + return ans; + } +} diff --git a/src/main/java/heap/MeetingRoomsII.java b/src/main/java/heap/MeetingRoomsII.java new file mode 100644 index 00000000..33131b41 --- /dev/null +++ b/src/main/java/heap/MeetingRoomsII.java @@ -0,0 +1,65 @@ +/* (C) 2024 YourCompanyName */ +package heap; + +import java.util.Arrays; +import java.util.PriorityQueue; + +/** + * Created by gouthamvidyapradhan on 27/11/2017. Given an array of meeting time intervals consisting + * of start and end times [[s1,e1],[s2,e2],...] (si < ei), find the minimum number of conference + * rooms required. + * + *

For example, Given [[0, 30],[5, 10],[15, 20]], return 2. + * + *

Solution: Sort the array based on start-time of the interval. Then, use the min-heap based on + * min end time. For every interval remove the top element of the priority queue if the end time of + * the top <= start time of the new interval. Add the new interval to the queue. The max size of the + * priority queue attained during this process will be the answer. + */ +public class MeetingRoomsII { + + public static class Interval { + int start; + int end; + + Interval() { + start = 0; + end = 0; + } + + Interval(int s, int e) { + start = s; + end = e; + } + } + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + Interval i1 = new Interval(0, 40); + Interval i2 = new Interval(2, 10); + Interval i3 = new Interval(10, 40); + Interval i4 = new Interval(15, 20); + Interval i5 = new Interval(20, 30); + Interval i6 = new Interval(20, 40); + Interval i7 = new Interval(1, 5); + Interval[] intervals = {i1, i2, i3, i4, i5, i6, i7}; + System.out.println(minMeetingRooms(intervals)); + } + + public static int minMeetingRooms(Interval[] intervals) { + Arrays.sort(intervals, (a, b) -> Integer.compare(a.start, b.start)); + PriorityQueue queue = new PriorityQueue<>((a, b) -> Integer.compare(a.end, b.end)); + int max = 0; + for (Interval i : intervals) { + while (!queue.isEmpty() && queue.peek().end <= i.start) { + queue.poll(); + } + queue.offer(i); + max = Math.max(max, queue.size()); + } + return max; + } +} diff --git a/src/main/java/heap/ReachableNodesInSubdividedGraph.java b/src/main/java/heap/ReachableNodesInSubdividedGraph.java new file mode 100644 index 00000000..00c85813 --- /dev/null +++ b/src/main/java/heap/ReachableNodesInSubdividedGraph.java @@ -0,0 +1,118 @@ +/* (C) 2024 YourCompanyName */ +package heap; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 07/05/2019 Starting with an undirected graph (the "original + * graph") with nodes from 0 to N-1, subdivisions are made to some of the edges. + * + *

The graph is given as follows: edges[k] is a list of integer pairs (i, j, n) such that (i, j) + * is an edge of the original graph, + * + *

and n is the total number of new nodes on that edge. + * + *

Then, the edge (i, j) is deleted from the original graph, n new nodes (x_1, x_2, ..., x_n) are + * added to the original graph, + * + *

and n+1 new edges (i, x_1), (x_1, x_2), (x_2, x_3), ..., (x_{n-1}, x_n), (x_n, j) are added to + * the original graph. + * + *

Now, you start at node 0 from the original graph, and in each move, you travel along one edge. + * + *

Return how many nodes you can reach in at most M moves. + * + *

Example 1: + * + *

Input: edges = [[0,1,10],[0,2,1],[1,2,2]], M = 6, N = 3 Output: 13 Explanation: The nodes that + * are reachable in the final graph after M = 6 moves are indicated below. + * + *

Example 2: + * + *

Input: edges = [[0,1,4],[1,2,6],[0,2,8],[1,3,1]], M = 10, N = 4 Output: 23 + * + *

Note: + * + *

0 <= edges.length <= 10000 0 <= edges[i][0] < edges[i][1] < N There does not exist any i != j + * for which edges[i][0] == edges[j][0] and edges[i][1] == edges[j][1]. The original graph has no + * parallel edges. 0 <= edges[i][2] <= 10000 0 <= M <= 10^9 1 <= N <= 3000 A reachable node is a + * node that can be travelled to using at most M moves starting from node 0. + * + *

Solution: O(E log N) E is the length of edges and N is the number of nodes. The n nodes on a + * edge form a weight and thus the graph becomes a weighted graph. Keep track of number of moves + * available and run a Dijkstra's algorithm. + */ +public class ReachableNodesInSubdividedGraph { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[][] edges = {{0, 1, 1000}, {0, 2, 1}, {1, 2, 1}}; + System.out.println(new ReachableNodesInSubdividedGraph().reachableNodes(edges, 200, 3)); + } + + static class Node { + int n, w; + + Node(int n, int w) { + this.n = n; + this.w = w; + } + } + + public int reachableNodes(int[][] edges, int M, int N) { + Map> graph = new HashMap<>(); + for (int[] e : edges) { + graph.putIfAbsent(e[0], new ArrayList<>()); + graph.get(e[0]).add(new Node(e[1], e[2] + 1)); + + graph.putIfAbsent(e[1], new ArrayList<>()); + graph.get(e[1]).add(new Node(e[0], e[2] + 1)); + } + + PriorityQueue pq = new PriorityQueue<>(Comparator.comparingInt(o -> o.w)); + Map distance = new HashMap<>(); + int count = 0; + pq.offer(new Node(0, 0)); + while (!pq.isEmpty()) { + Node curr = pq.poll(); + if (!distance.containsKey(curr.n)) { + count += 1; + distance.put(curr.n, curr.w); + List children = graph.get(curr.n); + if (children != null) { + for (Node c : children) { + if (!distance.containsKey(c.n)) { + int availableMoves = M - curr.w; + int nodesInBetween = c.w - 1; + if (nodesInBetween >= availableMoves) { + count += availableMoves; + } else { + count += nodesInBetween; + if (availableMoves >= c.w) { + Node child = new Node(c.n, distance.get(curr.n) + c.w); + pq.offer(child); + } + } + } else { + int childAvailableMoves = M - distance.get(c.n); + int nodesInBetween = c.w - 1; + int unvisitedNodes = nodesInBetween - childAvailableMoves; + if (unvisitedNodes > 0) { + int availableMovesForCurr = M - distance.get(curr.n); + count += + (unvisitedNodes >= availableMovesForCurr + ? availableMovesForCurr + : unvisitedNodes); + } + } + } + } + } + } + return count; + } +} diff --git a/src/main/java/heap/SlidingWindowMaximum.java b/src/main/java/heap/SlidingWindowMaximum.java new file mode 100644 index 00000000..138f78fe --- /dev/null +++ b/src/main/java/heap/SlidingWindowMaximum.java @@ -0,0 +1,59 @@ +/* (C) 2024 YourCompanyName */ +package heap; + +import java.util.ArrayDeque; +import java.util.Deque; + +/** + * Created by gouthamvidyapradhan on 10/03/2017. Given an array nums, there is a sliding window of + * size k which is moving from the very left of the array to the very right. You can only see the k + * numbers in the window. Each time the sliding window moves right by one position. + * + *

For example, Given nums = [1,3,-1,-3,5,3,6,7], and k = 3. + * + *

Window position Max --------------- ----- [1 3 -1] -3 5 3 6 7 3 1 [3 -1 -3] 5 3 6 7 3 1 3 [-1 + * -3 5] 3 6 7 5 1 3 -1 [-3 5 3] 6 7 5 1 3 -1 -3 [5 3 6] 7 6 1 3 -1 -3 5 [3 6 7] 7 Therefore, return + * the max sliding window as [3,3,5,5,6,7]. + * + *

Note: You may assume k is always valid, ie: 1 ≤ k ≤ input array's size for non-empty array. + */ +public class SlidingWindowMaximum { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] a = {1, 3, 1, 2, 0, 5}; + int[] result = new SlidingWindowMaximum().maxSlidingWindow(a, 3); + for (int i : result) System.out.print(i + " "); + } + + /** + * @param nums + * @param k + * @return + */ + public int[] maxSlidingWindow(int[] nums, int k) { + int[] result = new int[nums.length - (k - 1)]; + + if (nums.length == 0) return new int[0]; + + Deque queue = new ArrayDeque<>(); + for (int i = 0, j = 0, l = nums.length; i < l; i++) { + int head = i - (k - 1); + if (head >= 0) { + // remove out of range + if (queue.peek() != null && queue.peek() < head) queue.poll(); + } + while (queue.peekLast() != null && nums[queue.peekLast()] <= nums[i]) { + queue.pollLast(); + } + queue.offer(i); + if (i >= k - 1) result[j++] = nums[queue.peek()]; + } + + return result; + } +} diff --git a/src/main/java/heap/SmallestRotationWithHighestScore.java b/src/main/java/heap/SmallestRotationWithHighestScore.java new file mode 100644 index 00000000..35cf6be0 --- /dev/null +++ b/src/main/java/heap/SmallestRotationWithHighestScore.java @@ -0,0 +1,93 @@ +/* (C) 2024 YourCompanyName */ +package heap; + +import java.util.Comparator; +import java.util.PriorityQueue; + +/** + * Created by gouthamvidyapradhan on 06/04/2019 Given an array A, we may rotate it by a non-negative + * integer K so that the array becomes A[K], A[K+1], A{K+2], ... A[A.length - 1], A[0], A[1], ..., + * A[K-1]. Afterward, any entries that are less than or equal to their index are worth 1 point. + * + *

For example, if we have [2, 4, 1, 3, 0], and we rotate by K = 2, it becomes [1, 3, 0, 2, 4]. + * This is worth 3 points because 1 > 0 [no points], 3 > 1 [no points], 0 <= 2 [one point], 2 <= 3 + * [one point], 4 <= 4 [one point]. + * + *

Over all possible rotations, return the rotation index K that corresponds to the highest score + * we could receive. If there are multiple answers, return the smallest such index K. + * + *

Example 1: Input: [2, 3, 1, 4, 0] Output: 3 Explanation: Scores for each K are listed below: K + * = 0, A = [2,3,1,4,0], score 2 K = 1, A = [3,1,4,0,2], score 3 K = 2, A = [1,4,0,2,3], score 3 K = + * 3, A = [4,0,2,3,1], score 4 K = 4, A = [0,2,3,1,4], score 3 So we should choose K = 3, which has + * the highest score. + * + *

Example 2: Input: [1, 3, 0, 2, 4] Output: 0 Explanation: A will always have 3 points no matter + * how it shifts. So we will choose the smallest K, which is 0. Note: + * + *

A will have length at most 20000. A[i] will be in the range [0, A.length]. + * + *

Solution O(NLogN). The key insight to this problem is to notice that the point of a number + * changes to 1 from 0 if the position changes to A.length - 1 and similarly the point changes to 1 + * from 0 if the position changes to a index = NUM - 1. Maintain a priority queue with + * rotation_count (the number of rotation required to change its points from either 0 to 1 or from 1 + * to 0), pop all the indices from priority queue which has rotation_count equal to current rotation + * count and update the rotation_count to its next value. Maintain a max count and the rotation + * index pair and return rotation index as the answer. + */ +public class SmallestRotationWithHighestScore { + + private class Node { + int i, n, r, v; + + Node(int i, int n, int r, int v) { + this.i = i; + this.n = n; + this.r = r; + this.v = v; + } + } + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int[] A = {2, 3, 1, 4, 0}; + System.out.println(new SmallestRotationWithHighestScore().bestRotation(A)); + } + + public int bestRotation(int[] A) { + PriorityQueue pq = new PriorityQueue<>(Comparator.comparingInt(o -> o.r)); + int curr = 0; + for (int i = 0; i < A.length; i++) { + int num = A[i]; + int v = 0, r = Integer.MAX_VALUE; + if (num <= i) { + v = 1; + curr++; + } + if (num != 0) { + r = v == 0 ? i + 1 : (i - num + 1); + } + pq.offer(new Node(i, num, r, v)); + } + int R = 0, max = curr, ans = 0; + while (R < A.length) { + while (pq.peek().r - R == 0) { + Node top = pq.poll(); + top.v = (top.v + 1) % 2; + top.i = (top.i - R < 0) ? (A.length + (top.i - R)) : (top.i - R); + top.r = top.v == 0 ? top.i + 1 : (top.i - top.n + 1); + top.r += R; + curr = (top.v == 0) ? curr - 1 : curr + 1; + pq.offer(top); + } + if (curr > max) { + ans = R; + max = curr; + } + R++; + } + return ans; + } +} diff --git a/src/main/java/heap/TheSkylineProblem.java b/src/main/java/heap/TheSkylineProblem.java new file mode 100644 index 00000000..ad19755a --- /dev/null +++ b/src/main/java/heap/TheSkylineProblem.java @@ -0,0 +1,178 @@ +/* (C) 2024 YourCompanyName */ +package heap; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 13/09/2017. + * + *

A city's skyline is the outer contour of the silhouette formed by all the buildings in that + * city when viewed from a distance. Now suppose you are given the locations and height of all the + * buildings as shown on a cityscape photo (Figure A), write a program to output the skyline formed + * by these buildings collectively (Figure B). + * + *

+ * + *

See below link for image. https://leetcode.com/problems/the-skyline-problem/description/ + * + *

+ * + *

Buildings Skyline Contour The geometric information of each building is represented by a + * triplet of integers [Li, Ri, Hi], where Li and Ri are the x coordinates of the left and right + * edge of the ith building, respectively, and Hi is its height. It is guaranteed that 0 ≤ Li, Ri ≤ + * INT_MAX, 0 < Hi ≤ INT_MAX, and Ri - Li > 0. You may assume all buildings are perfect rectangles + * grounded on an absolutely flat surface at height 0. + * + *

For instance, the dimensions of all buildings in Figure A are recorded as: [ [2 9 10], [3 7 + * 15], [5 12 12], [15 20 10], [19 24 8] ] . + * + *

The output is a list of "key points" (red dots in Figure B) in the format of [ [x1,y1], [x2, + * y2], [x3, y3], ... ] that uniquely defines a skyline. A key point is the left endpoint of a + * horizontal line segment. Note that the last key point, where the rightmost building ends, is + * merely used to mark the termination of the skyline, and always has zero height. Also, the ground + * in between any two adjacent buildings should be considered part of the skyline contour. + * + *

For instance, the skyline in Figure B should be represented as:[ [2 10], [3 15], [7 12], [12 + * 0], [15 10], [20 8], [24, 0] ]. + * + *

Notes: + * + *

The number of buildings in any input list is guaranteed to be in the range [0, 10000]. The + * input list is already sorted in ascending order by the left x position Li. The output list must + * be sorted by the x position. There must be no consecutive horizontal lines of equal height in the + * output skyline. For instance, [...[2 3], [4 5], [7 5], [11 5], [12 7]...] is not acceptable; the + * three lines of height 5 should be merged into one in the final output as such: [...[2 3], [4 5], + * [12 7], ...] + * + *

Solution: 1. Sort array of points. Each point here is either a start of a rectangle or end of + * a rectangle. 2. Maintain a priority queue of rectangles ordered by increasing order of height, if + * height of two rectangle is same then, order by left most start index. 3. For each point starting + * from left-most point: 3.a. Add all the rectangles which starts at this point. 3.b. Remove all the + * rectangles which ends at this point. Keep a max of height for each rectangle removed. 3.c. If the + * current priority queue is empty then, include current point (x, 0) to the result set. This + * indicates this was the last rectangle and after this there is a gap of at least 1 unit. + * + *

If the max calculated in step b is greater than current max then, include current x and max + * height from priority queue to the result set. This indicates one of the larger rectangle's right + * edge intersects with a smaller one. + * + *

If the max calculated in stop b is smaller then check if the peek element in priority queue + * has the left edge value equal to current point. If so, then this indicates that a new larger + * rectangle starts from this point therefore add this point to the result set. 4. Return the result + * set + */ +public class TheSkylineProblem { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[][] A = { + {0, 30, 30}, {2, 9, 10}, {3, 7, 15}, {4, 8, 10}, {5, 12, 12}, {15, 20, 10}, {19, 24, 8} + }; + // int[][] A = {{2,9,10}, {3,9,11}, {4,9,12}, {5,9,13}}; + List result = new TheSkylineProblem().getSkyline(A); + result.forEach( + x -> { + System.out.println(x[0] + " " + x[1]); + }); + } + + public List getSkyline(int[][] buildings) { + PriorityQueue pq = + new PriorityQueue<>( + Comparator.comparing(Rectangle::getH) + .reversed() + .thenComparing( + Rectangle + ::getX1)); // order by height, if height is same then, order by left most + // starting edge. + List result = new ArrayList<>(); + Set set = new HashSet<>(); + for (int[] p : buildings) { + set.add(p[0]); + set.add(p[1]); + } + List points = new ArrayList<>(); + points.addAll(set); + points.sort(Integer::compare); + + for (int i = 0, j = 0, l = points.size(); i < l; i++) { + int curr = points.get(i); + + for (int k = j; + k < buildings.length; + k++) { // add all the rectangles that begin at this point + int[] rectangle = buildings[k]; + if (rectangle[0] == curr) { + pq.offer(new Rectangle(rectangle[0], rectangle[1], rectangle[2])); + } else if (rectangle[0] > curr) { + j = k; + break; + } + } + int max = Integer.MIN_VALUE; + while (!pq.isEmpty()) { // remove all the rectangles that end at this point + if (pq.peek().getX2() == curr) { + Rectangle top = pq.poll(); + max = Math.max(max, top.getH()); + } else if (pq.peek().getX2() < curr) { + pq.poll(); + } else { + break; + } + } + if (pq.isEmpty()) { + result.add( + makeNewPoint( + curr, + 0)); // This is the last rectangle after this there is a gap of at least one unit + } else { + if (max > pq.peek().getH()) { + result.add( + makeNewPoint( + curr, + pq.peek() + .getH())); // one of the larger rectangle's right edge intersects with a + // smaller one + } else if (max < pq.peek().getH() && pq.peek().getX1() == curr) { + result.add( + makeNewPoint(curr, pq.peek().getH())); // new larger rectangle begins at this point + } + } + } + return result; + } + + private int[] makeNewPoint(int x, int y) { + int[] point = new int[2]; + point[0] = x; + point[1] = y; + return point; + } + + class Rectangle { + private int x1, x2, h; + + Rectangle(int x1, int x2, int h) { + this.x1 = x1; + this.x2 = x2; + this.h = h; + } + + public int getH() { + return h; + } + + public int getX2() { + return x2; + } + + public int getX1() { + return x1; + } + } +} diff --git a/src/main/java/heap/TopKFrequentWords.java b/src/main/java/heap/TopKFrequentWords.java new file mode 100644 index 00000000..7774d477 --- /dev/null +++ b/src/main/java/heap/TopKFrequentWords.java @@ -0,0 +1,76 @@ +/* (C) 2024 YourCompanyName */ +package heap; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 07/04/2018. Given a non-empty list of words, return the k most + * frequent elements. + * + *

Your answer should be sorted by frequency from highest to lowest. If two words have the same + * frequency, then the word with the lower alphabetical order comes first. + * + *

Example 1: Input: ["i", "love", "leetcode", "i", "love", "coding"], k = 2 Output: ["i", + * "love"] Explanation: "i" and "love" are the two most frequent words. Note that "i" comes before + * "love" due to a lower alphabetical order. Example 2: Input: ["the", "day", "is", "sunny", "the", + * "the", "the", "sunny", "is", "is"], k = 4 Output: ["the", "is", "sunny", "day"] Explanation: + * "the", "is", "sunny" and "day" are the four most frequent words, with the number of occurrence + * being 4, 3, 2 and 1 respectively. Note: You may assume k is always valid, 1 ≤ k ≤ number of + * unique elements. Input words contain only lowercase letters. Follow up: Try to solve it in O(n + * log k) time and O(n) extra space. + * + *

Solution: O(n log k). Calculate frequency and maintain a inverse priority queue of size k and + * add elements. Return result by reversing the priority queue elements. + */ +public class TopKFrequentWords { + + class Pair { + String word; + int freq; + + Pair(String word, int freq) { + this.word = word; + this.freq = freq; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + String[] words = {"i", "love", "leetcode", "i", "love", "coding"}; + List sorted = new TopKFrequentWords().topKFrequent(words, 2); + sorted.stream().forEach(System.out::println); + } + + public List topKFrequent(String[] words, int k) { + Map map = new HashMap<>(); + for (String w : words) { + map.putIfAbsent(w, 0); + int freq = map.get(w); + map.put(w, freq + 1); + } + Queue pq = + new PriorityQueue<>( + (o1, o2) -> + (o1.freq == o2.freq) + ? o2.word.compareTo(o1.word) + : Integer.compare(o1.freq, o2.freq)); + for (String w : map.keySet()) { + int f = map.get(w); + pq.offer(new Pair(w, f)); + if (pq.size() > k) { + pq.poll(); + } + } + List result = new ArrayList<>(); + while (!pq.isEmpty()) { + result.add(pq.poll().word); + } + Collections.reverse(result); + return result; + } +} diff --git a/src/main/java/linked_list/DeleteNode.java b/src/main/java/linked_list/DeleteNode.java new file mode 100644 index 00000000..7b935e4c --- /dev/null +++ b/src/main/java/linked_list/DeleteNode.java @@ -0,0 +1,47 @@ +/* (C) 2024 YourCompanyName */ +package linked_list; + +/** + * Created by gouthamvidyapradhan on 04/07/2017. Write a function to delete a node (except the tail) + * in a singly linked list, given only access to that node. + * + *

Supposed the linked list is 1 -> 2 -> 3 -> 4 and you are given the third node with value 3, + * the linked list should become 1 -> 2 -> 4 after calling your function. + */ +public class DeleteNode { + public static class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + } + } + + public static void main(String[] args) { + ListNode node = new ListNode(1); + node.next = new ListNode(2); + node.next.next = new ListNode(3); + node.next.next.next = new ListNode(4); + new DeleteNode().deleteNode(node.next.next); + while (node != null) { + System.out.println(node.val); + node = node.next; + } + } + + public void deleteNode(ListNode node) { + ListNode prev = node; + ListNode last = node; + ListNode next = node.next; + while (next != null) { + last = prev; + int temp = prev.val; + prev.val = next.val; + next.val = temp; + prev = prev.next; + next = next.next; + } + last.next = null; + } +} diff --git a/src/main/java/linked_list/IntersectionOfTwoLists.java b/src/main/java/linked_list/IntersectionOfTwoLists.java new file mode 100644 index 00000000..b3abc9dd --- /dev/null +++ b/src/main/java/linked_list/IntersectionOfTwoLists.java @@ -0,0 +1,89 @@ +/* (C) 2024 YourCompanyName */ +package linked_list; + +/** + * Created by gouthamvidyapradhan on 24/02/2017. Write a program to find the node at which the + * intersection of two singly linked lists begins. + * + *

+ * + *

For example, the following two linked lists: + * + *

A: a1 → a2 ↘ c1 → c2 → c3 ↗ B: b1 → b2 → b3 begin to intersect at node c1. + * + *

+ * + *

Notes: + * + *

If the two linked lists have no intersection at all, return null. The linked lists must retain + * their original structure after the function returns. You may assume there are no cycles anywhere + * in the entire linked structure. Your code should preferably run in O(n) time and use only O(1) + * memory. + */ +public class IntersectionOfTwoLists { + + public static class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + next = null; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + ListNode node1 = new ListNode(2); + ListNode node2 = new ListNode(3); + node1.next = node2; + System.out.println(new IntersectionOfTwoLists().getIntersectionNode(node1, node2)); + } + + public ListNode getIntersectionNode(ListNode headA, ListNode headB) { + if (headA == null || headB == null) return null; + + int l1len = 0, l2len = 0; + ListNode temp1 = headA; + while (temp1 != null) { + temp1 = temp1.next; + l1len++; + } + temp1 = headB; + + while (temp1 != null) { + temp1 = temp1.next; + l2len++; + } + + int diff = Math.abs(l1len - l2len); + + ListNode temp2; + + if (l1len > l2len) { + temp1 = headA; + temp2 = headB; + } else { + temp1 = headB; + temp2 = headA; + } + + while (diff != 0) { + temp1 = temp1.next; + diff--; + } + while (!temp1.equals(temp2)) { + temp1 = temp1.next; + temp2 = temp2.next; + if (temp1 == null || temp2 == null) return null; + } + + if (temp1.equals(temp2)) return temp1; + return null; + } +} diff --git a/src/main/java/linked_list/LinkedListCycle.java b/src/main/java/linked_list/LinkedListCycle.java new file mode 100644 index 00000000..b9bcc130 --- /dev/null +++ b/src/main/java/linked_list/LinkedListCycle.java @@ -0,0 +1,53 @@ +/* (C) 2024 YourCompanyName */ +package linked_list; + +import java.util.HashSet; +import java.util.Set; + +/** + * Created by gouthamvidyapradhan on 23/02/2017. Given a linked list, determine if it has a cycle in + * it. + * + *

Follow up: Can you solve it without using extra space? + */ +public class LinkedListCycle { + private static Set hashCode = new HashSet<>(); + + static class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + next = null; + } + } + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) throws Exception { + ListNode node1 = new ListNode(1); + ListNode node2 = new ListNode(2); + ListNode node3 = new ListNode(3); + node1.next = node2; + node2.next = node3; + node3.next = node1; + System.out.println(new LinkedListCycle().hasCycle(node1)); + } + + public boolean hasCycle(ListNode head) { + ListNode slow = head; + ListNode fast = head; + while (slow != null && fast != null) { + slow = slow.next; + fast = fast.next; + if (fast != null) fast = fast.next; + else break; + if (fast != null && slow != null) if (fast.equals(slow)) return true; + } + return false; + } +} diff --git a/src/main/java/linked_list/MergeKSortedLists.java b/src/main/java/linked_list/MergeKSortedLists.java new file mode 100644 index 00000000..c128fce3 --- /dev/null +++ b/src/main/java/linked_list/MergeKSortedLists.java @@ -0,0 +1,102 @@ +/* (C) 2024 YourCompanyName */ +package linked_list; + +/** + * Created by gouthamvidyapradhan on 11/03/2017. Merge k sorted linked lists and return it as one + * sorted list. Analyze and describe its complexity. + */ +public class MergeKSortedLists { + public static class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + next = null; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + ListNode node2 = new ListNode(-1); + ListNode node3 = new ListNode(5); + ListNode node4 = new ListNode(11); + + ListNode node6 = new ListNode(6); + ListNode node10 = new ListNode(10); + + /*ListNode node1 = new ListNode(2); + ListNode node5 = new ListNode(3); + ListNode node7 = new ListNode(7); + ListNode node26 = new ListNode(26); + ListNode node111 = new ListNode(111); + + + ListNode node11 = new ListNode(1); + ListNode node9 = new ListNode(9); + ListNode node10 = new ListNode(10); + ListNode node12 = new ListNode(12); + ListNode node119 = new ListNode(119); + */ + + node2.next = node3; + node3.next = node4; + + node6.next = node10; + + /*node1.next = node5; + node5.next = node7; + node7.next = node26; + node26.next = node111; + + node11.next = node9; + node9.next = node10; + node10.next = node12; + node12.next = node119;*/ + ListNode[] list = new ListNode[4]; + list[0] = null; + list[1] = node2; + list[2] = null; + list[3] = node6; + ListNode result = new MergeKSortedLists().mergeKLists(list); + } + + public ListNode mergeKLists(ListNode[] lists) { + if (lists.length == 0) return null; + if (lists.length == 1) return lists[0]; + return merge(lists, 0, lists.length - 1); + } + + private ListNode merge(ListNode[] lists, int s, int e) { + if (s == e) return lists[s]; + int m = s + (e - s) / 2; + ListNode left = merge(lists, s, m); + ListNode right = merge(lists, m + 1, e); + ListNode prev, temp; + ListNode headNode = new ListNode(0); + headNode.next = left; + prev = headNode; + if (left == null && right == null) return null; + else if (left == null) return right; + else if (right == null) return left; + while (left != null && right != null) { + if (left.val > right.val) { + temp = right; + right = right.next; + prev.next = temp; + temp.next = left; + prev = prev.next; + } else { + left = left.next; + prev = prev.next; + } + } + if (left == null && right != null) prev.next = right; + return headNode.next; + } +} diff --git a/src/main/java/linked_list/MergeTwoSortedList.java b/src/main/java/linked_list/MergeTwoSortedList.java new file mode 100644 index 00000000..c3a5f87c --- /dev/null +++ b/src/main/java/linked_list/MergeTwoSortedList.java @@ -0,0 +1,55 @@ +/* (C) 2024 YourCompanyName */ +package linked_list; + +/** + * Created by gouthamvidyapradhan on 18/03/2017. Merge two sorted linked lists and return it as a + * new list. The new list should be made by splicing together the nodes of the first two lists. + */ +public class MergeTwoSortedList { + public static class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + next = null; + } + } + + public static void main(String[] args) throws Exception { + ListNode head = new ListNode(0); + ListNode head1 = new ListNode(3); + ListNode head2 = new ListNode(8); + + ListNode head3 = new ListNode(1); + ListNode head4 = new ListNode(2); + ListNode head5 = new ListNode(7); + ListNode head6 = new ListNode(10); + + head.next = head1; + head1.next = head2; + + head3.next = head4; + head4.next = head5; + head5.next = head6; + + ListNode newHead = new MergeTwoSortedList().mergeTwoLists(head, head3); + ListNode link = newHead; + while (link != null) { + System.out.println(link.val); + link = link.next; + } + } + + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if (l1 == null) return l2; + else if (l2 == null) return l1; + if (l1.val <= l2.val) { + l1.next = mergeTwoLists(l1.next, l2); + return l1; + } else { + l2.next = mergeTwoLists(l1, l2.next); + return l2; + } + } +} diff --git a/src/main/java/linked_list/MiddleOfLinkedList.java b/src/main/java/linked_list/MiddleOfLinkedList.java new file mode 100644 index 00000000..a75150d8 --- /dev/null +++ b/src/main/java/linked_list/MiddleOfLinkedList.java @@ -0,0 +1,54 @@ +/* (C) 2024 YourCompanyName */ +package linked_list; + +/** + * Created by gouthamvidyapradhan on 22/03/2019 Given a non-empty, singly linked list with head node + * head, return a middle node of linked list. + * + *

If there are two middle nodes, return the second middle node. + * + *

Example 1: + * + *

Input: [1,2,3,4,5] Output: Node 3 from this list (Serialization: [3,4,5]) The returned node + * has value 3. (The judge's serialization of this node is [3,4,5]). Note that we returned a + * ListNode object ans, such that: ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, and + * ans.next.next.next = NULL. Example 2: + * + *

Input: [1,2,3,4,5,6] Output: Node 4 from this list (Serialization: [4,5,6]) Since the list has + * two middle nodes with values 3 and 4, we return the second one. + * + *

Solution: O(N) Return the middle node. middle = count / 2 + */ +public class MiddleOfLinkedList { + + public class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + } + } + /** + * Main method + * + * @param args + */ + public static void main(String[] args) {} + + public ListNode middleNode(ListNode head) { + int count = 0; + ListNode temp = head; + while (temp != null) { + temp = temp.next; + count++; + } + int mid = count / 2; + int c = 0; + while (head != null && c < mid) { + head = head.next; + c++; + } + return head; + } +} diff --git a/src/main/java/linked_list/NextGreaterNodeInLinkedList.java b/src/main/java/linked_list/NextGreaterNodeInLinkedList.java new file mode 100644 index 00000000..b5e4a196 --- /dev/null +++ b/src/main/java/linked_list/NextGreaterNodeInLinkedList.java @@ -0,0 +1,94 @@ +/* (C) 2024 YourCompanyName */ +package linked_list; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 31/07/2019 We are given a linked list with head as the first + * node. Let's number the nodes in the list: node_1, node_2, node_3, ... etc. + * + *

Each node may have a next larger value: for node_i, next_larger(node_i) is the node_j.val such + * that j > i, node_j.val > node_i.val, and j is the smallest possible choice. If such a j does not + * exist, the next larger value is 0. + * + *

Return an array of integers answer, where answer[i] = next_larger(node_{i+1}). + * + *

Note that in the example inputs (not outputs) below, arrays such as [2,1,5] represent the + * serialization of a linked list with a head node value of 2, second node value of 1, and third + * node value of 5. + * + *

Example 1: + * + *

Input: [2,1,5] Output: [5,5,0] Example 2: + * + *

Input: [2,7,4,3,5] Output: [7,0,5,5,0] Example 3: + * + *

Input: [1,7,5,1,9,2,5,1] Output: [7,9,9,9,0,5,0,0] + * + *

Note: + * + *

1 <= node.val <= 10^9 for each node in the linked list. The given list has length in the range + * [0, 10000]. + * + *

Solution O(N) solve the problem in the inverse order starting from the tail of the list. + * Maintain a stack of values and on each iteration pop() all the values from the stack which are + * smaller then the current element. + */ +public class NextGreaterNodeInLinkedList { + + public static class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + } + } + + private List result; + + public static void main(String[] args) { + ListNode node = new ListNode(1); + node.next = new ListNode(2); + new NextGreaterNodeInLinkedList().nextLargerNodes(node); + } + + public int[] nextLargerNodes(ListNode head) { + result = new ArrayList<>(); + find(head, result); + Collections.reverse(result); + int[] answer = new int[result.size()]; + for (int i = 0, l = result.size(); i < l; i++) { + answer[i] = result.get(i); + } + return answer; + } + + private Stack find(ListNode head, List answer) { + if (head == null) { + return new Stack<>(); + } + Stack stack = find(head.next, answer); + if (stack.isEmpty()) { + answer.add(0); + stack.push(head.val); + } else { + if (stack.peek() > head.val) { + answer.add(stack.peek()); + stack.push(head.val); + } else { + while (!stack.isEmpty() && stack.peek() <= head.val) { + stack.pop(); + } + if (stack.isEmpty()) { + stack.push(head.val); + answer.add(0); + } else { + answer.add(stack.peek()); + stack.push(head.val); + } + } + } + return stack; + } +} diff --git a/src/main/java/linked_list/PaliandromeList.java b/src/main/java/linked_list/PaliandromeList.java new file mode 100644 index 00000000..6629d699 --- /dev/null +++ b/src/main/java/linked_list/PaliandromeList.java @@ -0,0 +1,84 @@ +/* (C) 2024 YourCompanyName */ +package linked_list; + +/** + * Created by gouthamvidyapradhan on 25/02/2017. Given a singly linked list, determine if it is a + * palindrome. + * + *

Follow up: Could you do it in O(n) time and O(1) space? + */ +public class PaliandromeList { + public static class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + next = null; + } + } + + ListNode headNode; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + ListNode node1 = new ListNode(1); + // ListNode node2 = new ListNode(2); + // ListNode node3 = new ListNode(3); + // ListNode node4 = new ListNode(3); + // ListNode node5 = new ListNode(2); + // ListNode node6 = new ListNode(1); + // node1.next = node2; + // node2.next = node3; + // node3.next = node5; + // node4.next = node5; + // node5.next = node6; + System.out.println(new PaliandromeList().isPalindrome(node1)); + } + + public boolean isPalindrome(ListNode head) { + int length = 0, count = 0; + if (head == null) return true; + ListNode temp = head; + while (temp != null) { + temp = temp.next; + length++; + } + if (length == 1) return true; + + int halfLen = length / 2; + + temp = head; + while (count < halfLen - 1) { + temp = temp.next; + count++; + } + + ListNode newHead = temp.next; + temp.next = null; + reverse(newHead); + ListNode first = head, second = headNode; + for (int i = 0; i < halfLen; i++) { + if (first.val != second.val) return false; + first = first.next; + second = second.next; + } + return true; + } + + private ListNode reverse(ListNode node) { + if (node.next == null) { + headNode = node; + return node; + } + ListNode prev = reverse(node.next); + node.next = null; + prev.next = node; + return node; + } +} diff --git a/src/main/java/linked_list/ReverseLinkedList.java b/src/main/java/linked_list/ReverseLinkedList.java new file mode 100644 index 00000000..e7b00d28 --- /dev/null +++ b/src/main/java/linked_list/ReverseLinkedList.java @@ -0,0 +1,56 @@ +/* (C) 2024 YourCompanyName */ +package linked_list; + +/** Created by gouthamvidyapradhan on 24/02/2017. Reverse a singly linked list. */ +public class ReverseLinkedList { + private ListNode newHead; + + public static class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + next = null; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + ListNode node1 = new ListNode(1); + ListNode node2 = new ListNode(2); + ListNode node3 = new ListNode(3); + ListNode node4 = new ListNode(4); + ListNode node5 = new ListNode(5); + ListNode node6 = new ListNode(6); + node1.next = node2; + node2.next = node3; + node3.next = node4; + node4.next = node5; + // node5.next = node6; + ListNode newNode = new ReverseLinkedList().reverseList(node1); + System.out.println(newNode.val); + } + + public ListNode reverseList(ListNode head) { + if (head == null) return null; + else if (head.next == null) return head; + reverse(head).next = null; + return newHead; + } + + private ListNode reverse(ListNode head) { + if (head.next == null) { + newHead = head; + return head; + } + ListNode node = reverse(head.next); + node.next = head; + return head; + } +} diff --git a/src/main/java/linked_list/ReverseNodesKGroup.java b/src/main/java/linked_list/ReverseNodesKGroup.java new file mode 100644 index 00000000..a253c32e --- /dev/null +++ b/src/main/java/linked_list/ReverseNodesKGroup.java @@ -0,0 +1,95 @@ +/* (C) 2024 YourCompanyName */ +package linked_list; + +/** + * Created by gouthamvidyapradhan on 06/07/2017. Given a linked list, reverse the nodes of a linked + * list k at a time and return its modified list. + * + *

k is a positive integer and is less than or equal to the length of the linked list. If the + * number of nodes is not a multiple of k then left-out nodes in the end should remain as it is. + * + *

You may not alter the values in the nodes, only nodes itself may be changed. + * + *

Only constant memory is allowed. + * + *

For example, Given this linked list: 1->2->3->4->5 + * + *

For k = 2, you should return: 2->1->4->3->5 + * + *

For k = 3, you should return: 3->2->1->4->5 + * + *

+ * + *

Solution: O(N) solution with constant space. Recursively reverse a group of K nodes and for + * each group join the tail of the prev group to the head of the next group. + */ +public class ReverseNodesKGroup { + public static class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + } + } + + private ListNode newHead, newStart, prev; + + public static void main(String[] args) throws Exception { + ListNode node = new ListNode(1); + node.next = new ListNode(2); + node.next.next = new ListNode(3); + node.next.next.next = new ListNode(4); + node.next.next.next.next = new ListNode(5); + ListNode result = new ReverseNodesKGroup().reverseKGroup(node, 2); + while (result != null) { + System.out.println(result.val + " "); + result = result.next; + } + } + + public ListNode reverseKGroup(ListNode head, int k) { + if (head == null) return null; + ListNode node = head; + int count = 0; + while (node != null) { + node = node.next; + count++; + } + if (k > count) return head; + int N = count / k; + newStart = head; + ListNode tail = null; + ListNode result = null; + while (N-- > 0) { + tail = reverse(newStart, 1, k); + tail.next = null; + if (result == null) result = newHead; // save the head only once + if (prev != null) { + prev.next = newHead; + } + prev = tail; + } + if (tail != null) tail.next = newStart; + return result; + } + + /** + * Reverse k nodes + * + * @param node head node + * @param count count + * @param k K + * @return + */ + private ListNode reverse(ListNode node, int count, int k) { + if (count == k) { + newStart = node.next; // new start node + newHead = node; // mark this as the new head + } else { + ListNode nNode = reverse(node.next, count + 1, k); + nNode.next = node; + } + return node; + } +} diff --git a/src/main/java/linked_list/SplitLinkedListInParts.java b/src/main/java/linked_list/SplitLinkedListInParts.java new file mode 100644 index 00000000..e0a43138 --- /dev/null +++ b/src/main/java/linked_list/SplitLinkedListInParts.java @@ -0,0 +1,96 @@ +/* (C) 2024 YourCompanyName */ +package linked_list; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 06/08/2019 Given a (singly) linked list with head node root, + * write a function to split the linked list into k consecutive linked list "parts". + * + *

The length of each part should be as equal as possible: no two parts should have a size + * differing by more than 1. This may lead to some parts being null. + * + *

The parts should be in order of occurrence in the input list, and parts occurring earlier + * should always have a size greater than or equal parts occurring later. + * + *

Return a List of ListNode's representing the linked list parts that are formed. + * + *

Examples 1->2->3->4, k = 5 // 5 equal parts [ [1], [2], [3], [4], null ] Example 1: Input: + * root = [1, 2, 3], k = 5 Output: [[1],[2],[3],[],[]] Explanation: The input and each element of + * the output are ListNodes, not arrays. For example, the input root has root.val = 1, root.next.val + * = 2, \root.next.next.val = 3, and root.next.next.next = null. The first element output[0] has + * output[0].val = 1, output[0].next = null. The last element output[4] is null, but it's string + * representation as a ListNode is []. Example 2: Input: root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = + * 3 Output: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]] Explanation: The input has been split into + * consecutive parts with size difference at most 1, and earlier parts are a larger size than the + * later parts. Note: + * + *

The length of root will be in the range [0, 1000]. Each value of a node in the input will be + * an integer in the range [0, 999]. k will be an integer in the range [1, 50]. + * + *

Solution O(N) do a linear scan and split the array by required size. + */ +public class SplitLinkedListInParts { + public static class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + } + } + + public static void main(String[] args) { + ListNode root = new ListNode(1); + root.next = new ListNode(2); + root.next.next = new ListNode(3); + ListNode[] result = new SplitLinkedListInParts().splitListToParts(root, 5); + System.out.println(result); + } + + public ListNode[] splitListToParts(ListNode root, int k) { + List list = new ArrayList<>(); + while (root != null) { + list.add(root.val); + root = root.next; + } + int tempK = k; + int N = list.size(); + List result = new ArrayList<>(); + ListNode head = new ListNode(-1); + ListNode prev = head; + int i = 0, j = 0; + int count = 0; + int P = N / tempK; + if ((N % tempK) > 0) { + P++; + } + for (; j < N; ) { + if (j - i < P) { + prev.next = new ListNode(list.get(j)); + prev = prev.next; + j++; + count++; + } else { + result.add(head.next); + i = j; + head = new ListNode(-1); + prev = head; + tempK--; + P = (N - count) / tempK; + if (((N - count) % tempK) > 0) { + P++; + } + } + } + result.add(head.next); + while (result.size() < k) { + result.add(null); + } + ListNode[] nodes = new ListNode[result.size()]; + for (int l = 0; l < result.size(); l++) { + nodes[l] = result.get(l); + } + return nodes; + } +} diff --git a/src/main/java/linked_list/SwapNodesInPairs.java b/src/main/java/linked_list/SwapNodesInPairs.java new file mode 100644 index 00000000..66e4a432 --- /dev/null +++ b/src/main/java/linked_list/SwapNodesInPairs.java @@ -0,0 +1,58 @@ +/* (C) 2024 YourCompanyName */ +package linked_list; + +/** + * Created by gouthamvidyapradhan on 13/08/2017. Given a linked list, swap every two adjacent nodes + * and return its head. + * + *

For example, Given 1->2->3->4, you should return the list as 2->1->4->3. + * + *

Your algorithm should use only constant space. You may not modify the values in the list, only + * nodes itself can be changed. + */ +public class SwapNodesInPairs { + + public static class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + } + } + + public static void main(String[] args) throws Exception { + ListNode node = new ListNode(1); + node.next = new ListNode(2); + node.next.next = new ListNode(3); + node.next.next.next = new ListNode(4); + node.next.next.next.next = new ListNode(5); + node.next.next.next.next.next = new ListNode(6); + ListNode head = new SwapNodesInPairs().swapPairs(node); + while (head != null) { + System.out.println(head.val); + head = head.next; + } + } + + public ListNode swapPairs(ListNode head) { + if (head == null || head.next == null) return head; + ListNode newHead = head.next; + ListNode curr = head.next; + ListNode prev = head; + ListNode prevPrev = new ListNode(-1); // dummy node + while (curr != null) { + prev.next = curr.next; + curr.next = prev; + prevPrev.next = curr; + if (prev.next != null) { + curr = prev.next.next; + prev = prev.next; + prevPrev = prevPrev.next.next; + } else { + curr = null; + } + } + return newHead; + } +} diff --git a/src/main/java/math/AddDigits.java b/src/main/java/math/AddDigits.java new file mode 100644 index 00000000..2fd67cf4 --- /dev/null +++ b/src/main/java/math/AddDigits.java @@ -0,0 +1,25 @@ +/* (C) 2024 YourCompanyName */ +package math; + +/** + * Created by gouthamvidyapradhan on 02/08/2017. Given a non-negative integer num, repeatedly add + * all its digits until the result has only one digit. + * + *

For example: + * + *

Given num = 38, the process is like: 3 + 8 = 11, 1 + 1 = 2. Since 2 has only one digit, return + * it. + * + *

Follow up: Could you do it without any loop/recursion in O(1) runtime? + */ +public class AddDigits { + + public static void main(String[] args) throws Exception { + System.out.println(new AddDigits().addDigits(38)); + } + + public int addDigits(int num) { + if (num == 0) return 0; + return num % 9 == 0 ? 9 : num % 9; + } +} diff --git a/src/main/java/math/AddTwoNumbers.java b/src/main/java/math/AddTwoNumbers.java new file mode 100644 index 00000000..fcd60431 --- /dev/null +++ b/src/main/java/math/AddTwoNumbers.java @@ -0,0 +1,78 @@ +/* (C) 2024 YourCompanyName */ +package math; + +/** + * Created by gouthamvidyapradhan on 13/03/2017. You are given two non-empty linked lists + * representing two non-negative integers. The digits are stored in reverse order and each of their + * nodes contain a single digit. Add the two numbers and return it as a linked list. + * + *

You may assume the two numbers do not contain any leading zero, except the number 0 itself. + * + *

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 0 -> 8 + */ +public class AddTwoNumbers { + public static class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + next = null; + } + } + + public static void main(String[] args) { + ListNode node = new ListNode(2); + node.next = new ListNode(4); + node.next.next = new ListNode(4); + + ListNode node1 = new ListNode(5); + node1.next = new ListNode(6); + node1.next.next = new ListNode(6); + + ListNode result = new AddTwoNumbers().addTwoNumbers(node, node1); + } + + private ListNode addTwoNumbers(ListNode l1, ListNode l2) { + if (l1 == null && l2 == null) return null; + ListNode first = l1; + ListNode second = l2; + int carry = 0; + ListNode head = new ListNode(0); + ListNode prev = head; + while (first != null && second != null) { + int q = (first.val + second.val + carry) / 10; + int r = (first.val + second.val + carry) % 10; + carry = q; + ListNode node = new ListNode(r); + prev.next = node; + prev = node; + first = first.next; + second = second.next; + } + + while (first != null) { + int q = (first.val + carry) / 10; + int r = (first.val + carry) % 10; + carry = q; + ListNode node = new ListNode(r); + prev.next = node; + prev = node; + first = first.next; + } + + while (second != null) { + int q = (second.val + carry) / 10; + int r = (second.val + carry) % 10; + carry = q; + ListNode node = new ListNode(r); + prev.next = node; + prev = node; + second = second.next; + } + + if (carry != 0) prev.next = new ListNode(carry); + + return head.next; + } +} diff --git a/src/main/java/math/Base7.java b/src/main/java/math/Base7.java new file mode 100644 index 00000000..1037a6e4 --- /dev/null +++ b/src/main/java/math/Base7.java @@ -0,0 +1,32 @@ +/* (C) 2024 YourCompanyName */ +package math; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 01/08/2019 Given an integer, return its base 7 string + * representation. + * + *

Example 1: Input: 100 Output: "202" Example 2: Input: -7 Output: "-10" Note: The input will be + * in range of [-1e7, 1e7]. + */ +public class Base7 { + public static void main(String[] args) { + // + } + + public String convertToBase7(int num) { + Integer.toString(7, 7); + if (num == 0) return "0"; + int q = Math.abs(num), r; + StringBuilder sb = new StringBuilder(); + while (q != 0) { + r = q % 7; + sb.append(r); + q /= 7; + } + if (num < 0) { + return "-" + sb.reverse().toString(); + } else return sb.reverse().toString(); + } +} diff --git a/src/main/java/math/BulbSwitcherII.java b/src/main/java/math/BulbSwitcherII.java new file mode 100644 index 00000000..e7c04b80 --- /dev/null +++ b/src/main/java/math/BulbSwitcherII.java @@ -0,0 +1,43 @@ +/* (C) 2024 YourCompanyName */ +package math; + +/** + * Created by gouthamvidyapradhan on 08/09/2017. There is a room with n lights which are turned on + * initially and 4 buttons on the wall. After performing exactly m unknown operations towards + * buttons, you need to return how many different kinds of status of the n lights could be. + * + *

Suppose n lights are labeled as number [1, 2, 3 ..., n], function of these 4 buttons are given + * below: + * + *

Flip all the lights. Flip lights with even numbers. Flip lights with odd numbers. Flip lights + * with (3k + 1) numbers, k = 0, 1, 2, ... + * + *

Example 1: Input: n = 1, m = 1. Output: 2 Explanation: Status can be: [on], [off] + * + *

Example 2: Input: n = 2, m = 1. Output: 3 Explanation: Status can be: [on, off], [off, on], + * [off, off] + * + *

Example 3: Input: n = 3, m = 1. Output: 4 Explanation: Status can be: [off, on, off], [on, + * off, on], [off, off, off], [off, on, on]. + * + *

Note: n and m both fit in range [0, 1000]. + */ +public class BulbSwitcherII { + + public static void main(String[] args) throws Exception { + System.out.println(new BulbSwitcherII().flipLights(1, 1000)); + } + + public int flipLights(int n, int m) { + if (n == 0 || m == 0) return 1; + if (n == 1 && m >= 1) return 2; + if (n == 2) { + if (m == 1) return 3; + if (m >= 2) return 4; + } else if (n >= 3) { + if (m == 1) return 4; + if (m == 2) return 7; + } + return 8; + } +} diff --git a/src/main/java/math/CountPrimes.java b/src/main/java/math/CountPrimes.java new file mode 100644 index 00000000..ee971487 --- /dev/null +++ b/src/main/java/math/CountPrimes.java @@ -0,0 +1,41 @@ +/* (C) 2024 YourCompanyName */ +package math; + +import java.util.BitSet; + +/** + * Created by gouthamvidyapradhan on 21/03/2017. Description: + * + *

Count the number of prime numbers less than a non-negative number, n. + */ +public class CountPrimes { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new CountPrimes().countPrimes(999187)); + } + + public int countPrimes(int n) { + if (n == 0 || n == 1 || n == 2) return 0; + else if (n == 3) return 1; + BitSet set = new BitSet(); + n = n - 1; + int sqRt = (int) Math.sqrt(n); + int count = n; + for (int i = 2; i <= sqRt; i++) { + if (!set.get(i)) { + for (int j = 2; (i * j) <= n; j++) { + if (!set.get(i * j)) { + count--; + set.set(i * j); + } + } + } + } + return count - 1; + } +} diff --git a/src/main/java/math/CouplesHoldingHands.java b/src/main/java/math/CouplesHoldingHands.java new file mode 100644 index 00000000..6d81c96b --- /dev/null +++ b/src/main/java/math/CouplesHoldingHands.java @@ -0,0 +1,79 @@ +/* (C) 2024 YourCompanyName */ +package math; + +/** + * Created by gouthamvidyapradhan on 23/06/2018. N couples sit in 2N seats arranged in a row and + * want to hold hands. We want to know the minimum number of swaps so that every couple is sitting + * side by side. A swap consists of choosing any two people, then they stand up and switch seats. + * + *

The people and seats are represented by an integer from 0 to 2N-1, the couples are numbered in + * order, the first couple being (0, 1), the second couple being (2, 3), and so on with the last + * couple being (2N-2, 2N-1). + * + *

The couples' initial seating is given by row[i] being the value of the person who is initially + * sitting in the i-th seat. + * + *

Example 1: + * + *

Input: row = [0, 2, 1, 3] Output: 1 Explanation: We only need to swap the second (row[1]) and + * third (row[2]) person. Example 2: + * + *

Input: row = [3, 2, 0, 1] Output: 0 Explanation: All couples are already seated side by side. + * Note: + * + *

len(row) is even and in the range of [4, 60]. row is guaranteed to be a permutation of + * 0...len(row)-1. + * + *

Solution: O(N ^ 2). Find the index i of every even-number n and (n + 1)th number. If the index + * i of number n is even then swap the number (n + 1) with index i + 1, else swap the number (n + 1) + * with index i - 1. Count the total swaps and return the answer. + */ +public class CouplesHoldingHands { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 3, 4, 0, 2, 5}; + System.out.println(new CouplesHoldingHands().minSwapsCouples(A)); + } + + public int minSwapsCouples(int[] row) { + int N = row.length; + int count = 0; + for (int i = 0; i < N; i += 2) { + int pos = find(row, i); + if ((pos % 2) == 0) { + if (row[pos + 1] != i + 1) { + int nexNumPos = find(row, i + 1); + swap(row, pos + 1, nexNumPos); + count++; + } + } else { + if (row[pos - 1] != i + 1) { + int nexNumPos = find(row, i + 1); + swap(row, pos - 1, nexNumPos); + count++; + } + } + } + return count; + } + + private int find(int[] A, int n) { + for (int i = 0; i < A.length; i++) { + if (A[i] == n) { + return i; + } + } + return -1; + } + + private void swap(int[] A, int i, int j) { + int temp = A[i]; + A[i] = A[j]; + A[j] = temp; + } +} diff --git a/src/main/java/math/DecodedStringAtIndex.java b/src/main/java/math/DecodedStringAtIndex.java new file mode 100644 index 00000000..357f7947 --- /dev/null +++ b/src/main/java/math/DecodedStringAtIndex.java @@ -0,0 +1,71 @@ +/* (C) 2024 YourCompanyName */ +package math; + +/** + * Created by gouthamvidyapradhan on 21/07/2019 An encoded string S is given. To find and write the + * decoded string to a tape, the encoded string is read one character at a time and the following + * steps are taken: + * + *

If the character read is a letter, that letter is written onto the tape. If the character read + * is a digit (say d), the entire current tape is repeatedly written d-1 more times in total. Now + * for some encoded string S, and an index K, find and return the K-th letter (1 indexed) in the + * decoded string. + * + *

Example 1: + * + *

Input: S = "leet2code3", K = 10 Output: "o" Explanation: The decoded string is + * "leetleetcodeleetleetcodeleetleetcode". The 10th letter in the string is "o". Example 2: + * + *

Input: S = "ha22", K = 5 Output: "h" Explanation: The decoded string is "hahahaha". The 5th + * letter is "h". Example 3: + * + *

Input: S = "a2345678999999999999999", K = 1 Output: "a" Explanation: The decoded string is "a" + * repeated 8301530446056247680 times. The 1st letter is "a". + * + *

Note: + * + *

2 <= S.length <= 100 S will only contain lowercase letters and digits 2 through 9. S starts + * with a letter. 1 <= K <= 10^9 The decoded string is guaranteed to have less than 2^63 letters. + * + *

Solution: General idea is as shown below example: If S = "leet2" and K = 6 the answer is "e" + * which is same as finding answer for K = 2. As soon as the product exceeds the total value of K as + * in this case the product of 4 (leet) x 2 is 8 and 8 clearly exceeds 6 therefore we can reduce K + * to 8 - 6 = 2 and start from the beginning once again. Repeat the same process until we reach the + * answer. + */ +public class DecodedStringAtIndex { + public static void main(String[] args) { + System.out.println( + new DecodedStringAtIndex().decodeAtIndex("a2345678999999999999999", 1000000000)); + } + + public String decodeAtIndex(String S, int K) { + long product = 0; + char lastC = S.charAt(0); + for (int i = 0, l = S.length(); i < l; ) { + char c = S.charAt(i); + if (Character.isLetter(c)) { + lastC = c; + product++; + i++; + if (K == product) break; + } else { + long temp = (product * Integer.parseInt(String.valueOf(c))); + if (temp == K) break; + else { + if (temp > K) { + long x = (K / product); + if ((product * x) == K) break; + K -= (product * x); + i = 0; + product = 0; + } else { + product = temp; + i++; + } + } + } + } + return String.valueOf(lastC); + } +} diff --git a/src/main/java/math/ExcelSheetColumnTitle.java b/src/main/java/math/ExcelSheetColumnTitle.java new file mode 100644 index 00000000..9b523996 --- /dev/null +++ b/src/main/java/math/ExcelSheetColumnTitle.java @@ -0,0 +1,40 @@ +/* (C) 2024 YourCompanyName */ +package math; + +/** + * Created by gouthamvidyapradhan on 12/08/2017. Given a positive integer, return its corresponding + * column title as appear in an Excel sheet. + * + *

For example: + * + *

1 -> A 2 -> B 3 -> C ... 26 -> Z 27 -> AA 28 -> AB + */ +public class ExcelSheetColumnTitle { + + private static final String CONST = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new ExcelSheetColumnTitle().convertToTitle(52)); + } + + public String convertToTitle(int n) { + StringBuilder ans = new StringBuilder(); + while (n > 0) { + int mod = n % 26; + n /= 26; + if (mod == 0) { + ans.append('Z'); + n -= 1; + } else { + ans.append(CONST.charAt(mod - 1)); + } + } + return ans.reverse().toString(); + } +} diff --git a/src/main/java/math/GlobalAndLocalInversions.java b/src/main/java/math/GlobalAndLocalInversions.java new file mode 100644 index 00000000..444dca0e --- /dev/null +++ b/src/main/java/math/GlobalAndLocalInversions.java @@ -0,0 +1,51 @@ +/* (C) 2024 YourCompanyName */ +package math; + +/** + * Created by gouthamvidyapradhan on 01/02/2018. + * + *

We have some permutation A of [0, 1, ..., N - 1], where N is the length of A. + * + *

The number of (global) inversions is the number of i < j with 0 <= i < j < N and A[i] > A[j]. + * + *

The number of local inversions is the number of i with 0 <= i < N and A[i] > A[i+1]. + * + *

Return true if and only if the number of global inversions is equal to the number of local + * inversions. + * + *

Example 1: + * + *

Input: A = [1,0,2] Output: true Explanation: There is 1 global inversion, and 1 local + * inversion. Example 2: + * + *

Input: A = [1,2,0] Output: false Explanation: There are 2 global inversions, and 1 local + * inversion. Note: + * + *

A will be a permutation of [0, 1, ..., A.length - 1]. A will have length in range [1, 5000]. + * The time limit for this problem has been reduced. + * + *

Solution: O(N) For every i, Maintain a max value up until (i - 1). If the current element at i + * < max value return false + */ +public class GlobalAndLocalInversions { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception {} + + public boolean isIdealPermutation(int[] A) { + if (A.length == 0 || A.length == 1) return true; + int max = Integer.MIN_VALUE; + for (int i = 1; i < A.length; i++) { + if (A[i] < max) { + return false; + } else { + max = Math.max(max, A[i - 1]); + } + } + return true; + } +} diff --git a/src/main/java/math/LargestComponentSizebyCommonFactor.java b/src/main/java/math/LargestComponentSizebyCommonFactor.java new file mode 100644 index 00000000..59df14d8 --- /dev/null +++ b/src/main/java/math/LargestComponentSizebyCommonFactor.java @@ -0,0 +1,161 @@ +/* (C) 2024 YourCompanyName */ +package math; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Created by gouthamvidyapradhan on 20/08/2019 Given a non-empty array of unique positive integers + * A, consider the following graph: + * + *

There are A.length nodes, labelled A[0] to A[A.length - 1]; There is an edge between A[i] and + * A[j] if and only if A[i] and A[j] share a common factor greater than 1. Return the size of the + * largest connected component in the graph. + * + *

Example 1: + * + *

Input: [4,6,15,35] Output: 4 + * + *

Example 2: + * + *

Input: [20,50,9,63] Output: 2 + * + *

Example 3: + * + *

Input: [2,3,6,7,4,12,21,39] Output: 8 + * + *

Note: + * + *

1 <= A.length <= 20000 1 <= A[i] <= 100000 + * + *

Solution: O(primes upto max[A[i]] x N) Find all the primes upto maximum of A[i] and build + * components (using union-find) by finding all the numbers in A[] which are divisible by each prime + * number - keep track of size of each component and return the size of the largest component. + */ +public class LargestComponentSizebyCommonFactor { + private static class UnionFind { + private int[] p; + private int[] rank; + private int[] size; + + UnionFind(int s) { + this.p = new int[s]; + this.rank = new int[s]; + this.size = new int[s]; + init(); + } + /** Initialize with its same index as its parent */ + private void init() { + for (int i = 0; i < p.length; i++) { + p[i] = i; + size[i] = 1; + } + } + /** + * Find the representative vertex + * + * @param i + * @return + */ + private int findSet(int i) { + if (p[i] != i) { + p[i] = findSet(p[i]); + } + return p[i]; + } + + /** + * Perform union of two vertex + * + * @param i + * @param j + * @return true if union is performed successfully, false otherwise + */ + public boolean union(int i, int j) { + int x = findSet(i); + int y = findSet(j); + if (x != y) { + if (rank[x] > rank[y]) { + p[y] = p[x]; + size[x] = size[x] + size[y]; + } else { + p[x] = p[y]; + size[y] = size[x] + size[y]; + if (rank[x] == rank[y]) { + rank[y]++; // increment the rank + } + } + return true; + } + return false; + } + + /** + * is attached to roof + * + * @param i + * @return + */ + public int size(int i) { + return size[findSet(i)]; + } + } + + public static void main(String[] args) { + int[] A = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + System.out.println(new LargestComponentSizebyCommonFactor().largestComponentSize(A)); + } + + public int largestComponentSize(int[] A) { + int max = 0; + for (int a : A) { + max = Math.max(max, a); + } + UnionFind unionFind = new UnionFind(max + 1); + List primeNums = primes(max, A); + int answer = 1; + for (int p : primeNums) { + int curr = -1; + for (int a : A) { + if ((a % p) == 0) { + if (curr != -1) { + unionFind.union(curr, a); + } else curr = a; + } + } + answer = Math.max(answer, unionFind.size(curr)); + } + return answer; + } + + private List primes(int N, int[] A) { + boolean[] P = new boolean[N + 1]; + int[] pF = new int[N + 1]; + int sqRt = (int) Math.sqrt(N); + for (int i = 2; i <= sqRt; i++) { + if (!P[i]) { + for (int j = 2; ; j++) { + if (i * j > N) break; + P[i * j] = true; + if (pF[i * j] == 0) { + pF[i * j] = i; + } + } + } + } + Map result = new HashMap<>(); + for (int a : A) { + if (a == 1) continue; + int n = pF[a]; + while (n != 0) { + result.putIfAbsent(n, 0); + result.put(n, result.get(n) + 1); + a /= n; + n = pF[a]; + } + result.putIfAbsent(a, 0); + result.put(a, result.get(a) + 1); + } + return result.keySet().stream().filter(x -> result.get(x) > 1).collect(Collectors.toList()); + } +} diff --git a/src/main/java/math/MinimumIndexSumOfTwoLists.java b/src/main/java/math/MinimumIndexSumOfTwoLists.java new file mode 100644 index 00000000..19acde3b --- /dev/null +++ b/src/main/java/math/MinimumIndexSumOfTwoLists.java @@ -0,0 +1,61 @@ +/* (C) 2024 YourCompanyName */ +package math; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 09/10/2019 Suppose Andy and Doris want to choose a restaurant + * for dinner, and they both have a list of favorite restaurants represented by strings. + * + *

You need to help them find out their common interest with the least list index sum. If there + * is a choice tie between answers, output all of them with no order requirement. You could assume + * there always exists an answer. + * + *

Example 1: Input: ["Shogun", "Tapioca Express", "Burger King", "KFC"] ["Piatti", "The Grill at + * Torrey Pines", "Hungry Hunter Steakhouse", "Shogun"] Output: ["Shogun"] Explanation: The only + * restaurant they both like is "Shogun". Example 2: Input: ["Shogun", "Tapioca Express", "Burger + * King", "KFC"] ["KFC", "Shogun", "Burger King"] Output: ["Shogun"] Explanation: The restaurant + * they both like and have the least index sum is "Shogun" with index sum 1 (0+1). Note: The length + * of both lists will be in the range of [1, 1000]. The length of strings in both lists will be in + * the range of [1, 30]. The index is starting from 0 to the list length minus 1. No duplicates in + * both lists. + * + *

Solution O(N) Maintain a hashmap of restaurant_name with index for one of the list. In the + * first iteration calculate the minimum of sum of indices and in the second iteration add the + * restaurant name to the list if any sum of indices equals the minimum. + */ +public class MinimumIndexSumOfTwoLists { + public static void main(String[] args) { + // + } + + public String[] findRestaurant(String[] list1, String[] list2) { + Map index = new HashMap<>(); + for (int i = 0; i < list2.length; i++) { + String s = list2[i]; + index.put(s, i); + } + int min = Integer.MAX_VALUE; + List list = new ArrayList<>(); + for (int i = 0; i < list1.length; i++) { + if (index.containsKey(list1[i])) { + if (i + index.get(list1[i]) <= min) { + min = i + index.get(list1[i]); + } + } + } + for (int i = 0; i < list1.length; i++) { + if (index.containsKey(list1[i])) { + if (i + index.get(list1[i]) == min) { + list.add(list1[i]); + } + } + } + String[] ans = new String[list.size()]; + int i = 0; + for (String s : list) { + ans[i++] = s; + } + return ans; + } +} diff --git a/src/main/java/math/NthDigit.java b/src/main/java/math/NthDigit.java new file mode 100644 index 00000000..eb02406d --- /dev/null +++ b/src/main/java/math/NthDigit.java @@ -0,0 +1,28 @@ +/* (C) 2024 YourCompanyName */ +package math; + +/** Created by gouthamvidyapradhan on 05/11/2019 */ +public class NthDigit { + public static void main(String[] args) { + System.out.println(new NthDigit().findNthDigit(1000000000)); + } + + public int findNthDigit(int n) { + if (n >= 1 && n <= 9) return n; + long sum = 0L; + for (int i = 0; ; i++) { + long pow = (9 * (new Double(Math.pow(10, i)).longValue())) * (i + 1); + sum += pow; + if (sum >= n) { + long diff = (long) n - (sum - pow); + long num = diff / (i + 1); + long mod = diff % (i + 1); + long result = new Double(Math.pow(10, i)).intValue() + (num - 1) + (mod > 0 ? 1 : 0); + String resultStr = String.valueOf(result); + return (mod == 0) + ? Integer.parseInt(String.valueOf(resultStr.charAt(resultStr.length() - 1))) + : Integer.parseInt(String.valueOf(resultStr.charAt((int) mod - 1))); + } + } + } +} diff --git a/src/main/java/math/NthMagicalNumber.java b/src/main/java/math/NthMagicalNumber.java new file mode 100644 index 00000000..9f957863 --- /dev/null +++ b/src/main/java/math/NthMagicalNumber.java @@ -0,0 +1,80 @@ +/* (C) 2024 YourCompanyName */ +package math; + +import java.math.BigInteger; + +/** + * Created by gouthamvidyapradhan on 23/03/2019 A positive integer is magical if it is divisible by + * either A or B. + * + *

Return the N-th magical number. Since the answer may be very large, return it modulo 10^9 + 7. + * + *

Example 1: + * + *

Input: N = 1, A = 2, B = 3 Output: 2 Example 2: + * + *

Input: N = 4, A = 2, B = 3 Output: 6 Example 3: + * + *

Input: N = 5, A = 2, B = 4 Output: 10 Example 4: + * + *

Input: N = 3, A = 6, B = 4 Output: 8 + * + *

Note: + * + *

1 <= N <= 10^9 2 <= A <= 40000 2 <= B <= 40000 + * + *

Solution: O(log((2 ^ 64) - 1)) Lets take example of N = 5, A = 4 and B = 6 The multiple of A + * are 4, 8, 12, 16, 20, 24 . . . The multiple of B are 6, 12, 18, 24 . . . + * + *

Lets take a arbitrary number E = 21 and see if this fits the correct answer E / A = 5 E / B = + * 3 This means there are 5 + 3 = 8 numbers which are divisible by either A or B such as 4, 6, 8, + * 12, 12, 16, 18, 20 but we have double counted number 12 so we have to reduce 8 by 1 therefore + * there are 7 numbers. But, 7 is greater than required number N = 5 that means we have to search + * between 0 and E - 1. Thus we can binary search to arrive at the answer. + * + *

The number of common multiples such as 12 in the above example can be found by E / LCM(4, 6) + */ +public class NthMagicalNumber { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + System.out.println(new NthMagicalNumber().nthMagicalNumber(3, 2, 4)); + } + + public int nthMagicalNumber(int N, int A, int B) { + final int CONST = 1000000007; + BigInteger bigInteger = new BigInteger(String.valueOf(A)); + long aL = (long) A * B; + long lcm = aL / bigInteger.gcd(new BigInteger(String.valueOf(B))).longValue(); + long l = 0, h = Long.MAX_VALUE; + while (l <= h) { + long m = l + (h - l) / 2; + int status = check(N, m, A, B, lcm); + if (status == 0) { + long modA = m % A; + long modB = m % B; + if (modA == 0 || modB == 0) return (int) (m % CONST); + else if (modA < modB) return (int) ((m - modA) % CONST); + else return (int) ((m - modB) % CONST); + } else if (status == -1) { + l = m + 1; + } else { + h = m - 1; + } + } + return 0; + } + + private int check(int N, long num, int A, int B, long lcm) { + long sum = (num / A) + (num / B); + long common = num / lcm; + sum -= common; + if (sum == N) return 0; + else if (sum > N) return 1; + else return -1; + } +} diff --git a/src/main/java/math/ProjectionAreaOf3DShapes.java b/src/main/java/math/ProjectionAreaOf3DShapes.java new file mode 100644 index 00000000..1416f844 --- /dev/null +++ b/src/main/java/math/ProjectionAreaOf3DShapes.java @@ -0,0 +1,74 @@ +/* (C) 2024 YourCompanyName */ +package math; +/** + * Created by gouthamvidyapradhan on 09/05/2019 + * + *

On a N * N grid, we place some 1 * 1 * 1 cubes that are axis-aligned with the x, y, and z + * axes. + * + *

Each value v = grid[i][j] represents a tower of v cubes placed on top of grid cell (i, j). + * + *

Now we view the projection of these cubes onto the xy, yz, and zx planes. + * + *

A projection is like a shadow, that maps our 3 dimensional figure to a 2 dimensional plane. + * + *

Here, we are viewing the "shadow" when looking at the cubes from the top, the front, and the + * side. + * + *

Return the total area of all three projections. + * + *

Example 1: + * + *

Input: [[2]] Output: 5 Example 2: + * + *

Input: [[1,2],[3,4]] Output: 17 Explanation: Here are the three projections ("shadows") of the + * shape made with each axis-aligned plane. + * + *

Example 3: + * + *

Input: [[1,0],[0,2]] Output: 8 Example 4: + * + *

Input: [[1,1,1],[1,0,1],[1,1,1]] Output: 14 Example 5: + * + *

Input: [[2,2,2],[2,1,2],[2,2,2]] Output: 21 + * + *

Note: + * + *

1 <= grid.length = grid[0].length <= 50 0 <= grid[i][j] <= 50 + * + *

Solution O(N x N) project the view on all three different planes. For top view its pretty + * simple because area of each cube is just 1 * 1, for all other planes take the maximum value of + * each grid. Sum up values on each planes + */ +public class ProjectionAreaOf3DShapes { + public static void main(String[] args) { + // + } + + public int projectionArea(int[][] grid) { + int area = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid.length; j++) { + area += (grid[i][j] > 0 ? 1 : 0); + } + } + + for (int i = 0; i < grid.length; i++) { + int max = 0; + for (int j = 0; j < grid[0].length; j++) { + max = Math.max(max, grid[i][j]); + } + area += max; + } + + for (int i = 0; i < grid[0].length; i++) { + int max = 0; + for (int j = 0; j < grid.length; j++) { + max = Math.max(max, grid[j][i]); + } + area += max; + } + + return area; + } +} diff --git a/src/main/java/math/RangeAdditionII.java b/src/main/java/math/RangeAdditionII.java new file mode 100644 index 00000000..17f197e4 --- /dev/null +++ b/src/main/java/math/RangeAdditionII.java @@ -0,0 +1,45 @@ +/* (C) 2024 YourCompanyName */ +package math; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 09/10/2019 Given an m * n matrix M initialized with all 0's and + * several update operations. + * + *

Operations are represented by a 2D array, and each operation is represented by an array with + * two positive integers a and b, which means M[i][j] should be added by one for all 0 <= i < a and + * 0 <= j < b. + * + *

You need to count and return the number of maximum integers in the matrix after performing all + * the operations. + * + *

Example 1: Input: m = 3, n = 3 operations = [[2,2],[3,3]] Output: 4 Explanation: Initially, M + * = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] + * + *

After performing [2,2], M = [[1, 1, 0], [1, 1, 0], [0, 0, 0]] + * + *

After performing [3,3], M = [[2, 2, 1], [2, 2, 1], [1, 1, 1]] + * + *

So the maximum integer in M is 2, and there are four of it in M. So return 4. Note: The range + * of m and n is [1,40000]. The range of a is [1,m], and the range of b is [1,n]. The range of + * operations size won't exceed 10,000. + * + *

Solution: O(N) where N is the number of operations. For every operation, keep track of minimum + * of each row and column and return the product of minR x minC + */ +public class RangeAdditionII { + public static void main(String[] args) { + // + } + + public int maxCount(int m, int n, int[][] ops) { + int minR = m; + int minC = n; + for (int[] v : ops) { + minR = Math.min(minR, v[0]); + minC = Math.min(minC, v[1]); + } + return minR * minC; + } +} diff --git a/src/main/java/math/ReachingPoints.java b/src/main/java/math/ReachingPoints.java new file mode 100644 index 00000000..36036e4c --- /dev/null +++ b/src/main/java/math/ReachingPoints.java @@ -0,0 +1,84 @@ +/* (C) 2024 YourCompanyName */ +package math; + +/** + * Created by gouthamvidyapradhan on 14/07/2018. A move consists of taking a point (x, y) and + * transforming it to either (x, x+y) or (x+y, y). + * + *

Given a starting point (sx, sy) and a target point (tx, ty), return True if and only if a + * sequence of moves exists to transform the point (sx, sy) to (tx, ty). Otherwise, return False. + * + *

Examples: Input: sx = 1, sy = 1, tx = 3, ty = 5 Output: True Explanation: One series of moves + * that transforms the starting point to the target is: (1, 1) -> (1, 2) (1, 2) -> (3, 2) (3, 2) -> + * (3, 5) + * + *

Input: sx = 1, sy = 1, tx = 2, ty = 2 Output: False + * + *

Input: sx = 1, sy = 1, tx = 1, ty = 1 Output: True + * + *

Note: + * + *

sx, sy, tx, ty will all be integers in the range [1, 10^9]. + * + *

Solution: Start from the target, reduce the target value to start value. If at any stage the + * target value goes below start value then there exist no solution hence return false. + */ +public class ReachingPoints { + + class Pair { + int x, y; + + Pair(int x, int y) { + this.x = x; + this.y = y; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new ReachingPoints().reachingPoints(1, 1, 153, 10)); + } + + public boolean reachingPoints(int sx, int sy, int tx, int ty) { + Pair target = new Pair(tx, ty); + Pair start = new Pair(sx, sy); + while (true) { + if (start.x == target.x && start.y == target.y) { + return true; + } else if (start.x > target.x || start.y > target.y || target.x == target.y) { + return false; + } else if (start.x == target.x) { + int t = target.y - start.y; + return (t % target.x) == 0; + } else if (start.y == target.y) { + int t = target.x - start.x; + return (t % target.y) == 0; + } else { + if (target.x > target.y) { + int[] R = reduce(target.x, target.y); + target.x = R[0]; + target.y = R[1]; + } else { + int[] R = reduce(target.y, target.x); + target.x = R[1]; + target.y = R[0]; + } + } + } + } + + private int[] reduce(int x, int y) { + int t = x - y; + int q = t / y; + x -= (y * q); + if ((t % y) != 0) { + x -= y; + } + return new int[] {x, y}; + } +} diff --git a/src/main/java/math/RectangleOverlap.java b/src/main/java/math/RectangleOverlap.java new file mode 100644 index 00000000..dd8d32b2 --- /dev/null +++ b/src/main/java/math/RectangleOverlap.java @@ -0,0 +1,37 @@ +/* (C) 2024 YourCompanyName */ +package math; + +/** + * Created by gouthamvidyapradhan on 30/11/2019 A rectangle is represented as a list [x1, y1, x2, + * y2], where (x1, y1) are the coordinates of its bottom-left corner, and (x2, y2) are the + * coordinates of its top-right corner. + * + *

Two rectangles overlap if the area of their intersection is positive. To be clear, two + * rectangles that only touch at the corner or edges do not overlap. + * + *

Given two (axis-aligned) rectangles, return whether they overlap. + * + *

Example 1: + * + *

Input: rec1 = [0,0,2,2], rec2 = [1,1,3,3] Output: true Example 2: + * + *

Input: rec1 = [0,0,1,1], rec2 = [1,0,2,1] Output: false Notes: + * + *

Both rectangles rec1 and rec2 are lists of 4 integers. All coordinates in rectangles will be + * between -10^9 and 10^9. + */ +public class RectangleOverlap { + public static void main(String[] args) { + int[] A = {0, 0, 2, 2}; + int[] B = {1, 1, 3, 3}; + System.out.println(new RectangleOverlap().isRectangleOverlap(A, B)); + } + + public boolean isRectangleOverlap(int[] rec1, int[] rec2) { + boolean x = + ((rec1[0] >= rec2[0] && rec1[0] < rec2[2]) || (rec2[0] >= rec1[0] && rec2[0] < rec1[2])); + boolean y = + ((rec1[1] >= rec2[1] && rec1[1] < rec2[3]) || (rec2[1] >= rec1[1] && rec2[1] < rec1[3])); + return x && y; + } +} diff --git a/src/main/java/math/RomanToInteger.java b/src/main/java/math/RomanToInteger.java new file mode 100644 index 00000000..273ec3c4 --- /dev/null +++ b/src/main/java/math/RomanToInteger.java @@ -0,0 +1,49 @@ +/* (C) 2024 YourCompanyName */ +package math; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 12/08/2017. + * + *

Given a roman numeral, convert it to an integer. + * + *

Input is guaranteed to be within the range from 1 to 3999. + */ +public class RomanToInteger { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new RomanToInteger().romanToInt("DXCIX")); + } + + public int romanToInt(String s) { + Map map = new HashMap<>(); + map.put('I', 1); + map.put('V', 5); + map.put('X', 10); + map.put('L', 50); + map.put('C', 100); + map.put('D', 500); + map.put('M', 1000); + + String str = new StringBuilder(s).reverse().toString(); + int sum = 0, prev = -1; + for (int i = 0, l = str.length(); i < l; i++) { + int curr = map.get(str.charAt(i)); + if (curr < prev) { + sum -= curr; + } else { + sum += curr; + } + prev = curr; + } + + return sum; + } +} diff --git a/src/main/java/math/RotateFunction.java b/src/main/java/math/RotateFunction.java new file mode 100644 index 00000000..c634ea54 --- /dev/null +++ b/src/main/java/math/RotateFunction.java @@ -0,0 +1,55 @@ +/* (C) 2024 YourCompanyName */ +package math; + +/** + * Created by gouthamvidyapradhan on 18/03/2017. Given an array of integers A and let n to be its + * length. + * + *

Assume Bk to be an array obtained by rotating the array A k positions clock-wise, we define a + * "rotation function" F on A as follow: + * + *

F(k) = 0 * Bk[0] + 1 * Bk[1] + ... + (n-1) * Bk[n-1]. + * + *

Calculate the maximum value of F(0), F(1), ..., F(n-1). + * + *

Note: n is guaranteed to be less than 105. + * + *

Example: + * + *

A = [4, 3, 2, 6] + * + *

F(0) = (0 * 4) + (1 * 3) + (2 * 2) + (3 * 6) = 0 + 3 + 4 + 18 = 25 F(1) = (0 * 6) + (1 * 4) + + * (2 * 3) + (3 * 2) = 0 + 4 + 6 + 6 = 16 F(2) = (0 * 2) + (1 * 6) + (2 * 4) + (3 * 3) = 0 + 6 + 8 + + * 9 = 23 F(3) = (0 * 3) + (1 * 2) + (2 * 6) + (3 * 4) = 0 + 2 + 12 + 12 = 26 + * + *

So the maximum value of F(0), F(1), F(2), F(3) is F(3) = 26. + */ +public class RotateFunction { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] a = {4, 3, 2, 6}; + System.out.println(new RotateFunction().maxRotateFunction(a)); + } + + public int maxRotateFunction(int[] A) { + if (A.length == 0 || A.length == 1) return 0; + int max = Integer.MIN_VALUE; + int l = A.length; + int sum = 0, prodSum = 0; + for (int i = 0; i < l; i++) { + prodSum += (A[i] * i); + sum += A[i]; + } + max = Math.max(max, prodSum); + for (int i = 0; i < l - 1; i++) { + prodSum = (prodSum - sum + A[i] + ((l - 1) * A[i])); + max = Math.max(max, prodSum); + } + return max; + } +} diff --git a/src/main/java/math/SmallestRangeI.java b/src/main/java/math/SmallestRangeI.java new file mode 100644 index 00000000..fa5e1bb0 --- /dev/null +++ b/src/main/java/math/SmallestRangeI.java @@ -0,0 +1,44 @@ +/* (C) 2024 YourCompanyName */ +package math; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 22/08/2019 Given an array A of integers, for each integer A[i] + * we may choose any x with -K <= x <= K, and add x to A[i]. + * + *

After this process, we have some array B. + * + *

Return the smallest possible difference between the maximum value of B and the minimum value + * of B. + * + *

Example 1: + * + *

Input: A = [1], K = 0 Output: 0 Explanation: B = [1] Example 2: + * + *

Input: A = [0,10], K = 2 Output: 6 Explanation: B = [2,8] Example 3: + * + *

Input: A = [1,3,6], K = 3 Output: 0 Explanation: B = [3,3,3] or B = [4,4,4] + * + *

Note: + * + *

1 <= A.length <= 10000 0 <= A[i] <= 10000 0 <= K <= 10000 + */ +public class SmallestRangeI { + public static void main(String[] args) { + // + } + + public int smallestRangeI(int[] A, int K) { + Arrays.sort(A); + if (A.length == 0 || A.length == 1) return 0; + else { + int low = A[0]; + int high = A[A.length - 1]; + int l = low + (K); + int r = high - (K); + if (r > l) return r - l; + else return 0; + } + } +} diff --git a/src/main/java/math/SolveTheEquation.java b/src/main/java/math/SolveTheEquation.java new file mode 100644 index 00000000..b829ad6c --- /dev/null +++ b/src/main/java/math/SolveTheEquation.java @@ -0,0 +1,106 @@ +/* (C) 2024 YourCompanyName */ +package math; + +/** + * Created by gouthamvidyapradhan on 16/02/2018. Solve a given equation and return the value of x in + * the form of string "x=#value". The equation contains only '+', '-' operation, the variable x and + * its coefficient. + * + *

If there is no solution for the equation, return "No solution". + * + *

If there are infinite solutions for the equation, return "Infinite solutions". + * + *

If there is exactly one solution for the equation, we ensure that the value of x is an + * integer. + * + *

Example 1: Input: "x+5-3+x=6+x-2" Output: "x=2" Example 2: Input: "x=x" Output: "Infinite + * solutions" Example 3: Input: "2x=x" Output: "x=0" Example 4: Input: "2x+3x-6x=x+2" Output: "x=-1" + * Example 5: Input: "x=x+2" Output: "No solution" + * + *

Solution: Solve the left and right part separately and then sum up the results. + */ +public class SolveTheEquation { + + int xL = 0, xR = 0, tL = 0, tR = 0; + + public static void main(String[] args) throws Exception { + System.out.println(new SolveTheEquation().solveEquation("x=x+2")); + } + + public String solveEquation(String equation) { + String[] parts = equation.split("="); + solve(parts[0], true); + solve(parts[1], false); + long right = (long) tR - tL; + long left = (long) xL - xR; + if (left == 0 && right == 0) { + return "Infinite solutions"; + } else if (left == 0) { + return "No solution"; + } else if (right == 0) { + return "x=0"; + } else { + return "x=" + (right / left); + } + } + + private void solve(String s, boolean isLeft) { + String num = ""; + int xSum = 0; + int rest = 0; + boolean isNeg = false; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '-') { + if (!num.isEmpty()) { + xSum = calculate(num, isNeg, xSum, rest)[0]; + rest = calculate(num, isNeg, xSum, rest)[1]; + } + isNeg = true; + num = ""; + } else if (c == '+') { + if (!num.isEmpty()) { + xSum = calculate(num, isNeg, xSum, rest)[0]; + rest = calculate(num, isNeg, xSum, rest)[1]; + } + isNeg = false; + num = ""; + } else { + num += c; + } + } + if (!num.isEmpty()) { + xSum = calculate(num, isNeg, xSum, rest)[0]; + rest = calculate(num, isNeg, xSum, rest)[1]; + } + if (isLeft) { + xL = xSum; + tL = rest; + } else { + xR = xSum; + tR = rest; + } + } + + private int[] calculate(String num, boolean isNeg, int xSum, int rest) { + int[] A = new int[2]; + if (num.contains("x")) { + num = num.substring(0, num.length() - 1); + if (isNeg) { + xSum -= num.isEmpty() ? 1 : Integer.parseInt(num); + } else { + xSum += num.isEmpty() ? 1 : Integer.parseInt(num); + } + + } else { + if (isNeg) { + rest -= Integer.parseInt(num); + } else { + rest += Integer.parseInt(num); + } + } + A[0] = xSum; + A[1] = rest; + return A; + } +} diff --git a/src/main/java/math/SquirrelSimulation.java b/src/main/java/math/SquirrelSimulation.java new file mode 100644 index 00000000..4b40f2f3 --- /dev/null +++ b/src/main/java/math/SquirrelSimulation.java @@ -0,0 +1,46 @@ +/* (C) 2024 YourCompanyName */ +package math; + +/** + * Created by gouthamvidyapradhan on 25/04/2019 There's a tree, a squirrel, and several nuts. + * Positions are represented by the cells in a 2D grid. Your goal is to find the minimal distance + * for the squirrel to collect all the nuts and put them under the tree one by one. The squirrel can + * only take at most one nut at one time and can move in four directions - up, down, left and right, + * to the adjacent cell. The distance is represented by the number of moves. Example 1: + * + *

Input: Height : 5 Width : 7 Tree position : [2,2] Squirrel : [4,4] Nuts : [[3,0], [2,5]] + * Output: 12 Explanation: ​​​​​ Note: + * + *

All given positions won't overlap. The squirrel can take at most one nut at one time. The + * given positions of nuts have no order. Height and width are positive integers. 3 <= height * + * width <= 10,000. The given positions contain at least one nut, only one tree and one squirrel. + * + *

Solution O(N) Calculate the Manhattan Distance from each of the nut to the tree and double + * this value - Let this value be D. We are doubling here to simulate going from tree to a nut and + * back. Now, to get the minimum distance - for each distance d from squirrel position to nut + * position do, Min(D + d - (distance from this nut to tree)) + */ +public class SquirrelSimulation { + public static void main(String[] args) { + int height = 5; + int width = 7; + int[] tree = {2, 2}; + int[] squirrel = {4, 4}; + int[][] nuts = {{3, 0}, {2, 5}}; + System.out.println(new SquirrelSimulation().minDistance(height, width, tree, squirrel, nuts)); + } + + public int minDistance(int height, int width, int[] tree, int[] squirrel, int[][] nuts) { + int dist = 0; + for (int[] n : nuts) { + dist += Math.abs(n[0] - tree[0]) + Math.abs(n[1] - tree[1]); + } + dist *= 2; + int ans = Integer.MAX_VALUE; + for (int[] n : nuts) { + int nutDist = Math.abs(n[0] - squirrel[0]) + Math.abs(n[1] - squirrel[1]); + ans = Math.min(ans, dist - (Math.abs(n[0] - tree[0]) + Math.abs(n[1] - tree[1])) + nutDist); + } + return ans; + } +} diff --git a/src/main/java/math/SuperWashingMachines.java b/src/main/java/math/SuperWashingMachines.java new file mode 100644 index 00000000..35fa07d5 --- /dev/null +++ b/src/main/java/math/SuperWashingMachines.java @@ -0,0 +1,56 @@ +/* (C) 2024 YourCompanyName */ +package math; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 30/01/2020 You have n super washing machines on a line. + * Initially, each washing machine has some dresses or is empty. + * + *

For each move, you could choose any m (1 ≤ m ≤ n) washing machines, and pass one dress of each + * washing machine to one of its adjacent washing machines at the same time . + * + *

Given an integer array representing the number of dresses in each washing machine from left to + * right on the line, you should find the minimum number of moves to make all the washing machines + * have the same number of dresses. If it is not possible to do it, return -1. + * + *

Example1 + * + *

Input: [1,0,5] + * + *

Output: 3 + * + *

Explanation: 1st move: 1 0 <-- 5 => 1 1 4 2nd move: 1 <-- 1 <-- 4 => 2 1 3 3rd move: 2 1 <-- 3 + * => 2 2 2 Example2 + * + *

Input: [0,3,0] + * + *

Output: 2 + * + *

Explanation: 1st move: 0 <-- 3 0 => 1 2 0 2nd move: 1 2 --> 0 => 1 1 1 Example3 + * + *

Input: [0,2,0] + * + *

Output: -1 + * + *

Explanation: It's impossible to make all the three washing machines have the same number of + * dresses. Note: The range of n is [1, 10000]. The range of dresses number in a super washing + * machine is [0, 1e5]. + */ +public class SuperWashingMachines { + public static void main(String[] args) { + // + } + + public int findMinMoves(int[] machines) { + long sum = Arrays.stream(machines).asLongStream().sum(); + if (((sum / machines.length) < 0) || ((sum % machines.length) != 0)) return -1; + int n = (int) (sum / machines.length); + int count = 0, moves = Integer.MIN_VALUE; + for (int i = 0; i < machines.length; i++) { + count += (machines[i] - n); + moves = Math.max(moves, Math.max(Math.abs(count), (machines[i] - n))); + } + return moves; + } +} diff --git a/src/main/java/math/WaterAndJugProblem.java b/src/main/java/math/WaterAndJugProblem.java new file mode 100644 index 00000000..dfc239b0 --- /dev/null +++ b/src/main/java/math/WaterAndJugProblem.java @@ -0,0 +1,43 @@ +/* (C) 2024 YourCompanyName */ +package math; + +import java.math.BigInteger; + +/** + * Created by gouthamvidyapradhan on 29/07/2017. You are given two jugs with capacities x and y + * litres. There is an infinite amount of water supply available. You need to determine whether it + * is possible to measure exactly z litres using these two jugs. + * + *

If z liters of water is measurable, you must have z liters of water contained within one or + * both buckets by the end. + * + *

Operations allowed: + * + *

Fill any of the jugs completely with water. Empty any of the jugs. Pour water from one jug + * into another till the other jug is completely full or the first jug itself is empty. Example 1: + * (From the famous "Die Hard" example) + * + *

Input: x = 3, y = 5, z = 4 Output: True Example 2: + * + *

Input: x = 2, y = 6, z = 5 Output: False + */ +public class WaterAndJugProblem { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new WaterAndJugProblem().canMeasureWater(0, 0, 1)); + } + + public boolean canMeasureWater(int x, int y, int z) { + if (x == y && y == z) return true; + if (z > (x + y)) return false; + BigInteger b1 = new BigInteger(String.valueOf(x)); + BigInteger b2 = new BigInteger(String.valueOf(y)); + BigInteger b3 = b1.gcd(b2); + return b3.intValue() != 0 && (z % b3.intValue()) == 0; + } +} diff --git a/src/main/java/reservoir_sampling/RandomPickIndex.java b/src/main/java/reservoir_sampling/RandomPickIndex.java new file mode 100644 index 00000000..68d6e750 --- /dev/null +++ b/src/main/java/reservoir_sampling/RandomPickIndex.java @@ -0,0 +1,60 @@ +/* (C) 2024 YourCompanyName */ +package reservoir_sampling; + +import java.util.Random; + +/** + * Created by gouthamvidyapradhan on 10/12/2017. Given an array of integers with possible + * duplicates, randomly output the index of a given target number. You can assume that the given + * target number must exist in the array. + * + *

Note: The array size can be very large. Solution that uses too much extra space will not pass + * the judge. + * + *

Example: + * + *

int[] nums = new int[] {1,2,3,3,3}; Solution solution = new Solution(nums); + * + *

// pick(3) should return either index 2, 3, or 4 randomly. Each index should have equal + * probability of returning. solution.pick(3); + * + *

// pick(1) should return 0. Since in the array only nums[0] is equal to 1. solution.pick(1); + */ +public class RandomPickIndex { + + private int[] nums; + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 2, 3, 3, 3}; + System.out.println(new RandomPickIndex(A).pick(1)); + } + + public RandomPickIndex(int[] nums) { + this.nums = nums; + } + + public int pick(int target) { + int count = 0; + for (int num : nums) { + if (num == target) { + count++; + } + } + Random random = new Random(); + int nPick = 1 + random.nextInt(count); + count = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] == target) { + if (++count == nPick) { + return i; + } + } + } + return 0; // this is impossible + } +} diff --git a/src/main/java/stack/BasicCalculator.java b/src/main/java/stack/BasicCalculator.java new file mode 100644 index 00000000..5338b314 --- /dev/null +++ b/src/main/java/stack/BasicCalculator.java @@ -0,0 +1,85 @@ +/* (C) 2024 YourCompanyName */ +package stack; + +import java.util.Stack; + +/** + * Created by gouthamvidyapradhan on 06/02/2018. Implement a basic calculator to evaluate a simple + * expression string. + * + *

The expression string may contain open ( and closing parentheses ), the plus + or minus sign + * -, non-negative integers and empty spaces . + * + *

You may assume that the given expression is always valid. + * + *

Some examples: "1 + 1" = 2 " 2-1 + 2 " = 3 "(1+(4+5+2)-3)+(6+8)" = 23 Note: Do not use the + * eval built-in library function. + * + *

Solution: O(n) where n is the length of the string. Maintain a stack and push each character + * from the string (ignore space). As soon as a close parentheses ')' is encountered, start to pop + * values and sum-up the total until '(' is poped. Push the total back to stack and continue to + * iterate. The final result will be in the top of the stack which is the last and only element in + * stack. + */ +public class BasicCalculator { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println( + new BasicCalculator().calculate("2-1 + (2 - 3) - ((2 - (2 - (3 - (4 - 5)))))")); + } + + public int calculate(String s) { + Stack stack = new Stack<>(); + String num = ""; + s = "(" + s + ")"; + for (char c : s.toCharArray()) { + switch (c) { + case ' ': + case '(': + case '+': + case '-': + if (!num.equals("")) { + stack.push(String.valueOf(num)); + num = ""; + } + if (c != ' ') { // ignore blank + stack.push(String.valueOf(c)); + } + break; + case ')': + if (!num.equals("")) { + stack.push(String.valueOf(num)); + num = ""; + } + int sum = 0; + int prev = 0; // maintain a prev value inorder to handle minus '-' + while (!stack.isEmpty()) { + String top = stack.pop(); + if (top.equals("-")) { + sum -= (prev * 2); + prev = 0; + } else if (top.equals("+")) { + // ignore + } else if (top.equals("(")) { + stack.push(String.valueOf(sum)); + break; + } else { + sum += Integer.parseInt(top); + prev = Integer.parseInt(top); + } + } + break; + default: + num += String.valueOf(c); + break; + } + } + return Integer.parseInt(stack.peek()); + } +} diff --git a/src/main/java/stack/DecodeString.java b/src/main/java/stack/DecodeString.java new file mode 100644 index 00000000..1e03fb91 --- /dev/null +++ b/src/main/java/stack/DecodeString.java @@ -0,0 +1,69 @@ +/* (C) 2024 YourCompanyName */ +package stack; + +import java.util.Stack; + +/** + * Created by gouthamvidyapradhan on 12/04/2018. Given an encoded string, return it's decoded + * string. + * + *

The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets + * is being repeated exactly k times. Note that k is guaranteed to be a positive integer. + * + *

You may assume that the input string is always valid; No extra white spaces, square brackets + * are well-formed, etc. + * + *

Furthermore, you may assume that the original data does not contain any digits and that digits + * are only for those repeat numbers, k. For example, there won't be input like 3a or 2[4]. + * + *

Examples: + * + *

s = "3[a]2[bc]", return "aaabcbc". s = "3[a2[c]]", return "accaccacc". s = "2[abc]3[cd]ef", + * return "abcabccdcdcdef". + * + *

Solution: Maintain a stack and push items when a character other than ] is encountered. When a + * character ] is encountered pop elements, build string and duplicate it. + */ +public class DecodeString { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new DecodeString().decodeString("100[leetcode]")); + } + + public String decodeString(String s) { + Stack stack = new Stack<>(); + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == ']') { + StringBuilder stackBuff = new StringBuilder(); + while (stack.peek() != '[') { + stackBuff.append(stack.pop()); + } + stack.pop(); // pop '[' + String num = ""; + while (!stack.isEmpty() && !Character.isAlphabetic(stack.peek()) && stack.peek() != '[') { + num = stack.pop() + num; + } + String str = stackBuff.reverse().toString(); + StringBuilder stringMultiple = new StringBuilder(); + int N = Integer.parseInt(num); + while (N-- > 0) { + stringMultiple.append(str); + } + for (int j = 0; j < stringMultiple.length(); j++) { + stack.push(stringMultiple.charAt(j)); + } + } else stack.push(s.charAt(i)); + } + StringBuilder result = new StringBuilder(); + while (!stack.isEmpty()) { + result.append(stack.pop()); + } + return result.reverse().toString(); + } +} diff --git a/src/main/java/stack/DecodedStringAtIndex.java b/src/main/java/stack/DecodedStringAtIndex.java new file mode 100644 index 00000000..47f8d3f8 --- /dev/null +++ b/src/main/java/stack/DecodedStringAtIndex.java @@ -0,0 +1,69 @@ +/* (C) 2024 YourCompanyName */ +package stack; + +import java.util.Stack; + +/** Created by gouthamvidyapradhan on 12/05/2019 */ +public class DecodedStringAtIndex { + + public static void main(String[] args) { + System.out.println(new DecodedStringAtIndex().decodeAtIndex("ha22", 5)); + } + + class Node { + String S; + long count; + int multiple; + + Node(String S, long count, int multiple) { + this.S = S; + this.count = count; + this.multiple = multiple; + } + } + + public String decodeAtIndex(String S, int K) { + Stack stack = new Stack<>(); + StringBuilder sb = new StringBuilder(); + char prev = ' '; + for (char c : S.toCharArray()) { + if (Character.isDigit(c)) { + String currStr = sb.toString(); + long len = 0L; + if (!stack.isEmpty()) { + len = stack.peek().count * stack.peek().multiple; + } + stack.push( + new Node(currStr, len + (currStr.length()), Integer.parseInt(String.valueOf(c)))); + if (((len + (currStr.length())) * Integer.parseInt(String.valueOf(c))) >= K) { + break; + } + prev = c; + } else { + if (Character.isDigit(prev)) { + sb = new StringBuilder(); + } + sb.append(c); + prev = c; + } + } + while (!stack.isEmpty()) { + Node top = stack.peek(); + long l = top.count; + if (K <= l) { + return String.valueOf(top.S.charAt((int) l - K - 1)); + } + long mod = (K % l); + if (mod == 0) { + return String.valueOf(top.S.charAt(top.S.length() - 1)); + } + if (l - top.S.length() < mod) { + long i = l - mod; + return String.valueOf(top.S.charAt(top.S.length() - (int) i - 1)); + } else { + stack.pop(); + } + } + return ""; + } +} diff --git a/src/main/java/stack/ExclusiveTimeOfFunctions.java b/src/main/java/stack/ExclusiveTimeOfFunctions.java new file mode 100644 index 00000000..23890ad6 --- /dev/null +++ b/src/main/java/stack/ExclusiveTimeOfFunctions.java @@ -0,0 +1,93 @@ +/* (C) 2024 YourCompanyName */ +package stack; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Stack; + +/** + * Created by gouthamvidyapradhan on 20/01/2018. Given the running logs of n functions that are + * executed in a nonpreemptive single threaded CPU, find the exclusive time of these functions. + * + *

Each function has a unique id, start from 0 to n-1. A function may be called recursively or by + * another function. + * + *

A log is a string has this format : function_id:start_or_end:timestamp. For example, + * "0:start:0" means function 0 starts from the very beginning of time 0. "0:end:0" means function 0 + * ends to the very end of time 0. + * + *

Exclusive time of a function is defined as the time spent within this function, the time spent + * by calling other functions should not be considered as this function's exclusive time. You should + * return the exclusive time of each function sorted by their function id. + * + *

Example 1: Input: n = 2 logs = ["0:start:0", "1:start:2", "1:end:5", "0:end:6"] Output:[3, 4] + * Explanation: Function 0 starts at time 0, then it executes 2 units of time and reaches the end of + * time 1. Now function 0 calls function 1, function 1 starts at time 2, executes 4 units of time + * and end at time 5. Function 0 is running again at time 6, and also end at the time 6, thus + * executes 1 unit of time. So function 0 totally execute 2 + 1 = 3 units of time, and function 1 + * totally execute 4 units of time. Note: Input logs will be sorted by timestamp, NOT log id. Your + * output should be sorted by function id, which means the 0th element of your output corresponds to + * the exclusive time of function 0. Two functions won't start or end at the same time. Functions + * could be called recursively, and will always end. 1 <= n <= 100 + * + *

Solution: Use a stack to store the logs and update time. + */ +public class ExclusiveTimeOfFunctions { + + class Log { + int funId, time; + String fun; + + Log(int funId, String fun, int time) { + this.funId = funId; + this.fun = fun; + this.time = time; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] N = + new ExclusiveTimeOfFunctions() + .exclusiveTime(2, Arrays.asList("0:start:0", "1:start:2", "1:end:5", "0:end:6")); + Arrays.stream(N).forEach(System.out::println); + } + + public int[] exclusiveTime(int n, List logs) { + int[] N = new int[n]; + List functions = new ArrayList<>(); + for (String s : logs) { + String[] parts = s.split(":"); + functions.add(new Log(Integer.parseInt(parts[0]), parts[1], Integer.parseInt(parts[2]))); + } + Stack stack = new Stack<>(); + stack.push(functions.get(0)); + for (int i = 1, l = functions.size(); i < l; i++) { + Log next = functions.get(i); + if (stack.isEmpty()) { + stack.push(next); + continue; + } + Log curr = stack.peek(); + if (next.fun.equals("end")) { + N[curr.funId] += (next.time - curr.time + 1); + stack.pop(); // since the end has reached, remove from stack + if (!stack.isEmpty()) { + stack.peek().time = + next.time + 1; // IMPORTANT: update the time of the old function to a new start + // time + } + } else { + stack.push(next); + N[curr.funId] += (next.time - curr.time); + } + } + return N; + } +} diff --git a/src/main/java/stack/LargestRectangleInHistogram.java b/src/main/java/stack/LargestRectangleInHistogram.java new file mode 100644 index 00000000..9c53b2e6 --- /dev/null +++ b/src/main/java/stack/LargestRectangleInHistogram.java @@ -0,0 +1,54 @@ +/* (C) 2024 YourCompanyName */ +package stack; + +import java.util.Stack; + +/** + * Created by gouthamvidyapradhan on 20/06/2017. Given n non-negative integers representing the + * histogram's bar height where the width of each bar is 1, find the area of largest rectangle in + * the histogram. + * + *

For example, Given heights = [2,1,5,6,2,3], return 10. (min of index 2 and 3 multiplied by + * two) + * + *

Solution O(N): + * + *

1) Create an empty stack. + * + *

2) Start from first bar, and do following for every bar ‘hist[i]’ where ‘i’ varies from 0 to + * n-1. a) If stack is empty or hist[i] is higher than the bar at top of stack, then push ‘i’ to + * stack. b) If this bar is smaller than the top of stack, then keep removing the top of stack while + * top of the stack is greater. Let the removed bar be hist[tp]. Calculate area of rectangle with + * hist[tp] as smallest bar. For hist[tp], the ‘left index’ is previous (previous to tp) item in + * stack and ‘right index’ is ‘i’ (current index). + * + *

3) If the stack is not empty, then one by one remove all bars from stack and do step 2.b for + * every removed bar. + */ +public class LargestRectangleInHistogram { + public static void main(String[] args) throws Exception { + int[] A = {2, 3}; + System.out.println(new LargestRectangleInHistogram().largestRectangleArea(A)); + } + + public int largestRectangleArea(int[] heights) { + if (heights.length == 0) return 0; + int maxArea = Integer.MIN_VALUE; + Stack stack = new Stack<>(); + int i = 0; + for (; i < heights.length; i++) { + while (!stack.isEmpty() && heights[stack.peek()] >= heights[i]) { + int top = stack.pop(); + int base = stack.isEmpty() ? i : i - stack.peek() - 1; + maxArea = Math.max(maxArea, base * heights[top]); + } + stack.push(i); + } + while (!stack.isEmpty()) { + int top = stack.pop(); + int base = stack.isEmpty() ? i : i - stack.peek() - 1; + maxArea = Math.max(maxArea, base * heights[top]); + } + return maxArea; + } +} diff --git a/src/main/java/stack/LongestValidParentheses.java b/src/main/java/stack/LongestValidParentheses.java new file mode 100644 index 00000000..3535b33d --- /dev/null +++ b/src/main/java/stack/LongestValidParentheses.java @@ -0,0 +1,70 @@ +/* (C) 2024 YourCompanyName */ +package stack; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 08/07/2018. Given a string containing just the characters '(' + * and ')', find the length of the longest valid (well-formed) parentheses substring. + * + *

Example 1: + * + *

Input: "(()" Output: 2 Explanation: The longest valid parentheses substring is "()" Example 2: + * + *

Input: ")()())" Output: 4 Explanation: The longest valid parentheses substring is "()()" + * + *

Solution: O(N) Iterate through each of the parentheses and if '(' is encountered push it to + * stack else check the top of the stack to see if there is a matching parentheses, if yes pop it + * and then take the length (currIndex - index at top of the stack). Maintain a max length and + * return this as the answer. + */ +public class LongestValidParentheses { + + private class Node { + char c; + int i; + + Node(char c, int i) { + this.c = c; + this.i = i; + } + } + + /** + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new LongestValidParentheses().longestValidParentheses("((()()(((())))))")); + } + + public int longestValidParentheses(String s) { + Stack stack = new Stack<>(); + int max = 0; + for (int i = 0, l = s.length(); i < l; i++) { + char c = s.charAt(i); + switch (c) { + case '(': + stack.push(new Node(c, i)); + break; + + case ')': + if (!stack.isEmpty()) { + if (stack.peek().c == '(') { + stack.pop(); + if (stack.isEmpty()) { + max = Math.max(max, i + 1); + } else { + max = Math.max(max, i - stack.peek().i); + } + } else { + stack.push(new Node(c, i)); + } + } else { + stack.push(new Node(c, i)); + } + } + } + return max; + } +} diff --git a/src/main/java/stack/MaximalRectangle.java b/src/main/java/stack/MaximalRectangle.java new file mode 100644 index 00000000..8d56347e --- /dev/null +++ b/src/main/java/stack/MaximalRectangle.java @@ -0,0 +1,84 @@ +/* (C) 2024 YourCompanyName */ +package stack; + +import java.util.Stack; + +/** + * Created by gouthamvidyapradhan on 29/11/2017. + * + *

Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only + * 1's and return its area. + * + *

For example, given the following matrix: + * + *

1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0 Return 6. + * + *

Solution O(n * m): This problem is similar to LargestRectangleInHistogram. Run the largest + * rectangle in histogram algorithm for each row. + */ +public class MaximalRectangle { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + char[][] matrix = { + {'1', '0', '1', '0', '0'}, + {'1', '0', '1', '1', '1'}, + {'1', '1', '1', '1', '1'}, + {'1', '0', '0', '1', '0'} + }; + System.out.println(new MaximalRectangle().maximalRectangle(matrix)); + } + + public int maximalRectangle(char[][] matrix) { + if (matrix.length == 0 || matrix[0].length == 0) return 0; + int[] A = new int[matrix[0].length]; + int max = Integer.MIN_VALUE; + for (int i = 0; i < matrix.length; i++) { + for (int j = 0; j < matrix[0].length; j++) { + if (matrix[i][j] == '1') { + if (i > 0 && matrix[i - 1][j] == '1') { + A[j] = A[j] + 1; + } else { + A[j] = 1; + } + } else { + A[j] = 0; + } + } + // calculate max rectangle for this row + max = Math.max(max, getMaxRectangle(A)); + } + return max; + } + + /** + * Get max rectangle algorithm similar to max rectangle in histogram + * + * @param heights + * @return + */ + private int getMaxRectangle(int[] heights) { + int maxArea = Integer.MIN_VALUE; + Stack stack = new Stack<>(); + int i = 0; + for (; i < heights.length; i++) { + while (!stack.isEmpty() && heights[stack.peek()] >= heights[i]) { + int top = stack.pop(); + int base = stack.isEmpty() ? i : i - stack.peek() - 1; + maxArea = Math.max(maxArea, base * heights[top]); + } + stack.push(i); + } + while (!stack.isEmpty()) { + int top = stack.pop(); + int base = stack.isEmpty() ? i : i - stack.peek() - 1; + maxArea = Math.max(maxArea, base * heights[top]); + } + return maxArea; + } +} diff --git a/src/main/java/stack/MinStack.java b/src/main/java/stack/MinStack.java new file mode 100644 index 00000000..07948d21 --- /dev/null +++ b/src/main/java/stack/MinStack.java @@ -0,0 +1,69 @@ +/* (C) 2024 YourCompanyName */ +package stack; + +import java.util.Stack; + +/** + * Created by gouthamvidyapradhan on 08/03/2017. Design a stack that supports push, pop, top, and + * retrieving the minimum element in constant time. + * + *

push(x) -- Push element x onto stack. pop() -- Removes the element on top of the stack. top() + * -- Get the top element. getMin() -- Retrieve the minimum element in the stack. Example: MinStack + * minStack = new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); + * minStack.getMin(); --> Returns -3. minStack.pop(); minStack.top(); --> Returns 0. + * minStack.getMin(); --> Returns -2. + */ +public class MinStack { + class Node { + int value, min; + + Node(int value, int min) { + this.value = value; + this.min = min; + } + } + + private Stack stack = new Stack<>(); + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + MinStack minStack = new MinStack(); + minStack.push(-2); + minStack.push(0); + minStack.push(-3); + System.out.println(minStack.getMin()); + minStack.pop(); + System.out.println(minStack.top()); + System.out.println(minStack.getMin()); + } + + public MinStack() {} + + public void push(int x) { + Node node; + if (!stack.isEmpty()) { + Node top = stack.peek(); + node = new Node(x, Math.min(top.min, x)); + } else { + node = new Node(x, x); + } + stack.push(node); + } + + public void pop() { + stack.pop(); + } + + public int top() { + return stack.peek().value; + } + + public int getMin() { + return stack.peek().min; + } +} diff --git a/src/main/java/stack/MyQueue.java b/src/main/java/stack/MyQueue.java new file mode 100644 index 00000000..d15ba1f7 --- /dev/null +++ b/src/main/java/stack/MyQueue.java @@ -0,0 +1,76 @@ +/* (C) 2024 YourCompanyName */ +package stack; + +import java.util.Stack; + +/** + * Created by gouthamvidyapradhan on 29/07/2017. Implement the following operations of a queue using + * stacks. + * + *

push(x) -- Push element x to the back of queue. pop() -- Removes the element from in front of + * queue. peek() -- Get the front element. empty() -- Return whether the queue is empty. + * + *

Notes: You must use only standard operations of a stack -- which means only push to top, + * peek/pop from top, size, and is empty operations are valid. Depending on your language, stack may + * not be supported natively. You may simulate a stack by using a list or deque (double-ended + * queue), as long as you use only standard operations of a stack. You may assume that all + * operations are valid (for example, no pop or peek operations will be called on an empty queue). + */ +public class MyQueue { + + private Stack stack; + + public static void main(String[] args) throws Exception { + MyQueue myQueue = new MyQueue(); + myQueue.push(5); + myQueue.push(12); + myQueue.push(7); + myQueue.push(9); + System.out.println(myQueue.peek()); + System.out.println(myQueue.pop()); + myQueue.push(56); + myQueue.push(53); + System.out.println(myQueue.pop()); + } + + /** Initialize your data structure here. */ + public MyQueue() { + stack = new Stack<>(); + } + + /** Push element x to the back of queue. */ + public void push(int x) { + stack.push(x); + } + + /** Removes the element from in front of queue and returns that element. */ + public int pop() { + Stack auxStack = new Stack<>(); + while (!stack.isEmpty()) { + auxStack.push(stack.pop()); + } + int result = auxStack.pop(); + while (!auxStack.isEmpty()) { + stack.push(auxStack.pop()); + } + return result; + } + + /** Get the front element. */ + public int peek() { + Stack auxStack = new Stack<>(); + while (!stack.isEmpty()) { + auxStack.push(stack.pop()); + } + int result = auxStack.peek(); + while (!auxStack.isEmpty()) { + stack.push(auxStack.pop()); + } + return result; + } + + /** Returns whether the queue is empty. */ + public boolean empty() { + return stack.isEmpty(); + } +} diff --git a/src/main/java/stack/StudentAttendanceRecordII.java b/src/main/java/stack/StudentAttendanceRecordII.java new file mode 100644 index 00000000..753d2f35 --- /dev/null +++ b/src/main/java/stack/StudentAttendanceRecordII.java @@ -0,0 +1,58 @@ +/* (C) 2024 YourCompanyName */ +package stack; + +/** + * Created by gouthamvidyapradhan on 10/05/2019 Given a positive integer n, return the number of all + * possible attendance records with length n, which will be regarded as rewardable. The answer may + * be very large, return it after mod 109 + 7. + * + *

A student attendance record is a string that only contains the following three characters: + * + *

'A' : Absent. 'L' : Late. 'P' : Present. A record is regarded as rewardable if it doesn't + * contain more than one 'A' (absent) or more than two continuous 'L' (late). + * + *

Example 1: Input: n = 2 Output: 8 Explanation: There are 8 records with length 2 will be + * regarded as rewardable: "PP" , "AP", "PA", "LP", "PL", "AL", "LA", "LL" Only "AA" won't be + * regarded as rewardable owing to more than one absent times. Note: The value of n won't exceed + * 100,000. + * + *

Solution O(N): Start with a base case for a single days attendance record which is 'A', 'P' + * and 'L' so, in total there are three possible records. Now, keep adding a new possible attendance + * record to all the above three possibilities. Now, since we cannot have a combination such as 'AA' + * we can maintain a variable with count of combinations which already has one 'A' in it and + * similarly maintain a combination which already has two 'L's it it, only one 'L' and only 'P' in + * it - keep incrementing the count of each of the variables when a new combination belongs to any + * one of this. Continue upto n and sum up the all the variables and return the answer % 10 ^ 9 + 7 + */ +public class StudentAttendanceRecordII { + public static void main(String[] args) { + System.out.println(new StudentAttendanceRecordII().checkRecord(5)); + } + + int mod = 1000000007; + + public int checkRecord(int n) { + if (n == 0) return 1; + int P = 1; + int A = 1; + int LA = 0, LX = 1, LLA = 0, LLX = 0; + for (int i = n - 1; i > 0; i--) { + int temP = (((P + LX) % mod) + LLX) % mod; + int tempLX = P; + int tempLA = A; + int tempLLX = LX; + int tempLLA = LA; + int tempA = + ((((((((((P + LX) % mod) + LLX) % mod) + A) % mod) + LA) % mod) + LLA) + % mod); // A + LA + LLA + // is because we can add P to each of these forming PA, PLA and PLLA + P = temP; + LX = tempLX; + LA = tempLA; + LLX = tempLLX; + LLA = tempLLA; + A = tempA; + } + return ((((((((((P + LX) % mod) + LA) % mod) + LLX) % mod) + LLA) % mod) + A) % mod); + } +} diff --git a/src/main/java/stack/ValidParentheses.java b/src/main/java/stack/ValidParentheses.java new file mode 100644 index 00000000..fbe69062 --- /dev/null +++ b/src/main/java/stack/ValidParentheses.java @@ -0,0 +1,55 @@ +/* (C) 2024 YourCompanyName */ +package stack; + +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; + +/** + * Created by gouthamvidyapradhan on 25/02/2017. Given a string containing just the characters '(', + * ')', '{', '}', '[' and ']', determine if the input string is valid. + * + *

The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and + * "([)]" are not. + */ +public class ValidParentheses { + public static void main(String[] args) { + System.out.println(hasBalancedBrackets("(h[e")); + } + + private static Map MAP = new HashMap<>(); + + // METHOD SIGNATURE BEGINS, THIS METHOD IS REQUIRED + public static int hasBalancedBrackets(String str) { + if (str == null) return 1; + + MAP.put(')', '('); + MAP.put('}', '{'); + MAP.put('>', '<'); + MAP.put(']', '['); + + Stack stack = new Stack<>(); + for (int i = 0, l = str.length(); i < l; i++) { + switch (str.charAt(i)) { + case '(': + case '{': + case '[': + case '<': + stack.push(str.charAt(i)); + break; + + case ')': + case '}': + case ']': + case '>': + if (stack.isEmpty()) return 0; + char top = stack.pop(); + if (top != MAP.get(str.charAt(i))) return 0; + break; + + default: // ignore + } + } + return stack.isEmpty() ? 1 : 0; + } +} diff --git a/src/main/java/string/AddBinary.java b/src/main/java/string/AddBinary.java new file mode 100644 index 00000000..5eb80046 --- /dev/null +++ b/src/main/java/string/AddBinary.java @@ -0,0 +1,49 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 25/11/2017. + * + *

Given two binary strings, return their sum (also a binary string). + * + *

For example, a = "11" b = "1" Return "100". + */ +public class AddBinary { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + System.out.println(new AddBinary().addBinary("000001010000101001", "0")); + } + + public String addBinary(String a, String b) { + if (a.length() > b.length()) { + return calculate(a, b); + } else return calculate(b, a); + } + + /** + * Calculate sum + * + * @param a length of a should always be greater or equal to b + * @param b length of b should always be smaller of equal to a + * @return + */ + private String calculate(String a, String b) { + int carry = 0; + int d = a.length() - b.length(); + StringBuilder sb = new StringBuilder(); + for (int i = a.length() - 1; i >= 0; i--) { + int first = Integer.parseInt(String.valueOf(a.charAt(i))); + int second = i - d >= 0 ? Integer.parseInt(String.valueOf(b.charAt(i - d))) : 0; + int sum = (first + second + carry); + carry = sum / 2; + sb.append(sum % 2); + } + if (carry != 0) sb.append(carry); + return sb.reverse().toString(); + } +} diff --git a/src/main/java/string/CompareVersionNumbers.java b/src/main/java/string/CompareVersionNumbers.java new file mode 100644 index 00000000..c45f221e --- /dev/null +++ b/src/main/java/string/CompareVersionNumbers.java @@ -0,0 +1,50 @@ +/* (C) 2024 YourCompanyName */ +package string; + +import java.util.StringTokenizer; + +/** + * Created by pradhang on 7/11/2017. Compare two version numbers version1 and version2. If version1 + * > version2 return 1, if version1 < version2 return -1, otherwise return 0. + * + *

You may assume that the version strings are non-empty and contain only digits and the . + * character. The . character does not represent a decimal point and is used to separate number + * sequences. For instance, 2.5 is not "two and a half" or "half way to version three", it is the + * fifth second-level revision of the second first-level revision. + * + *

Here is an example of version numbers ordering: + * + *

0.1 < 1.1 < 1.2 < 13.37 + */ +public class CompareVersionNumbers { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new CompareVersionNumbers().compareVersion("1.11.1", "1.11")); + } + + public int compareVersion(String version1, String version2) { + StringTokenizer st1 = new StringTokenizer(version1, "."); + StringTokenizer st2 = new StringTokenizer(version2, "."); + while (st1.hasMoreTokens() & st2.hasMoreTokens()) { + int token1 = Integer.parseInt(st1.nextToken()); + int token2 = Integer.parseInt(st2.nextToken()); + if (token1 > token2) return 1; + else if (token2 > token1) return -1; + } + if (st1.countTokens() > st2.countTokens()) { + while (st1.hasMoreTokens()) { + if (Integer.parseInt(st1.nextToken()) > 0) return 1; + } + } else if (st2.countTokens() > st1.countTokens()) { + while (st2.hasMoreTokens()) { + if (Integer.parseInt(st2.nextToken()) > 0) return -1; + } + } + return 0; + } +} diff --git a/src/main/java/string/CountAndSay.java b/src/main/java/string/CountAndSay.java new file mode 100644 index 00000000..e50983a4 --- /dev/null +++ b/src/main/java/string/CountAndSay.java @@ -0,0 +1,52 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 20/01/2018. + * + *

The count-and-say sequence is the sequence of integers with the first five terms as following: + * + *

1. 1 2. 11 3. 21 4. 1211 5. 111221 1 is read off as "one 1" or 11. 11 is read off as "two 1s" + * or 21. 21 is read off as "one 2, then one 1" or 1211. Given an integer n, generate the nth term + * of the count-and-say sequence. + * + *

Note: Each term of the sequence of integers will be represented as a string. + * + *

Example 1: + * + *

Input: 1 Output: "1" Example 2: + * + *

Input: 4 Output: "1211" + */ +public class CountAndSay { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) throws Exception { + System.out.println(new CountAndSay().countAndSay(4)); + } + + public String countAndSay(int n) { + String result = "1"; + for (int i = 1; i < n; i++) { + int count = 1; + char num = result.charAt(0); + StringBuilder temp = new StringBuilder(); + for (int j = 1, l = result.length(); j < l; j++) { + if (result.charAt(j) == num) { + count++; + } else { + temp = temp.append(String.valueOf(count)).append(String.valueOf(num)); + num = result.charAt(j); + count = 1; + } + } + temp = temp.append(String.valueOf(count)).append(String.valueOf(num)); + result = temp.toString(); + } + return result; + } +} diff --git a/src/main/java/string/ExcelSheetColumnNumber.java b/src/main/java/string/ExcelSheetColumnNumber.java new file mode 100644 index 00000000..f0ecd7e2 --- /dev/null +++ b/src/main/java/string/ExcelSheetColumnNumber.java @@ -0,0 +1,30 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 07/07/2017. Given a column title as appear in an Excel sheet, + * return its corresponding column number. + * + *

For example: + * + *

A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 + */ +public class ExcelSheetColumnNumber { + String CONST = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + public static void main(String[] args) throws Exception { + System.out.println(new ExcelSheetColumnNumber().titleToNumber("AAB")); + } + + public int titleToNumber(String s) { + int total = 0; + int j = 0; + for (int i = s.length() - 1; i >= 0; i--) { + char c = s.charAt(i); + int pos = CONST.indexOf(c) + 1; + int pow = (int) Math.pow(26, j++); + total += (pow * pos); + } + return total; + } +} diff --git a/src/main/java/string/FindTheClosestPalindrome.java b/src/main/java/string/FindTheClosestPalindrome.java new file mode 100644 index 00000000..86459c41 --- /dev/null +++ b/src/main/java/string/FindTheClosestPalindrome.java @@ -0,0 +1,133 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 21/04/2018. Given an integer n, find the closest integer (not + * including itself), which is a palindrome. + * + *

The 'closest' is defined as absolute difference minimized between two integers. + * + *

Example 1: Input: "123" Output: "121" Note: The input n is a positive integer represented by + * string, whose length will not exceed 18. If there is a tie, return the smaller one as answer. + * + *

Solution O(N): General idea is to consider the first half of the string and make a new string + * by reversing the first half of string. Concatenate the first_half and the new_string and return + * this as an answer. There are also a lot of edge cases to be considered using this approach. + */ +public class FindTheClosestPalindrome { + public static void main(String[] args) throws Exception { + System.out.println(new FindTheClosestPalindrome().nearestPalindromic("1837722381")); + } + + public String nearestPalindromic(String n) { + if (n.length() == 1) return String.valueOf(Integer.parseInt(n) - 1); + String p1, p2; + String palindrome; + if (isPaliandrome(n)) { + String newFirstHalf; + if (n.length() % 2 == 0) { + String firstHalf = n.substring(0, n.length() / 2); + newFirstHalf = String.valueOf(Long.parseLong(firstHalf) - 1); + p1 = newFirstHalf + new StringBuilder(newFirstHalf).reverse(); + newFirstHalf = String.valueOf(Long.parseLong(firstHalf) + 1); + p2 = newFirstHalf + new StringBuilder(newFirstHalf).reverse(); + } else { + String firstHalf = n.substring(0, n.length() / 2); + char middle = n.charAt(n.length() / 2); + if (middle == '0') { + p1 = firstHalf + "1" + new StringBuilder(firstHalf).reverse(); + } else { + p1 = + firstHalf + + (Integer.parseInt(String.valueOf(middle)) - 1) + + new StringBuilder(firstHalf).reverse(); + } + newFirstHalf = String.valueOf(Long.parseLong(firstHalf) + 1); + p2 = newFirstHalf + "0" + new StringBuilder(newFirstHalf).reverse(); + } + } else { + String firstHalf = n.substring(0, n.length() / 2); + if (n.length() % 2 == 0) { + p1 = firstHalf + new StringBuilder(firstHalf).reverse(); + String temp = String.valueOf(Long.parseLong(firstHalf) + 1); + p2 = temp + new StringBuilder(temp).reverse(); + temp = String.valueOf(Long.parseLong(firstHalf) - 1); + String p3 = temp + new StringBuilder(temp).reverse(); + p1 = + Math.abs(Long.parseLong(p3) - Long.parseLong(n)) + <= Math.abs(Long.parseLong(p1) - Long.parseLong(n)) + ? p3 + : p1; + } else { + char middle = n.charAt(n.length() / 2); + p1 = firstHalf + middle + new StringBuilder(firstHalf).reverse(); + String temp = String.valueOf(Long.parseLong(firstHalf) + 1); + p2 = temp + "0" + new StringBuilder(temp).reverse(); + String p3 = + firstHalf + + (Integer.parseInt(String.valueOf(middle)) + 1) + + new StringBuilder(firstHalf).reverse(); + String p4 = null; + if (middle != '0') { + p4 = + firstHalf + + (Integer.parseInt(String.valueOf(middle)) - 1) + + new StringBuilder(firstHalf).reverse(); + } + p1 = + Math.abs(Long.parseLong(p1) - Long.parseLong(n)) + <= Math.abs(Long.parseLong(p3) - Long.parseLong(n)) + ? p1 + : p3; + if (p4 != null) { + p1 = + Math.abs(Long.parseLong(p4) - Long.parseLong(n)) + <= Math.abs(Long.parseLong(p1) - Long.parseLong(n)) + ? p4 + : p1; + } + } + } + long l1 = Math.abs(Long.parseLong(n) - Long.parseLong(p1)); + long l2 = Math.abs(Long.parseLong(n) - Long.parseLong(p2)); + if (l1 <= l2) { + palindrome = p1; + } else palindrome = p2; + long m1 = Math.abs(Long.parseLong(getLow(n)) - Long.parseLong(n)); + long m2 = Math.abs(Long.parseLong(palindrome) - Long.parseLong(n)); + long m3 = Math.abs(Long.parseLong(getHigh(n)) - Long.parseLong(n)); + long min = Math.min(Math.min(m1, m2), m3); + if (min == m1) return getLow(n); + else if (min == m2) return palindrome; + else return getHigh(n); + } + + private String getLow(String s) { + int n = s.length() - 1; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < n; i++) { + sb.append("9"); + } + return sb.toString(); + } + + private String getHigh(String s) { + int n = s.length() - 1; + StringBuilder sb = new StringBuilder(); + sb.append("1"); + for (int i = 0; i < n; i++) { + sb.append("0"); + } + sb.append("1"); + return sb.toString(); + } + + private boolean isPaliandrome(String s) { + for (int i = 0, j = s.length() - 1; i < j; i++, j--) { + if (s.charAt(i) != s.charAt(j)) { + return false; + } + } + return true; + } +} diff --git a/src/main/java/string/FindWordsThatCanBeFormedbyCharacters.java b/src/main/java/string/FindWordsThatCanBeFormedbyCharacters.java new file mode 100644 index 00000000..6a16bf0b --- /dev/null +++ b/src/main/java/string/FindWordsThatCanBeFormedbyCharacters.java @@ -0,0 +1,64 @@ +/* (C) 2024 YourCompanyName */ +package string; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 28/08/2019 You are given an array of strings words and a string + * chars. + * + *

A string is good if it can be formed by characters from chars (each character can only be used + * once). + * + *

Return the sum of lengths of all good strings in words. + * + *

Example 1: + * + *

Input: words = ["cat","bt","hat","tree"], chars = "atach" Output: 6 Explanation: The strings + * that can be formed are "cat" and "hat" so the answer is 3 + 3 = 6. Example 2: + * + *

Input: words = ["hello","world","leetcode"], chars = "welldonehoneyr" Output: 10 Explanation: + * The strings that can be formed are "hello" and "world" so the answer is 5 + 5 = 10. + * + *

Note: + * + *

1 <= words.length <= 1000 1 <= words[i].length, chars.length <= 100 All strings contain + * lowercase English letters only. + * + *

Solution Do a linear check for each of the words and each of the characters and sum up the + * lengths. Keep a hashmap of key-values to avoid picking the same character again. + */ +public class FindWordsThatCanBeFormedbyCharacters { + public static void main(String[] args) { + String[] A = {"cat", "bt", "hat", "problems/src/tree"}; + String chars = "atach"; + new FindWordsThatCanBeFormedbyCharacters().countCharacters(A, chars); + } + + public int countCharacters(String[] words, String chars) { + Map countMap = new HashMap<>(); + for (char c : chars.toCharArray()) { + countMap.putIfAbsent(c, 0); + countMap.put(c, countMap.get(c) + 1); + } + int ans = 0; + for (String s : words) { + Map subMap = new HashMap<>(); + for (char c : s.toCharArray()) { + subMap.putIfAbsent(c, 0); + subMap.put(c, subMap.get(c) + 1); + } + boolean possible = true; + for (char k : subMap.keySet()) { + if (!countMap.containsKey(k) || subMap.get(k) > countMap.get(k)) { + possible = false; + break; + } + } + if (possible) { + ans += s.length(); + } + } + return ans; + } +} diff --git a/src/main/java/string/FirstUniqueCharacterInAString.java b/src/main/java/string/FirstUniqueCharacterInAString.java new file mode 100644 index 00000000..9eabdc6a --- /dev/null +++ b/src/main/java/string/FirstUniqueCharacterInAString.java @@ -0,0 +1,38 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 09/03/2017. Given a string, find the first non-repeating + * character in it and return it's index. If it doesn't exist, return -1. + * + *

Examples: + * + *

s = "leetcode" return 0. + * + *

s = "loveleetcode", return 2. Note: You may assume the string contain only lowercase letters. + */ +public class FirstUniqueCharacterInAString { + int[] CHAR = new int[256]; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new FirstUniqueCharacterInAString().firstUniqChar("loveleetcode")); + } + + public int firstUniqChar(String s) { + if (s == null || s.isEmpty()) return -1; + + for (int i = 0, l = s.length(); i < l; i++) CHAR[s.charAt(i)]++; + + for (int i = 0, l = s.length(); i < l; i++) { + if (CHAR[s.charAt(i)] == 1) return i; + } + + return -1; + } +} diff --git a/src/main/java/string/ImplementStrStr.java b/src/main/java/string/ImplementStrStr.java new file mode 100644 index 00000000..a2e52a32 --- /dev/null +++ b/src/main/java/string/ImplementStrStr.java @@ -0,0 +1,39 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 24/06/2017. Implement strStr(). + * + *

Returns the index of the first occurrence of needle in haystack, or -1 if needle is not part + * of haystack. + * + *

Solution O(N ^ 2) + */ +public class ImplementStrStr { + public static void main(String[] args) throws Exception { + System.out.println(new ImplementStrStr().strStr("AABB", "")); + } + + public int strStr(String haystack, String needle) { + if (haystack.isEmpty() && needle.isEmpty()) return 0; + if (needle.isEmpty()) return 0; + for (int i = 0, l = haystack.length(); i < l; i++) { + if (haystack.charAt(i) == needle.charAt(0)) { + if (isEqual(haystack, needle, i)) return i; + } + } + return -1; + } + + private boolean isEqual(String haystack, String needle, int i) { + int hL = haystack.length(); + int nL = needle.length(); + int j = 0; + while (i < hL && j < nL) { + if (haystack.charAt(i) != needle.charAt(j)) return false; + i++; + j++; + } + return j >= nL; + } +} diff --git a/src/main/java/string/IsomorphicStrings.java b/src/main/java/string/IsomorphicStrings.java new file mode 100644 index 00000000..5956e51d --- /dev/null +++ b/src/main/java/string/IsomorphicStrings.java @@ -0,0 +1,54 @@ +/* (C) 2024 YourCompanyName */ +package string; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 11/04/2018. Given two strings s and t, determine if they are + * isomorphic. + * + *

Two strings are isomorphic if the characters in s can be replaced to get t. + * + *

All occurrences of a character must be replaced with another character while preserving the + * order of characters. No two characters may map to the same character but a character may map to + * itself. + * + *

For example, Given "egg", "add", return true. + * + *

Given "foo", "bar", return false. + * + *

Given "paper", "title", return true. + * + *

Note: You may assume both s and t have the same length. Solution O(N): Maintain two hashmaps + * and compare character by character. + */ +public class IsomorphicStrings { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new IsomorphicStrings().isIsomorphic("abc", "dea")); + } + + public boolean isIsomorphic(String s, String t) { + if (s.length() != t.length()) return false; + Map first = new HashMap<>(); + Map second = new HashMap<>(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (first.containsKey(c)) { + char secondC = first.get(c); + if (t.charAt(i) != secondC) return false; + } else { + first.put(c, t.charAt(i)); + if (second.containsKey(t.charAt(i))) return false; + second.put(t.charAt(i), c); + } + } + return true; + } +} diff --git a/src/main/java/string/KeyboardRow.java b/src/main/java/string/KeyboardRow.java new file mode 100644 index 00000000..ab25ecfe --- /dev/null +++ b/src/main/java/string/KeyboardRow.java @@ -0,0 +1,56 @@ +/* (C) 2024 YourCompanyName */ +package string; +/** + * Created by gouthamvidyapradhan on 09/04/2019 + * + *

Given a List of words, return the words that can be typed using letters of alphabet on only + * one row's of American keyboard like the image below. + * + *

Example: + * + *

Input: ["Hello", "Alaska", "Dad", "Peace"] Output: ["Alaska", "Dad"] + * + *

Note: + * + *

You may use one character in the keyboard more than once. You may assume the input string will + * only contain letters of alphabet. + */ +import java.util.*; + +public class KeyboardRow { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) {} + + public String[] findWords(String[] words) { + String R1 = "qwertyuiop"; + String R2 = "asdfghjkl"; + String R3 = "zxcvbnm"; + List answer = new ArrayList<>(); + for (String s : words) { + Set set = new HashSet<>(); + for (char c : s.toCharArray()) { + if (R1.indexOf(c) != -1) { + set.add('1'); + } else if (R2.indexOf(c) != -1) { + set.add('2'); + } else if (R3.indexOf(c) != -1) { + set.add('3'); + } + } + if (set.size() == 1) { + answer.add(s); + } + } + String[] ans = new String[answer.size()]; + int i = 0; + for (String s : answer) { + ans[i++] = s; + } + return ans; + } +} diff --git a/src/main/java/string/LongestCommonPrefix.java b/src/main/java/string/LongestCommonPrefix.java new file mode 100644 index 00000000..f6ec92c0 --- /dev/null +++ b/src/main/java/string/LongestCommonPrefix.java @@ -0,0 +1,36 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 12/04/2018. Write a function to find the longest common prefix + * string amongst an array of strings. + * + *

Solution: O(N x M) where N is the length of the given array and M is the max_length of a + * string. + */ +public class LongestCommonPrefix { + /** + * Main method + * + * @param args + */ + public static void main(String[] args) throws Exception { + String[] A = {"abc", "a", "adkd"}; + System.out.println(new LongestCommonPrefix().longestCommonPrefix(A)); + } + + public String longestCommonPrefix(String[] strs) { + if (strs.length == 0) return ""; + String result = strs[0]; + for (int i = 1; i < strs.length; i++) { + String s = strs[i]; + for (int j = 0; j < result.length(); j++) { + if (j >= s.length() || result.charAt(j) != s.charAt(j)) { + result = result.substring(0, j); + break; + } + } + } + return result; + } +} diff --git a/src/main/java/string/LongestPalindrome.java b/src/main/java/string/LongestPalindrome.java new file mode 100644 index 00000000..5e90a731 --- /dev/null +++ b/src/main/java/string/LongestPalindrome.java @@ -0,0 +1,54 @@ +/* (C) 2024 YourCompanyName */ +package string; +/** + * Created by gouthamvidyapradhan on 20/03/2019 Given a string which consists of lowercase or + * uppercase letters, find the length of the longest palindromes that can be built with those + * letters. + * + *

This is case sensitive, for example "Aa" is not considered a palindrome here. + * + *

Note: Assume the length of given string will not exceed 1,010. + * + *

Example: + * + *

Input: "abccccdd" + * + *

Output: 7 + * + *

Explanation: One longest palindrome that can be built is "dccaccd", whose length is 7. + */ +import java.util.*; + +public class LongestPalindrome { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + int result = new LongestPalindrome().longestPalindrome("asdfasdf"); + System.out.println(result); + } + + public int longestPalindrome(String s) { + Map map = new HashMap<>(); + for (char c : s.toCharArray()) { + map.putIfAbsent(c, 0); + int count = map.get(c); + map.put(c, count + 1); + } + int max = 0; + boolean odd = false; + for (char c : map.keySet()) { + int count = map.get(c); + max += count; + if ((count % 2) != 0) { + max--; + odd = true; + } + } + if (odd) max++; + return max; + } +} diff --git a/src/main/java/string/LongestWordInDictonary.java b/src/main/java/string/LongestWordInDictonary.java new file mode 100644 index 00000000..e0ab0776 --- /dev/null +++ b/src/main/java/string/LongestWordInDictonary.java @@ -0,0 +1,55 @@ +/* (C) 2024 YourCompanyName */ +package string; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 15/02/2018. Given a string and a string dictionary, find the + * longest string in the dictionary that can be formed by deleting some characters of the given + * string. If there are more than one possible results, return the longest word with the smallest + * lexicographical order. If there is no possible result, return the empty string. + * + *

Example 1: Input: s = "abpcplea", d = ["ale","apple","monkey","plea"] + * + *

Output: "apple" Example 2: Input: s = "abpcplea", d = ["a","b","c"] + * + *

Output: "a" Note: All the strings in the input will only contain lower-case letters. The size + * of the dictionary won't exceed 1,000. The length of all the strings in the input won't exceed + * 1,000. + * + *

Solution: O((n x m x log n) + (m ^ 2 + m x n))) sort the dictionary based on the longest first + * and then lexicographically and compare each sorted word with given word and do a two pointer + * comparison to check for sub-sequence. + */ +public class LongestWordInDictonary { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) throws Exception { + List dict = Arrays.asList("ale", "apple", "monkey", "plea"); + System.out.println(new LongestWordInDictonary().findLongestWord("abpcplea", dict)); + } + + public String findLongestWord(String s, List d) { + Collections.sort( + d, Comparator.comparing(String::length).reversed().thenComparing(String::compareTo)); + for (String str : d) { + if (str.length() <= s.length()) { + int i = 0, j = 0; + for (int l1 = s.length(), l2 = str.length(); i < l1 && j < l2; ) { + if (s.charAt(i) == str.charAt(j)) { + i++; + j++; + } else { + i++; + } + } + if (j >= str.length()) return str; + } + } + return ""; + } +} diff --git a/src/main/java/string/MinimumAddtoMakeParenthesesValid.java b/src/main/java/string/MinimumAddtoMakeParenthesesValid.java new file mode 100644 index 00000000..eaa5cb7b --- /dev/null +++ b/src/main/java/string/MinimumAddtoMakeParenthesesValid.java @@ -0,0 +1,54 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 20/08/2019 Given a string S of '(' and ')' parentheses, we add + * the minimum number of parentheses ( '(' or ')', and in any positions ) so that the resulting + * parentheses string is valid. + * + *

Formally, a parentheses string is valid if and only if: + * + *

It is the empty string, or It can be written as AB (A concatenated with B), where A and B are + * valid strings, or It can be written as (A), where A is a valid string. Given a parentheses + * string, return the minimum number of parentheses we must add to make the resulting string valid. + * + *

Example 1: + * + *

Input: "())" Output: 1 Example 2: + * + *

Input: "(((" Output: 3 Example 3: + * + *

Input: "()" Output: 0 Example 4: + * + *

Input: "()))((" Output: 4 + * + *

Note: + * + *

S.length <= 1000 S only consists of '(' and ')' characters. + * + *

Solution O(N) Keep track of count of open parentheses, when ever a closed parentheses appear + * if the count of open parentheses is greater than 0 then decrement this value (identifying that + * there is a matching parentheses already), if the count is 0 then there is a miss match with + * parentheses and hence add one to the result. The final answer is the total of result + open + * parentheses + */ +public class MinimumAddtoMakeParenthesesValid { + public static void main(String[] args) { + System.out.println(new MinimumAddtoMakeParenthesesValid().minAddToMakeValid("()))((")); + } + + public int minAddToMakeValid(String S) { + int result = 0; + int open = 0; + for (char c : S.toCharArray()) { + if (c == '(') { + open++; + } else if (c == ')') { + if (open > 0) { + open--; + } else result++; + } + } + return result + open; + } +} diff --git a/src/main/java/string/MonotoneIncreasingDigits.java b/src/main/java/string/MonotoneIncreasingDigits.java new file mode 100644 index 00000000..238ba12f --- /dev/null +++ b/src/main/java/string/MonotoneIncreasingDigits.java @@ -0,0 +1,59 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 01/05/2018. Given a non-negative integer N, find the largest + * number that is less than or equal to N with monotone increasing digits. + * + *

(Recall that an integer has monotone increasing digits if and only if each pair of adjacent + * digits x and y satisfy x <= y.) + * + *

Example 1: Input: N = 10 Output: 9 Example 2: Input: N = 1234 Output: 1234 Example 3: Input: N + * = 332 Output: 299 Note: N is an integer in the range [0, 10^9]. + * + *

Solution O(N): Convert to string for easier manipulation. Start from N.length - 1 and iterate + * through until index 0.Mark the index where the violation occurs. Decrement the value of the + * latest index where the violation occurs and append '9' to rest of the trailing digits. Convert + * the string to integer before returning. + */ +public class MonotoneIncreasingDigits { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new MonotoneIncreasingDigits().monotoneIncreasingDigits(100001)); + } + + public int monotoneIncreasingDigits(int N) { + String s = String.valueOf(N); + if (s.length() == 1) return N; + int p = -1; + int prev = N % 10; + for (int i = s.length() - 2; i >= 0; i--) { + int curr = Integer.parseInt(String.valueOf(s.charAt(i))); + if (curr > prev) { + p = i; + prev = curr - 1; + } else { + prev = curr; + } + } + if (p == -1) return N; + StringBuilder result = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + if (i == p) { + int pV = Integer.parseInt(String.valueOf(s.charAt(i))); + result.append(pV - 1); + break; + } + result.append(String.valueOf(s.charAt(i))); + } + for (int i = p + 1; i < s.length(); i++) { + result.append("9"); + } + return Integer.parseInt(result.toString()); + } +} diff --git a/src/main/java/string/MultiplyStrings.java b/src/main/java/string/MultiplyStrings.java new file mode 100644 index 00000000..cce90724 --- /dev/null +++ b/src/main/java/string/MultiplyStrings.java @@ -0,0 +1,74 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 01/02/2018. Given two non-negative integers num1 and num2 + * represented as strings, return the product of num1 and num2. + * + *

Note: + * + *

The length of both num1 and num2 is < 110. Both num1 and num2 contains only digits 0-9. Both + * num1 and num2 does not contain any leading zero. You must not use any built-in BigInteger library + * or convert the inputs to integer directly. + * + *

Solution: O(N x M) where N and M are length of strings + */ +public class MultiplyStrings { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new MultiplyStrings().multiply("00", "0000")); + } + + public String multiply(String num1, String num2) { + if ((num1.length() == 1 && num1.equals("0")) || (num2.length() == 1 && num2.equals("0"))) + return "0"; + if (num1.length() < num2.length()) return multiply(num2, num1); + String temp2 = "", trail = ""; + int carry = 0; + for (int i = 0; i < num1.length(); i++) { + temp2 += "0"; + } + for (int i = num1.length() - 1; i >= 0; i--) { + String temp1 = ""; + for (int j = num2.length() - 1; j >= 0; j--) { + int prod = + Integer.parseInt(String.valueOf(num2.charAt(j))) + * Integer.parseInt(String.valueOf(num1.charAt(i))); + prod += carry; + temp1 = (prod % 10) + temp1; + carry = (prod / 10); + } + if (carry > 0) { + temp1 = String.valueOf(carry) + temp1; + carry = 0; + } + String temp3 = add(temp1, temp2); + temp2 = temp3.substring(0, temp3.length() - 1); + trail = temp3.substring(temp3.length() - 1, temp3.length()) + trail; + } + return temp2 + trail; + } + + private String add(String s1, String s2) { + String result = ""; + int carry = 0; + int i = s1.length() - 1, j = s2.length() - 1; + for (; i >= 0 || j >= 0; i--, j--) { + int l = (i >= 0) ? Integer.parseInt(String.valueOf(s1.charAt(i))) : 0; + int r = (j >= 0) ? Integer.parseInt(String.valueOf(s2.charAt(j))) : 0; + int sum = l + r + carry; + carry = sum / 10; + result = sum % 10 + result; + } + if (carry > 0) { + result = carry + result; + } + return result; + } +} diff --git a/src/main/java/string/NumberOfMatchingSubsequences.java b/src/main/java/string/NumberOfMatchingSubsequences.java new file mode 100644 index 00000000..a873117b --- /dev/null +++ b/src/main/java/string/NumberOfMatchingSubsequences.java @@ -0,0 +1,54 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 04/04/2019 Given string S and a dictionary of words words, find + * the number of words[i] that is a subsequence of S. + * + *

Example : Input: S = "abcde" words = ["a", "bb", "acd", "ace"] Output: 3 Explanation: There + * are three words in words that are a subsequence of S: "a", "acd", "ace". Note: + * + *

All words in words and S will only consists of lowercase letters. The length of S will be in + * the range of [1, 50000]. The length of words will be in the range of [1, 5000]. The length of + * words[i] will be in the range of [1, 50]. + */ +public class NumberOfMatchingSubsequences { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + String[] A = {"a", "bb", "acd", "ace"}; + System.out.println(new NumberOfMatchingSubsequences().numMatchingSubseq("abcde", A)); + } + + public int numMatchingSubseq(String S, String[] words) { + int count = 0; + for (int i = 0; i < words.length; i++) { + String w = words[i]; + if (isSubsequence(S, w)) { + count++; + } + } + return count; + } + + private boolean isSubsequence(String S, String P) { + int i = 0, j = 0; + if (P.length() > S.length()) return false; + for (; ; ) { + if (j >= P.length()) return true; + else if (i >= S.length()) return false; + else { + if (S.charAt(i) == P.charAt(j)) { + i++; + j++; + } else { + i++; + } + } + } + } +} diff --git a/src/main/java/string/OneEditDistance.java b/src/main/java/string/OneEditDistance.java new file mode 100644 index 00000000..657391c4 --- /dev/null +++ b/src/main/java/string/OneEditDistance.java @@ -0,0 +1,55 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 09/12/2017. + * + *

Given two strings S and T, determine if they are both one edit distance apart. + */ +public class OneEditDistance { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new OneEditDistance().isOneEditDistance("abxd", "adxb")); + } + + public boolean isOneEditDistance(String s, String t) { + if (Math.abs(s.length() - t.length()) > 1 || s.equals(t)) return false; + if (s.length() > t.length()) { + return hasDiffOne(s, t, false); + } else if (t.length() > s.length()) { + return hasDiffOne(t, s, false); + } else { + return hasDiffOne(s, t, true); + } + } + + private boolean hasDiffOne(String s, String t, boolean sameLength) { + int count = 0, i = 0, j = 0; + for (int l1 = s.length(), l2 = t.length(); i < l1 && j < l2; ) { + if (s.charAt(i) == t.charAt(j)) { + i++; + j++; + } else { + if (count > 0) return false; + count++; + if (sameLength) { + i++; + j++; + } else { + i++; + } + } + } + if (i == j) { + return true; + } else { + return (s.charAt(s.length() - 1) == t.charAt(t.length() - 1)); + } + } +} diff --git a/src/main/java/string/PermutationInString.java b/src/main/java/string/PermutationInString.java new file mode 100644 index 00000000..b9998019 --- /dev/null +++ b/src/main/java/string/PermutationInString.java @@ -0,0 +1,54 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 18/09/2017. Given two strings s1 and s2, write a function to + * return true if s2 contains the permutation of s1. In other words, one of the first string's + * permutations is the substring of the second string. + * + *

Example 1: Input:s1 = "ab" s2 = "eidbaooo" Output:True Explanation: s2 contains one + * permutation of s1 ("ba"). + * + *

Example 2: Input:s1= "ab" s2 = "eidboaoo" Output: False Note: The input strings only contain + * lower case letters. The length of both given strings is in range [1, 10,000]. + */ +public class PermutationInString { + private int[] S1 = new int[256]; + private int[] S2 = new int[256]; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new PermutationInString().checkInclusion("ab", "eidboaoo")); + } + + public boolean checkInclusion(String s1, String s2) { + if (s2.length() < s1.length()) return false; + for (int i = 0, l = s1.length(); i < l; i++) { + S1[s1.charAt(i)]++; + S2[s2.charAt(i)]++; + } + if (isEqual()) return true; + for (int i = 1, j = s1.length(), l = s2.length(); j < l; i++, j++) { + S2[s2.charAt(i - 1)]--; + S2[s2.charAt(j)]++; + if (isEqual()) return true; + } + return false; + } + + private boolean isEqual() { + boolean equal = true; + for (int i = 0; i < 256; i++) { + if (S1[i] != S2[i]) { + equal = false; + break; + } + } + return equal; + } +} diff --git a/src/main/java/string/PushDominoes.java b/src/main/java/string/PushDominoes.java new file mode 100644 index 00000000..2514d9ae --- /dev/null +++ b/src/main/java/string/PushDominoes.java @@ -0,0 +1,76 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 24/07/2019 There are N dominoes in a line, and we place each + * domino vertically upright. + * + *

In the beginning, we simultaneously push some of the dominoes either to the left or to the + * right. + * + *

After each second, each domino that is falling to the left pushes the adjacent domino on the + * left. + * + *

Similarly, the dominoes falling to the right push their adjacent dominoes standing on the + * right. + * + *

When a vertical domino has dominoes falling on it from both sides, it stays still due to the + * balance of the forces. + * + *

For the purposes of this question, we will consider that a falling domino expends no + * additional force to a falling or already fallen domino. + * + *

Given a string "S" representing the initial state. S[i] = 'L', if the i-th domino has been + * pushed to the left; S[i] = 'R', if the i-th domino has been pushed to the right; S[i] = '.', if + * the i-th domino has not been pushed. + * + *

Return a string representing the final state. + * + *

Example 1: + * + *

Input: ".L.R...LR..L.." Output: "LL.RR.LLRRLL.." Example 2: + * + *

Input: "RR.L" Output: "RR.L" Explanation: The first domino expends no additional force on the + * second domino. Note: + * + *

0 <= N <= 10^5 String dominoes contains only 'L', 'R' and '.' Solution: O(N) + */ +public class PushDominoes { + public static void main(String[] args) { + System.out.println(new PushDominoes().pushDominoes("RR.L")); + } + + public String pushDominoes(String dominoes) { + int R = -1, L = -1; + char[] A = dominoes.toCharArray(); + for (int i = 0; i < A.length; i++) { + if (A[i] == 'L') { + if (R > L) { + int d = (i - R); + int st; + st = R + d / 2; + if ((d % 2) == 0) { + A[st] = '.'; + } + for (int j = st + 1; j < i; j++) { + A[j] = 'L'; + } + } else { + for (int j = (L == -1 ? 0 : L); j < i; j++) { + A[j] = 'L'; + } + } + L = i; + } else { + if (A[i] == 'R') { + R = i; + } else { + if (R > L) { + A[i] = 'R'; + } + } + } + } + return String.valueOf(A); + } +} diff --git a/src/main/java/string/ReconstructOriginalDigitsFromEnglish.java b/src/main/java/string/ReconstructOriginalDigitsFromEnglish.java new file mode 100644 index 00000000..92efa05d --- /dev/null +++ b/src/main/java/string/ReconstructOriginalDigitsFromEnglish.java @@ -0,0 +1,97 @@ +/* (C) 2024 YourCompanyName */ +package string; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 04/06/2019 Given a non-empty string containing an out-of-order + * English representation of digits 0-9, output the digits in ascending order. + * + *

Note: Input contains only lowercase English letters. Input is guaranteed to be valid and can + * be transformed to its original digits. That means invalid inputs such as "abc" or "zerone" are + * not permitted. Input length is less than 50,000. Example 1: Input: "owoztneoer" + * + *

Output: "012" Example 2: Input: "fviefuro" + * + *

Output: "45" + * + *

Solution: O(N) General idea is to note some unique characters in english representation of a + * digit such as 'x' 'x' can occur only in digit 6, similarly for 'z' it can occur only for digit 0 + * and likewise. Keep a character frequency hashmap and decrement the count as and when a new digit + * is formed. Sort the digits and return a concatenated string. + */ +public class ReconstructOriginalDigitsFromEnglish { + public static void main(String[] args) { + System.out.println( + new ReconstructOriginalDigitsFromEnglish() + .originalDigits( + "fviefurofviefurofviefurofviefurofviefurofviefurofviefurofviefurofviefurofviefuro")); + } + + public String originalDigits(String s) { + Map map = new HashMap<>(); + for (char c : s.toCharArray()) { + map.putIfAbsent(c, 0); + map.put(c, map.get(c) + 1); + } + Map intMap = new HashMap<>(); + if (map.containsKey('x')) { + update(map, intMap, 6, 'x', Arrays.asList('s', 'i', 'x')); + } + if (map.containsKey('g')) { + update(map, intMap, 8, 'g', Arrays.asList('e', 'i', 'g', 'h', 't')); + } + if (map.containsKey('w')) { + update(map, intMap, 2, 'w', Arrays.asList('t', 'w', 'o')); + } + if (map.containsKey('z')) { + update(map, intMap, 0, 'z', Arrays.asList('z', 'e', 'r', 'o')); + } + if (map.containsKey('u')) { + update(map, intMap, 4, 'u', Arrays.asList('f', 'o', 'u', 'r')); + } + if (map.containsKey('f')) { + update(map, intMap, 5, 'f', Arrays.asList('f', 'i', 'v', 'e')); + } + if (map.containsKey('v')) { + update(map, intMap, 7, 'v', Arrays.asList('s', 'e', 'v', 'e', 'n')); + } + if (map.containsKey('i')) { + update(map, intMap, 9, 'i', Arrays.asList('n', 'i', 'n', 'e')); + } + if (map.containsKey('t')) { + update(map, intMap, 3, 't', Arrays.asList('t', 'h', 'r', 'e', 'e')); + } + if (map.containsKey('o')) { + update(map, intMap, 1, 'o', Arrays.asList('o', 'n', 'e')); + } + Set keys = intMap.keySet(); + List list = new ArrayList<>(keys); + list.sort(Comparator.comparingInt(o -> o)); + StringBuilder sb = new StringBuilder(); + for (int i : list) { + int count = intMap.get(i); + while (count-- > 0) { + sb.append(i); + } + } + return sb.toString(); + } + + private void update( + Map map, + Map intMap, + int num, + char id, + List list) { + if (map.containsKey(id)) { + int count = map.get(id); + intMap.put(num, count); + while (count-- > 0) { + for (char c : list) { + map.put(c, map.get(c) - 1); + } + } + } + } +} diff --git a/src/main/java/string/RepeatedSubstringPattern.java b/src/main/java/string/RepeatedSubstringPattern.java new file mode 100644 index 00000000..c0a31d9e --- /dev/null +++ b/src/main/java/string/RepeatedSubstringPattern.java @@ -0,0 +1,53 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 25/03/2017. Given a non-empty string check if it can be + * constructed by taking a substring of it and appending multiple copies of the substring together. + * You may assume the given string consists of lowercase English letters only and its length will + * not exceed 10000. + * + *

Example 1: Input: "abab" + * + *

Output: True + * + *

Explanation: It's the substring "ab" twice. Example 2: Input: "aba" + * + *

Output: False Example 3: Input: "abcabcabcabc" + * + *

Output: True + * + *

Explanation: It's the substring "abc" four times. (And the substring "abcabc" twice.) + */ +public class RepeatedSubstringPattern { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new RepeatedSubstringPattern().repeatedSubstringPattern("a")); + } + + public boolean repeatedSubstringPattern(String s) { + boolean found; + for (int i = 1, l = s.length(); i < l; i++) { + found = true; + String subI = s.substring(0, i); + int j = i; + if (j >= l) return false; + while (j < l) { + if ((j + i) >= l + 1) return false; + String subJ = s.substring(j, j + i); + if (!subI.equals(subJ)) { + found = false; + break; + } + j += i; + } + if (found) return true; + } + return false; + } +} diff --git a/src/main/java/string/ReplaceWords.java b/src/main/java/string/ReplaceWords.java new file mode 100644 index 00000000..b85be6ba --- /dev/null +++ b/src/main/java/string/ReplaceWords.java @@ -0,0 +1,108 @@ +/* (C) 2024 YourCompanyName */ +package string; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +/** + * Created by gouthamvidyapradhan on 04/04/2019 In English, we have a concept called root, which can + * be followed by some other words to form another longer word - let's call this word successor. For + * example, the root an, followed by other, which can form another word another. + * + *

Now, given a dictionary consisting of many roots and a sentence. You need to replace all the + * successor in the sentence with the root forming it. If a successor has many roots can form it, + * replace it with the root with the shortest length. + * + *

You need to output the sentence after the replacement. + * + *

Example 1: + * + *

Input: dict = ["cat", "bat", "rat"] sentence = "the cattle was rattled by the battery" Output: + * "the cat was rat by the bat" + * + *

Note: + * + *

The input will only have lower-case letters. 1 <= dict words number <= 1000 1 <= sentence + * words number <= 1000 1 <= root length <= 100 1 <= sentence words length <= 1000 + * + *

Solution: O(w + S) where w is the max length of each word in the dictionary and S is the + * length of the string. Add all the words in the dictionary to a trie and evaluate each word in the + * string to check if it matches any path in the trie. Terminate the search as soon as a leaf node + * in the trie has been reached. + */ +public class ReplaceWords { + class Trie { + private Map map; + + /** Initialize your data structure here. */ + public Trie() { + map = new HashMap<>(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + if (word != null) { + add(0, word, word.length()); + } + } + + public String find(String s) { + return search(this, s, 0, new StringBuilder()); + } + + private void add(int i, String word, int length) { + if (i < length) { + char c = word.charAt(i); + Trie subTrie = map.get(c); + if (subTrie == null) { + subTrie = new Trie(); + map.put(c, subTrie); + } + subTrie.add(i + 1, word, length); + } else map.put(null, new Trie()); // use null to indicate end of string + } + + private String search(Trie curr, String s, int i, StringBuilder sb) { + if (s.length() == i) return sb.toString(); + else { + Trie subTrie = curr.map.get(s.charAt(i)); + if (subTrie == null) { + return curr.map.containsKey(null) ? sb.toString() : ""; + } else { + sb.append(s.charAt(i)); + if (subTrie.map.containsKey(null)) return sb.toString(); + return search(subTrie, s, i + 1, sb); + } + } + } + } + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + List words = Arrays.asList("a", "aa", "aaa"); + String sentence = "aa aa"; + System.out.println(new ReplaceWords().replaceWords(words, sentence)); + } + + public String replaceWords(List dict, String sentence) { + Trie root = new Trie(); + dict.forEach(root::insert); + String[] words = sentence.split(" "); + StringBuilder result = new StringBuilder(); + Stream.of(words) + .map( + w -> { + String s = root.find(w); + return s.isEmpty() ? w.concat(" ") : s.concat(" "); + }) + .forEach(result::append); + return result.toString().trim(); + } +} diff --git a/src/main/java/string/ReverseStringII.java b/src/main/java/string/ReverseStringII.java new file mode 100644 index 00000000..7550f99e --- /dev/null +++ b/src/main/java/string/ReverseStringII.java @@ -0,0 +1,38 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 30/07/2019 Given a string and an integer k, you need to reverse + * the first k characters for every 2k characters counting from the start of the string. If there + * are less than k characters left, reverse all of them. If there are less than 2k but greater than + * or equal to k characters, then reverse the first k characters and left the other as original. + * Example: Input: s = "abcdefg", k = 2 Output: "bacdfeg" Restrictions: The string consists of lower + * English letters only. Length of the given string and k will in the range [1, 10000] + * + *

Solution O(N) + */ +public class ReverseStringII { + public static void main(String[] args) { + System.out.println(new ReverseStringII().reverseStr("abcdefg", 2)); + } + + public String reverseStr(String s, int k) { + StringBuilder sb = new StringBuilder(); + for (int i = 0, l = s.length(); i < l; i++) { + if (i % (2 * k) == 0) { + int count = 0; + StringBuilder temp = new StringBuilder(); + while (count < k && i < l) { + temp.append(s.charAt(i)); + count++; + i++; + } + sb.append(temp.reverse()); + } + if (i < l) { + sb.append(s.charAt(i)); + } + } + return sb.toString(); + } +} diff --git a/src/main/java/string/ReverseWordsII.java b/src/main/java/string/ReverseWordsII.java new file mode 100644 index 00000000..ba001240 --- /dev/null +++ b/src/main/java/string/ReverseWordsII.java @@ -0,0 +1,66 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 21/03/2017. Given an input string, reverse the string word by + * word. A word is defined as a sequence of non-space characters. + * + *

The input string does not contain leading or trailing spaces and the words are always + * separated by a single space. + * + *

For example, Given s = "the sky is blue", return "blue is sky the". + * + *

Could you do it in-place without allocating extra space? + */ +public class ReverseWordsII { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + char[] c = {'t', 'h', 'e', ' ', 's', 'k', 'y', ' ', 'i', 's', ' ', 'b', 'l', 'u', 'e'}; + new ReverseWordsII().reverseWords(c); + for (char i : c) System.out.print(i); + } + + public void reverseWords(char[] s) { + for (int i = 0, j = s.length - 1; i < j; i++, j--) { + char temp = s[i]; + s[i] = s[j]; + s[j] = temp; + } + for (int i = 0, j = 0, l = s.length; i < l; ) { + if (s[i] == ' ') { + if (s[i - 1] == ' ') { + j = i; + i++; + j++; + } else { + i = i - 1; + for (int p = j, q = i; p < q; p++, q--) { + char temp = s[p]; + s[p] = s[q]; + s[q] = temp; + } + i = i + 1; + j = i; + i++; + j++; + } + } else if (i == l - 1) { + for (int p = j, q = i; p < q; p++, q--) { + char temp = s[p]; + s[p] = s[q]; + s[q] = temp; + } + j = i; + i++; + j++; + } else { + i++; + } + } + } +} diff --git a/src/main/java/string/ReverseWordsInAString.java b/src/main/java/string/ReverseWordsInAString.java new file mode 100644 index 00000000..6e71c8c2 --- /dev/null +++ b/src/main/java/string/ReverseWordsInAString.java @@ -0,0 +1,44 @@ +/* (C) 2024 YourCompanyName */ +package string; + +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +/** + * Created by gouthamvidyapradhan on 04/07/2017. Given an input string, reverse the string word by + * word. + * + *

For example, Given s = "the sky is blue", return "blue is sky the". + * + *

Clarification: What constitutes a word? A sequence of non-space characters constitutes a word. + * Could the input string contain leading or trailing spaces? Yes. However, your reversed string + * should not contain leading or trailing spaces. How about multiple spaces between two words? + * Reduce them to a single space in the reversed string. + */ +public class ReverseWordsInAString { + public static void main(String[] args) throws Exception { + System.out.println(new ReverseWordsInAString().reverseWords(" the sky is blue")); + } + + public String reverseWords(String s) { + if (s == null || s.isEmpty()) return ""; + StringBuilder sb = new StringBuilder(s.trim()); + String reverse = sb.reverse().toString(); + StringTokenizer st = new StringTokenizer(reverse, " "); + List list = new ArrayList<>(); + while (st.hasMoreTokens()) { + list.add(st.nextToken()); + } + for (int i = 0, l = list.size(); i < l; i++) { + String str = list.get(i); + String newStr = new StringBuilder(str).reverse().toString(); + list.set(i, newStr); + } + StringBuilder result = new StringBuilder(); + for (String str : list) { + result.append(str).append(" "); + } + return result.toString().trim(); + } +} diff --git a/src/main/java/string/RotateString.java b/src/main/java/string/RotateString.java new file mode 100644 index 00000000..548bb2fe --- /dev/null +++ b/src/main/java/string/RotateString.java @@ -0,0 +1,41 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 28/03/2019 We are given two strings, A and B. + * + *

A shift on A consists of taking string A and moving the leftmost character to the rightmost + * position. For example, if A = 'abcde', then it will be 'bcdea' after one shift on A. Return True + * if and only if A can become B after some number of shifts on A. + * + *

Example 1: Input: A = 'abcde', B = 'cdeab' Output: true + * + *

Example 2: Input: A = 'abcde', B = 'abced' Output: false Note: + * + *

A and B will have length at most 100. + */ +public class RotateString { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + System.out.println(new RotateString().rotateString("abcde", "cdeab")); + } + + public boolean rotateString(String A, String B) { + if (A.length() == 1 || A.isEmpty() || B.length() == 1 || B.isEmpty()) { + return A.equals(B); + } else if (A.length() != B.length()) { + return false; + } + for (int i = 0, l = A.length(); i < l; i++) { + char s = A.charAt(0); + A = A.substring(1) + s; + if (A.equals(B)) return true; + } + return false; + } +} diff --git a/src/main/java/string/ShortestPalindrome.java b/src/main/java/string/ShortestPalindrome.java new file mode 100644 index 00000000..ef68c011 --- /dev/null +++ b/src/main/java/string/ShortestPalindrome.java @@ -0,0 +1,60 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 21/07/2018. + * + *

Given a string s, you are allowed to convert it to a palindrome by adding characters in front + * of it. Find and return the shortest palindrome you can find by performing this transformation. + * + *

Example 1: + * + *

Input: "aacecaaa" Output: "aaacecaaa" Example 2: + * + *

Input: "abcd" Output: "dcbabcd" + * + *

Solution: O(N ^ 2): for i : (s.length() - 1 -> 0) check if (0, i) is a paliandrome, if not + * append char at i to result string else return string (result + (0, i)) + */ +public class ShortestPalindrome { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new ShortestPalindrome().shortestPalindrome("aaaaaaaaaa")); + } + + public String shortestPalindrome(String s) { + if (s.length() == 0 || s.length() == 1) { + return s; + } else if (s.length() == 2) { + if (s.charAt(0) == s.charAt(1)) { + return s; + } else { + return (s.charAt(1) + s); + } + } + if (isPaliandrome(s, 0, s.length() - 1)) return s; + StringBuilder sb = new StringBuilder(""); + for (int i = 0, j = s.length() - 1; j >= i; j--) { + if (!isPaliandrome(s, i, j)) { + sb.append(s.charAt(j)); + } else { + sb.append(s.substring(0, s.length())); + break; + } + } + return sb.toString(); + } + + boolean isPaliandrome(String s, int x, int y) { + for (int i = x, j = y; i < j; i++, j--) { + if (s.charAt(i) != s.charAt(j)) return false; + } + return true; + } +} diff --git a/src/main/java/string/SimplifyPath.java b/src/main/java/string/SimplifyPath.java new file mode 100644 index 00000000..0f4ab3bc --- /dev/null +++ b/src/main/java/string/SimplifyPath.java @@ -0,0 +1,49 @@ +/* (C) 2024 YourCompanyName */ +package string; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.StringTokenizer; + +/** + * Created by gouthamvidyapradhan on 28/07/2017. + * + *

Given an absolute path for a file (Unix-style), simplify it. + * + *

For example, path = "/home/", => "/home" path = "/a/./b/../../c/", => "/c" + * + *

Corner Cases: Did you consider the case where path = "/../"? In this case, you should return + * "/". Another corner case is the path might contain multiple slashes '/' together, such as + * "/home//foo/". In this case, you should ignore redundant slashes and return "/home/foo". + */ +public class SimplifyPath { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new SimplifyPath().simplifyPath("/home/")); + } + + public String simplifyPath(String path) { + if (path == null || path.isEmpty()) return "/"; + StringTokenizer st = new StringTokenizer(path, "/"); + Deque dQueue = new ArrayDeque<>(); + while (st.hasMoreTokens()) { + String token = st.nextToken(); + if (token.trim().equals("..")) { + if (!dQueue.isEmpty()) dQueue.pop(); + } else if (token.trim().equals(".")) { + // ignore + } else dQueue.push(token); + } + if (dQueue.isEmpty()) return "/"; + StringBuilder finalStr = new StringBuilder(); + while (!dQueue.isEmpty()) { + finalStr.append("/").append(dQueue.removeLast()); + } + return finalStr.toString(); + } +} diff --git a/src/main/java/string/SplitConcatenatedStrings.java b/src/main/java/string/SplitConcatenatedStrings.java new file mode 100644 index 00000000..139605c1 --- /dev/null +++ b/src/main/java/string/SplitConcatenatedStrings.java @@ -0,0 +1,67 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 10/05/2019 Given a list of strings, you could concatenate these + * strings together into a loop, where for each string you could choose to reverse it or not. Among + * all the possible loops, you need to find the lexicographically biggest string after cutting the + * loop, which will make the looped string into a regular one. + * + *

Specifically, to find the lexicographically biggest string, you need to experience two phases: + * + *

Concatenate all the strings into a loop, where you can reverse some strings or not and connect + * them in the same order as given. Cut and make one breakpoint in any place of the loop, which will + * make the looped string into a regular one starting from the character at the cutpoint. And your + * job is to find the lexicographically biggest one among all the possible regular strings. + * + *

Example: Input: "abc", "xyz" Output: "zyxcba" Explanation: You can get the looped string + * "-abcxyz-", "-abczyx-", "-cbaxyz-", "-cbazyx-", where '-' represents the looped status. The + * answer string came from the fourth looped one, where you could cut from the middle character 'a' + * and get "zyxcba". Note: The input strings will only contain lowercase letters. The total length + * of all the strings will not over 1,000. + */ +public class SplitConcatenatedStrings { + public static void main(String[] args) { + String[] A = {"abc"}; + System.out.println(new SplitConcatenatedStrings().splitLoopedString(A)); + } + + public String splitLoopedString(String[] strs) { + String max = ""; + for (int i = 0; i < strs.length; i++) { + String s = strs[i]; + String result = findMax(strs, (i + 1) % strs.length); + + String ans; + for (int k = 0, l = s.length(); k < l; k++) { + StringBuilder sb = new StringBuilder(); + String start = s.substring(k); + String end = s.substring(0, k); + ans = sb.append(start).append(result).append(end).toString(); + max = max.compareTo(ans) > 0 ? max : ans; + } + + s = new StringBuilder(s).reverse().toString(); + for (int k = 0, l = s.length(); k < l; k++) { + StringBuilder sb = new StringBuilder(); + String start = s.substring(k); + String end = s.substring(0, k); + ans = sb.append(start).append(result).append(end).toString(); + max = max.compareTo(ans) > 0 ? max : ans; + } + } + return max; + } + + private String findMax(String[] strs, int i) { + int c = 1; + StringBuilder sb = new StringBuilder(); + for (int j = i, l = strs.length; c < l; j = (j + 1) % l, c++) { + String nextStr = strs[j]; + String reverse = new StringBuilder(nextStr).reverse().toString(); + String result = nextStr.compareTo(reverse) > 0 ? nextStr : reverse; + sb.append(result); + } + return sb.toString(); + } +} diff --git a/src/main/java/string/StampingTheSequence.java b/src/main/java/string/StampingTheSequence.java new file mode 100644 index 00000000..1ba7694d --- /dev/null +++ b/src/main/java/string/StampingTheSequence.java @@ -0,0 +1,123 @@ +/* (C) 2024 YourCompanyName */ +package string; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Created by gouthamvidyapradhan on 12/10/2019 You want to form a target string of lowercase + * letters. + * + *

At the beginning, your sequence is target.length '?' marks. You also have a stamp of lowercase + * letters. + * + *

On each turn, you may place the stamp over the sequence, and replace every letter in the + * sequence with the corresponding letter from the stamp. You can make up to 10 * target.length + * turns. + * + *

For example, if the initial sequence is "?????", and your stamp is "abc", then you may make + * "abc??", "?abc?", "??abc" in the first turn. (Note that the stamp must be fully contained in the + * boundaries of the sequence in order to stamp.) + * + *

If the sequence is possible to stamp, then return an array of the index of the left-most + * letter being stamped at each turn. If the sequence is not possible to stamp, return an empty + * array. + * + *

For example, if the sequence is "ababc", and the stamp is "abc", then we could return the + * answer [0, 2], corresponding to the moves "?????" -> "abc??" -> "ababc". + * + *

Also, if the sequence is possible to stamp, it is guaranteed it is possible to stamp within 10 + * * target.length moves. Any answers specifying more than this number of moves will not be + * accepted. + * + *

Example 1: + * + *

Input: stamp = "abc", target = "ababc" Output: [0,2] ([1,0,2] would also be accepted as an + * answer, as well as some other answers.) Example 2: + * + *

Input: stamp = "abca", target = "aabcaca" Output: [3,0,1] + * + *

Note: + * + *

1 <= stamp.length <= target.length <= 1000 stamp and target only contain lowercase letters. + * + *

Solution: O(N ^ 2) General idea is to work the answer in the reverse order. For example if the + * target string is 'aaabb' and stamp is 'aabb' then first stamp would be at 0 resulting in aabb? + * and the next stamp would be at 1 resulting in 'aaabb' Consider each window of size = stamp.size + * from index 0 (call this window at index i). For every window keep track of matched indices and + * unmatched indices. Also, additionally Maintain a general-matched-index set containing all the + * indices that are already matched. For every window, if all the characters at each index of stamp + * sequence and target sequence match then add the window index to the answer also additionally + * revisit every widow index that have been previously visited in starting from i - 1 to 0 and + * verify if any window contains all the matched indices this can be checked by verifying the + * unmatched set at each widow to general-matched-index - if any of the window satisfy this + * condition then add this window index to the answer. Return the answer in the reverse order. + */ +public class StampingTheSequence { + public static void main(String[] args) { + int[] ans = new StampingTheSequence().movesToStamp("abca", "aaaaaaaaabcaaca"); + for (int a : ans) System.out.print(a + " "); + } + + private class Window { + Set matched, unmatched; + + Window(Set matched, Set unmatched) { + this.matched = matched; + this.unmatched = unmatched; + } + } + + public int[] movesToStamp(String stamp, String target) { + List windows = new ArrayList<>(); + Set matchedTarget = new HashSet<>(); + Stack answer = new Stack<>(); + for (int i = 0; i <= target.length() - stamp.length(); i++) { + Window current = new Window(new HashSet<>(), new HashSet<>()); + for (int j = i, s = 0; j < (i + stamp.length()); j++, s++) { + if (stamp.charAt(s) == target.charAt(j) || matchedTarget.contains(j)) { + current.matched.add(j); + } else current.unmatched.add(j); + } + if (current.unmatched.isEmpty()) { + answer.push(i); + matchedTarget.addAll(current.matched); + for (int k = windows.size() - 1; k >= 0; k--) { + if (!windows.get(k).unmatched.isEmpty()) { + Set newUnmatched = + windows + .get(k) + .unmatched + .stream() + .filter(u -> !matchedTarget.contains(u)) + .collect(Collectors.toSet()); + windows.get(k).unmatched = newUnmatched; + if (newUnmatched.isEmpty()) { + Set newMatched = + windows + .get(k) + .matched + .stream() + .filter(m -> !matchedTarget.contains(m)) + .collect(Collectors.toSet()); + if (!newMatched.isEmpty()) { + answer.push(k); + matchedTarget.addAll(newMatched); + } + } + } else break; + } + } + windows.add(current); + } + if (matchedTarget.size() == target.length()) { + int[] finalAns = new int[answer.size()]; + int i = 0; + while (!answer.isEmpty()) { + finalAns[i++] = answer.pop(); + } + return finalAns; + } + return new int[] {}; + } +} diff --git a/src/main/java/string/StringCompression.java b/src/main/java/string/StringCompression.java new file mode 100644 index 00000000..5c2144aa --- /dev/null +++ b/src/main/java/string/StringCompression.java @@ -0,0 +1,81 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 12/04/2018. Given an array of characters, compress it in-place. + * + *

The length after compression must always be smaller than or equal to the original array. + * + *

Every element of the array should be a character (not int) of length 1. + * + *

After you are done modifying the input array in-place, return the new length of the array. + * + *

Follow up: Could you solve it using only O(1) extra space? + * + *

Example 1: Input: ["a","a","b","b","c","c","c"] + * + *

Output: Return 6, and the first 6 characters of the input array should be: + * ["a","2","b","2","c","3"] + * + *

Explanation: "aa" is replaced by "a2". "bb" is replaced by "b2". "ccc" is replaced by "c3". + * Example 2: Input: ["a"] + * + *

Output: Return 1, and the first 1 characters of the input array should be: ["a"] + * + *

Explanation: Nothing is replaced. Example 3: Input: + * ["a","b","b","b","b","b","b","b","b","b","b","b","b"] + * + *

Output: Return 4, and the first 4 characters of the input array should be: ["a","b","1","2"]. + * + *

Explanation: Since the character "a" does not repeat, it is not compressed. "bbbbbbbbbbbb" is + * replaced by "b12". Notice each digit has it's own entry in the array. Note: All characters have + * an ASCII value in [35, 126]. 1 <= len(chars) <= 1000. + * + *

Solution O(N) time complexity and O(1) space complexity. Maintain read and write pointers. + * Read from read pointer and increment count when a repetition is found, when there is no + * repetition write the count value using write pointer. + */ +public class StringCompression { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + char[] A = {'a', 'a', 'b', 'b', 'c', 'c', 'c'}; + System.out.println(new StringCompression().compress(A)); + } + + public int compress(char[] chars) { + int count = 0; + int i = 0; + int p = 0; + for (int j = 0; j < chars.length; j++) { + if (chars[i] == chars[j]) { + count++; + } else { + chars[p] = chars[i]; + p++; + if (count > 1) { + String countStr = String.valueOf(count); + for (int l = 0; l < countStr.length(); l++) { + chars[p++] = countStr.charAt(l); + } + } + i = j; + count = 1; + } + } + chars[p] = chars[i]; + p++; + if (count > 1) { + String countStr = String.valueOf(count); + for (int l = 0; l < countStr.length(); l++) { + chars[p++] = countStr.charAt(l); + } + } + return p; + } +} diff --git a/src/main/java/string/StringToInteger.java b/src/main/java/string/StringToInteger.java new file mode 100644 index 00000000..fb5df48f --- /dev/null +++ b/src/main/java/string/StringToInteger.java @@ -0,0 +1,54 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 21/03/2017. Implement atoi to convert a string to an integer. + * + *

Hint: Carefully consider all possible input cases. If you want a challenge, please do not see + * below and ask yourself what are the possible input cases. + * + *

Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You + * are responsible to gather all the input requirements up front. + */ +public class StringToInteger { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new StringToInteger().myAtoi(" 2147483649a sdfasdf")); + } + + public int myAtoi(String str) { + boolean isPositive = true; + if (str == null || str.trim().isEmpty()) return 0; + str = str.trim(); + if (str.charAt(0) == '+') { + isPositive = true; + str = str.substring(1, str.length()); + } else if (str.charAt(0) == '-') { + isPositive = false; + str = str.substring(1, str.length()); + } else if (str.charAt(0) > '9' || str.charAt(0) < '0') return 0; + int i = 0; + for (int l = str.length(); i < l; i++) { + if (str.charAt(i) > '9' || str.charAt(i) < '0') break; + } + str = str.substring(0, i); + long num = 0; + for (int j = 0, l = str.length(); j < l; j++) { + int n = (str.charAt(j) - '0'); + num *= 10; + num += n; + if (isPositive) { + if (num > Integer.MAX_VALUE) return Integer.MAX_VALUE; + } else { + if ((num * -1) < Integer.MIN_VALUE) return Integer.MIN_VALUE; + } + } + if (isPositive) return (int) num; + else return (int) (num * -1); + } +} diff --git a/src/main/java/string/StudentAttendanceRecordI.java b/src/main/java/string/StudentAttendanceRecordI.java new file mode 100644 index 00000000..da553682 --- /dev/null +++ b/src/main/java/string/StudentAttendanceRecordI.java @@ -0,0 +1,30 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 10/05/2019 You are given a string representing an attendance + * record for a student. The record only contains the following three characters: 'A' : Absent. 'L' + * : Late. 'P' : Present. A student could be rewarded if his attendance record doesn't contain more + * than one 'A' (absent) or more than two continuous 'L' (late). + * + *

You need to return whether the student could be rewarded according to his attendance record. + * + *

Example 1: Input: "PPALLP" Output: True Example 2: Input: "PPALLL" Output: False + * + *

Solution O(N) Simple linear check + */ +public class StudentAttendanceRecordI { + public static void main(String[] args) {} + + public boolean checkRecord(String s) { + int count = 0; + for (int c : s.toCharArray()) { + if (c == 'A') { + count++; + } + if (count > 1) return false; + } + if (s.contains("LLL")) return false; + return true; + } +} diff --git a/src/main/java/string/TextJustification.java b/src/main/java/string/TextJustification.java new file mode 100644 index 00000000..a8cb70c9 --- /dev/null +++ b/src/main/java/string/TextJustification.java @@ -0,0 +1,81 @@ +/* (C) 2024 YourCompanyName */ +package string; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 09/03/2017. Given an array of words and a length L, format the + * text such that each line has exactly L characters and is fully (left and right) justified. + * + *

You should pack your words in a greedy approach; that is, pack as many words as you can in + * each line. Pad extra spaces ' ' when necessary so that each line has exactly L characters. + * + *

Extra spaces between words should be distributed as evenly as possible. If the number of + * spaces on a line do not divide evenly between words, the empty slots on the left will be assigned + * more spaces than the slots on the right. + * + *

For the last line of text, it should be left justified and no extra space is inserted between + * words. + * + *

For example, words: ["This", "is", "an", "example", "of", "text", "justification."] L: 16. + * + *

Return the formatted lines as: [ "This is an", "example of text", "justification. " ] Note: + * Each word is guaranteed not to exceed L in length. + */ +public class TextJustification { + public List fullJustify(String[] words, int L) { + int wCount = 0, charCount = 0; + List line = new ArrayList<>(); + List result = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + + for (int i = 0, l = words.length; i < l; i++) { + String next = words[i]; + if ((L - (charCount + wCount)) >= next.length()) { + line.add(next); + charCount += next.length(); + wCount++; + } else { + // justify and add to list + sb.append(line.get(0)); + StringBuilder space = new StringBuilder(); + if (line.size() > 1) { + int spaceCount = (L - charCount) / (wCount - 1); + int remaining = (L - charCount) % (wCount - 1); + + for (int j = 0; j < spaceCount; j++) space.append(' '); + + for (int k = 1, kl = line.size(); k < kl; k++) { + sb.append(space); + if (remaining > 0) { + sb.append(' '); + --remaining; + } + sb.append(line.get(k)); + } + } else { + int balance = L - (charCount + (wCount - 1)); + for (int j = 0; j < balance; j++) sb.append(' '); + } + result.add(sb.toString()); + sb = new StringBuilder(); + line.clear(); + line.add(next); + charCount = next.length(); + wCount = 1; + } + } + if (!line.isEmpty()) { + sb.append(line.get(0)); + for (int i = 1, l = line.size(); i < l; i++) { + sb.append(' '); + sb.append(line.get(i)); + } + } + int balance = L - (charCount + (wCount - 1)); + for (int i = 0; i < balance; i++) sb.append(' '); + result.add(sb.toString()); + return result; + } +} diff --git a/src/main/java/string/ValidPalindrome.java b/src/main/java/string/ValidPalindrome.java new file mode 100644 index 00000000..384ec3ac --- /dev/null +++ b/src/main/java/string/ValidPalindrome.java @@ -0,0 +1,41 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 13/07/2017. Given a string, determine if it is a palindrome, + * considering only alphanumeric characters and ignoring cases. + * + *

For example, "A man, a plan, a canal: Panama" is a palindrome. "race a car" is not a + * palindrome. + * + *

Note: Have you consider that the string might be empty? This is a good question to ask during + * an interview. + * + *

For the purpose of this problem, we define empty string as valid palindrome. + */ +public class ValidPalindrome { + public static void main(String[] args) throws Exception { + System.out.println(new ValidPalindrome().isPalindrome("989 ")); + } + + public boolean isPalindrome(String s) { + if (s == null || s.isEmpty()) return true; + s = s.toLowerCase(); + for (int i = 0, j = s.length() - 1; i < j; ) { + char f = s.charAt(i); + char l = s.charAt(j); + if (!(f >= 'a' && f <= 'z') && !(f >= '0' && f <= '9')) { + i++; + continue; + } + if (!(l >= 'a' && l <= 'z') && !(l >= '0' && l <= '9')) { + j--; + continue; + } + if (f != l) return false; + i++; + j--; + } + return true; + } +} diff --git a/src/main/java/string/ValidPalindromeII.java b/src/main/java/string/ValidPalindromeII.java new file mode 100644 index 00000000..37114591 --- /dev/null +++ b/src/main/java/string/ValidPalindromeII.java @@ -0,0 +1,45 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 09/12/2017. Given a non-empty string s, you may delete at most + * one character. Judge whether you can make it a palindrome. + * + *

Example 1: Input: "aba" Output: True Example 2: Input: "abca" Output: True Explanation: You + * could delete the character 'c'. Note: The string will only contain lowercase characters a-z. The + * maximum length of the string is 50000. + */ +public class ValidPalindromeII { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new ValidPalindromeII().validPalindrome("aaaaaab")); + } + + public boolean validPalindrome(String s) { + for (int i = 0, j = s.length() - 1; i < j; ) { + if (s.charAt(i) == s.charAt(j)) { + i++; + j--; + } else { + return isPaliandrome(s.substring(i, j)) || isPaliandrome(s.substring(i + 1, j + 1)); + } + } + return true; + } + + private boolean isPaliandrome(String s) { + for (int i = 0, j = s.length() - 1; i < j; ) { + if (s.charAt(i) == s.charAt(j)) { + i++; + j--; + } else return false; + } + return true; + } +} diff --git a/src/main/java/string/ValidWordAbbreviation.java b/src/main/java/string/ValidWordAbbreviation.java new file mode 100644 index 00000000..5630c91b --- /dev/null +++ b/src/main/java/string/ValidWordAbbreviation.java @@ -0,0 +1,71 @@ +/* (C) 2024 YourCompanyName */ +package string; +/** + * Created by gouthamvidyapradhan on 20/03/2019 Given a non-empty string s and an abbreviation abbr, + * return whether the string matches with the given abbreviation. + * + *

A string such as "word" contains only the following valid abbreviations: + * + *

["word", "1ord", "w1rd", "wo1d", "wor1", "2rd", "w2d", "wo2", "1o1d", "1or1", "w1r1", "1o2", + * "2r1", "3d", "w3", "4"] Notice that only the above abbreviations are valid abbreviations of the + * string "word". Any other string is not a valid abbreviation of "word". + * + *

Note: Assume s contains only lowercase letters and abbr contains only lowercase letters and + * digits. + * + *

Example 1: Given s = "internationalization", abbr = "i12iz4n": + * + *

Return true. Example 2: Given s = "apple", abbr = "a2e": + * + *

Return false. + */ +public class ValidWordAbbreviation { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + System.out.println(new ValidWordAbbreviation().validWordAbbreviation("abbreviation", "a10n")); + } + + public boolean validWordAbbreviation(String word, String abbr) { + if (abbr.length() > word.length()) return false; + StringBuilder num = new StringBuilder(); + int j = 0; + for (int i = 0; i < abbr.length() && j < word.length(); i++) { + char curr = abbr.charAt(i); + if (curr == '0' && num.toString().isEmpty()) return false; + if (curr >= '0' && curr <= '9') { + num.append(curr); + } else { + if (num.toString().isEmpty()) { + if (word.charAt(j) != abbr.charAt(i)) { + return false; + } + j++; + } else { + int next = Integer.parseInt(num.toString()); + j += next; + if (word.length() <= j) { + return false; + } + if (word.charAt(j) != abbr.charAt(i)) { + return false; + } + num = new StringBuilder(); + j++; + } + } + } + if (!num.toString().isEmpty()) { + int next = Integer.parseInt(num.toString()); + j += next; + if (j > word.length() || j < word.length()) { + return false; + } + } + return true; + } +} diff --git a/src/main/java/string/ValidWordSquare.java b/src/main/java/string/ValidWordSquare.java new file mode 100644 index 00000000..6b5a8f3e --- /dev/null +++ b/src/main/java/string/ValidWordSquare.java @@ -0,0 +1,78 @@ +/* (C) 2024 YourCompanyName */ +package string; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 04/06/2019 Given a sequence of words, check whether it forms a + * valid word square. + * + *

A sequence of words forms a valid word square if the kth row and column read the exact same + * string, where 0 ≤ k < max(numRows, numColumns). + * + *

Note: The number of words given is at least 1 and does not exceed 500. Word length will be at + * least 1 and does not exceed 500. Each word contains only lowercase English alphabet a-z. Example + * 1: + * + *

Input: [ "abcd", "bnrt", "crmy", "dtye" ] + * + *

Output: true + * + *

Explanation: The first row and first column both read "abcd". The second row and second column + * both read "bnrt". The third row and third column both read "crmy". The fourth row and fourth + * column both read "dtye". + * + *

Therefore, it is a valid word square. Example 2: + * + *

Input: [ "abcd", "bnrt", "crm", "dt" ] + * + *

Output: true + * + *

Explanation: The first row and first column both read "abcd". The second row and second column + * both read "bnrt". The third row and third column both read "crm". The fourth row and fourth + * column both read "dt". + * + *

Therefore, it is a valid word square. Example 3: + * + *

Input: [ "ball", "area", "read", "lady" ] + * + *

Output: false + * + *

Explanation: The third row reads "read" while the third column reads "lead". + * + *

Therefore, it is NOT a valid word square. + * + *

Solution: O(N x M) where N is number of words and M is max length of a string. Save strings + * for each column and each row in a array and compare them both. + */ +public class ValidWordSquare { + public static void main(String[] args) { + List arr = Arrays.asList("abcd", "bnrt", "crmy", "dtye"); + System.out.println(new ValidWordSquare().validWordSquare(arr)); + } + + public boolean validWordSquare(List words) { + List newList = new ArrayList<>(); + int max = 0; + for (int i = 0; i < words.size(); i++) { + max = Math.max(max, words.get(i).length()); + } + + for (int i = 0; i < max; i++) { + StringBuilder sb = new StringBuilder(); + for (String w : words) { + if (i < w.length()) { + sb.append(w.charAt(i)); + } else break; + } + newList.add(sb.toString()); + } + + if (words.size() != newList.size()) return false; + + for (int i = 0, l = words.size(); i < l; i++) { + if (!words.get(i).equals(newList.get(i))) return false; + } + return true; + } +} diff --git a/src/main/java/string/ValidateIPAddress.java b/src/main/java/string/ValidateIPAddress.java new file mode 100644 index 00000000..a1df8914 --- /dev/null +++ b/src/main/java/string/ValidateIPAddress.java @@ -0,0 +1,96 @@ +/* (C) 2024 YourCompanyName */ +package string; + +/** + * Created by gouthamvidyapradhan on 01/08/2019 Write a function to check whether an input string is + * a valid IPv4 address or IPv6 address or neither. + * + *

IPv4 addresses are canonically represented in dot-decimal notation, which consists of four + * decimal numbers, each ranging from 0 to 255, separated by dots ("."), e.g.,172.16.254.1; + * + *

Besides, leading zeros in the IPv4 is invalid. For example, the address 172.16.254.01 is + * invalid. + * + *

IPv6 addresses are represented as eight groups of four hexadecimal digits, each group + * representing 16 bits. The groups are separated by colons (":"). For example, the address + * 2001:0db8:85a3:0000:0000:8a2e:0370:7334 is a valid one. Also, we could omit some leading zeros + * among four hexadecimal digits and some low-case characters in the address to upper-case ones, so + * 2001:db8:85a3:0:0:8A2E:0370:7334 is also a valid IPv6 address(Omit leading zeros and using upper + * cases). + * + *

However, we don't replace a consecutive group of zero value with a single empty group using + * two consecutive colons (::) to pursue simplicity. For example, 2001:0db8:85a3::8A2E:0370:7334 is + * an invalid IPv6 address. + * + *

Besides, extra leading zeros in the IPv6 is also invalid. For example, the address + * 02001:0db8:85a3:0000:0000:8a2e:0370:7334 is invalid. + * + *

Note: You may assume there is no extra space or special characters in the input string. + * + *

Example 1: Input: "172.16.254.1" + * + *

Output: "IPv4" + * + *

Explanation: This is a valid IPv4 address, return "IPv4". Example 2: Input: + * "2001:0db8:85a3:0:0:8A2E:0370:7334" + * + *

Output: "IPv6" + * + *

Explanation: This is a valid IPv6 address, return "IPv6". Example 3: Input: "256.256.256.256" + * + *

Output: "Neither" + * + *

Explanation: This is neither a IPv4 address nor a IPv6 address. + * + *

Solution: O(N) split the string by each '.' or ':' and then validate each parts. + */ +public class ValidateIPAddress { + public static void main(String[] args) { + + System.out.println( + new ValidateIPAddress().validIPAddress("02001:0db8:85a3:0000:0000:8a2e:0370:7334")); + } + + public String validIPAddress(String IP) { + if (IP.contains(".")) { + if (IP.endsWith(".") || IP.startsWith(".")) return "Neither"; + String[] ipv4 = IP.split("\\."); + if (ipv4.length != 4) return "Neither"; + else { + for (String part : ipv4) { + if (part.isEmpty()) return "Neither"; + if (part.length() > 1 && part.startsWith("0")) return "Neither"; + else { + if (part.length() > 3) return "Neither"; + for (char c : part.toCharArray()) { + if (c < '0' || c > '9') return "Neither"; + } + int value = Integer.parseInt(part); + if (value < 0 || value > 255) return "Neither"; + } + } + } + return "IPv4"; + } else if (IP.contains(":")) { + if (IP.endsWith(":") || IP.startsWith(":")) return "Neither"; + String[] ipv6 = IP.split(":"); + if (ipv6.length != 8) return "Neither"; + else { + for (String part : ipv6) { + if (part.isEmpty()) return "Neither"; + if (part.length() > 4) return "Neither"; + else { + for (char c : part.toCharArray()) { + if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { + + } else { + return "Neither"; + } + } + } + } + } + return "IPv6"; + } else return "Neither"; + } +} diff --git a/src/main/java/string/ZigZagConversion.java b/src/main/java/string/ZigZagConversion.java new file mode 100644 index 00000000..182e0015 --- /dev/null +++ b/src/main/java/string/ZigZagConversion.java @@ -0,0 +1,69 @@ +/* (C) 2024 YourCompanyName */ +package string; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 19/05/2017. The string "PAYPALISHIRING" is written in a zigzag + * pattern on a given number of rows like this: (you may want to display this pattern in a fixed + * font for better legibility) + * + *

P A H N A P L S I I G Y I R And then read line by line: "PAHNAPLSIIGYIR" Write the code that + * will take a string and make this conversion given a number of rows: + * + *

string convert(string text, int nRows); convert("PAYPALISHIRING", 3) should return + * "PAHNAPLSIIGYIR". + */ +public class ZigZagConversion { + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + System.out.println(new ZigZagConversion().convert("PAYPALISHIRING", 5)); + } + + /** + * Convert and return the result + * + * @param s input string + * @param numRows max rows + * @return Result string + */ + public String convert(String s, int numRows) { + if (s == null || s.length() <= numRows || numRows == 1) return s; + List list = new ArrayList<>(); + char[] A = new char[numRows]; + int direction = 1; // 1 indicates forward, 0 indicates backwards + int n = 1; + A[0] = s.charAt(0); + for (int j = 1; j < numRows; ) { + if (n >= s.length()) break; + A[j] = s.charAt(n++); + if (j == numRows - 1) { + list.add(String.valueOf(A)); + A = new char[numRows]; + Arrays.fill(A, ' '); + direction = 0; + } else if (j == 0) { + list.add(String.valueOf(A)); + A = new char[numRows]; + Arrays.fill(A, ' '); + direction = 1; + } + j = direction == 1 ? j + 1 : j - 1; + } + if (!String.valueOf(A).trim().isEmpty()) list.add(String.valueOf(A)); + char[] arr = new char[s.length()]; + int k = 0; + for (int j = 0; j < numRows; j++) { + for (String aList : list) { + if (aList.charAt(j) != ' ') arr[k++] = aList.charAt(j); + } + } + return new String(arr).trim(); + } +} diff --git a/src/main/java/tree/AllNodesDistanceKInBinaryTree.java b/src/main/java/tree/AllNodesDistanceKInBinaryTree.java new file mode 100644 index 00000000..aba385bb --- /dev/null +++ b/src/main/java/tree/AllNodesDistanceKInBinaryTree.java @@ -0,0 +1,116 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 26/04/2019 We are given a binary tree (with root node root), a + * target node, and an integer value K. + * + *

Return a list of the values of all nodes that have a distance K from the target node. The + * answer can be returned in any order. + * + *

Example 1: + * + *

Input: root = [3,5,1,6,2,0,8,null,null,7,4], target = 5, K = 2 + * + *

Output: [7,4,1] + * + *

3 / \ 5 1 / \ / \ 6 2 0 8 / \ 7 4 Explanation: The nodes that are a distance 2 from the target + * node (with value 5) have values 7, 4, and 1. + * + *

Note that the inputs "root" and "target" are actually TreeNodes. The descriptions of the + * inputs above are just serializations of these objects. + * + *

Note: + * + *

The given tree is non-empty. Each node in the tree has unique values 0 <= node.val <= 500. The + * target node is a node in the tree. 0 <= K <= 1000. + * + *

Solution: O(N) The general intuition is as below. All the nodes from which a target nodes can + * be reached (including the target node) can have child nodes at a distance of K from target node. + * All the nodes from which a target node cannot be reached definitely cannot have a child node at a + * distance of K from target node. Do a dfs from root to find the target node. As soon as a target + * node is found, all the nodes in the recursion stack are the ancestors of target node i.e the + * target node can be reached from each of these nodes. Now do another dfs from each of the nodes + * starting from target node and all its ancestors up to the root to find nodes at a distance of (K + * - dk) where dk is the distance to the target node. Keep track of visited nodes in order not to + * revisit the same node once again. + */ +public class AllNodesDistanceKInBinaryTree { + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) {} + + class Node { + int v, d; + + Node(int v, int d) { + this.d = d; + this.v = v; + } + } + + private Set done; + + public List distanceK(TreeNode root, TreeNode target, int K) { + done = new HashSet<>(); + List result = new ArrayList<>(); + findAndProcess(root, result, K, target); + return result; + } + + private int findAndProcess(TreeNode node, List result, int K, TreeNode target) { + if (node != null) { + if (target == node) { + fillResult(node, result, 0, K); + return 1; + } else { + int status = findAndProcess(node.left, result, K, target); + if (status > 0) { + if (K - status >= 0) { + fillResult(node, result, 0, K - status); + } + return status + 1; + } else { + status = findAndProcess(node.right, result, K, target); + if (status > 0) { + if (K - status >= 0) { + fillResult(node, result, 0, K - status); + } + return status + 1; + } + } + return -1; + } + } else return -1; + } + + private void fillResult(TreeNode node, List result, int d, int K) { + done.add(node.val); + if (d == K) { + result.add(node.val); + return; + } + if (node.left != null && !done.contains(node.left.val)) { + fillResult(node.left, result, d + 1, K); + } + if (node.right != null && !done.contains(node.right.val)) { + fillResult(node.right, result, d + 1, K); + } + } +} diff --git a/src/main/java/tree/AllPossibleFullBinaryTrees.java b/src/main/java/tree/AllPossibleFullBinaryTrees.java new file mode 100644 index 00000000..0925a91c --- /dev/null +++ b/src/main/java/tree/AllPossibleFullBinaryTrees.java @@ -0,0 +1,79 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 30/04/2019 A full binary tree is a binary tree where each node + * has exactly 0 or 2 children. + * + *

Return a list of all possible full binary trees with N nodes. Each element of the answer is + * the root node of one possible tree. + * + *

Each node of each tree in the answer must have node.val = 0. + * + *

You may return the final list of trees in any order. + * + *

Example 1: + * + *

Input: 7 Output: + * [[0,0,0,null,null,0,0,null,null,0,0],[0,0,0,null,null,0,0,0,0],[0,0,0,0,0,0,0], + * [0,0,0,0,0,null,null,null, null,0,0],[0,0,0,0,0,null,null,0,0]] + * + *

Note: + * + *

1 <= N <= 20 + * + *

Solution: O(2 ^ N) A full binary tree can only be generated for a case with odd number of + * nodes. Start with a base case - when only one node is given a full binary tree can be formed with + * only one node. Cache this value in a hashmap. + * + *

Now, iteratively generate a list of possible trees for 3, 5, 7 . . . N - ((N + 1) % 2) and + * cache this in a hashmap. + */ +public class AllPossibleFullBinaryTrees { + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + List result = new AllPossibleFullBinaryTrees().allPossibleFBT(7); + System.out.println(result.size()); + } + + public List allPossibleFBT(int N) { + if (N % 2 == 0) return new ArrayList<>(); + Map> map = new HashMap<>(); + map.put(1, Arrays.asList(new TreeNode(0))); + for (int i = 3; i <= N; i += 2) { + List list = new ArrayList<>(); + for (int j = 1; j < i - 1; j += 2) { + int l = j, r = i - 1 - j; + List leftList = map.get(l); + List rightList = map.get(r); + for (TreeNode leftNode : leftList) { + for (TreeNode rightNode : rightList) { + TreeNode root = new TreeNode(0); + root.left = leftNode; + root.right = rightNode; + list.add(root); + } + } + } + map.put(i, list); + } + return map.get(N); + } +} diff --git a/src/main/java/tree/AverageOfLevelsInBinaryTree.java b/src/main/java/tree/AverageOfLevelsInBinaryTree.java new file mode 100644 index 00000000..d136b3ed --- /dev/null +++ b/src/main/java/tree/AverageOfLevelsInBinaryTree.java @@ -0,0 +1,76 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.List; +import java.util.Queue; + +/** + * Created by gouthamvidyapradhan on 16/12/2017. Given a non-empty binary tree, return the average + * value of the nodes on each level in the form of an array. Example 1: Input: 3 / \ 9 20 / \ 15 7 + * Output: [3, 14.5, 11] Explanation: The average value of nodes on level 0 is 3, on level 1 is + * 14.5, and on level 2 is 11. Hence return [3, 14.5, 11]. Note: The range of node's value is in the + * range of 32-bit signed integer. + * + *

Solution O(n) : Perform a BFS and calculate average for each level. + */ +public class AverageOfLevelsInBinaryTree { + + class LevelNode { + int level; + TreeNode node; + + LevelNode(int level, TreeNode node) { + this.level = level; + this.node = node; + } + } + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception {} + + public List averageOfLevels(TreeNode root) { + Queue queue = new ArrayDeque<>(); + LevelNode node = new LevelNode(0, root); + queue.offer(node); + int curLevel = 0, count = 0; + long sum = 0L; + List result = new ArrayList<>(); + while (!queue.isEmpty()) { + LevelNode first = queue.poll(); + if (first.level == curLevel) { + sum += first.node.val; + count++; + } else { + result.add((double) sum / count); + sum = first.node.val; + count = 1; + curLevel++; + } + if (first.node.left != null) { + queue.offer(new LevelNode(curLevel + 1, first.node.left)); + } + if (first.node.right != null) { + queue.offer(new LevelNode(curLevel + 1, first.node.right)); + } + } + result.add((double) sum / count); + return result; + } +} diff --git a/src/main/java/tree/BSTtoDoublyLinkedList.java b/src/main/java/tree/BSTtoDoublyLinkedList.java new file mode 100644 index 00000000..087bd4dc --- /dev/null +++ b/src/main/java/tree/BSTtoDoublyLinkedList.java @@ -0,0 +1,58 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 23/01/2018. Convert a BST to a sorted circular doubly-linked + * list in-place. Think of the left and right pointers as synonymous to the previous and next + * pointers in a doubly-linked list. + * + *

Solution: Do a preorder traversal, keep track of previous node at every step and construct the + * dd-linked list in-place. + */ +public class BSTtoDoublyLinkedList { + + static class Node { + public int val; + public Node left; + public Node right; + + public Node() {} + + public Node(int _val, Node _left, Node _right) { + val = _val; + left = _left; + right = _right; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + Node root = new Node(4, new Node(2, null, null), new Node(5, null, null)); + Node result = new BSTtoDoublyLinkedList().treeToDoublyList(root); + // print result + } + + public Node treeToDoublyList(Node root) { + if (root == null) return null; + Node head = new Node(); + Node last = preorder(root, head); + last.right = head.right; + head.right.left = last; + return head.right; + } + + Node preorder(Node node, Node prev) { + if (node == null) return prev; + else { + Node left = preorder(node.left, prev); + left.right = node; + node.left = left; + return preorder(node.right, node); + } + } +} diff --git a/src/main/java/tree/BinarayTreeRightSideView.java b/src/main/java/tree/BinarayTreeRightSideView.java new file mode 100644 index 00000000..360ade9e --- /dev/null +++ b/src/main/java/tree/BinarayTreeRightSideView.java @@ -0,0 +1,64 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 12/03/2017. Given a binary tree, imagine yourself standing on + * the right side of it, return the values of the nodes you can see ordered from top to bottom. + * + *

For example: Given the following binary tree, 1 <--- / \ 2 3 <--- \ \ 5 4 <--- You should + * return [1, 3, 4]. + */ +public class BinarayTreeRightSideView { + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + private int maxHeigh = Integer.MIN_VALUE; + List list = new ArrayList<>(); + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(2); + root.left = new TreeNode(3); + root.right = new TreeNode(4); + root.right.right = new TreeNode(5); + root.right.left = new TreeNode(4); + root.right.left.right = new TreeNode(8); + root.right.left.left = new TreeNode(7); + root.right.left.left.right = new TreeNode(10); + root.right.left.left.left = new TreeNode(7); + + List list = new BinarayTreeRightSideView().rightSideView(root); + } + + public List rightSideView(TreeNode root) { + if (root == null) return list; + dfs(root, 0); + return list; + } + + private void dfs(TreeNode node, int height) { + if (node != null) { + if (height > maxHeigh) { + list.add(node.val); + maxHeigh = height; + } + dfs(node.right, height + 1); + dfs(node.left, height + 1); + } + } +} diff --git a/src/main/java/tree/BinaryTreeInorderTraversal.java b/src/main/java/tree/BinaryTreeInorderTraversal.java new file mode 100644 index 00000000..31c4d8a5 --- /dev/null +++ b/src/main/java/tree/BinaryTreeInorderTraversal.java @@ -0,0 +1,56 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * Created by gouthamvidyapradhan on 06/08/2017. Given a binary tree, return the inorder traversal + * of its nodes' values. + * + *

For example: Given binary tree [1,null,2,3], 1 \ 2 / 3 return [1,3,2]. + * + *

Note: Recursive solution is trivial, could you do it iteratively? + */ +public class BinaryTreeInorderTraversal { + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(3); + root.left = new TreeNode(4); + root.left.left = new TreeNode(5); + root.left.right = new TreeNode(6); + root.left.left.left = new TreeNode(9); + root.left.left.right = new TreeNode(10); + root.right = new TreeNode(2); + root.right.left = new TreeNode(7); + root.right.right = new TreeNode(8); + List result = new BinaryTreeInorderTraversal().inorderTraversal(root); + System.out.println(result); + } + + public List inorderTraversal(TreeNode root) { + Stack stack = new Stack<>(); + TreeNode curr = root; + List result = new ArrayList<>(); + while (curr != null || !stack.isEmpty()) { + while (curr != null) { + stack.push(curr); + curr = curr.left; + } + curr = stack.pop(); + result.add(curr.val); + curr = curr.right; + } + return result; + } +} diff --git a/src/main/java/tree/BinaryTreeLongestConsecutiveSequenceII.java b/src/main/java/tree/BinaryTreeLongestConsecutiveSequenceII.java new file mode 100644 index 00000000..3505a092 --- /dev/null +++ b/src/main/java/tree/BinaryTreeLongestConsecutiveSequenceII.java @@ -0,0 +1,96 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 11/02/2018. Given a binary tree, you need to find the length of + * Longest Consecutive Path in Binary Tree. + * + *

Especially, this path can be either increasing or decreasing. For example, [1,2,3,4] and + * [4,3,2,1] are both considered valid, but the path [1,2,4,3] is not valid. On the other hand, the + * path can be in the child-Parent-child order, where not necessarily be parent-child order. + * + *

Example 1: Input: 1 / \ 2 3 Output: 2 Explanation: The longest consecutive path is [1, 2] or + * [2, 1]. Example 2: Input: 2 / \ 1 3 Output: 3 Explanation: The longest consecutive path is [1, 2, + * 3] or [3, 2, 1]. Note: All the values of tree nodes are in the range of [-1e7, 1e7]. + */ +public class BinaryTreeLongestConsecutiveSequenceII { + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + private class Node { + int i, d; + int val; + + Node(int i, int d, int val) { + this.i = i; + this.d = d; + this.val = val; + } + } + + private int max = Integer.MIN_VALUE; + + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(2); + root.left = new TreeNode(1); + // root.left.left = new TreeNode(4); + root.right = new TreeNode(3); + System.out.println(new BinaryTreeLongestConsecutiveSequenceII().longestConsecutive(root)); + } + + public int longestConsecutive(TreeNode root) { + Node n = preorder(root); + if (n != null) { + max = Math.max(max, n.d); + max = Math.max(max, n.i); + if (n.i > 1 && n.d > 1) { + max = Math.max(max, n.d + n.i - 1); + } + } + if (max == Integer.MIN_VALUE) return 0; + return max; + } + + private Node preorder(TreeNode node) { + if (node == null) return null; + Node left = preorder(node.left); + Node curr = new Node(1, 1, node.val); + if (left != null) { + max = Math.max(max, left.d); + max = Math.max(max, left.i); + if (left.val == node.val + 1) { + curr.d = left.d + 1; + curr.i = 1; + } else if (left.val == node.val - 1) { + curr.i = left.i + 1; + curr.d = 1; + } + } + Node right = preorder(node.right); + if (right != null) { + max = Math.max(max, right.d); + max = Math.max(max, right.i); + if (right.val == node.val + 1) { + if (right.d + 1 > curr.d) { + curr.d = right.d + 1; + } + } else if (right.val == node.val - 1) { + if (right.i + 1 > curr.i) { + curr.i = right.i + 1; + } + } + } + if (curr.i > 1 && curr.d > 1) { + max = Math.max(max, curr.d + curr.i - 1); + } + return curr; + } +} diff --git a/src/main/java/tree/BinaryTreeMaximumPathSum.java b/src/main/java/tree/BinaryTreeMaximumPathSum.java new file mode 100644 index 00000000..44e80fb0 --- /dev/null +++ b/src/main/java/tree/BinaryTreeMaximumPathSum.java @@ -0,0 +1,63 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 03/04/2017. Given a binary tree, find the maximum path sum. + * + *

For this problem, a path is defined as any sequence of nodes from some starting node to any + * node in the tree along the parent-child connections. The path must contain at least one node and + * does not need to go through the root. + * + *

For example: Given the below binary tree, + * + *

1 / \ 2 3 Return 6. + */ +public class BinaryTreeMaximumPathSum { + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + private int max = Integer.MIN_VALUE; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(5); + root.left = new TreeNode(4); + root.left.left = new TreeNode(3); + root.left.left.left = new TreeNode(-1); + root.right = new TreeNode(7); + root.right.left = new TreeNode(2); + root.right.left.left = new TreeNode(9); + System.out.println(new BinaryTreeMaximumPathSum().maxPathSum(root)); + } + + public int maxPathSum(TreeNode root) { + if (root == null) return 0; + dfs(root); + return max; + } + + private int dfs(TreeNode root) { + if (root == null) return 0; + int left = dfs(root.left); + int right = dfs(root.right); + max = Math.max(max, root.val); + max = Math.max(max, root.val + left); + max = Math.max(max, root.val + right); + max = Math.max(max, root.val + left + right); + int leftVal = Math.max(root.val, root.val + left); + int rightVal = Math.max(root.val, root.val + right); + return Math.max(leftVal, rightVal); + } +} diff --git a/src/main/java/tree/BinaryTreePaths.java b/src/main/java/tree/BinaryTreePaths.java new file mode 100644 index 00000000..e15fabd1 --- /dev/null +++ b/src/main/java/tree/BinaryTreePaths.java @@ -0,0 +1,44 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 09/12/2017. Given a binary tree, return all root-to-leaf paths. + * + *

For example, given the following binary tree: + * + *

1 / \ 2 3 \ 5 All root-to-leaf paths are: + * + *

["1->2->5", "1->3"] + */ +public class BinaryTreePaths { + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public List binaryTreePaths(TreeNode root) { + List result = new ArrayList<>(); + new BinaryTreePaths().inorder(root, result, ""); + return result; + } + + private void inorder(TreeNode node, List list, String path) { + if (node != null) { + if (node.left == null && node.right == null) { + list.add(path + node.val); + } else { + inorder(node.left, list, path + node.val + "->"); + inorder(node.right, list, path + node.val + "->"); + } + } + } +} diff --git a/src/main/java/tree/BinaryTreePostorderTraversal.java b/src/main/java/tree/BinaryTreePostorderTraversal.java new file mode 100644 index 00000000..53c465e7 --- /dev/null +++ b/src/main/java/tree/BinaryTreePostorderTraversal.java @@ -0,0 +1,57 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 28/07/2018. Given a binary tree, return the postorder traversal + * of its nodes' values. + * + *

Example: + * + *

Input: [1,null,2,3] 1 \ 2 / 3 + * + *

Output: [3,2,1] Follow up: Recursive solution is trivial, could you do it iteratively? + * + *

Solution: O(N). Maintain a stack, for every node which you pop from stack add it to result + * list, push left and right node to stack. Reverse the result list and return this as the answer. + */ +public class BinaryTreePostorderTraversal { + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(1); + root.right = new TreeNode(2); + root.right.left = new TreeNode(3); + List result = new BinaryTreePostorderTraversal().postorderTraversal(root); + result.forEach(System.out::println); + } + + public List postorderTraversal(TreeNode root) { + Stack stack = new Stack<>(); + List result = new ArrayList<>(); + if (root != null) { + stack.push(root); + } + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + result.add(node.val); + if (node.left != null) { + stack.push(node.left); + } + if (node.right != null) { + stack.push(node.right); + } + } + Collections.reverse(result); + return result; + } +} diff --git a/src/main/java/tree/BinaryTreeTilt.java b/src/main/java/tree/BinaryTreeTilt.java new file mode 100644 index 00000000..21feebec --- /dev/null +++ b/src/main/java/tree/BinaryTreeTilt.java @@ -0,0 +1,55 @@ +/* (C) 2024 YourCompanyName */ +package tree; +/** + * Created by gouthamvidyapradhan on 14/08/2019 Given a binary tree, return the tilt of the whole + * tree. + * + *

The tilt of a tree node is defined as the absolute difference between the sum of all left + * subtree node values and the sum of all right subtree node values. Null node has tilt 0. + * + *

The tilt of the whole tree is defined as the sum of all nodes' tilt. + * + *

Example: Input: 1 / \ 2 3 Output: 1 Explanation: Tilt of node 2 : 0 Tilt of node 3 : 0 Tilt of + * node 1 : |2-3| = 1 Tilt of binary tree : 0 + 0 + 1 = 1 Note: + * + *

The sum of node values in any subtree won't exceed the range of 32-bit integer. All the tilt + * values won't exceed the range of 32-bit integer. + * + *

Solution: Find tilt of left node and find tilt of right node and return left + right + curr to + * its parent. + */ +public class BinaryTreeTilt { + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public static void main(String[] args) { + TreeNode node = new TreeNode(1); + node.left = new TreeNode(2); + node.right = new TreeNode(3); + System.out.println(new BinaryTreeTilt().findTilt(node)); + } + + int sum = 0; + + public int findTilt(TreeNode root) { + if (root == null) return 0; + tilt(root); + return sum; + } + + private int tilt(TreeNode node) { + if (node == null) return 0; + int left = tilt(node.left); + int right = tilt(node.right); + sum += Math.abs(left - right); + return left + right + node.val; + } +} diff --git a/src/main/java/tree/BoundaryOfBinaryTree.java b/src/main/java/tree/BoundaryOfBinaryTree.java new file mode 100644 index 00000000..708e86e7 --- /dev/null +++ b/src/main/java/tree/BoundaryOfBinaryTree.java @@ -0,0 +1,141 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 27/03/2017. Given a binary tree, return the values of its + * boundary in anti-clockwise direction starting from root. Boundary includes left boundary, leaves, + * and right boundary in order without duplicate nodes. + * + *

Left boundary is defined as the path from root to the left-most node. Right boundary is + * defined as the path from root to the right-most node. If the root doesn't have left subtree or + * right subtree, then the root itself is left boundary or right boundary. Note this definition only + * applies to the input binary tree, and not applies to any subtrees. + * + *

The left-most node is defined as a leaf node you could reach when you always firstly travel to + * the left subtree if exists. If not, travel to the right subtree. Repeat until you reach a leaf + * node. + * + *

The right-most node is also defined by the same way with left and right exchanged. + * + *

Example 1 Input: 1 \ 2 / \ 3 4 + * + *

Ouput: [1, 3, 4, 2] + * + *

Explanation: The root doesn't have left subtree, so the root itself is left boundary. The + * leaves are node 3 and 4. The right boundary are node 1,2,4. Note the anti-clockwise direction + * means you should output reversed right boundary. So order them in anti-clockwise without + * duplicates and we have [1,3,4,2]. Example 2 Input: ____1_____ / \ 2 3 / \ / 4 5 6 / \ / \ 7 8 9 + * 10 + * + *

Ouput: [1,2,4,7,8,9,10,6,3] + * + *

Explanation: The left boundary are node 1,2,4. (4 is the left-most node according to + * definition) The leaves are node 4,7,8,9,10. The right boundary are node 1,3,6,10. (10 is the + * right-most node). So order them in anti-clockwise without duplicate nodes we have + * [1,2,4,7,8,9,10,6,3]. + */ +public class BoundaryOfBinaryTree { + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + private Set done = new HashSet<>(); + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(1); + /*root.right = new TreeNode(2); + root.right.right = new TreeNode(3); + root.right.right.right = new TreeNode(4); + root.right.right.right.left = new TreeNode(5); + root.right.right.right.left.right = new TreeNode(6); + /*root.left = new TreeNode(2); + root.left.left = new TreeNode(4); + root.left.right = new TreeNode(5); + root.left.right.left = new TreeNode(7); + root.left.right.right = new TreeNode(8); + root.right = new TreeNode(3); + root.right.left = new TreeNode(6); + root.right.left.left = new TreeNode(9); + root.right.left.right = new TreeNode(10);*/ + System.out.println(new BoundaryOfBinaryTree().boundaryOfBinaryTree(root)); + } + + public List boundaryOfBinaryTree(TreeNode root) { + if (root == null) return new ArrayList<>(); + List antiClockwiseCollection = new ArrayList<>(); + List collection = new ArrayList<>(); + + if (root.left != null) leftShoulder(root, collection); + else { + if (!done.contains(root)) { + done.add(root); + collection.add(root.val); + } + } + + antiClockwiseCollection.addAll(collection); + collection.clear(); + leafNode(root, collection); + antiClockwiseCollection.addAll(collection); + collection.clear(); + + if (root.right != null) rightShoulder(root, collection); + else { + if (!done.contains(root)) { + done.add(root); + collection.add(root.val); + } + } + + Stack stack = new Stack<>(); + stack.addAll(collection); + while (!stack.isEmpty()) antiClockwiseCollection.add(stack.pop()); + return new ArrayList<>(antiClockwiseCollection); + } + + private void leftShoulder(TreeNode node, List list) { + if (node == null) return; + if (!done.contains(node)) { + list.add(node.val); + done.add(node); + } + + if (node.left != null) leftShoulder(node.left, list); + else if (node.right != null) leftShoulder(node.right, list); + } + + private void rightShoulder(TreeNode node, List list) { + if (node == null) return; + if (!done.contains(node)) { + list.add(node.val); + done.add(node); + } + if (node.right != null) rightShoulder(node.right, list); + else if (node.left != null) rightShoulder(node.left, list); + } + + private void leafNode(TreeNode node, List list) { + if (node == null) return; + if (node.left == null && node.right == null) + if (!done.contains(node)) { + list.add(node.val); + done.add(node); + } + leafNode(node.left, list); + leafNode(node.right, list); + } +} diff --git a/src/main/java/tree/ClosestBinarySearchTreeValue.java b/src/main/java/tree/ClosestBinarySearchTreeValue.java new file mode 100644 index 00000000..843ec3eb --- /dev/null +++ b/src/main/java/tree/ClosestBinarySearchTreeValue.java @@ -0,0 +1,58 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 10/05/2017. Given a non-empty binary search tree and a target + * value, find the value in the BST that is closest to the target. + * + *

Note: Given target value is a floating point. You are guaranteed to have only one unique value + * in the BST that is closest to the target. + * + *

Solution: Simple dfs recursive algorithm to find the closest match. Worst case time complexity + * is O(h) where h is height of the tree + */ +public class ClosestBinarySearchTreeValue { + /** TreeNode */ + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + private double absDiff = Double.MAX_VALUE; + private int closest; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(10); + root.left = new TreeNode(9); + root.left.left = new TreeNode(8); + System.out.println(new ClosestBinarySearchTreeValue().closestValue(root, 7.63354D)); + } + + /** + * Find closest + * + * @param root Root node + * @param target double target + * @return closest value + */ + public int closestValue(TreeNode root, double target) { + if (root == null) return closest; + if (Math.abs(target - root.val) < absDiff) { + absDiff = Math.abs(target - root.val); + closest = root.val; + } + if (root.val > target) return closestValue(root.left, target); + else return closestValue(root.right, target); + } +} diff --git a/src/main/java/tree/ClosestLeafInABinaryTree.java b/src/main/java/tree/ClosestLeafInABinaryTree.java new file mode 100644 index 00000000..7afc7ba4 --- /dev/null +++ b/src/main/java/tree/ClosestLeafInABinaryTree.java @@ -0,0 +1,133 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 02/05/2018. Given a binary tree where every node has a unique + * value, and a target key k, find the value of the nearest leaf node to target k in the tree. + * + *

Here, nearest to a leaf means the least number of edges travelled on the binary tree to reach + * any leaf of the tree. Also, a node is called a leaf if it has no children. + * + *

In the following examples, the input tree is represented in flattened form row by row. The + * actual root tree given will be a TreeNode object. + * + *

Example 1: + * + *

Input: root = [1, 3, 2], k = 1 Diagram of binary tree: 1 / \ 3 2 + * + *

Output: 2 (or 3) + * + *

Explanation: Either 2 or 3 is the nearest leaf node to the target of 1. Example 2: + * + *

Input: root = [1], k = 1 Output: 1 + * + *

Explanation: The nearest leaf node is the root node itself. Example 3: + * + *

Input: root = [1,2,3,4,null,null,null,5,null,6], k = 2 Diagram of binary tree: 1 / \ 2 3 / 4 / + * 5 / 6 + * + *

Output: 3 Explanation: The leaf node with value 3 (and not the leaf node with value 6) is + * nearest to the node with value 2. Note: root represents a binary tree with at least 1 node and at + * most 1000 nodes. Every node has a unique node.val in range [1, 1000]. There exists some node in + * the given binary tree for which node.val == k. + * + *

Solution: O(N): Maintain a hashmap of distances from each node in the first iteration. In the + * second iteration, find the key value node and then calculate distance from each node during + * backtrack. + */ +public class ClosestLeafInABinaryTree { + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + private static class Pair { + int n, d; + + Pair(int n, int d) { + this.n = n; + this.d = d; + } + } + + private Map map; + private Pair minNode; + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(1); + root.left = new TreeNode(2); + root.right = new TreeNode(3); + root.left.left = new TreeNode(4); + root.left.left.left = new TreeNode(5); + root.left.left.left.left = new TreeNode(6); + // root.right = new TreeNode(3); + System.out.println(new ClosestLeafInABinaryTree().findClosestLeaf(root, 2)); + } + + public int findClosestLeaf(TreeNode root, int k) { + map = new HashMap<>(); + minNode = new Pair(-1, Integer.MAX_VALUE); + findDistanceToLeaf(root); + findMin(root, k); + return minNode.n; + } + + private Pair findDistanceToLeaf(TreeNode node) { + if (node != null) { + if (node.left == null && node.right == null) { + map.put(node.val, new Pair(node.val, 0)); + return new Pair(node.val, 1); + } else { + Pair left = findDistanceToLeaf(node.left); + Pair right = findDistanceToLeaf(node.right); + if (left.d < right.d) { + map.put(node.val, left); + return new Pair(left.n, left.d + 1); + } else { + map.put(node.val, right); + return new Pair(right.n, right.d + 1); + } + } + } + return new Pair(-1, Integer.MAX_VALUE); + } + + private int findMin(TreeNode node, int k) { + if (node != null) { + if (node.val == k) { + if (map.get(node.val).d < minNode.d) { + minNode = map.get(node.val); + } + return 1; + } else { + int left = findMin(node.left, k); + int right = findMin(node.right, k); + if (left != -1) { + if ((left + map.get(node.val).d) < minNode.d) { + minNode = new Pair(map.get(node.val).n, (left + map.get(node.val).d)); + } + return left + 1; + } else if (right != -1) { + if ((right + map.get(node.val).d) < minNode.d) { + minNode = new Pair(map.get(node.val).n, (right + map.get(node.val).d)); + } + return right + 1; + } + } + } + return -1; + } +} diff --git a/src/main/java/tree/ConstructBinaryTreefromString.java b/src/main/java/tree/ConstructBinaryTreefromString.java new file mode 100644 index 00000000..a73aae56 --- /dev/null +++ b/src/main/java/tree/ConstructBinaryTreefromString.java @@ -0,0 +1,88 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 30/07/2019 You need to construct a binary tree from a string + * consisting of parenthesis and integers. + * + *

The whole input represents a binary tree. It contains an integer followed by zero, one or two + * pairs of parenthesis. The integer represents the root's value and a pair of parenthesis contains + * a child binary tree with the same structure. + * + *

You always start to construct the left child node of the parent first if it exists. + * + *

Example: Input: "4(2(3)(1))(6(5))" Output: return the tree root node representing the + * following tree: + * + *

4 / \ 2 6 /\ / 3 1 5 + * + *

Note: There will only be '(', ')', '-' and '0' ~ '9' in the input string. An empty tree is + * represented by "" instead of "()". + * + *

Solution: O(N ^ 2) Form a node for every number and treat the first sub-string within round + * braces as left node and the second sub-string within the round braces as the right node. + * Recursively solve each substring within the round braces. + */ +public class ConstructBinaryTreefromString { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public static void main(String[] args) { + System.out.println(new ConstructBinaryTreefromString().str2tree("4(2(3)(1))(6(5))")); + } + + private TreeNode str2tree(String s) { + if (s == null || s.isEmpty()) return null; + TreeNode current; + StringBuilder num = new StringBuilder(); + boolean isNeg = false; + int i = 0; + for (; i < s.length(); i++) { + if (s.charAt(i) == '-') { + isNeg = true; + } else if (s.charAt(i) >= '0' && s.charAt(i) <= '9') { + num.append(s.charAt(i)); + } else break; + } + if (isNeg) { + current = new TreeNode(Integer.parseInt(num.toString()) * -1); + } else current = new TreeNode(Integer.parseInt(num.toString())); + int count = 0; + StringBuilder left = new StringBuilder(); + for (; i < s.length(); i++) { + if (s.charAt(i) == '(') { + count++; + } else if (s.charAt(i) == ')') { + count--; + } + left.append(s.charAt(i)); + if (count == 0) { + break; + } + } + i++; + String leftStr = ""; + String rightStr = ""; + if (i < s.length()) { + rightStr = s.substring(i); + } + if (left.length() > 0) { + leftStr = left.subSequence(1, left.length() - 1).toString(); + } + if (rightStr.length() > 0) { + rightStr = rightStr.substring(1, rightStr.length() - 1); + } + TreeNode leftNode = str2tree(leftStr); + TreeNode rightNode = str2tree(rightStr); + current.left = leftNode; + current.right = rightNode; + return current; + } +} diff --git a/src/main/java/tree/ConstructStringFromBinaryTree.java b/src/main/java/tree/ConstructStringFromBinaryTree.java new file mode 100644 index 00000000..28138cbf --- /dev/null +++ b/src/main/java/tree/ConstructStringFromBinaryTree.java @@ -0,0 +1,60 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 10/06/2017. Accepted You need to construct a string consists of + * parenthesis and integers from a binary tree with the preorder traversing way. + * + *

The null node needs to be represented by empty parenthesis pair "()". And you need to omit all + * the empty parenthesis pairs that don't affect the one-to-one mapping relationship between the + * string and the original binary tree. + * + *

Example 1: Input: Binary tree: [1,2,3,4] 1 / \ 2 3 / 4 + * + *

Output: "1(2(4))(3)" + * + *

Explanation: Originallay it needs to be "1(2(4)())(3()())", but you need to omit all the + * unnecessary empty parenthesis pairs. And it will be "1(2(4))(3)". Example 2: Input: Binary tree: + * [1,2,3,null,4] 1 / \ 2 3 \ 4 + * + *

Output: "1(2()(4))(3)" + * + *

Explanation: Almost the same as the first example, except we can't omit the first parenthesis + * pair to break the one-to-one mapping relationship between the input and the output. + */ +public class ConstructStringFromBinaryTree { + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + TreeNode t = new TreeNode(1); + t.left = new TreeNode(2); + t.left.left = new TreeNode(4); + t.right = new TreeNode(3); + System.out.println(new ConstructStringFromBinaryTree().tree2str(t)); + } + + public String tree2str(TreeNode t) { + if (t == null) return ""; + String left = tree2str(t.left); + String right = tree2str(t.right); + if (left.equals("") && right.equals("")) return String.valueOf(t.val); + if (left.equals("")) left = "()"; + else left = "(" + left + ")"; + if (!right.equals("")) right = "(" + right + ")"; + return t.val + left + right; + } +} diff --git a/src/main/java/tree/ConvertBSTToGreaterTree.java b/src/main/java/tree/ConvertBSTToGreaterTree.java new file mode 100644 index 00000000..2c84753f --- /dev/null +++ b/src/main/java/tree/ConvertBSTToGreaterTree.java @@ -0,0 +1,53 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 14/03/2019 Given a Binary Search Tree (BST), convert it to a + * Greater Tree such that every key of the original BST is changed to the original key plus sum of + * all keys greater than the original key in BST. + * + *

Example: + * + *

Input: The root of a Binary Search Tree like this: 5 / \ 2 13 + * + *

Output: The root of a Greater Tree like this: 18 / \ 20 13 + */ +public class ConvertBSTToGreaterTree { + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + TreeNode node = new TreeNode(5); + node.right = new TreeNode(13); + node.left = new TreeNode(2); + node.left.left = new TreeNode(1); + node.left.right = new TreeNode(3); + TreeNode result = new ConvertBSTToGreaterTree().convertBST(node); + System.out.println(result); + } + + public TreeNode convertBST(TreeNode root) { + postOrder(root, 0); + return root; + } + + private int postOrder(TreeNode node, int value) { + if (node == null) return value; + int right = postOrder(node.right, value); + node.val = node.val + right; + return postOrder(node.left, node.val); + } +} diff --git a/src/main/java/tree/ConvertSortedArrayToBST.java b/src/main/java/tree/ConvertSortedArrayToBST.java new file mode 100644 index 00000000..60317bea --- /dev/null +++ b/src/main/java/tree/ConvertSortedArrayToBST.java @@ -0,0 +1,37 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 09/03/2017. Given an array where elements are sorted in + * ascending order, convert it to a height balanced BST. + */ +public class ConvertSortedArrayToBST { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public TreeNode sortedArrayToBST(int[] nums) { + if (nums.length == 0) return null; + return build(0, nums.length - 1, nums); + } + + private TreeNode build(int s, int e, int[] nums) { + if (s > e) return null; + + int m = (e - s) / 2; + int node = nums[s + m]; + TreeNode root = new TreeNode(node); + if (s == e) return root; + + root.left = build(s, s + m - 1, nums); + root.right = build(s + m + 1, e, nums); + + return root; + } +} diff --git a/src/main/java/tree/DiameterOfBinaryTree.java b/src/main/java/tree/DiameterOfBinaryTree.java new file mode 100644 index 00000000..0d41b272 --- /dev/null +++ b/src/main/java/tree/DiameterOfBinaryTree.java @@ -0,0 +1,55 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 18/10/2017. + * + *

Given a binary tree, you need to compute the length of the diameter of the tree. The diameter + * of a binary tree is the length of the longest path between any two nodes in a tree. This path may + * or may not pass through the root. + * + *

Example: Given a binary tree 1 / \ 2 3 / \ 4 5 Return 3, which is the length of the path + * [4,2,1,3] or [5,2,1,3]. + * + *

Note: The length of path between two nodes is represented by the number of edges between them. + */ +public class DiameterOfBinaryTree { + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + private int max = 0; + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(5); + root.left = new TreeNode(4); + System.out.println(new DiameterOfBinaryTree().diameterOfBinaryTree(root)); + } + + public int diameterOfBinaryTree(TreeNode root) { + dfs(root); + return max; + } + + private int dfs(TreeNode node) { + if (node != null) { + int left = dfs(node.left); + int right = dfs(node.right); + max = Math.max(max, left + right); + return left > right ? left + 1 : right + 1; + } + return 0; + } +} diff --git a/src/main/java/tree/EqualTreePartition.java b/src/main/java/tree/EqualTreePartition.java new file mode 100644 index 00000000..c90a1280 --- /dev/null +++ b/src/main/java/tree/EqualTreePartition.java @@ -0,0 +1,77 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 17/02/2018. Given a binary tree with n nodes, your task is to + * check if it's possible to partition the tree to two trees which have the equal sum of values + * after removing exactly one edge on the original tree. + * + *

Example 1: Input: 5 / \ 10 10 / \ 2 3 + * + *

Output: True Explanation: 5 / 10 + * + *

Sum: 15 + * + *

10 / \ 2 3 + * + *

Sum: 15 Example 2: Input: 1 / \ 2 10 / \ 2 20 + * + *

Output: False Explanation: You can't split the tree into two trees with equal sum after + * removing exactly one edge on the tree. Note: The range of tree node value is in the range of + * [-100000, 100000]. 1 <= n <= 10000 + */ +public class EqualTreePartition { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + private long sum; + private boolean possible = false; + + public static void main(String[] args) throws Exception {} + + public boolean checkEqualTree(TreeNode root) { + sum = 0L; + getSum(root); + getDiff(root); + return possible; + } + + private void getSum(TreeNode node) { + if (node != null) { + sum += node.val; + getSum(node.left); + getSum(node.right); + } + } + + private Long getDiff(TreeNode node) { + if (node == null) return null; + Long left = getDiff(node.left); + Long right = getDiff(node.right); + if (left != null) { + if ((sum - left) == left) { + possible = true; + } + } + if (right != null) { + if ((sum - right) == right) { + possible = true; + } + } + Long curr = (long) node.val; + if (left != null) { + curr += left; + } + if (right != null) { + curr += right; + } + return curr; + } +} diff --git a/src/main/java/tree/FindBottomLeftTreeValue.java b/src/main/java/tree/FindBottomLeftTreeValue.java new file mode 100644 index 00000000..86ee8a57 --- /dev/null +++ b/src/main/java/tree/FindBottomLeftTreeValue.java @@ -0,0 +1,59 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 30/08/2017. Given a binary tree, find the leftmost value in the + * last row of the tree. + * + *

Example 1: Input: + * + *

2 / \ 1 3 + * + *

Output: 1 Example 2: Input: + * + *

1 / \ 2 3 / / \ 4 5 6 / 7 + * + *

Output: 7 Note: You may assume the tree (i.e., the given root node) is not NULL. Solution: + * O(N) do a inorder search to find the left most value. Keep a level counter to keep track of what + * level you are at when you do a inorder search. + */ +public class FindBottomLeftTreeValue { + private int max = 0, result; + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(1); + root.left = new TreeNode(2); + root.left.left = new TreeNode(4); + root.right = new TreeNode(3); + root.right.left = new TreeNode(5); + root.right.left.left = new TreeNode(7); + root.right.right = new TreeNode(6); + System.out.println(new FindBottomLeftTreeValue().findBottomLeftValue(root)); + } + + public int findBottomLeftValue(TreeNode root) { + inorder(root, 1); + return result; + } + + private void inorder(TreeNode node, int level) { + if (node != null) { + if (level > max) { + result = node.val; + max = level; + } + inorder(node.left, level + 1); + inorder(node.right, level + 1); + } + } +} diff --git a/src/main/java/tree/FindLargestValueInEachTreeRow.java b/src/main/java/tree/FindLargestValueInEachTreeRow.java new file mode 100644 index 00000000..a54e869b --- /dev/null +++ b/src/main/java/tree/FindLargestValueInEachTreeRow.java @@ -0,0 +1,66 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 01/08/2019 You need to find the largest value in each row of a + * binary tree. + * + *

Example: Input: + * + *

1 / \ 3 2 / \ \ 5 3 9 + * + *

Output: [1, 3, 9] Solution: O(N) do a bfs to check largest in each row. + */ +public class FindLargestValueInEachTreeRow { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + Map maxRow = new HashMap<>(); + + class Node { + int row; + TreeNode val; + + Node(int row, TreeNode val) { + this.row = row; + this.val = val; + } + } + + public List largestValues(TreeNode root) { + if (root == null) return new ArrayList<>(); + Queue queue = new ArrayDeque<>(); + queue.offer(new Node(0, root)); + while (!queue.isEmpty()) { + Node top = queue.poll(); + maxRow.putIfAbsent(top.row, top.val.val); + maxRow.put(top.row, Math.max(maxRow.get(top.row), top.val.val)); + if (top.val.left != null) { + queue.offer(new Node(top.row + 1, top.val.left)); + } + if (top.val.right != null) { + queue.offer(new Node(top.row + 1, top.val.right)); + } + } + List answer = new ArrayList<>(); + List keyList = new ArrayList<>(maxRow.keySet()); + keyList.sort(Integer::compareTo); + for (int k : keyList) { + answer.add(maxRow.get(k)); + } + return answer; + } + + public static void main(String[] args) { + // + } +} diff --git a/src/main/java/tree/FlattenBinaryTree.java b/src/main/java/tree/FlattenBinaryTree.java new file mode 100644 index 00000000..274e45fd --- /dev/null +++ b/src/main/java/tree/FlattenBinaryTree.java @@ -0,0 +1,77 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 04/07/2017. Given a binary tree, flatten it to a linked list + * in-place. + * + *

For example, Given + * + *

1 / \ 2 5 / \ \ 3 4 6 + * + *

The flattened tree should look like: 1 \ 2 \ 3 \ 4 \ 5 \ 6 + * + *

Solution: Do a pre-order traversal and maintain head and tail of a linked list at each + * recursive step. i. Join the current node to the head of the left sub-list to form the current + * node as the new head. ii. Join the tail of the left sub-list to the head of the right sub-list. + * iii. Mark the left of the current node as null + */ +public class FlattenBinaryTree { + + /** Class to keep track of head and tail */ + private class LinkNode { + TreeNode head; + TreeNode tail; + + LinkNode(TreeNode head, TreeNode tail) { + this.head = head; + this.tail = tail; + } + } + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(3); + root.left = new TreeNode(2); + root.right = new TreeNode(1); + new FlattenBinaryTree().flatten(root); + System.out.print(root.val + " "); + System.out.print(root.right.val + " "); + System.out.print(root.right.right.val); + } + + public void flatten(TreeNode root) { + preOrder(root); + } + + private LinkNode preOrder(TreeNode node) { + if (node == null) return null; + LinkNode left = preOrder(node.left); + LinkNode right = preOrder(node.right); + LinkNode lNode; + if (left == null && right == null) { + lNode = new LinkNode(node, node); + } else if (left == null) { + node.right = right.head; + lNode = new LinkNode(node, right.tail); + } else if (right == null) { + node.right = left.head; + lNode = new LinkNode(node, left.tail); + } else { + node.right = left.head; + left.tail.right = right.head; + lNode = new LinkNode(node, right.tail); + } + node.left = null; + return lNode; + } +} diff --git a/src/main/java/tree/FlipBinaryTree.java b/src/main/java/tree/FlipBinaryTree.java new file mode 100644 index 00000000..b1e0e41a --- /dev/null +++ b/src/main/java/tree/FlipBinaryTree.java @@ -0,0 +1,61 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.*; + +/** Created by gouthamvidyapradhan on 26/01/2020 */ +public class FlipBinaryTree { + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public static void main(String[] args) { + // + } + + private int i, count; + private List result; + + public List flipMatchVoyage(TreeNode root, int[] voyage) { + i = 0; + count = 0; + result = new ArrayList<>(); + inorderCount(root); + if (count != voyage.length) return Arrays.asList(-1); + preorder(root, voyage); + if (i == voyage.length) return result; + return Arrays.asList(-1); + } + + private void inorderCount(TreeNode node) { + if (node != null) { + count++; + inorderCount(node.left); + inorderCount(node.right); + } + } + + private void preorder(TreeNode node, int[] voyage) { + if (node != null) { + if (voyage[i] == node.val) { + i++; + } + if (node.left != null && node.right != null) { + if (voyage[i] == node.right.val) { + TreeNode temp = node.left; + node.left = node.right; + node.right = temp; + result.add(node.val); + } + } + preorder(node.left, voyage); + preorder(node.right, voyage); + } + } +} diff --git a/src/main/java/tree/FlipEquivalentBinaryTrees.java b/src/main/java/tree/FlipEquivalentBinaryTrees.java new file mode 100644 index 00000000..03c3d6f4 --- /dev/null +++ b/src/main/java/tree/FlipEquivalentBinaryTrees.java @@ -0,0 +1,131 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 06/08/2019 For a binary tree T, we can define a flip operation + * as follows: choose any node, and swap the left and right child subtrees. + * + *

A binary tree X is flip equivalent to a binary tree Y if and only if we can make X equal to Y + * after some number of flip operations. + * + *

Write a function that determines whether two binary trees are flip equivalent. The trees are + * given by root nodes root1 and root2. + * + *

Example 1: + * + *

Input: root1 = [1,2,3,4,5,6,null,null,null,7,8], root2 = + * [1,3,2,null,6,4,5,null,null,null,null,8,7] Output: true Explanation: We flipped at nodes with + * values 1, 3, and 5. Flipped Trees Diagram + * + *

Note: + * + *

Each tree will have at most 100 nodes. Each value in each tree will be a unique integer in the + * range [0, 99]. Solution O(N ^ 2) Since the node values are unique general idea is to find the + * node on right tree for every node on the left tree and check if the values need to be swapped, if + * yes then swap the node's left and right child in the left tree. After this operation is complete + * check if both the trees are equal + */ +public class FlipEquivalentBinaryTrees { + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public static void main(String[] args) { + TreeNode node = new TreeNode(1); + node.left = new TreeNode(2); + node.left.left = new TreeNode(4); + node.left.right = new TreeNode(5); + node.left.right.left = new TreeNode(7); + node.left.right.right = new TreeNode(8); + node.right = new TreeNode(3); + node.right.left = new TreeNode(6); + + TreeNode node1 = new TreeNode(1); + node1.left = new TreeNode(3); + node1.left.right = new TreeNode(6); + node1.right = new TreeNode(2); + node1.right.left = new TreeNode(4); + node1.right.right = new TreeNode(5); + node1.right.right.left = new TreeNode(8); + node1.right.right.right = new TreeNode(7); + System.out.println(new FlipEquivalentBinaryTrees().flipEquiv(node, node1)); + } + + public boolean flipEquiv(TreeNode root1, TreeNode root2) { + flip(root1, root2); + return checkIfBothAreSame(root1, root2); + } + + private boolean checkIfBothAreSame(TreeNode root1, TreeNode root2) { + if (root1 == null && root2 == null) return true; + else if (root1 == null) return false; + else if (root2 == null) return false; + else { + if (root1.val != root2.val) return false; + if (!checkIfBothAreSame(root1.left, root2.left)) return false; + return checkIfBothAreSame(root1.right, root2.right); + } + } + + private void flip(TreeNode root1, TreeNode root2) { + if (root1 != null) { + TreeNode result = find(root2, root1.val); + boolean valid = true; + if (result != null) { + if (root1.left == null) { + if (result.right != null) { + valid = false; + } + } + if (root1.right == null) { + if (result.left != null) { + valid = false; + } + } + if (root1.left != null) { + if (result.right == null) { + valid = false; + } else { + if (root1.left.val != result.right.val) { + valid = false; + } + } + } + if (root1.right != null) { + if (result.left == null) { + valid = false; + } else { + if (root1.right.val != result.left.val) { + valid = false; + } + } + } + if (valid) { + TreeNode temp = result.left; + result.left = result.right; + result.right = temp; + } + } + flip(root1.left, root2); + flip(root1.right, root2); + } + } + + private TreeNode find(TreeNode node, int value) { + if (node != null) { + if (node.val == value) return node; + TreeNode left = find(node.left, value); + if (left != null) return left; + TreeNode right = find(node.right, value); + if (right != null) return right; + } + return null; + } +} diff --git a/src/main/java/tree/InorderSuccessorInBST.java b/src/main/java/tree/InorderSuccessorInBST.java new file mode 100644 index 00000000..6d25ae6f --- /dev/null +++ b/src/main/java/tree/InorderSuccessorInBST.java @@ -0,0 +1,71 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 14/05/2017. Given a binary search tree and a node in it, find + * the in-order successor of that node in the BST. + * + *

Note: If the given node has no in-order successor in the tree, return null. + * + *

Solution: The below solution works with worst case time complexity of O(h) where h is the + * height of the tree. If the current node is <= target_node, recursively iterate the right of the + * current node. else if the current node is > target_node then mark the current node as the + * successor and recursively iterate the left of the current node. + */ +public class InorderSuccessorInBST { + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(10); + root.left = new TreeNode(5); + root.left.left = new TreeNode(3); + root.left.right = new TreeNode(6); + root.right = new TreeNode(15); + root.right.left = new TreeNode(13); + root.right.left.left = new TreeNode(12); + root.right.left.right = new TreeNode(14); + root.right.right = new TreeNode(17); + TreeNode ans = new InorderSuccessorInBST().inorderSuccessor(root, root.right.left.right); + if (ans != null) System.out.println(ans.val); + else System.out.println(ans); + } + + /** + * Find successor + * + * @param root root node + * @param p target + * @return successor + */ + public TreeNode inorderSuccessor(TreeNode root, TreeNode p) { + return inOrder(root, p, null); + } + + /** + * Inorder traversal + * + * @param curr current node + * @param target target node + * @param successor successor + * @return successor node + */ + private TreeNode inOrder(TreeNode curr, TreeNode target, TreeNode successor) { + if (curr == null) return successor; + if (curr.val <= target.val) return inOrder(curr.right, target, successor); + return inOrder(curr.left, target, curr); // make the current node as successor + } +} diff --git a/src/main/java/tree/InsufficientNodesinRoottoLeafPaths.java b/src/main/java/tree/InsufficientNodesinRoottoLeafPaths.java new file mode 100644 index 00000000..da5338fd --- /dev/null +++ b/src/main/java/tree/InsufficientNodesinRoottoLeafPaths.java @@ -0,0 +1,57 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** Created by gouthamvidyapradhan on 29/01/2020 */ +public class InsufficientNodesinRoottoLeafPaths { + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public static void main(String[] args) { + TreeNode root = new TreeNode(1); + root.left = new TreeNode(2); + root.left.left = new TreeNode(-5); + root.right = new TreeNode(-3); + root.right.left = new TreeNode(4); + System.out.println(new InsufficientNodesinRoottoLeafPaths().sufficientSubset(root, -1)); + } + + public TreeNode sufficientSubset(TreeNode root, int limit) { + long result = dfs(root, 0, limit); + if (result < limit) return null; + else return root; + } + + private long dfs(TreeNode node, long curr, int limit) { + if (node == null) return Integer.MIN_VALUE; + long sumLeft = dfs(node.left, curr + node.val, limit); + long sumRight = dfs(node.right, curr + node.val, limit); + if (sumLeft == Integer.MIN_VALUE && sumRight == Integer.MIN_VALUE) { + return node.val; + } else if (sumLeft == Integer.MIN_VALUE) { + if ((sumRight + curr + node.val) < limit) { + node.right = null; + } + return node.val + sumRight; + } else if (sumRight == Integer.MIN_VALUE) { + if ((sumLeft + curr + node.val) < limit) { + node.left = null; + } + return node.val + sumLeft; + } else { + if ((sumLeft + curr + node.val) < limit) { + node.left = null; + } + if ((sumRight + curr + node.val) < limit) { + node.right = null; + } + return Math.max(node.val + sumLeft, node.val + sumRight); + } + } +} diff --git a/src/main/java/tree/LCA.java b/src/main/java/tree/LCA.java new file mode 100644 index 00000000..0d9f52ee --- /dev/null +++ b/src/main/java/tree/LCA.java @@ -0,0 +1,46 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 21/03/2017. Given a binary tree, find the lowest common + * ancestor (LCA) of two given nodes in the tree. + * + *

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined + * between two nodes v and w as the lowest node in T that has both v and w as descendants (where we + * allow a node to be a descendant of itself).” + * + *

_______3______ / \ ___5__ ___1__ / \ / \ 6 _2 0 8 / \ 7 4 For example, the lowest common + * ancestor (LCA) of nodes 5 and 1 is 3. Another example is LCA of nodes 5 and 4 is 5, since a node + * can be a descendant of itself according to the LCA definition. + */ +public class LCA { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception {} + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root != null) { + if (root.equals(p) || root.equals(q)) return root; + TreeNode left = lowestCommonAncestor(root.left, p, q); + TreeNode right = lowestCommonAncestor(root.right, p, q); + if (left != null && right != null) return root; + else if (left != null) return left; + else return right; + } + return null; + } +} diff --git a/src/main/java/tree/LargestBSTSubtree.java b/src/main/java/tree/LargestBSTSubtree.java new file mode 100644 index 00000000..04d7edaa --- /dev/null +++ b/src/main/java/tree/LargestBSTSubtree.java @@ -0,0 +1,106 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 08/05/2017. + * + *

Given a binary tree, find the largest subtree which is a Binary Search Tree (BST), where + * largest means subtree with largest number of nodes in it. + * + *

Note: A subtree must include all of its descendants. Here's an example: 10 / \ 5 15 / \ \ 1 8 + * 7 The Largest BST Subtree in this case is the highlighted one (5-1-8). The return value is the + * subtree's size, which is 3. + * + *

Follow up: Can you figure out ways to solve it with O(n) time complexity? + * + *

Solution: The below solution works with O(n). Validate the BST property from the leaf node and + * increment the count, as soon as a violation of BST property is found terminate the count. + */ +public class LargestBSTSubtree { + /** Range class */ + private class Range { + int min, max, count; + + Range(int min, int max, int count) { + this.min = min; + this.max = max; + this.count = count; + } + } + + /** TreeNode */ + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** Count */ + private static int count = 0; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(10); + root.left = new TreeNode(9); + root.left.left = new TreeNode(8); + System.out.println(new LargestBSTSubtree().largestBSTSubtree(root)); + } + + /** + * Largest subtree count + * + * @param root root node + * @return count + */ + public int largestBSTSubtree(TreeNode root) { + getCount(root); + return count; + } + + /** + * Get count + * + * @param node root node + * @return Range + */ + private Range getCount(TreeNode node) { + if (node == null) return null; + Range left = getCount(node.left); + Range right = getCount(node.right); + if (left == null && right == null) { + count = Math.max(count, 1); + return new Range(node.val, node.val, 1); + } else if (left == null) { + if (node.val < right.min + && right.count != -1) // check for -1 ensures that there is no violation of BST property + return countMaxAndBuildNewRange(right.count + 1, node.val, right.max); + } else if (right == null) { + if (node.val > left.max && left.count != -1) + return countMaxAndBuildNewRange(left.count + 1, left.min, node.val); + } else if (node.val > left.max && node.val < right.min && right.count != -1 && left.count != -1) + return countMaxAndBuildNewRange(left.count + right.count + 1, left.min, right.max); + return new Range(0, 0, -1); // violation of BST property + } + + /** + * Record max and build new range + * + * @param sum total sum + * @param min min + * @param max max + * @return new Range + */ + private Range countMaxAndBuildNewRange(int sum, int min, int max) { + count = Math.max(count, sum); + return new Range(min, max, sum); + } +} diff --git a/src/main/java/tree/LeafSimilarTrees.java b/src/main/java/tree/LeafSimilarTrees.java new file mode 100644 index 00000000..d5247e5e --- /dev/null +++ b/src/main/java/tree/LeafSimilarTrees.java @@ -0,0 +1,58 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 23/08/2019 Consider all the leaves of a binary tree. From left + * to right order, the values of those leaves form a leaf value sequence. + * + *

For example, in the given tree above, the leaf value sequence is (6, 7, 4, 9, 8). + * + *

Two binary trees are considered leaf-similar if their leaf value sequence is the same. + * + *

Return true if and only if the two given trees with head nodes root1 and root2 are + * leaf-similar. + * + *

Solution: Do a inorder traversal for each trree and keep track of all the leaf nodes of the + * tree in a list. Compare the list and return the answer. + */ +public class LeafSimilarTrees { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public static void main(String[] args) {} + + public boolean leafSimilar(TreeNode root1, TreeNode root2) { + List list1 = new ArrayList<>(); + List list2 = new ArrayList<>(); + inorder(root1, list1); + inorder(root2, list2); + if (list1.size() != list2.size()) return false; + else { + for (int i = 0, l = list1.size(); i < l; i++) { + if (list1.get(i).intValue() != list2.get(i).intValue()) { + return false; + } + } + } + return true; + } + + private void inorder(TreeNode node, List list) { + if (node != null) { + if (node.left == null && node.right == null) { + list.add(node.val); + } + inorder(node.left, list); + inorder(node.right, list); + } + } +} diff --git a/src/main/java/tree/LowestCommonAncestorBST.java b/src/main/java/tree/LowestCommonAncestorBST.java new file mode 100644 index 00000000..48df25f1 --- /dev/null +++ b/src/main/java/tree/LowestCommonAncestorBST.java @@ -0,0 +1,38 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 09/03/2017. Given a binary search tree (BST), find the lowest + * common ancestor (LCA) of two given nodes in the BST. + * + *

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined + * between two nodes v and w as the lowest node in T that has both v and w as descendants (where we + * allow a node to be a descendant of itself).” + * + *

_______6______ / \ ___2__ ___8__ / \ / \ 0 _4 7 9 / \ 3 5 For example, the lowest common + * ancestor (LCA) of nodes 2 and 8 is 6. Another example is LCA of nodes 2 and 4 is 2, since a node + * can be a descendant of itself according to the LCA definition. + */ +public class LowestCommonAncestorBST { + class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public static void main(String[] args) throws Exception {} + + private TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null) return null; + + if (p.val == root.val || q.val == root.val) return root; + else if ((p.val < root.val && q.val > root.val) || (q.val < root.val && p.val > root.val)) + return root; + else if (p.val < root.val && q.val < root.val) return lowestCommonAncestor(root.left, p, q); + else return lowestCommonAncestor(root.right, p, q); + } +} diff --git a/src/main/java/tree/MaximumBinaryTree.java b/src/main/java/tree/MaximumBinaryTree.java new file mode 100644 index 00000000..f23823aa --- /dev/null +++ b/src/main/java/tree/MaximumBinaryTree.java @@ -0,0 +1,75 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 19/08/2017. Given an integer array with no duplicates. A + * maximum tree building on this array is defined as follow: + * + *

The root is the maximum number in the array. The left subtree is the maximum tree constructed + * from left part subarray divided by the maximum number. The right subtree is the maximum tree + * constructed from right part subarray divided by the maximum number. Construct the maximum tree by + * the given array and output the root node of this tree. + * + *

Example 1: Input: [3,2,1,6,0,5] Output: return the tree root node representing the following + * tree: + * + *

6 / \ 3 5 \ / 2 0 \ 1 + * + *

Note: The size of the given array will be in the range [1,1000]. + */ +public class MaximumBinaryTree { + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + private int[][] max; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] nums = {3, 2, 1, 6, 0, 5}; + TreeNode root = new MaximumBinaryTree().constructMaximumBinaryTree(nums); + System.out.println(root.val); // print root + } + + public TreeNode constructMaximumBinaryTree(int[] nums) { + + max = new int[nums.length][nums.length]; + + // pre-fill with initial values + for (int i = 0; i < nums.length; i++) { + max[i][i] = i; + } + + // pre-calculate max for range index + for (int i = 0; i < nums.length; i++) { + for (int j = i + 1; j < nums.length; j++) { + max[i][j] = nums[max[i][j - 1]] > nums[j] ? max[i][j - 1] : j; + } + } + + return build(0, nums.length - 1, nums); + } + + private TreeNode build(int s, int e, int[] nums) { + if (s <= e) { + int val = nums[max[s][e]]; + TreeNode n = new TreeNode(val); + n.left = build(s, max[s][e] - 1, nums); + n.right = build(max[s][e] + 1, e, nums); + return n; + } + return null; + } +} diff --git a/src/main/java/tree/MaximumLevelSumofABinaryTree.java b/src/main/java/tree/MaximumLevelSumofABinaryTree.java new file mode 100644 index 00000000..6e0b7763 --- /dev/null +++ b/src/main/java/tree/MaximumLevelSumofABinaryTree.java @@ -0,0 +1,64 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.*; + +/** + * Created by gouthamvidyapradhan on 28/08/2019 Given the root of a binary tree, the level of its + * root is 1, the level of its children is 2, and so on. + * + *

Return the smallest level X such that the sum of all the values of nodes at level X is + * maximal. + * + *

Example 1: + * + *

Input: [1,7,0,7,-8,null,null] Output: 2 Explanation: Level 1 sum = 1. Level 2 sum = 7 + 0 = 7. + * Level 3 sum = 7 + -8 = -1. So we return the level with the maximum sum which is level 2. + * + *

Note: + * + *

The number of nodes in the given tree is between 1 and 10^4. -10^5 <= node.val <= 10^5 + * + *

Solution: Keep a hashmap key-value pairs where key is the level and value is the sum of values + * at that level, do a inorder search in the tree and sum up the values at each level. + */ +public class MaximumLevelSumofABinaryTree { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + Map levelMap; + + public static void main(String[] args) { + // + } + + public int maxLevelSum(TreeNode root) { + levelMap = new HashMap<>(); + inorder(root, 1); + int max = Integer.MIN_VALUE; + int ans = 0; + for (int k : levelMap.keySet()) { + if (levelMap.get(k) > max) { + max = levelMap.get(k); + ans = k; + } + } + return ans; + } + + private void inorder(TreeNode root, int level) { + if (root != null) { + levelMap.putIfAbsent(level, 0); + levelMap.put(level, levelMap.get(level) + root.val); + inorder(root.left, level + 1); + inorder(root.right, level + 1); + } + } +} diff --git a/src/main/java/tree/MaximumWidthOfBinaryTree.java b/src/main/java/tree/MaximumWidthOfBinaryTree.java new file mode 100644 index 00000000..6b419e8c --- /dev/null +++ b/src/main/java/tree/MaximumWidthOfBinaryTree.java @@ -0,0 +1,80 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 03/05/2018. Given a binary tree, write a function to get the + * maximum width of the given tree. The width of a tree is the maximum width among all levels. The + * binary tree has the same structure as a full binary tree, but some nodes are null. + * + *

The width of one level is defined as the length between the end-nodes (the leftmost and right + * most non-null nodes in the level, where the null nodes between the end-nodes are also counted + * into the length calculation. + * + *

Example 1: Input: + * + *

1 / \ 3 2 / \ \ 5 3 9 + * + *

Output: 4 Explanation: The maximum width existing in the third level with the length 4 + * (5,3,null,9). Example 2: Input: + * + *

1 / 3 / \ 5 3 + * + *

Output: 2 Explanation: The maximum width existing in the third level with the length 2 (5,3). + * Example 3: Input: + * + *

1 / \ 3 2 / 5 + * + *

Output: 2 Explanation: The maximum width existing in the second level with the length 2 (3,2). + * Example 4: Input: + * + *

1 / \ 3 2 / \ 5 9 / \ 6 7 Output: 8 Explanation:The maximum width existing in the fourth level + * with the length 8 (6,null,null,null,null,null,null,7). + * + *

Solution: O(N): General idea is to give a position value to each node. On every left traversal + * give the value curr_pos * 2 and on every right traversal give the value curr_pos * 2 + 1 + * Calculate maximum width for each level using right - left + 1 + */ +public class MaximumWidthOfBinaryTree { + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + private Map> map; + + public static void main(String[] args) {} + + public int widthOfBinaryTree(TreeNode root) { + map = new HashMap<>(); + preorder(root, 1, 1); + int max = 0; + for (int k : map.keySet()) { + List list = map.get(k); + if (list.size() == 1) { + max = Math.max(max, 1); + } else { + max = Math.max(max, list.get(list.size() - 1) - list.get(0) + 1); + } + } + return max; + } + + private void preorder(TreeNode node, int level, int pos) { + if (node != null) { + preorder(node.left, level + 1, pos * 2); + map.putIfAbsent(level, new ArrayList<>()); + map.get(level).add(pos); + preorder(node.right, level + 1, pos * 2 + 1); + } + } +} diff --git a/src/main/java/tree/MinimumAbsoluteDifferenceInBST.java b/src/main/java/tree/MinimumAbsoluteDifferenceInBST.java new file mode 100644 index 00000000..a3b3d40a --- /dev/null +++ b/src/main/java/tree/MinimumAbsoluteDifferenceInBST.java @@ -0,0 +1,53 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 15/02/2018. Given a binary search tree with non-negative + * values, find the minimum absolute difference between values of any two nodes. + * + *

Example: + * + *

Input: + * + *

1 \ 3 / 2 + * + *

Output: 1 + * + *

Explanation: The minimum absolute difference is 1, which is the difference between 2 and 1 (or + * between 2 and 3). Note: There are at least two nodes in this BST. + */ +public class MinimumAbsoluteDifferenceInBST { + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + int min = Integer.MAX_VALUE; + + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(1); + root.right = new TreeNode(2); + root.right.right = new TreeNode(3); + new MinimumAbsoluteDifferenceInBST().getMinimumDifference(root); + } + + public int getMinimumDifference(TreeNode root) { + getMin(root, null); + return min; + } + + private Integer getMin(TreeNode node, Integer prev) { + if (node == null) return prev; + Integer left = getMin(node.left, prev); + if (left != null) { + min = Math.min(min, Math.abs(node.val - left)); + } + return getMin(node.right, node.val); + } +} diff --git a/src/main/java/tree/MostFrequentSubtreeSum.java b/src/main/java/tree/MostFrequentSubtreeSum.java new file mode 100644 index 00000000..e801de74 --- /dev/null +++ b/src/main/java/tree/MostFrequentSubtreeSum.java @@ -0,0 +1,80 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 27/03/2017. Given the root of a tree, you are asked to find the + * most frequent subtree sum. The subtree sum of a node is defined as the sum of all the node values + * formed by the subtree rooted at that node (including the node itself). So what is the most + * frequent subtree sum value? If there is a tie, return all the values with the highest frequency + * in any order. + * + *

Examples 1 Input: + * + *

5 / \ 2 -3 return [2, -3, 4], since all the values happen only once, return all of them in any + * order. Examples 2 Input: + * + *

5 / \ 2 -5 return [2], since 2 happens twice, however -5 only occur once. Note: You may assume + * the sum of values in any subtree is in the range of 32-bit signed integer. + */ +public class MostFrequentSubtreeSum { + static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + private Map> fList = new HashMap<>(); + private Map fCount = new HashMap<>(); + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + MostFrequentSubtreeSum mfs = new MostFrequentSubtreeSum(); + TreeNode node = new TreeNode(5); + // node.left = new TreeNode(2); + // node.right = new TreeNode(-5); + int[] result = mfs.findFrequentTreeSum(node); + } + + public int[] findFrequentTreeSum(TreeNode root) { + int[] resArr = new int[0]; + if (root == null) return resArr; + postOrder(root); + for (Map.Entry entry : fCount.entrySet()) { + int frequency = entry.getValue(); + List list = fList.get(frequency); + if (list == null) list = new ArrayList<>(); + list.add(entry.getKey()); + fList.put(frequency, list); + } + int max = Integer.MIN_VALUE; + List result; + for (int key : fList.keySet()) max = Math.max(max, key); + result = fList.get(max); + resArr = new int[result.size()]; + for (int i = 0, l = resArr.length; i < l; i++) resArr[i] = result.get(i); + return resArr; + } + + private int postOrder(TreeNode root) { + if (root == null) return 0; + int sum = postOrder(root.left) + postOrder(root.right) + root.val; + Integer fSum = fCount.get(sum); + if (fSum == null) fCount.put(sum, 1); + else fCount.put(sum, fSum + 1); + return sum; + } +} diff --git a/src/main/java/tree/NextRightPointer.java b/src/main/java/tree/NextRightPointer.java new file mode 100644 index 00000000..a49b5f7b --- /dev/null +++ b/src/main/java/tree/NextRightPointer.java @@ -0,0 +1,77 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.ArrayDeque; +import java.util.Queue; + +/** + * Created by gouthamvidyapradhan on 07/07/2017. + * + *

Given a binary tree + * + *

struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode *next; } Populate + * each next pointer to point to its next right node. If there is no next right node, the next + * pointer should be set to NULL. + * + *

Initially, all next pointers are set to NULL. + * + *

Note: + * + *

You may only use constant extra space. You may assume that it is a perfect binary tree (ie, + * all leaves are at the same level, and every parent has two children). For example, Given the + * following perfect binary tree, 1 / \ 2 3 / \ / \ 4 5 6 7 After calling your function, the tree + * should look like: 1 -> NULL / \ 2 -> 3 -> NULL / \ / \ 4->5->6->7 -> NULL + * + *

Solution: Perform a level order traversal using BFS, keep track of prev node at each level. + * Link the prev node to current node if both the nodes are in the same level. + */ +public class NextRightPointer { + private class LevelNode { + int level; + TreeLinkNode node; + + LevelNode(TreeLinkNode node, int level) { + this.node = node; + this.level = level; + } + } + + public static class TreeLinkNode { + int val; + TreeLinkNode left, right, next; + + TreeLinkNode(int x) { + val = x; + } + } + + public static void main(String[] args) throws Exception { + TreeLinkNode node = new TreeLinkNode(2); + node.left = new TreeLinkNode(1); + node.right = new TreeLinkNode(3); + new NextRightPointer().connect(node); + System.out.println(node.next); + System.out.println(node.left.next.val); + System.out.println(node.right.next); + } + + public void connect(TreeLinkNode root) { + Queue queue = new ArrayDeque<>(); + LevelNode zero = new LevelNode(root, 0); + queue.offer(zero); + LevelNode prev = null; + while (!queue.isEmpty()) { + LevelNode levelNode = queue.poll(); + if (levelNode.node == null) break; + TreeLinkNode curr = levelNode.node; + if (prev != null) { + if (prev.level == levelNode.level) { + prev.node.next = levelNode.node; + } + } + prev = levelNode; + queue.offer(new LevelNode(curr.left, levelNode.level + 1)); + queue.offer(new LevelNode(curr.right, levelNode.level + 1)); + } + } +} diff --git a/src/main/java/tree/NextRightPointerII.java b/src/main/java/tree/NextRightPointerII.java new file mode 100644 index 00000000..a70faea4 --- /dev/null +++ b/src/main/java/tree/NextRightPointerII.java @@ -0,0 +1,64 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 03/10/2017. + * + *

Follow up for problem "Populating Next Right Pointers in Each Node". + * + *

What if the given tree could be any binary tree? Would your previous solution still work? + * + *

Note: + * + *

You may only use constant extra space. For example, Given the following binary tree, 1 / \ 2 3 + * / \ \ 4 5 7 After calling your function, the tree should look like: 1 -> NULL / \ 2 -> 3 -> NULL + * / \ \ 4-> 5 -> 7 -> NULL + */ +public class NextRightPointerII { + + public static void main(String[] args) throws Exception { + TreeLinkNode root = new TreeLinkNode(1); + root.left = new TreeLinkNode(2); + root.right = new TreeLinkNode(3); + root.right.right = new TreeLinkNode(4); + root.right.right.left = new TreeLinkNode(5); + root.right.right.right = new TreeLinkNode(6); + new NextRightPointerII().connect(root); + } + + public void connect(TreeLinkNode root) { + TreeLinkNode prev = new TreeLinkNode(0); + TreeLinkNode first = null; + while (root != null) { + if (root.left != null) { + prev.next = root.left; + prev = root.left; + if (first == null) { + first = root.left; + } + } + if (root.right != null) { + prev.next = root.right; + prev = root.right; + if (first == null) { + first = root.right; + } + } + root = root.next; + if (root == null) { + root = first; + first = null; + prev = new TreeLinkNode(0); + } + } + } + + public static class TreeLinkNode { + int val; + TreeLinkNode left, right, next; + + TreeLinkNode(int x) { + val = x; + } + } +} diff --git a/src/main/java/tree/PathSumIII.java b/src/main/java/tree/PathSumIII.java new file mode 100644 index 00000000..bac60064 --- /dev/null +++ b/src/main/java/tree/PathSumIII.java @@ -0,0 +1,65 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 08/04/2017. You are given a binary tree in which each node + * contains an integer value. + * + *

Find the number of paths that sum to a given value. + * + *

The path does not need to start or end at the root or a leaf, but it must go downwards + * (traveling only from parent nodes to child nodes). + * + *

The tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000. + * + *

Example: + * + *

root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8 + * + *

10 / \ 5 -3 / \ \ 3 2 11 / \ \ 3 -2 1 + * + *

Return 3. The paths that sum to 8 are: + * + *

1. 5 -> 3 2. 5 -> 2 -> 1 3. -3 -> 11 + */ +public class PathSumIII { + /** */ + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + private Map pathCount = new HashMap<>(); + private int totalCount; + + public static void main(String[] args) throws Exception { + TreeNode node = new TreeNode(1); + System.out.println(new PathSumIII().pathSum(node, 0)); + } + + public int pathSum(TreeNode root, int sum) { + if (root == null) return 0; + dfs(root, sum, 0); + return totalCount; + } + + private void dfs(TreeNode root, int target, int pSum) { + if (root != null) { + pSum += root.val; + if (pSum == target) totalCount++; + totalCount += pathCount.getOrDefault(pSum - target, 0); + pathCount.put(pSum, pathCount.getOrDefault(pSum, 0) + 1); + dfs(root.left, target, pSum); + dfs(root.right, target, pSum); + pathCount.put(pSum, pathCount.get(pSum) - 1); + } + } +} diff --git a/src/main/java/tree/PostorderToBT.java b/src/main/java/tree/PostorderToBT.java new file mode 100644 index 00000000..655a528f --- /dev/null +++ b/src/main/java/tree/PostorderToBT.java @@ -0,0 +1,74 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 23/02/2017. Given inorder and postorder traversal of a tree, + * construct the binary tree. + * + *

Note: You may assume that duplicates do not exist in the tree. + */ +public class PostorderToBT { + + private Map INDEX = new HashMap<>(); + private static int postIndex; + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int in[] = new int[] {1, 2}; + int post[] = new int[] {1, 2}; + TreeNode root = new PostorderToBT().buildTree(in, post); + new PostorderToBT().preorderPrint(root); + } + + public TreeNode buildTree(int[] inorder, int[] postorder) { + int count = 0; + for (int i : inorder) INDEX.put(i, count++); + postIndex = postorder.length - 1; + return build(0, inorder.length - 1, postorder); + } + + private void preorderPrint(TreeNode root) { + if (root != null) { + System.out.print(root.val + " "); + preorderPrint(root.left); + preorderPrint(root.right); + } + } + + private TreeNode build(int s, int e, int[] postorder) { + if (postIndex >= 0 && s <= e) { + int poi = postorder[postIndex]; + + int ini = INDEX.get(poi); + + TreeNode node = new TreeNode(poi); + postIndex--; + + if (s == e) return node; // leaf node + + node.right = build(ini + 1, e, postorder); + node.left = build(s, ini - 1, postorder); + + return node; + } + return null; + } +} diff --git a/src/main/java/tree/PreorderToBT.java b/src/main/java/tree/PreorderToBT.java new file mode 100644 index 00000000..23958b59 --- /dev/null +++ b/src/main/java/tree/PreorderToBT.java @@ -0,0 +1,58 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by gouthamvidyapradhan on 25/02/2017. Given preorder and inorder traversal of a tree, + * construct the binary tree. + * + *

Note: You may assume that duplicates do not exist in the tree. + */ +public class PreorderToBT { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + Map MAP = new HashMap<>(); + private int index = 0, totalLen = 0; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] perorder = {7, -10, -4, 3, -1, 2, -8, 11}; + int[] inorder = {-4, -10, 3, -1, 7, 11, -8, 2}; + new PreorderToBT().buildTree(perorder, inorder); + } + + public TreeNode buildTree(int[] preorder, int[] inorder) { + for (int i = 0, l = inorder.length; i < l; i++) MAP.put(inorder[i], i); + totalLen = preorder.length; + return build(preorder, 0, inorder.length - 1); + } + + private TreeNode build(int[] preorder, int s, int e) { + if (s > e || index >= totalLen) return null; + + int n = preorder[index++]; + int pos = MAP.get(n); + + TreeNode node = new TreeNode(n); + if (s == e) return node; + + node.left = build(preorder, s, pos - 1); + node.right = build(preorder, pos + 1, e); + return node; + } +} diff --git a/src/main/java/tree/RecoverBinarySearchTree.java b/src/main/java/tree/RecoverBinarySearchTree.java new file mode 100644 index 00000000..e18c7f91 --- /dev/null +++ b/src/main/java/tree/RecoverBinarySearchTree.java @@ -0,0 +1,89 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 28/07/2018. Two elements of a binary search tree (BST) are + * swapped by mistake. + * + *

Recover the tree without changing its structure. + * + *

Example 1: + * + *

Input: [1,3,null,null,2] + * + *

1 / 3 \ 2 + * + *

Output: [3,1,null,null,2] + * + *

3 / 1 \ 2 Example 2: + * + *

Input: [3,1,4,null,null,2] + * + *

3 / \ 1 4 / 2 + * + *

Output: [2,1,4,null,null,3] + * + *

2 / \ 1 4 / 3 Follow up: + * + *

A solution using O(n) space is pretty straight forward. Could you devise a constant space + * solution? + * + *

Solution: O(N) time and O(1) space. Step 1, perform a inorder traversal and mark left and + * right pointer at the node where violation of BST occurs. Step2, find the next node which is + * smaller or equal to right pointer node. Finally swap left and right node values. + */ +public class RecoverBinarySearchTree { + private boolean violation; + private TreeNode left, right, prev; + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(10); + root.left = new TreeNode(1); + root.left.left = new TreeNode(3); + root.left.left.left = new TreeNode(5); + new RecoverBinarySearchTree().recoverTree(root); + } + + public void recoverTree(TreeNode root) { + inorder(root); + if (left != null && right != null) { + int temp = left.val; + left.val = right.val; + right.val = temp; + } + } + + private void inorder(TreeNode root) { + if (root != null) { + inorder(root.left); + if (prev != null) { + if (!violation) { + if (prev.val > root.val) { + violation = true; + left = prev; + right = root; + } else { + prev = root; + } + } else { + if (root.val <= right.val) { + right = root; + } + } + } else { + prev = root; + } + inorder(root.right); + } + } +} diff --git a/src/main/java/tree/SameTree.java b/src/main/java/tree/SameTree.java new file mode 100644 index 00000000..69bf6a81 --- /dev/null +++ b/src/main/java/tree/SameTree.java @@ -0,0 +1,64 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 23/01/2018. Given two binary trees, write a function to check + * if they are the same or not. + * + *

Two binary trees are considered the same if they are structurally identical and the nodes have + * the same value. + * + *

Example 1: + * + *

Input: 1 1 / \ / \ 2 3 2 3 + * + *

[1,2,3], [1,2,3] + * + *

Output: true Example 2: + * + *

Input: 1 1 / \ 2 2 + * + *

[1,2], [1,null,2] + * + *

Output: false Example 3: + * + *

Input: 1 1 / \ / \ 2 1 1 2 + * + *

[1,2,1], [1,1,2] + * + *

Output: false + * + *

Solution: Do a pre-order traversal of both the trees in parallel and compare each node + */ +public class SameTree { + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception {} + + public boolean isSameTree(TreeNode p, TreeNode q) { + if ((p == null && q != null) || (p != null && q == null)) return false; + if (p == null && q == null) return true; + else { + boolean status = isSameTree(p.left, q.left); + if (!status || p.val != q.val) { + return false; + } + return isSameTree(p.right, q.right); + } + } +} diff --git a/src/main/java/tree/SerializeAndDeserializeNAryTree.java b/src/main/java/tree/SerializeAndDeserializeNAryTree.java new file mode 100644 index 00000000..a525061a --- /dev/null +++ b/src/main/java/tree/SerializeAndDeserializeNAryTree.java @@ -0,0 +1,120 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Created by gouthamvidyapradhan on 16/03/2019 Serialization is the process of converting a data + * structure or object into a sequence of bits so that it can be stored in a file or memory buffer, + * or transmitted across a network connection link to be reconstructed later in the same or another + * computer environment. + * + *

Design an algorithm to serialize and deserialize an N-ary tree. An N-ary tree is a rooted tree + * in which each node has no more than N children. There is no restriction on how your + * serialization/deserialization algorithm should work. You just need to ensure that an N-ary tree + * can be serialized to a string and this string can be deserialized to the original tree structure. + * + *

For example, you may serialize the following 3-ary tree + * + *

1 /|\ 3 2 4 /\ 5 6 + * + *

as [1 [3[5 6] 2 4]]. You do not necessarily need to follow this format, so please be creative + * and come up with different approaches yourself. + * + *

Note: + * + *

N is in the range of [1, 1000] Do not use class member/global/static variables to store + * states. Your serialize and deserialize algorithms should be stateless. + * + *

Solution: To encode recursively iterate through each node and build a root and its children as + * 3[5,6] where 3 is the root and 5, 6 are its children. To decode, build the root node first and + * then recursively build its children. + */ +public class SerializeAndDeserializeNAryTree { + + static class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + Node n1 = new Node(5, new ArrayList<>()); + Node n2 = new Node(6, Arrays.asList(n1)); + Node n3 = new Node(2, Arrays.asList(n2)); + Node n4 = new Node(4, Arrays.asList(n3)); + Node n5 = new Node(3, Arrays.asList(n4)); + Node root = new Node(1, Arrays.asList(n5)); + SerializeAndDeserializeNAryTree serializer = new SerializeAndDeserializeNAryTree(); + String result = serializer.serialize(root); + Node rootNode = serializer.deserialize(result); + System.out.println(result); + System.out.println(rootNode); + } + + // Encodes a tree to a single string. + public String serialize(Node root) { + if (root != null) { + String curr = String.valueOf(root.val); + List children = root.children; + return children != null + ? curr + + "[" + + children.stream().map(this::serialize).collect(Collectors.joining(",")) + + "]" + : curr + "[]"; + } else { + return ""; + } + } + + // Decodes your encoded data to tree. + public Node deserialize(String data) { + char[] arr = data.toCharArray(); + StringBuilder num = new StringBuilder(); + Queue queue = new ArrayDeque<>(); + for (char c : arr) { + if (c >= '0' && c <= '9') { + num.append(c); + } else if (c == '[') { + if (num.length() != 0) { + queue.offer(num.toString()); + num = new StringBuilder(); + } + queue.offer("["); + } else { + queue.offer(String.valueOf(c)); + } + } + if (queue.isEmpty()) return null; + return decode(queue).get(0); + } + + private List decode(Queue elements) { + List children = new ArrayList<>(); + while (!elements.isEmpty()) { + String curr = elements.poll(); + if (curr.equals("[") || curr.equals(",")) { + } else if (curr.equals("]")) { + return children; + } else { + int num = Integer.parseInt(curr); + Node currNode = new Node(num, decode(elements)); + children.add(currNode); + } + } + return children; + } +} diff --git a/src/main/java/tree/SortedArrayToBST.java b/src/main/java/tree/SortedArrayToBST.java new file mode 100644 index 00000000..dcb3d57f --- /dev/null +++ b/src/main/java/tree/SortedArrayToBST.java @@ -0,0 +1,59 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 25/02/2017. Given an array where elements are sorted in + * ascending order, convert it to a height balanced BST. + */ +public class SortedArrayToBST { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 2, 3, 4, 5, 6}; + new SortedArrayToBST().sortedArrayToBST(A); + } + + public TreeNode sortedArrayToBST(int[] nums) { + if (nums.length == 0) return null; + + TreeNode root = new SortedArrayToBST().build(0, nums.length - 1, nums); + preorder(root); + return root; + } + + private void preorder(TreeNode node) { + if (node != null) { + preorder(node.left); + System.out.println(node.val); + preorder(node.right); + } + } + + private TreeNode build(int s, int e, int[] nums) { + if (s > e) return null; + + int m = (e - s) / 2; + int node = nums[s + m]; + TreeNode root = new TreeNode(node); + if (s == e) return root; + + root.left = build(s, s + m - 1, nums); + root.right = build(s + m + 1, e, nums); + + return root; + } +} diff --git a/src/main/java/tree/SplitBST.java b/src/main/java/tree/SplitBST.java new file mode 100644 index 00000000..741c68c6 --- /dev/null +++ b/src/main/java/tree/SplitBST.java @@ -0,0 +1,85 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 01/05/2018. Given a Binary Search Tree (BST) with root node + * root, and a target value V, split the tree into two subtrees where one subtree has nodes that are + * all smaller or equal to the target value, while the other subtree has all nodes that are greater + * than the target value. It's not necessarily the case that the tree contains a node with value V. + * + *

Additionally, most of the structure of the original tree should remain. Formally, for any + * child C with parent P in the original tree, if they are both in the same subtree after the split, + * then node C should still have the parent P. + * + *

You should output the root TreeNode of both subtrees after splitting, in any order. + * + *

Example 1: + * + *

Input: root = [4,2,6,1,3,5,7], V = 2 Output: [[2,1],[4,3,6,null,null,5,7]] Explanation: Note + * that root, output[0], and output[1] are TreeNode objects, not arrays. + * + *

The given tree [4,2,6,1,3,5,7] is represented by the following diagram: + * + *

4 / \ 2 6 / \ / \ 1 3 5 7 + * + *

while the diagrams for the outputs are: + * + *

4 / \ 3 6 and 2 / \ / 5 7 1 Note: + * + *

The size of the BST will not exceed 50. The BST is always valid and each node's value is + * different. + * + *

Solution: O(N) if a current node is <= to key then the current node and its child nodes form + * the left sub-tree. Split the right node further recursively + */ +public class SplitBST { + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(4); + root.left = new TreeNode(2); + root.left.left = new TreeNode(1); + root.left.right = new TreeNode(3); + root.right = new TreeNode(6); + root.right.left = new TreeNode(5); + root.right.right = new TreeNode(7); + root.right.right.right = new TreeNode(9); + TreeNode[] result = new SplitBST().splitBST(root, 3); + } + + public TreeNode[] splitBST(TreeNode root, int V) { + if (root == null) { + return new TreeNode[] {null, null}; + } else { + TreeNode[] result = new TreeNode[2]; + if (root.val <= V) { + result[0] = root; + TreeNode[] right = splitBST(root.right, V); + root.right = right[0]; + result[1] = right[1]; + return result; + } else { + TreeNode[] left = splitBST(root.left, V); + root.left = left[1]; + result[0] = left[0]; + result[1] = root; + return result; + } + } + } +} diff --git a/src/main/java/tree/SubtreeOfAnotherTree.java b/src/main/java/tree/SubtreeOfAnotherTree.java new file mode 100644 index 00000000..026ba64b --- /dev/null +++ b/src/main/java/tree/SubtreeOfAnotherTree.java @@ -0,0 +1,46 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 07/07/2017. Given two non-empty binary trees s and t, check + * whether tree t has exactly the same structure and node values with a subtree of s. A subtree of s + * is a tree consists of a node in s and all of this node's descendants. The tree s could also be + * considered as a subtree of itself. + * + *

Example 1: Given tree s: + * + *

3 / \ 4 5 / \ 1 2 Given tree t: 4 / \ 1 2 Return true, because t has the same structure and + * node values with a subtree of s. Example 2: Given tree s: + * + *

3 / \ 4 5 / \ 1 2 / 0 Given tree t: 4 / \ 1 2 Return false. + */ +public class SubtreeOfAnotherTree { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public static void main(String[] args) throws Exception {} + + public boolean isSubtree(TreeNode s, TreeNode t) { + if (s != null) { + if (s.val == t.val) { + if (equal(s, t)) return true; + else return (isSubtree(s.left, t) || isSubtree(s.right, t)); + } else return (isSubtree(s.left, t) || isSubtree(s.right, t)); + } + return false; + } + + private boolean equal(TreeNode s, TreeNode t) { + if (s == null && t == null) return true; + else if (s == null || t == null) return false; + else if (s.val != t.val) return false; + else return equal(s.left, t.left) && equal(s.right, t.right); + } +} diff --git a/src/main/java/tree/SumofLeftLeaves.java b/src/main/java/tree/SumofLeftLeaves.java new file mode 100644 index 00000000..7d6bf15d --- /dev/null +++ b/src/main/java/tree/SumofLeftLeaves.java @@ -0,0 +1,49 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 13/12/2017. Find the sum of all left leaves in a given binary + * tree. + * + *

Example: + * + *

3 / \ 9 20 / \ 15 7 + * + *

There are two left leaves in the binary tree, with values 9 and 15 respectively. Return 24. + */ +public class SumofLeftLeaves { + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception {} + + public int sumOfLeftLeaves(TreeNode root) { + return inorder(root, false); + } + + private int inorder(TreeNode node, boolean isLeft) { + if (node != null) { + if (node.left == null && node.right == null) { + if (isLeft) { + return node.val; + } else return 0; + } + return inorder(node.left, true) + inorder(node.right, false); + } + return 0; + } +} diff --git a/src/main/java/tree/SymmetricTree.java b/src/main/java/tree/SymmetricTree.java new file mode 100644 index 00000000..f167a51e --- /dev/null +++ b/src/main/java/tree/SymmetricTree.java @@ -0,0 +1,49 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 14/08/2017. Given a binary tree, check whether it is a mirror + * of itself (ie, symmetric around its center). + * + *

For example, this binary tree [1,2,2,3,4,4,3] is symmetric: + * + *

1 / \ 2 2 / \ / \ 3 4 4 3 + * + *

But the following [1,2,2,null,3,null,3] is not: 1 / \ 2 2 \ \ 3 3 + */ +public class SymmetricTree { + + static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + TreeNode node = new TreeNode(3); + node.left = new TreeNode(4); + node.right = new TreeNode(5); + System.out.println(new SymmetricTree().isSymmetric(node)); + } + + public boolean isSymmetric(TreeNode root) { + if (root == null) return true; + return dfs(root.left, root.right); + } + + private boolean dfs(TreeNode left, TreeNode right) { + if (left == null && right == null) return true; + else if (left == null || right == null) return false; + return dfs(left.left, right.right) && left.val == right.val && dfs(left.right, right.left); + } +} diff --git a/src/main/java/tree/TwoSumIV.java b/src/main/java/tree/TwoSumIV.java new file mode 100644 index 00000000..9e32e2a5 --- /dev/null +++ b/src/main/java/tree/TwoSumIV.java @@ -0,0 +1,62 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.HashSet; + +/** + * Created by gouthamvidyapradhan on 16/12/2017. Given a Binary Search Tree and a target number, + * return true if there exist two elements in the BST such that their sum is equal to the given + * target. + * + *

Example 1: Input: 5 / \ 3 6 / \ \ 2 4 7 + * + *

Target = 9 + * + *

Output: True Example 2: Input: 5 / \ 3 6 / \ \ 2 4 7 + * + *

Target = 28 + * + *

Output: False + */ +public class TwoSumIV { + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception {} + + public boolean findTarget(TreeNode root, int k) { + return inorder(root, new HashSet<>(), k); + } + + private boolean inorder(TreeNode node, HashSet set, int k) { + if (node != null) { + int req = k - (node.val); + if (set.contains(req)) { + return true; + } + set.add(node.val); + if (inorder(node.left, set, k)) { + return true; + } else { + if (inorder(node.right, set, k)) { + return true; + } + } + } + return false; + } +} diff --git a/src/main/java/tree/ValidBinarySearchTree.java b/src/main/java/tree/ValidBinarySearchTree.java new file mode 100644 index 00000000..bb0fbb18 --- /dev/null +++ b/src/main/java/tree/ValidBinarySearchTree.java @@ -0,0 +1,65 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +/** + * Created by gouthamvidyapradhan on 09/03/2017. Given a binary tree, determine if it is a valid + * binary search tree (BST). + * + *

Assume a BST is defined as follows: + * + *

The left subtree of a node contains only nodes with keys less than the node's key. The right + * subtree of a node contains only nodes with keys greater than the node's key. Both the left and + * right subtrees must also be binary search trees. Example 1: 2 / \ 1 3 Binary tree [2,1,3], return + * true. Example 2: 1 / \ 2 3 Binary tree [1,2,3], return false. + */ +public class ValidBinarySearchTree { + class Range { + long low, high; + } + + static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + TreeNode root = new TreeNode(Integer.MIN_VALUE); + root.right = new TreeNode(Integer.MAX_VALUE); + System.out.println(new ValidBinarySearchTree().isValidBST(root)); + } + + private boolean isValidBST(TreeNode root) { + if (root == null || (root.right == null && root.left == null)) return true; + Range range = new Range(); + range.high = Long.MAX_VALUE; + range.low = Long.MIN_VALUE; + return validate(root, range); + } + + private boolean validate(TreeNode root, Range range) { + if ((root.val > range.low) && (root.val < range.high)) { + long temp = range.high; + if (root.left != null) { + range.high = root.val; + if (!validate(root.left, range)) return false; + } + if (root.right != null) { + range.high = temp; + range.low = root.val; + if (!validate(root.right, range)) return false; + } + return true; + } else return false; + } +} diff --git a/src/main/java/tree/ZigZagTraversal.java b/src/main/java/tree/ZigZagTraversal.java new file mode 100644 index 00000000..5236a18c --- /dev/null +++ b/src/main/java/tree/ZigZagTraversal.java @@ -0,0 +1,51 @@ +/* (C) 2024 YourCompanyName */ +package tree; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * Created by pradhang on 7/11/2017. Given a binary tree, return the zigzag level order traversal of + * its nodes' values. (ie, from left to right, then right to left for the next level and alternate + * between). + * + *

For example: Given binary tree [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 return its zigzag + * level order traversal as: [ [3], [20,9], [15,7] ] + */ +public class ZigZagTraversal { + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public static void main(String[] args) throws Exception {} + + public List> zigzagLevelOrder(TreeNode root) { + List> result = new ArrayList<>(); + if (root == null) return result; + dfs(root, 0, result); + return result; + } + + @SuppressWarnings("unchecked") + private void dfs(TreeNode root, int level, List> result) { + if (root != null) { + LinkedList subList; + if (level >= result.size()) { + subList = new LinkedList<>(); + result.add(subList); + } else subList = (LinkedList) result.get(level); + if (level % 2 == 0) subList.addFirst(root.val); // add to right + else subList.add(root.val); // add to left + dfs(root.right, level + 1, result); + dfs(root.left, level + 1, result); + } + } +} diff --git a/src/main/java/two_pointers/FourSum.java b/src/main/java/two_pointers/FourSum.java new file mode 100644 index 00000000..0eeb74d8 --- /dev/null +++ b/src/main/java/two_pointers/FourSum.java @@ -0,0 +1,63 @@ +/* (C) 2024 YourCompanyName */ +package two_pointers; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 29/03/2017. Given an array S of n integers, are there elements + * a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array + * which gives the sum of target. + * + *

Note: The solution set must not contain duplicate quadruplets. + * + *

For example, given array S = [1, 0, -1, 0, -2, 2], and target = 0. + * + *

A solution set is: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ] + */ +public class FourSum { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] nums = {1, 0, -1, 0, -2, 2}; + System.out.println(new FourSum().fourSum(nums, 0)); + } + + public List> fourSum(int[] nums, int target) { + List> result = new ArrayList<>(); + if (nums.length < 4) return result; + Arrays.sort(nums); + for (int i = 0; i < nums.length - 3; i++) { + if (i == 0 || nums[i] != nums[i - 1]) { + for (int j = i + 1; j < nums.length - 2; j++) { + if (j == i + 1 || nums[j] != nums[j - 1]) { + int k = j + 1, l = nums.length - 1; + while (k < l) { + if (k != j + 1 && nums[k] == nums[k + 1]) { + k++; + continue; + } + int sum = nums[i] + nums[j] + nums[k] + nums[l]; + if (sum == target) { + result.add(Arrays.asList(nums[i], nums[j], nums[k], nums[l])); + k++; + l--; + } else if (sum < target) { + k++; + } else { + l--; + } + } + } + } + } + } + return result; + } +} diff --git a/src/main/java/two_pointers/LastSubstringInLexicographicalOrder.java b/src/main/java/two_pointers/LastSubstringInLexicographicalOrder.java new file mode 100644 index 00000000..4b9195c2 --- /dev/null +++ b/src/main/java/two_pointers/LastSubstringInLexicographicalOrder.java @@ -0,0 +1,69 @@ +/* (C) 2024 YourCompanyName */ +package two_pointers; +/** + * Created by gouthamvidyapradhan on 30/08/2019 Given a string s, return the last substring of s in + * lexicographical order. + * + *

Example 1: + * + *

Input: "abab" Output: "bab" Explanation: The substrings are ["a", "ab", "aba", "abab", "b", + * "ba", "bab"]. The lexicographically maximum substring is "bab". Example 2: + * + *

Input: "leetcode" Output: "tcode" + * + *

Note: + * + *

1 <= s.length <= 4 * 10^5 s contains only lowercase English letters. + * + *

Solution O(N) General idea is as below. Fix the index 0 as the answer initially and start + * iterating the string character by character, if a char is encountered with is greater than the + * current answer then mark this as the answer, if it is same as the current answer then this new + * char can be a potential candidate for a answer hence mark this as a candidate and start comparing + * all the further characters of candidate char and all further chars of current answer if any point + * the char further down the candidate is greater than the char further down the current answer then + * mark the new candidate as the answer. + */ +public class LastSubstringInLexicographicalOrder { + public static void main(String[] args) { + System.out.println(new LastSubstringInLexicographicalOrder().lastSubstring("babcbd")); + } + + public String lastSubstring(String s) { + int currAns = 0; + int candidate = -1; + int prevIndex = 1; + for (int i = 1, l = s.length(); i < l; i++) { + if (candidate != -1) { + if (s.charAt(i) == s.charAt(prevIndex)) { + prevIndex++; + } else if (s.charAt(i) > s.charAt(prevIndex)) { + if (s.charAt(i) > s.charAt(candidate)) { + currAns = i; + candidate = -1; + prevIndex = currAns + 1; + } else if (s.charAt(i) == s.charAt(candidate)) { + currAns = candidate; + candidate = i; + prevIndex = currAns + 1; + } else { + currAns = candidate; + candidate = -1; + prevIndex = currAns + 1; + } + } else { + candidate = -1; + prevIndex = currAns + 1; + } + } else { + if (s.charAt(i) > s.charAt(currAns)) { + currAns = i; + candidate = -1; + prevIndex = currAns + 1; + } else if (s.charAt(i) == s.charAt(currAns)) { + candidate = i; + } + } + } + return s.substring(currAns); + } +} diff --git a/src/main/java/two_pointers/LongestSubstringWitoutRepeats.java b/src/main/java/two_pointers/LongestSubstringWitoutRepeats.java new file mode 100644 index 00000000..85b80c54 --- /dev/null +++ b/src/main/java/two_pointers/LongestSubstringWitoutRepeats.java @@ -0,0 +1,50 @@ +/* (C) 2024 YourCompanyName */ +package two_pointers; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Created by gouthamvidyapradhan on 09/03/2017. Given a string, find the length of the longest + * substring without repeating characters. + * + *

Examples: + * + *

Given "abcabcbb", the answer is "abc", which the length is 3. + * + *

Given "bbbbb", the answer is "b", with the length of 1. + * + *

Given "pwwkew", the answer is "wke", with the length of 3. Note that the answer must be a + * substring, "pwke" is a subsequence and not a substring. + */ +public class LongestSubstringWitoutRepeats { + Set set = new HashSet<>(); + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println( + new LongestSubstringWitoutRepeats() + .lengthOfLongestSubstring("asdfsdfsdfsdfasdfdjdjjdjjdjjjjjajsdjjdjdjjd")); + } + + private int lengthOfLongestSubstring(String s) { + if (s == null || s.isEmpty()) return 0; + Map map = new HashMap<>(); + int i = 0, max = Integer.MIN_VALUE; + for (int j = 0, l = s.length(); j < l; j++) { + if (map.keySet().contains(s.charAt(j))) { + i = Math.max(map.get(s.charAt(j)) + 1, i); + } + map.put(s.charAt(j), j); + max = Math.max(max, (j - i) + 1); + } + return max; + } +} diff --git a/src/main/java/two_pointers/MinimumSizeSubarraySum.java b/src/main/java/two_pointers/MinimumSizeSubarraySum.java new file mode 100644 index 00000000..0800c502 --- /dev/null +++ b/src/main/java/two_pointers/MinimumSizeSubarraySum.java @@ -0,0 +1,57 @@ +/* (C) 2024 YourCompanyName */ +package two_pointers; + +/** + * Created by gouthamvidyapradhan on 03/12/2017. + * + *

Given an array of n positive integers and a positive integer s, find the minimal length of a + * contiguous subarray of which the sum ≥ s. If there isn't one, return 0 instead. + * + *

For example, given the array [2,3,1,2,4,3] and s = 7, the subarray [4,3] has the minimal + * length under the problem constraint. + * + *

click to show more practice. + * + *

Credits: Special thanks to @Freezen for adding this problem and creating all test cases. + * + *

Solution: O(n) solution. Solve using sliding window sub-array sum using two pointers. + */ +public class MinimumSizeSubarraySum { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] nums = {2, 3, 1, 2, 4, 3}; + System.out.println(new MinimumSizeSubarraySum().minSubArrayLen(7, nums)); + } + + public int minSubArrayLen(int s, int[] nums) { + int sum = 0, count = 0, min = Integer.MAX_VALUE; + for (int i = 0, j = 0; j < nums.length; ) { + if (nums[j] >= s) { + return 1; + } else { + sum += nums[j]; + count++; + if (sum >= s) { + min = Math.min(min, count); + while (j > i) { + sum -= nums[i]; + count--; + i++; + if (sum < s) break; + min = Math.min(min, count); + } + } + } + j++; + } + if (min == Integer.MAX_VALUE) { + return 0; + } + return min; + } +} diff --git a/src/main/java/two_pointers/MinimumWindowSubstring.java b/src/main/java/two_pointers/MinimumWindowSubstring.java new file mode 100644 index 00000000..fa1f641d --- /dev/null +++ b/src/main/java/two_pointers/MinimumWindowSubstring.java @@ -0,0 +1,82 @@ +/* (C) 2024 YourCompanyName */ +package two_pointers; + +/** + * Created by gouthamvidyapradhan on 03/12/2017. + * + *

Given a string S and a string T, find the minimum window in S which will contain all the + * characters in T in complexity O(n). + * + *

For example, S = "ADOBECODEBANC" T = "ABC" Minimum window is "BANC". + * + *

Note: If there is no such window in S that covers all characters in T, return the empty string + * "". + * + *

If there are multiple such windows, you are guaranteed that there will always be only one + * unique minimum window in S. + * + *

Solution O(n). Sliding window sub-sting using two pointers. + */ +public class MinimumWindowSubstring { + private int[] hash = new int[256]; + private int[] curr = new int[256]; + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(new MinimumWindowSubstring().minWindow("ADOBECODEBANC", "ABC")); + } + + public String minWindow(String s, String t) { + if (s.isEmpty() && t.isEmpty()) return ""; + if (t.length() > s.length()) return ""; + int start = -1, end = -1, min = Integer.MAX_VALUE; + for (int i = 0, l = t.length(); i < l; i++) { + hash[t.charAt(i)]++; + } + + for (int i = 0, l = t.length() - 1; i < l; i++) { + curr[s.charAt(i)]++; + } + + for (int i = 0, j = t.length() - 1, l = s.length(); j < l; ) { + curr[s.charAt(j)]++; + if (isMatch()) { + if (j - i < min) { + min = j - i; + start = i; + end = j; + } + while (j > i) { + curr[s.charAt(i)]--; + i++; + if (isMatch()) { + if (j - i < min) { + min = j - i; + start = i; + end = j; + } + } else break; + } + } + j++; + } + if (min == Integer.MAX_VALUE) { + return ""; + } + return s.substring(start, end + 1); + } + + private boolean isMatch() { + for (int i = 0; i < 256; i++) { + if (curr[i] < hash[i]) { + return false; + } + } + return true; + } +} diff --git a/src/main/java/two_pointers/MoveZeroes.java b/src/main/java/two_pointers/MoveZeroes.java new file mode 100644 index 00000000..460f09df --- /dev/null +++ b/src/main/java/two_pointers/MoveZeroes.java @@ -0,0 +1,35 @@ +/* (C) 2024 YourCompanyName */ +package two_pointers; + +/** + * Created by gouthamvidyapradhan on 13/06/2017. Accepted Given an array nums, write a function to + * move all 0's to the end of it while maintaining the relative order of the non-zero elements. + * + *

For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, + * 12, 0, 0]. + * + *

Note: You must do this in-place without making a copy of the array. Minimize the total number + * of operations. + */ +public class MoveZeroes { + public static void main(String[] args) throws Exception { + int[] nums = {0, 0, 0, 0, 1, 0, 1, 0, 2}; + new MoveZeroes().moveZeroes(nums); + for (int n : nums) System.out.print(n); + } + + public void moveZeroes(int[] nums) { + int i = 0; + for (int j = 0, l = nums.length; j < l; ) { + if (nums[j] == 0) j++; + else { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + i++; + j++; + } + } + while (i < nums.length) nums[i++] = 0; + } +} diff --git a/src/main/java/two_pointers/NumberOfMatchingSubsequences.java b/src/main/java/two_pointers/NumberOfMatchingSubsequences.java new file mode 100644 index 00000000..6eca1354 --- /dev/null +++ b/src/main/java/two_pointers/NumberOfMatchingSubsequences.java @@ -0,0 +1,57 @@ +/* (C) 2024 YourCompanyName */ +package two_pointers; + +/** + * Created by gouthamvidyapradhan on 04/04/2019 Given string S and a dictionary of words words, find + * the number of words[i] that is a subsequence of S. + * + *

Example : Input: S = "abcde" words = ["a", "bb", "acd", "ace"] Output: 3 Explanation: There + * are three words in words that are a subsequence of S: "a", "acd", "ace". Note: + * + *

All words in words and S will only consists of lowercase letters. The length of S will be in + * the range of [1, 50000]. The length of words will be in the range of [1, 5000]. The length of + * words[i] will be in the range of [1, 50]. + * + *

Solution: O((w + S) x N (no of words)) Using two pointers technique check if each of the given + * string is a sub-sequence of the main string. + */ +public class NumberOfMatchingSubsequences { + + /** + * Main method + * + * @param args + */ + public static void main(String[] args) { + String[] A = {"a", "bb", "acd", "ace"}; + System.out.println(new NumberOfMatchingSubsequences().numMatchingSubseq("abcde", A)); + } + + public int numMatchingSubseq(String S, String[] words) { + int count = 0; + for (int i = 0; i < words.length; i++) { + String w = words[i]; + if (isSubsequence(S, w)) { + count++; + } + } + return count; + } + + private boolean isSubsequence(String S, String P) { + int i = 0, j = 0; + if (P.length() > S.length()) return false; + for (; ; ) { + if (j >= P.length()) return true; + else if (i >= S.length()) return false; + else { + if (S.charAt(i) == P.charAt(j)) { + i++; + j++; + } else { + i++; + } + } + } + } +} diff --git a/src/main/java/two_pointers/RemoveDuplicates.java b/src/main/java/two_pointers/RemoveDuplicates.java new file mode 100644 index 00000000..749db9a4 --- /dev/null +++ b/src/main/java/two_pointers/RemoveDuplicates.java @@ -0,0 +1,34 @@ +/* (C) 2024 YourCompanyName */ +package two_pointers; + +/** + * Created by gouthamvidyapradhan on 04/07/2017. Given a sorted array, remove the duplicates in + * place such that each element appear only once and return the new length. + * + *

Do not allocate extra space for another array, you must do this in place with constant memory. + * + *

For example, Given input array nums = [1,1,2], + * + *

Your function should return length = 2, with the first two elements of nums being 1 and 2 + * respectively. It doesn't matter what you leave beyond the new length. + */ +public class RemoveDuplicates { + public static void main(String[] args) throws Exception { + int[] nums = {1, 1, 2}; + int N = new RemoveDuplicates().removeDuplicates(nums); + for (int i = 0; i < N; i++) System.out.print(nums[i] + " "); + } + + public int removeDuplicates(int[] nums) { + if (nums.length == 1) return 1; + int size = 1; + for (int j = 0, i = 1; i < nums.length; i++) { + if (nums[i] != nums[i - 1]) { + size++; + j++; + nums[j] = nums[i]; + } + } + return size; + } +} diff --git a/src/main/java/two_pointers/RemoveDuplicatesII.java b/src/main/java/two_pointers/RemoveDuplicatesII.java new file mode 100644 index 00000000..db90a4ab --- /dev/null +++ b/src/main/java/two_pointers/RemoveDuplicatesII.java @@ -0,0 +1,43 @@ +/* (C) 2024 YourCompanyName */ +package two_pointers; + +/** + * Created by gouthamvidyapradhan on 20/01/2018. Follow up for "Remove Duplicates": What if + * duplicates are allowed at most twice? + * + *

For example, Given sorted array nums = [1,1,1,2,2,3], + * + *

Your function should return length = 5, with the first five elements of nums being 1, 1, 2, 2 + * and 3. It doesn't matter what you leave beyond the new length. + */ +public class RemoveDuplicatesII { + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] A = {1, 1, 1, 2, 2, 2, 3, 4, 4}; + System.out.println(new RemoveDuplicatesII().removeDuplicates(A)); + } + + public int removeDuplicates(int[] nums) { + if (nums.length == 0) return 0; + int j = 0; + int count = 1; + for (int i = 1; i < nums.length; i++) { + if (nums[i - 1] == nums[i]) { + count++; + } else { + count = 1; + } + if (count == 1 || count == 2) { + j++; + nums[j] = nums[i]; + } + } + return j + 1; + } +} diff --git a/src/main/java/two_pointers/SmallestRange.java b/src/main/java/two_pointers/SmallestRange.java new file mode 100644 index 00000000..73e4cb4c --- /dev/null +++ b/src/main/java/two_pointers/SmallestRange.java @@ -0,0 +1,81 @@ +/* (C) 2024 YourCompanyName */ +package two_pointers; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.PriorityQueue; + +/** + * Created by gouthamvidyapradhan on 23/01/2018. You have k lists of sorted integers in ascending + * order. Find the smallest range that includes at least one number from each of the k lists. + * + *

We define the range [a,b] is smaller than range [c,d] if b-a < d-c or a < c if b-a == d-c. + * + *

Example 1: Input:[[4,10,15,24,26], [0,9,12,20], [5,18,22,30]] Output: [20,24] Explanation: + * List 1: [4, 10, 15, 24,26], 24 is in range [20,24]. List 2: [0, 9, 12, 20], 20 is in range + * [20,24]. List 3: [5, 18, 22, 30], 22 is in range [20,24]. Note: The given list may contain + * duplicates, so ascending order means >= here. 1 <= k <= 3500 -105 <= value of elements <= 105. + * For Java users, please note that the input type has been changed to List>. And + * after you reset the code template, you'll see this point. + * + *

Solution O(n log m) where m is the total number of lists and n in the total elements in all + * the list combined. + */ +public class SmallestRange { + + class MinIndex { + int i, j; + + MinIndex(int i, int j) { + this.i = i; + this.j = j; + } + } + + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + List> list = new ArrayList<>(); + List row1 = Arrays.asList(4, 10, 15, 24, 26); + List row2 = Arrays.asList(0, 9, 12, 20); + List row3 = Arrays.asList(5, 18, 22, 30); + list.add(row1); + list.add(row2); + list.add(row3); + int[] R = new SmallestRange().smallestRange(list); + System.out.println(R[0] + " " + R[1]); + } + + public int[] smallestRange(List> nums) { + PriorityQueue pq = + new PriorityQueue<>( + (o1, o2) -> Integer.compare(nums.get(o1.i).get(o1.j), nums.get(o2.i).get(o2.j))); + int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE; + for (int i = 0, l = nums.size(); i < l; i++) { + min = Math.min(min, nums.get(i).get(0)); + max = Math.max(max, nums.get(i).get(0)); + pq.offer(new MinIndex(i, 0)); + } + if (min == max) return new int[] {min, max}; + int ansMin = min, ansMax = max; + while (true) { + MinIndex minIndex = pq.poll(); + if (minIndex.j + 1 >= nums.get(minIndex.i).size()) { + return new int[] {ansMin, ansMax}; + } + int next = nums.get(minIndex.i).get(minIndex.j + 1); + max = Math.max(max, next); // update max if any + pq.offer(new MinIndex(minIndex.i, minIndex.j + 1)); + min = nums.get(pq.peek().i).get(pq.peek().j); // new minimum + if ((max - min) < (ansMax - ansMin)) { + ansMax = max; + ansMin = min; + } + } + } +} diff --git a/src/main/java/two_pointers/SubarrayProductLessThanK.java b/src/main/java/two_pointers/SubarrayProductLessThanK.java new file mode 100644 index 00000000..5d255e71 --- /dev/null +++ b/src/main/java/two_pointers/SubarrayProductLessThanK.java @@ -0,0 +1,60 @@ +/* (C) 2024 YourCompanyName */ +package two_pointers; +/** + * Created by gouthamvidyapradhan on 17/02/2018. Your are given an array of positive integers nums. + * + *

Count and print the number of (contiguous) subarrays where the product of all the elements in + * the subarray is less than k. + * + *

Example 1: Input: nums = [10, 5, 2, 6], k = 100 Output: 8 Explanation: The 8 subarrays that + * have product less than 100 are: [10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6]. Note + * that [10, 5, 2] is not included as the product of 100 is not strictly less than k. Note: + * + *

0 < nums.length <= 50000. 0 < nums[i] < 1000. 0 <= k < 10^6. + */ +import java.util.ArrayDeque; +import java.util.Queue; + +public class SubarrayProductLessThanK { + + public static void main(String[] args) throws Exception { + int[] A = {10, 2, 2, 5, 4, 4, 4, 3, 7, 7}; + System.out.println(new SubarrayProductLessThanK().numSubarrayProductLessThanK(A, 289)); + } + + public int numSubarrayProductLessThanK(int[] nums, int k) { + long prod = 1; + int count = 0; + Queue queue = new ArrayDeque<>(); + for (int i = 0; i < nums.length; i++) { + if (nums[i] < k) { + count++; + if ((prod * nums[i]) < k) { + prod *= nums[i]; + if (!queue.isEmpty()) { + count += (i - queue.peek()); + } + } else { + while (!queue.isEmpty()) { + int last = queue.poll(); + prod /= nums[last]; + if ((prod * nums[i]) < k) { + prod = prod * nums[i]; + if (!queue.isEmpty()) { + count += (i - queue.peek()); + } + break; + } + } + } + if (queue.isEmpty()) { + prod = nums[i]; + } + queue.offer(i); + } else { + queue.clear(); + } + } + return count; + } +} diff --git a/src/main/java/two_pointers/SubarraysWithKDifferentIntegers.java b/src/main/java/two_pointers/SubarraysWithKDifferentIntegers.java new file mode 100644 index 00000000..9728d4fd --- /dev/null +++ b/src/main/java/two_pointers/SubarraysWithKDifferentIntegers.java @@ -0,0 +1,56 @@ +/* (C) 2024 YourCompanyName */ +package two_pointers; +/** + * Created by gouthamvidyapradhan on 25/07/2019 Given an array A of positive integers, call a + * (contiguous, not necessarily distinct) subarray of A good if the number of different integers in + * that subarray is exactly K. + * + *

(For example, [1,2,3,1,2] has 3 different integers: 1, 2, and 3.) + * + *

Return the number of good subarrays of A. + * + *

Example 1: + * + *

Input: A = [1,2,1,2,3], K = 2 Output: 7 Explanation: Subarrays formed with exactly 2 different + * integers: [1,2], [2,1], [1,2], [2,3], [1,2,1], [2,1,2], [1,2,1,2]. Example 2: + * + *

Input: A = [1,2,1,3,4], K = 3 Output: 3 Explanation: Subarrays formed with exactly 3 different + * integers: [1,2,1,3], [2,1,3], [1,3,4]. + * + *

Note: + * + *

1 <= A.length <= 20000 1 <= A[i] <= A.length 1 <= K <= A.length Solution: O(N) General idea is + * to find subarraysWithKDistinct(A, atMost(K)) - subarraysWithKDistinct(A, atMost(K - 1)). + */ +public class SubarraysWithKDifferentIntegers { + public static void main(String[] args) { + int[] A = {1, 2, 1, 2, 3}; + SubarraysWithKDifferentIntegers task = new SubarraysWithKDifferentIntegers(); + System.out.println(task.subarraysWithKDistinct(A, 2)); + } + + public int subarraysWithKDistinct(int[] A, int K) { + return calculate(A, K) - calculate(A, K - 1); + } + + private int calculate(int[] A, int K) { + int count = 0; + int[] frequency = new int[A.length + 1]; + int currCount = 0; + for (int i = 0, j = 0; i < A.length; i++) { + frequency[A[i]]++; + if (frequency[A[i]] == 1) { + currCount++; + } + while (currCount > K) { + frequency[A[j]]--; + if (frequency[A[j]] == 0) { + currCount--; + } + j++; + } + count += (i - j + 1); + } + return count; + } +} diff --git a/src/main/java/two_pointers/ThreeSum.java b/src/main/java/two_pointers/ThreeSum.java new file mode 100644 index 00000000..5f928fd9 --- /dev/null +++ b/src/main/java/two_pointers/ThreeSum.java @@ -0,0 +1,58 @@ +/* (C) 2024 YourCompanyName */ +package two_pointers; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by gouthamvidyapradhan on 29/03/2017. Given an array S of n integers, are there elements + * a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum + * of zero. + * + *

Note: The solution set must not contain duplicate triplets. + * + *

For example, given array S = [-1, 0, 1, 2, -1, -4], + * + *

A solution set is: [ [-1, 0, 1], [-1, -1, 2] ] + */ +public class ThreeSum { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] nums = { + -1, 0, 1, 2, -1, -4, -1, 0, 1, 2, -1, -4, -1, 0, 1, 2, -1, -4, -1, 0, 1, 2, -1, -4, -1, 0, 1, + 2, -1, -4, -1, 0, 1, 2, -1, -4, -1, 0, 1, 2, -1, -4, -1, 0, 1, 2, -1, -4 + }; + System.out.println(new ThreeSum().threeSum(nums)); + } + + public List> threeSum(int[] nums) { + List> result = new ArrayList<>(); + if (nums.length < 3) return result; + Arrays.sort(nums); + for (int i = 0, l = nums.length; i < l - 2; i++) { + if (i == 0 || nums[i] != nums[i - 1]) { + int j = i + 1, k = l - 1; + while (k > j) { + if (j != i + 1 && nums[j] == nums[j - 1]) { + j++; + continue; + } + int sum = nums[i] + nums[j] + nums[k]; + if (sum == 0) { + result.add(Arrays.asList(nums[i], nums[j], nums[k])); + k--; + j++; + } else if (sum > 0) k--; + else j++; + } + } + } + return result; + } +} diff --git a/src/main/java/two_pointers/ThreeSumClosest.java b/src/main/java/two_pointers/ThreeSumClosest.java new file mode 100644 index 00000000..98f9118c --- /dev/null +++ b/src/main/java/two_pointers/ThreeSumClosest.java @@ -0,0 +1,56 @@ +/* (C) 2024 YourCompanyName */ +package two_pointers; + +import java.util.Arrays; + +/** + * Created by gouthamvidyapradhan on 13/06/2017. Accepted Given an array S of n integers, find three + * integers in S such that the sum is closest to a given number, target. Return the sum of the three + * integers. You may assume that each input would have exactly one solution. + * + *

For example, given array S = {-1 2 1 -4}, and target = 1. + * + *

The sum that is closest to the target is 2. (-1 + 2 + 1 = 2). + */ +public class ThreeSumClosest { + + public static void main(String[] args) { + int[] a = {-1, 2, 1, -4}; + System.out.println(new ThreeSumClosest().threeSumClosest(a, 1)); + } + + public int threeSumClosest(int[] a, int target) { + Arrays.sort(a); + int min = Integer.MAX_VALUE, ans = -1; + for (int i = 0, l = a.length; i < l - 2; i++) { + if (i == 0 || !(a[i] == a[i - 1])) { + int j = i + 1, k = l - 1; + while (k > j) { + if (j != i + 1 && (a[j] == a[j - 1])) { + j++; + continue; + } + int sum = a[i] + a[j] + a[k]; + if (sum < target) { + int diff = Math.abs(sum - target); + if (diff < min) { + min = diff; + ans = sum; + } + j++; + } else if (sum > target) { + int diff = Math.abs(sum - target); + if (diff < min) { + min = diff; + ans = sum; + } + k--; + } else { + return sum; + } + } + } + } + return ans; + } +} diff --git a/src/main/java/two_pointers/TrappingRainWater.java b/src/main/java/two_pointers/TrappingRainWater.java new file mode 100644 index 00000000..a2462374 --- /dev/null +++ b/src/main/java/two_pointers/TrappingRainWater.java @@ -0,0 +1,51 @@ +/* (C) 2024 YourCompanyName */ +package two_pointers; + +/** + * Created by gouthamvidyapradhan on 08/03/2017. Given n non-negative integers representing an + * elevation map where the width of each bar is 1, compute how much water it is able to trap after + * raining. + * + *

For example, Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6. + */ +public class TrappingRainWater { + /** + * Main method + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + int[] height = {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}; + System.out.println(new TrappingRainWater().trap(height)); + } + + private int trap(int[] height) { + if (height.length == 0) return 0; + + int[] left = new int[height.length]; + int[] right = new int[height.length]; + int max = 0; + left[0] = 0; + right[height.length - 1] = 0; + + int total = 0; + + for (int i = 1, l = height.length; i < l; i++) { + left[i] = Math.max(max, height[i - 1]); + max = left[i]; + } + max = 0; + for (int i = height.length - 2; i >= 0; i--) { + right[i] = Math.max(max, height[i + 1]); + max = right[i]; + } + for (int i = 0, l = height.length; i < l; i++) { + int min = Math.min(left[i], right[i]); + if (min > height[i]) { + total += (min - height[i]); + } + } + return total; + } +}