├── README.md ├── Tree ├── Binary Tree │ ├── Node.java │ └── BinarySearchTreeDemo.java ├── N-ary Tree │ └── Node.java └── Trie.java ├── Arrays ├── Iterations │ └── TwoDimensionalArrayIteration.java ├── Kth Element In The Array │ ├── KthLargestElementInTheArrayUsingSort.java │ ├── KthSmallestInTheArray.java │ ├── KthLargestElementInTheArray.java │ ├── KthLargestElementInTheArrayUsingQuickSelect │ └── KthSmallestElementInSortedMatrixUsingMaxHeap.java ├── RemoveDuplicatesInSortedArray.java ├── MostCommonWord │ ├── MostCommonWordUsingStreams.java │ └── MostCommonWordUsingHashSetAndHashMap.java └── MedianOfTwoSortedArrays.java ├── Traversals ├── Notes.md ├── BinaryTreeLevelOrderTraversal.java ├── InorderPreorderPostorderRecursive.java └── InorderPreorderPostorderIterative.java ├── LinkedList └── ReversedLinkedList.java ├── TwoSum ├── TwoSumBruteForce.java ├── ThreeSumSolutionNoSort.java ├── Two Sum2WithSortedInputArray.java ├── TwoSumUsingHashMapSinglePass.java └── TwoSumMethodsPerformanceChecks.java ├── Sorting and Searching ├── KthLargestElementInAnArrayAdvanced.java ├── KthLargestElementInAnArraySimple.java └── ReorderLogFilesUsingComparator.java ├── SlidingWindow ├── FindTheLengthOfLongestSubstring.java └── FindTheLengthOfLongestSubstringUsingWhileLoop.java ├── Palindrome ├── BasicPalindrome.java ├── LongestPalindromicSubstringUsingSlidingWindow.java ├── LongestPalindromicSubstringViaBruteForce.java ├── ValidPalindromWithTestCases.java └── MinimumStepsRequiredToConvertBinaryStringToPalindrome.java ├── Data Structure ├── Queue.java └── Stack.java ├── Design └── LRUCacheUsingLinkedHashMap.java └── Anagram ├── GroupedAnagrams.java └── GroupsAnagramsWithNotes.java /README.md: -------------------------------------------------------------------------------- 1 | # algorithms 2 | A collection of my solutions to Leetcode, HackerRank problem sets 3 | 4 | You can find the gists here: 5 | https://gist.github.com/jsbonso 6 | -------------------------------------------------------------------------------- /Tree/Binary Tree/Node.java: -------------------------------------------------------------------------------- 1 | /** 2 | ROOT 3 | / \ 4 | / \ 5 | Left Right 6 | 7 | */ 8 | class Node{ 9 | 10 | String value; 11 | Node leftNode, rightNode; 12 | 13 | Node(String value){ 14 | this.value; 15 | leftNode = null; 16 | rightNode = null; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /Arrays/Iterations/TwoDimensionalArrayIteration.java: -------------------------------------------------------------------------------- 1 | class TwoDimensionalArrayIteration{ 2 | 3 | public void kthSmallest(int[][] matrix) { 4 | 5 | // Iterate the rows 6 | for (int row=0; row < matrix.length; row++){ 7 | // Iterate the columns 8 | for (int col=0; col < matrix[row].length; col++){ 9 | System.out.print(matrix[row][col]+ " "); 10 | } 11 | System.out.println(); 12 | } 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Traversals/Notes.md: -------------------------------------------------------------------------------- 1 | # Traversal Types and Sub-Types 2 | 3 | 1. Breadth-First Search 4 | 2. Depth-First Search 5 | - 2.a. Pre-Order 6 | - 2.b. In-Order 7 | - 2.c. Post-Order 8 | 9 | # Core Concepts 10 | 11 | 1. Breadth-First Search 12 | - 13 | 14 | 15 | 3. Depth-First Search 16 | - 2.a. Pre-Order 17 | - 2.b. In-Order 18 | - 2.c. Post-Order 19 | 20 | # Visualization Tools: 21 | 22 | - All Algorithms: https://www.cs.usfca.edu/~galles/visualization/Algorithms.html 23 | 24 | - Depth-First Search: https://www.cs.usfca.edu/~galles/visualization/DFS.html 25 | - Breadth-First Search: https://www.cs.usfca.edu/~galles/visualization/DFS.html 26 | 27 | 28 | #Problem Sets: 29 | 30 | -------------------------------------------------------------------------------- /Tree/N-ary Tree/Node.java: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | An N-Aary tree is composed of nodes where each node can have one or more children nodes (represented by "N") 4 | 5 | R O O T 6 | / | \ 7 | / | \ 8 | child1 child2 child3 9 | 10 | This class has generics which can transform into the data type you specific 11 | */ 12 | 13 | import java.util.*; 14 | 15 | public class Node{ 16 | 17 | String value; 18 | Node[] children; 19 | 20 | Node (String value){ 21 | this.value = data; 22 | this.children = null; 23 | } 24 | 25 | Node (String value, Node[] children){ 26 | this.value = data; 27 | this.children = children; 28 | } 29 | 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Tree/Binary Tree/BinarySearchTreeDemo.java: -------------------------------------------------------------------------------- 1 | class Node{ 2 | 3 | String value; 4 | Node left, right; 5 | 6 | Node(String value){ 7 | this.value = value; 8 | left = right = null; 9 | } 10 | 11 | Node(String value, Node left, Node right){ 12 | this.value = value; 13 | this.left = left; 14 | this.right = right; 15 | } 16 | 17 | 18 | } 19 | public class BinarySearchTreeDemo 20 | { 21 | public static void main(String[] args) { 22 | System.out.println("Welcome to Online IDE!! Happy Coding :)"); 23 | 24 | Node root = new Node("3"); 25 | root.left = new Node("4"); 26 | root.right = new Node("5"); 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Arrays/Kth Element In The Array/KthLargestElementInTheArrayUsingSort.java: -------------------------------------------------------------------------------- 1 | import java.util.Random; 2 | 3 | /** 4 | 5 | Given an integer array nums and an integer k, return the kth largest element in the array. 6 | 7 | Note that it is the kth largest element in the sorted order, not the kth distinct element. 8 | 9 | You must solve it in O(n) time complexity. 10 | 11 | 12 | 13 | Example 1: 14 | 15 | Input: nums = [3,2,1,5,6,4], k = 2 16 | Output: 5 17 | Example 2: 18 | 19 | Input: nums = [3,2,3,1,2,4,5,5,6], k = 4 20 | Output: 4 21 | 22 | 23 | Constraints: 24 | 25 | 1 <= k <= nums.length <= 105 26 | -104 <= nums[i] <= 104 27 | 28 | 29 | */ 30 | 31 | class KthLargestElementInTheArrayUsingSort { 32 | 33 | public int findKthLargest(int[] nums, int k) { 34 | Arrays.sort(nums); 35 | return (nums[nums.length-k]); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LinkedList/ReversedLinkedList.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * public class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode() {} 7 | * ListNode(int val) { this.val = val; } 8 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 9 | * } 10 | */ 11 | class ReversedLinkedList { 12 | public ListNode reverseList(ListNode head) { 13 | 14 | ListNode previous = null; 15 | ListNode current = head; 16 | 17 | while (current != null){ 18 | 19 | // Get the original next value. 20 | ListNode next = current.next; 21 | 22 | // Switch the next value to the previous value 23 | current.next = previous; 24 | 25 | // Switch the previous value to the current value 26 | previous = current; 27 | 28 | // Update the value of current to the original next value. 29 | current = next; 30 | } 31 | 32 | return previous; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Traversals/BinaryTreeLevelOrderTraversal.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | 3 | /** 4 | 5 | Example 1: 6 | 7 | 8 | Input: root = [3,9,20,null,null,15,7] 9 | Output: [[3],[9,20],[15,7]] 10 | Example 2: 11 | 12 | Input: root = [1] 13 | Output: [[1]] 14 | Example 3: 15 | 16 | Input: root = [] 17 | Output: [] 18 | 19 | 20 | */ 21 | public List> levelOrder(TreeNode root) { 22 | List> ans = new LinkedList<>(); 23 | if(root == null){ 24 | return ans; 25 | } 26 | Queue q = new LinkedList<>(); 27 | q.add(root); 28 | while(!q.isEmpty()){ 29 | int size = q.size(); 30 | List level = new LinkedList<>(); 31 | for(int i = 0; i < size; i++){ 32 | TreeNode node = q.poll(); 33 | if(node.left != null){ 34 | q.add(node.left); 35 | } 36 | if(node.right != null){ 37 | q.add(node.right); 38 | } 39 | level.add(node.val); 40 | } 41 | ans.add(level); 42 | } 43 | return ans; 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /TwoSum/TwoSumBruteForce.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | 4 | Two Sum Solution #1 - Brute Force Approach 5 | 6 | Approach 7 | - Brute force approach by using a nested loop 8 | - Create the two loops to process the array, wherein the second loop is one step ahead of the previous loop and traversing the array elements in a quadratic manner 9 | - The first loop uses the variable i to hold the first index while the second loop uses the variable j to hold the latter one. 10 | - Compare the values of the i and j indices. If they are the same, return the indices as output 11 | - Return an empty integer array if no match was found 12 | 13 | Complexity 14 | - Time complexity: O(n^2) 15 | - Space complexity: O(1) 16 | 17 | */ 18 | 19 | class TwoSumBruteForce { 20 | 21 | public int[] twoSum(int[] nums, int target) { 22 | 23 | for (int i=0; i < nums.length ;i++){ 24 | 25 | for (int j=i+1; j < nums.length ;j++){ 26 | if ((nums[i] + nums[j]) == target){ 27 | return new int[]{i,j}; 28 | } 29 | } 30 | } 31 | 32 | // returns an empty array if no match found 33 | return new int[]{}; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Arrays/Kth Element In The Array/KthSmallestInTheArray.java: -------------------------------------------------------------------------------- 1 | import java.util.Random; 2 | 3 | class Solution { 4 | 5 | public int KthSmallestInTheArray.java(int[] nums, int k) { 6 | 7 | // The PriorityQueue implements a MAX heap structure, in which the "root" 8 | // or the first element in the array is always the maximum/highest value 9 | // of the entire heap 10 | 11 | PriorityQueue heap = 12 | // To get the Kth SMALLEST Element in an Array 13 | new PriorityQueue(Comparator.reverseOrder()); 14 | 15 | // keep k largest elements in the heap 16 | for (int n: nums) { 17 | 18 | System.out.println("Current head: " + heap.peek()); 19 | System.out.println("Adding: " + n); 20 | heap.add(n); 21 | 22 | System.out.println("New head: " + heap.peek()); 23 | if (heap.size() > k){ 24 | System.out.println("Poll the queue (remove): " + heap.peek()); 25 | 26 | // To get the Kth SMALLEST Element in an Array 27 | heap.remove(); 28 | } 29 | 30 | System.out.println("Current Size: " + heap.size()); 31 | System.out.println(Arrays.toString(heap.toArray())); 32 | System.out.println("Final head: " + heap.peek()); 33 | System.out.println(); 34 | 35 | } 36 | 37 | return heap.peek(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Arrays/Kth Element In The Array/KthLargestElementInTheArray.java: -------------------------------------------------------------------------------- 1 | import java.util.Random; 2 | 3 | class KthLargestElementInTheArray { 4 | 5 | public int findKthLargest(int[] nums, int k) { 6 | 7 | // The PriorityQueue implements a min heap structure, in which the "root" 8 | // or the first element in the array is always the minimum/smallest value 9 | // of the entire heap 10 | 11 | PriorityQueue heap = 12 | // To get the Kth LARGEST Element in an Array 13 | new PriorityQueue(); 14 | 15 | // To get the Kth SMALLEST Element in an Array 16 | // new PriorityQueue(Comparator.reverseOrder()); 17 | 18 | // keep k largest elements in the heap 19 | for (int n: nums) { 20 | 21 | System.out.println("Current head: " + heap.peek()); 22 | System.out.println("Adding: " + n); 23 | heap.add(n); 24 | 25 | System.out.println("New head: " + heap.peek()); 26 | if (heap.size() > k){ 27 | System.out.println("Poll the queue (remove): " + heap.peek()); 28 | 29 | // To get the Kth LARGEST Element in an Array 30 | heap.poll(); 31 | // To get the Kth SMALLEST Element in an Array 32 | // heap.remove(); 33 | } 34 | 35 | System.out.println("Current Size: " + heap.size()); 36 | System.out.println(Arrays.toString(heap.toArray())); 37 | System.out.println("Final head: " + heap.peek()); 38 | System.out.println(); 39 | 40 | } 41 | 42 | return heap.peek(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Arrays/RemoveDuplicatesInSortedArray.java: -------------------------------------------------------------------------------- 1 | class RemoveDuplicatesInSortedArray { 2 | 3 | /* 4 | Input: sorted array 5 | Outputs: 1. The K length of the unique numbers 6 | 2. Modified the array where the first part is the list of unique characters 7 | 8 | 9 | Example #1: 10 | Input: nums = [1,1,2] 11 | Output: 12 | 2, 13 | nums = [1,2,_] 14 | 15 | Example #2: 16 | Input: nums = [0,0,1,1,1,2,2,3,3,4] 17 | Output: 18 | 2, 19 | nums = [0,1,2,3,4,_,_,_,_,_] 20 | 21 | 22 | Constraints: 23 | - Sorted Array 24 | - The length of the input array should still be the same. 25 | - No extra data structure 26 | 27 | Strategy: Use sliding window 28 | 29 | Approach: 30 | 31 | - The left pointer will add the unique characters 32 | - The right pointer will traverse and compare the characters 33 | 34 | if the current and next items are equal with each other. 35 | 36 | 37 | */ 38 | public int removeDuplicates(int[] nums) { 39 | int left = 0; 40 | int right = 1; 41 | 42 | System.out.println("original: " + Arrays.toString(nums)); 43 | while ( right < nums.length){ 44 | 45 | if (nums[left] == nums[right]){ 46 | right++; 47 | } else { 48 | left++; 49 | nums[left]=nums[right]; 50 | } 51 | 52 | 53 | } 54 | 55 | System.out.println("modified: " + Arrays.toString(nums)); 56 | // Return the length of the unique character set 57 | return left+1; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Arrays/MostCommonWord/MostCommonWordUsingStreams.java: -------------------------------------------------------------------------------- 1 | class MostCommonWordUsingStreams { 2 | 3 | /** 4 | Returns the most unbanned common word from the paragraph 5 | 6 | Input: paragraph = "Bob hit a ball, the hit BALL flew far after it was hit.", banned = ["hit"] 7 | Output: "ball" 8 | 9 | APPROACH: 10 | 11 | - Convert the paragraph into a String array, delimited by a space (" ") 12 | - Create a sorted treemap with the key as the word and the number of occurence as the value 13 | - Iterate the words in the String array 14 | - If the word is part of the unbanned word, skip it. 15 | - Add the word in the map and increment the count whenever it occured again 16 | - 17 | 18 | CONSTRAINTS: 19 | 20 | 1 <= paragraph.length <= 1000 21 | paragraph consists of English letters, space ' ', or one of the symbols: "!?',;.". 22 | 0 <= banned.length <= 100 23 | 1 <= banned[i].length <= 10 24 | banned[i] consists of only lowercase English letters. 25 | 26 | */ 27 | public String mostCommonWord(String paragraph, String[] banned) { 28 | 29 | Set bannedSet = Arrays.stream(banned) 30 | .collect(Collectors.toSet()); 31 | 32 | Map count = new HashMap<>(); 33 | 34 | Arrays.stream(paragraph.replaceAll("[^a-zA-Z0-9]+"," ").split("\\s+")) 35 | .map(String::toLowerCase) 36 | // .peek(System.out::println) 37 | .filter(word -> !bannedSet.contains(word)) 38 | .forEach(word -> count.put(word, count.getOrDefault(word,0)+1) ); 39 | 40 | return count.entrySet() 41 | .stream() 42 | .max(Comparator.comparing(Map.Entry::getValue)) 43 | .map(Map.Entry::getKey) 44 | .orElse(""); 45 | 46 | 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /Sorting and Searching/KthLargestElementInAnArrayAdvanced.java: -------------------------------------------------------------------------------- 1 | import java.util.Random; 2 | class KthLargestElementInAnArrayAdvanced { 3 | int [] nums; 4 | 5 | public void swap(int a, int b) { 6 | int tmp = this.nums[a]; 7 | this.nums[a] = this.nums[b]; 8 | this.nums[b] = tmp; 9 | } 10 | 11 | 12 | public int partition(int left, int right, int pivot_index) { 13 | int pivot = this.nums[pivot_index]; 14 | // 1. move pivot to end 15 | swap(pivot_index, right); 16 | int store_index = left; 17 | 18 | // 2. move all smaller elements to the left 19 | for (int i = left; i <= right; i++) { 20 | if (this.nums[i] < pivot) { 21 | swap(store_index, i); 22 | store_index++; 23 | } 24 | } 25 | 26 | // 3. move pivot to its final place 27 | swap(store_index, right); 28 | 29 | return store_index; 30 | } 31 | 32 | public int quickselect(int left, int right, int k_smallest) { 33 | /* 34 | Returns the k-th smallest element of list within left..right. 35 | */ 36 | 37 | if (left == right) // If the list contains only one element, 38 | return this.nums[left]; // return that element 39 | 40 | // select a random pivot_index 41 | Random random_num = new Random(); 42 | int pivot_index = left + random_num.nextInt(right - left); 43 | 44 | pivot_index = partition(left, right, pivot_index); 45 | 46 | // the pivot is on (N - k)th smallest position 47 | if (k_smallest == pivot_index) 48 | return this.nums[k_smallest]; 49 | // go left side 50 | else if (k_smallest < pivot_index) 51 | return quickselect(left, pivot_index - 1, k_smallest); 52 | // go right side 53 | return quickselect(pivot_index + 1, right, k_smallest); 54 | } 55 | 56 | public int findKthLargest(int[] nums, int k) { 57 | this.nums = nums; 58 | int size = nums.length; 59 | // kth largest is (N - k)th smallest 60 | return quickselect(0, size - 1, size - k); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /SlidingWindow/FindTheLengthOfLongestSubstring.java: -------------------------------------------------------------------------------- 1 | class FindTheLengthOfLongestSubstring { 2 | public int lengthOfLongestSubstring(String s) { 3 | 4 | /** 5 | Examples: 6 | 7 | #1 - 8 | eabcdabcbb = 4 9 | "abcd" is the longest substring 10 | 4 is the length of "abcd" 11 | 12 | #2 - 13 | bbbbb = 1 14 | "b" is the longest substring 15 | 1 is the length of the substring "b" (which is just one character) 16 | 17 | #3 - 18 | pwwkew = 3 19 | "pww" is the longest substring 20 | 3 is the length of "pww" 21 | 22 | */ 23 | 24 | Map map = new HashMap(); 25 | int result = 0; 26 | 27 | /** 28 | * This For loop with two pointers (left, right) is an implementation of 29 | * the Sliding Window Technique 30 | */ 31 | 32 | for (int left=0, right=0; right < s.length(); right++ ){ 33 | 34 | // check map if it already contains the character 35 | if (map.containsKey(s.charAt(right))){ 36 | int indexOfExistingChar = map.get(s.charAt(right)); 37 | // Update the value of the left pointer 38 | // to the index of the matched character, 39 | // or to its current value, whichever is greater. 40 | left = Math.max(indexOfExistingChar, left); 41 | } 42 | 43 | // Update the result value by getting the difference 44 | // of the right and left pointer plus 1 (as per the requirement) 45 | // or to its current value, whichever is greater 46 | result = Math.max(right - left + 1, result); 47 | 48 | // Put the Character as the key and the index as the value 49 | map.put(s.charAt(right), right+1); 50 | 51 | } 52 | 53 | 54 | return result; 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Palindrome/BasicPalindrome.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | public class BasicPalindrome 4 | { 5 | public static void main(String[] args) { 6 | 7 | String input = "ababa"; 8 | String input1 = "mom"; 9 | String input2 = "nono"; 10 | String input3 = "A man, a plan, a canal: Panama!"; 11 | String input4 = "Dammit I'm mad."; 12 | String input5 = "Philippines"; 13 | 14 | System.out.println("Is the input: `" + input + "` a palindrome? " + isPalindrome(input)); 15 | System.out.println("Is the input: `" + input1 + "` a palindrome? " + isPalindrome(input1)); 16 | System.out.println("Is the input: `" + input2 + "` a palindrome? " + isPalindrome(input2)); 17 | System.out.println("Is the input: `" + input3 + "` a palindrome? " + isPalindrome(input3)); 18 | System.out.println("Is the input: `" + input4 + "` a palindrome? " + isPalindrome(input4)); 19 | System.out.println("Is the input: `" + input5 + "` a palindrome? " + isPalindrome(input5)); 20 | } 21 | 22 | /** 23 | * Checks if a given string is a palindrome. 24 | * 25 | * Essentially, a palindrome is simply a string that is the same when reversed. 26 | * 27 | * e.g: 28 | * ababa = ababa 29 | * mom = mom 30 | * noon = noon 31 | * 32 | * Approach: 33 | * - Reverse the string and check if it still the same. 34 | */ 35 | public static boolean isPalindrome(String input){ 36 | 37 | // System.out.println("raw input: " + input); 38 | input = input.replaceAll("[^a-zA-Z]", ""); 39 | input = input.toLowerCase(); 40 | // System.out.println("trimmed input: " + input); 41 | 42 | char[] ch = input.toCharArray(); 43 | int right = 0; 44 | right = ch.length - 1; 45 | 46 | for (int i=0;i < ch.length/2 ;i++){ 47 | if (ch[i] != ch[right--]){ 48 | return false; 49 | } 50 | } 51 | 52 | return true; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /SlidingWindow/FindTheLengthOfLongestSubstringUsingWhileLoop.java: -------------------------------------------------------------------------------- 1 | class FindTheLengthOfLongestSubstringUsingWhileLoop { 2 | public int lengthOfLongestSubstring(String s) { 3 | 4 | /** 5 | Examples: 6 | 7 | #1 - 8 | eabcdabcbb = 4 9 | "abcd" is the longest substring 10 | 4 is the length of "abcd" 11 | 12 | #2 - 13 | bbbbb = 1 14 | "b" is the longest substring 15 | 1 is the length of the substring "b" (which is just one character) 16 | 17 | #3 - 18 | pwwkew = 3 19 | "pww" is the longest substring 20 | 3 is the length of "pww" 21 | 22 | */ 23 | 24 | Map map = new HashMap(); 25 | int result = 0; 26 | 27 | /** 28 | Sliding Window technique with an (O)n time complexity performance 29 | that uses a while loop 30 | */ 31 | int left=0; 32 | int right=0; 33 | while (right < s.length()){ 34 | // check map if it already contains the character 35 | if (map.containsKey(s.charAt(right))){ 36 | int indexOfExistingChar = map.get(s.charAt(right)); 37 | // Update the value of the left pointer 38 | // to the index of the matched character, 39 | // or to its current value, whichever is greater. 40 | left = Math.max(indexOfExistingChar, left); 41 | } 42 | 43 | // Update the result value by getting the difference 44 | // of the right and left pointer plus 1 (as per the requirement) 45 | // or to its current value, whichever is greater 46 | result = Math.max(right - left + 1, result); 47 | 48 | // Put the Character as the key and the index as the value 49 | map.put(s.charAt(right), right+1); 50 | right++; 51 | 52 | } 53 | 54 | return result; 55 | 56 | } 57 | 58 | 59 | 60 | } 61 | -------------------------------------------------------------------------------- /Data Structure/Queue.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Queue Example. 4 | 5 | INSIGHT: 6 | - A queue follows the concept of FIFO (First In, First Out) 7 | - The core operations of a queue are: 8 | 1. Enqueue 9 | 2. Dequeue 10 | 11 | - This means that the first element that goes to the queue is also the first one to go out 12 | - In Java, the Queue interface has the following operations: 13 | 1. add() - add an element to the queue 14 | 2. remove() - returns and removes the element from the queue based on its insertion order (FIFO) 15 | 2. peek() - only returns the current front element from the queue based on its insertion order (FIFO) 16 | 3. isEmpty() - checks if the queue is empty 17 | 18 | CONSTRAINTS: 19 | - ArrayDeque does NOT support NULL values 20 | */ 21 | 22 | import java.util.*; 23 | 24 | public class Queue{ 25 | public static void main(String[] args) { 26 | 27 | Queue queue = new LinkedList<>(); 28 | 29 | // Check the initial content of the queue 30 | System.out.println("Queue: " + queue); 31 | 32 | // Push one element to the queue 33 | queue.add(8); 34 | System.out.println("Queue: " + queue); 35 | 36 | // Push another element to the queue 37 | queue.add(2); 38 | System.out.println("Queue: " + queue); 39 | 40 | // Push multiple elements to the queue 41 | queue.add(4); 42 | queue.add(9); 43 | queue.add(7); 44 | System.out.println("Queue: " + queue); 45 | 46 | // Remove the front element to the queue 47 | // so since the first one we added was 8, this number will be deleted first. 48 | queue.remove(); 49 | System.out.println("Queue: " + queue); 50 | 51 | // Let's iterate through the queue and remove the value 52 | // as long as it is NOT empty. 53 | 54 | while (!queue.isEmpty()){ 55 | queue.remove(); 56 | System.out.println("Is the queue empty? " + queue.isEmpty()); 57 | } 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Arrays/MedianOfTwoSortedArrays.java: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Median of Two Sorted Arrays 4 | 5 | Given two sorted arrays nums1 and nums2 of size m and n respectively, 6 | return the median of the two sorted arrays. 7 | 8 | The overall run time complexity should be O(log (m+n)). 9 | 10 | 11 | Examples: 12 | 13 | Input: nums1 = [1,3], nums2 = [2] 14 | Output: 2.00000 15 | Explanation: merged array = [1,2,3] and median is 2. 16 | 17 | Input: nums1 = [1,2], nums2 = [3,4] 18 | Output: 2.50000 19 | Explanation: merged array = [1,2,3,4] and median is (2 + 3) / 2 = 2.5. 20 | 21 | 22 | Approach 23 | 24 | */ 25 | 26 | class MedianOfTwoSortedArrays { 27 | 28 | public double findMedianSortedArrays(int[] nums1, int[] nums2) { 29 | int median = nums1.length; 30 | int nums2Length = nums2.length; 31 | int left = (median + nums2Length + 1) / 2; 32 | int right = (median + nums2Length + 2) / 2; 33 | 34 | // recursively fetch the media values 35 | return (double)(getkth(nums1, 0, nums2, 0, left) + 36 | getkth(nums1, 0, nums2, 0, right)) / 2; 37 | } 38 | 39 | // Recursive function to traverse the arrays 40 | public double getkth(int[] A, int aStart, int[] B, int bStart, int k) { 41 | 42 | if (aStart > A.length - 1){ 43 | return B[bStart + k - 1]; 44 | } 45 | 46 | if (bStart > B.length - 1) { 47 | return A[aStart + k - 1]; 48 | } 49 | if (k == 1) { 50 | return Math.min(A[aStart], B[bStart]); 51 | } 52 | 53 | int aMid = Integer.MAX_VALUE; 54 | int bMid = Integer.MAX_VALUE; 55 | if (aStart + k/2 - 1 < A.length){ 56 | aMid = A[aStart + k/2 - 1]; 57 | } 58 | 59 | if (bStart + k/2 - 1 < B.length){ 60 | bMid = B[bStart + k/2 - 1]; 61 | } 62 | 63 | if (aMid < bMid){ 64 | // Check: aRight + bLeft 65 | return getkth(A, aStart + k/2, B, bStart, k - k/2); 66 | } else { 67 | // Check: bRight 68 | return getkth(A, aStart, B, bStart + k/2, k - k/2); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Arrays/MostCommonWord/MostCommonWordUsingHashSetAndHashMap.java: -------------------------------------------------------------------------------- 1 | class MostCommonWordUsingHashSetAndHashMap { 2 | 3 | /** 4 | Returns the most unbanned common word from the paragraph 5 | 6 | Input: paragraph = "Bob hit a ball, the hit BALL flew far after it was hit.", banned = ["hit"] 7 | Output: "ball" 8 | 9 | APPROACH: 10 | 11 | - Convert the paragraph into a String array, delimited by a space (" ") 12 | - Create a sorted treemap with the key as the word and the number of occurence as the value 13 | - Iterate the words in the String array 14 | - If the word is part of the unbanned word, skip it. 15 | - Add the word in the map and increment the count whenever it occured again 16 | - 17 | 18 | CONSTRAINTS: 19 | 20 | 1 <= paragraph.length <= 1000 21 | paragraph consists of English letters, space ' ', or one of the symbols: "!?',;.". 22 | 0 <= banned.length <= 100 23 | 1 <= banned[i].length <= 10 24 | banned[i] consists of only lowercase English letters. 25 | 26 | */ 27 | public String mostCommonWord(String paragraph, String[] banned) { 28 | 29 | // Remove the special characters from the paragraph 30 | String normalizedStr = paragraph.replaceAll("[^a-zA-Z0-9 ]", " ").toLowerCase(); 31 | String[] words = normalizedStr.split("\\s+"); 32 | 33 | // Populate the banned words 34 | Set bannedWords = new HashSet<>(); 35 | for (String bannedWord: banned){ 36 | bannedWords.add(bannedWord); 37 | } 38 | 39 | Map wordCount = new HashMap<>(); 40 | 41 | for (String word: words){ 42 | // Skip banned words and populate valid words 43 | if (!bannedWords.contains(word)){ 44 | 45 | // Increment the count 46 | wordCount.put(word, wordCount.getOrDefault(word, 0) + 1); 47 | } 48 | } 49 | 50 | // Return the word with the highest number occurence 51 | return Collections.max( wordCount.entrySet(), Map.Entry.comparingByValue() ).getKey(); 52 | 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Data Structure/Stack.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Stack Example. 4 | 5 | INSIGHT: 6 | - A stack follows the concept of LIFO (Last In, First Out) 7 | - The core operations of a stack are: 8 | 1. push 9 | 2. pop 10 | 11 | - This means that the last element that goes to the stack is also the first one to go out 12 | - In Java, the Stack interface has the following operations: 13 | 1. push() - add an element to the stack 14 | 2. pop() - returns and removes the element from the stack based on its insertion order (LIFO) 15 | 3. peek() - only returns the current top element from the stack based on its insertion order (LIFO) 16 | 4. empty() - checks if the stack is empty 17 | 5. search(o) - searches the object (o) from the stack 18 | 19 | CONSTRAINTS: 20 | - ArrayDeque does NOT support NULL values 21 | */ 22 | 23 | import java.util.*; 24 | 25 | public class Stack{ 26 | public static void main(String[] args) { 27 | 28 | Stack stack = new Stack<>(); 29 | 30 | // Check the initial content of the queue 31 | System.out.println("Stack: " + stack); 32 | 33 | // Push one element to the stack 34 | stack.push(8); 35 | System.out.println("Stack: " + stack); 36 | 37 | // Push another element to the stack 38 | stack.push(2); 39 | System.out.println("Stack: " + stack); 40 | 41 | // Push multiple elements to the stack 42 | stack.push(4); 43 | stack.push(9); 44 | stack.push(7); // last element to be added 45 | System.out.println("Stack: " + stack); 46 | 47 | // Remove the top element to the stack 48 | // so since the last one we added was 7, this number will be deleted first as per the LIFO concept. 49 | stack.pop(); 50 | System.out.println("Stack: " + stack); 51 | 52 | // Let's iterate through the stack and remove the value 53 | // as long as it is NOT empty. 54 | 55 | while (!stack.empty()){ 56 | stack.pop(); 57 | System.out.println("Is the queue stack? " + stack.empty()); 58 | } 59 | 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Palindrome/LongestPalindromicSubstringUsingSlidingWindow.java: -------------------------------------------------------------------------------- 1 | class LongestPalindromicSubstringUsingSlidingWindow { 2 | /* 3 | Longest Palindromic Substring 4 | 5 | Given a string s, return the longest palindromic substring in s. 6 | 7 | A string is called a palindrome string if the reverse of that 8 | string is the same as the original string. 9 | 10 | Example 1: 11 | 12 | Input: s = "babad" 13 | Output: "bab" 14 | Explanation: "aba" is also a valid answer. 15 | 16 | Example 2: 17 | 18 | Input: s = "cbbd" 19 | Output: "bb" 20 | 21 | 22 | Constraints: 23 | 24 | 1 <= s.length <= 1000 25 | s consist of only digits and English letters. 26 | 27 | 28 | Insights: 29 | - Traverse every element, and do an expanding sliding window from that element as the center 30 | 31 | Visualization: 32 | 33 | Input: babad 34 | 35 | 1: a b a d 36 | 1.1 -- expandingWindow won't run 37 | 38 | 2: b b a d 39 | 2.1 b b 40 | 2.2 Found a palindrome. Note the start and index. 41 | 42 | 3: b a a d 43 | 2.1 a a 44 | 2.2 b _ _ d 45 | 2.2 No palindrome. 46 | 47 | */ 48 | public String longestPalindrome(String s) { 49 | 50 | if (s == null || s.length() < 1) return ""; 51 | int start = 0, end = 0; 52 | for (int i = 0; i < s.length(); i++) { 53 | int len1 = expandAroundCenter(s, i, i); 54 | int len2 = expandAroundCenter(s, i, i + 1); 55 | int len = Math.max(len1, len2); 56 | 57 | if (len > end - start) { 58 | start = i - (len - 1) / 2; 59 | end = i + len / 2; 60 | } 61 | } 62 | return s.substring(start, end + 1); 63 | } 64 | 65 | private int expandAroundCenter(String s, int left, int right) { 66 | int L = left; 67 | int R = right; 68 | while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) { 69 | L--; 70 | R++; 71 | } 72 | return R - L - 1; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /TwoSum/ThreeSumSolutionNoSort.java: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0. 4 | 5 | Notice that the solution set must not contain duplicate triplets. 6 | 7 | 8 | 9 | Example 1: 10 | 11 | Input: nums = [-1,0,1,2,-1,-4] 12 | Output: [[-1,-1,2],[-1,0,1]] 13 | Explanation: 14 | nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0. 15 | nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0. 16 | nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0. 17 | The distinct triplets are [-1,0,1] and [-1,-1,2]. 18 | Notice that the order of the output and the order of the triplets does not matter. 19 | Example 2: 20 | 21 | Input: nums = [0,1,1] 22 | Output: [] 23 | Explanation: The only possible triplet does not sum up to 0. 24 | Example 3: 25 | 26 | Input: nums = [0,0,0] 27 | Output: [[0,0,0]] 28 | Explanation: The only possible triplet sums up to 0. 29 | 30 | 31 | Constraints: 32 | 33 | 3 <= nums.length <= 3000 34 | -105 <= nums[i] <= 105 35 | 36 | */ 37 | 38 | class ThreeSumSolutionNoSort { 39 | 40 | /** 41 | 42 | - Input: unsorted 43 | - Create a list of list of Integers 44 | - Iterate the array 45 | - 46 | 47 | */ 48 | public List> threeSum(int[] nums) { 49 | 50 | Set> res = new HashSet<>(); 51 | Set dups = new HashSet<>(); 52 | Map seen = new HashMap<>(); 53 | 54 | for (int i = 0; i < nums.length; ++i) 55 | // The "add" function return true if the element doesn't exist yet 56 | if (dups.add(nums[i])) { 57 | // the nums[i] element is a brand new one 58 | // Iterate through the array 59 | for (int j = i + 1; j < nums.length; ++j) { 60 | int complement = -nums[i] - nums[j]; 61 | if (seen.containsKey(complement) && seen.get(complement) == i) { 62 | List triplet = Arrays.asList(nums[i], nums[j], complement); 63 | Collections.sort(triplet); 64 | res.add(triplet); 65 | } 66 | seen.put(nums[j], i); 67 | } 68 | } 69 | return new ArrayList(res); 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Palindrome/LongestPalindromicSubstringViaBruteForce.java: -------------------------------------------------------------------------------- 1 | class LongestPalindromicSubstringViaBruteForce { 2 | /* 3 | Longest Palindromic Substring 4 | 5 | Given a string s, return the longest palindromic substring in s. 6 | 7 | A string is called a palindrome string if the reverse of that 8 | string is the same as the original string. 9 | 10 | Example 1: 11 | 12 | Input: s = "babad" 13 | Output: "bab" 14 | Explanation: "aba" is also a valid answer. 15 | 16 | Example 2: 17 | 18 | Input: s = "cbbd" 19 | Output: "bb" 20 | 21 | 22 | Constraints: 23 | 24 | 1 <= s.length <= 1000 25 | s consist of only digits and English letters. 26 | 27 | 28 | Insights: 29 | - Traverse 30 | 31 | 1 - b 32 | a b a d 33 | 2 - a 34 | b a d 35 | 3 - b 36 | a d 37 | 38 | */ 39 | public String longestPalindrome(String s) { 40 | 41 | char[] stringArray = s.toCharArray(); 42 | boolean hasPalindrome = false; 43 | 44 | // a map sorted in a decreasing order based on the key (palindrome's character length) 45 | // We used "Collections.reverseOrder()" to make the order descending 46 | TreeMap map = new TreeMap<>(Collections.reverseOrder()); 47 | 48 | for (int i=0; i < stringArray.length; i++){ 49 | String str = stringArray[i]+""; 50 | for (int j=i+1; j < stringArray.length; j++){ 51 | str += stringArray[j]; 52 | 53 | // do palindrome check 54 | if (palindrome(str)){ 55 | hasPalindrome = true; 56 | map.put((Integer)str.length(), str); 57 | } 58 | 59 | } 60 | 61 | } 62 | 63 | return map.isEmpty() ? stringArray[0]+"" : map.firstEntry().getValue(); 64 | } 65 | 66 | boolean palindrome (String input){ 67 | int left = 0; 68 | int right = input.length()-1; 69 | char[] c = input.toCharArray(); 70 | 71 | while (right >= input.length()/2){ 72 | if (c[left] != c[right]){ 73 | return false; 74 | } 75 | left++; 76 | right--; 77 | } 78 | return true; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Design/LRUCacheUsingLinkedHashMap.java: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Design a data structure that follows the constraints of a Least Recently Used (LRU) cache. 4 | 5 | Implement the LRUCache class: 6 | 7 | LRUCache(int capacity) Initialize the LRU cache with positive size capacity. 8 | int get(int key) Return the value of the key if the key exists, otherwise return -1. 9 | void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. 10 | 11 | If the number of keys exceeds the capacity from this operation, evict the least recently used key. 12 | The functions get and put must each run in O(1) average time complexity. 13 | 14 | 15 | 16 | Example 1: 17 | 18 | Input 19 | ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"] 20 | [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]] 21 | Output 22 | [null, null, null, 1, null, -1, null, -1, 3, 4] 23 | 24 | Explanation 25 | LRUCache lRUCache = new LRUCache(2); 26 | lRUCache.put(1, 1); // cache is {1=1} 27 | lRUCache.put(2, 2); // cache is {1=1, 2=2} 28 | lRUCache.get(1); // return 1 29 | lRUCache.put(3, 3); // LRU key was 2, evicts key 2, cache is {1=1, 3=3} 30 | lRUCache.get(2); // returns -1 (not found) 31 | lRUCache.put(4, 4); // LRU key was 1, evicts key 1, cache is {4=4, 3=3} 32 | lRUCache.get(1); // return -1 (not found) 33 | lRUCache.get(3); // return 3 34 | lRUCache.get(4); // return 4 35 | 36 | 37 | Constraints: 38 | 39 | 1 <= capacity <= 3000 40 | 0 <= key <= 104 41 | 0 <= value <= 105 42 | At most 2 * 105 calls will be made to get and put. 43 | */ 44 | 45 | 46 | class LRUCacheUsingLinkedHashMap extends LinkedHashMap { 47 | 48 | private int capacity; 49 | 50 | 51 | 52 | /** 53 | * Your LRUCache object will be instantiated and called as such: 54 | * LRUCache obj = new LRUCache(capacity); 55 | * int param_1 = obj.get(key); 56 | * obj.put(key,value); 57 | */ 58 | 59 | public LRUCache(int capacity) { 60 | super(capacity, 0.75F, true); 61 | this.capacity = capacity; 62 | } 63 | 64 | public int get(int key) { 65 | return super.getOrDefault(key, -1); 66 | } 67 | 68 | public void put(int key, int value) { 69 | super.put(key, value); 70 | } 71 | 72 | @Override 73 | protected boolean removeEldestEntry(Map.Entry eldest) { 74 | return size() > capacity; 75 | } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /Tree/Trie.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Trie implementation 3 | * 4 | * Basics: 5 | * - "Trie" is pronounced as "Try" 6 | * - The name "Trie" is based from the word "ReTRIEval" 7 | * - Also known as Prefix Tree 8 | * 9 | * Trie Properties 10 | * - The root node of the trie always represents the null node. 11 | * - Each child of nodes is alphabetically sorted 12 | * - Each node in the Trie tree can have a maximum of 26 children (A to Z). 13 | * - Each node, except for the root node, can store one letter of the alphabet. 14 | * 15 | * Use Cases: 16 | * - Spell Checker 17 | * - Auto-complete 18 | * - browser history 19 | * 20 | * 21 | */ 22 | 23 | 24 | import java.util.ArrayList; 25 | import java.util.Collections; 26 | import java.util.List; 27 | 28 | class Trie 29 | { 30 | // 26 characters for `a – z` 31 | private static final int CHAR_SIZE = 26; 32 | 33 | private boolean isChild; 34 | private List children = null; 35 | 36 | // Constructor 37 | Trie(){ 38 | isChild = false; 39 | children = new ArrayList<>(Collections.nCopies(CHAR_SIZE, null)); 40 | } 41 | 42 | /** 43 | * Insert 44 | * 45 | */ 46 | public void insert(String key){ 47 | 48 | Trie curr = this; 49 | for (char c: key.toCharArray()){ 50 | if (curr.children.get(c - 'a') == null) { 51 | curr.children.set(c - 'a', new Trie()); 52 | } 53 | curr = curr.children.get(c - 'a'); 54 | } 55 | curr.isChild = true; 56 | } 57 | 58 | /** 59 | * Search 60 | */ 61 | public boolean search(String key){ 62 | 63 | Trie current = this; 64 | 65 | for (char c: key.toCharArray()){ 66 | current = current.children.get(c - 'a'); 67 | if (current == null) { 68 | return false; 69 | } 70 | } 71 | return current.isChild; 72 | } 73 | } 74 | 75 | class Main 76 | { 77 | public static void main (String[] args) 78 | { 79 | // construct a new Trie node 80 | Trie trie = new Trie(); 81 | 82 | trie.insert("tutorials"); 83 | trie.insert("tutorial"); 84 | trie.insert("tutor"); 85 | 86 | System.out.println(trie.search("tuto")); // true 87 | System.out.println(trie.search("tutorial")); // true 88 | System.out.println(trie.search("tutorials")); // true 89 | System.out.println(trie.search("tutorialsdojo")); // false 90 | 91 | trie.insert("tutorialsdojo"); 92 | 93 | System.out.println(trie.search("tuto")); // true 94 | System.out.println(trie.search("tutorial")); // true 95 | System.out.println(trie.search("tutorials")); // true 96 | System.out.println(trie.search("tutorialsdojo")); // true 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Arrays/Kth Element In The Array/KthLargestElementInTheArrayUsingQuickSelect: -------------------------------------------------------------------------------- 1 | import java.util.Random; 2 | 3 | /** 4 | 5 | Given an integer array nums and an integer k, return the kth largest element in the array. 6 | 7 | Note that it is the kth largest element in the sorted order, not the kth distinct element. 8 | 9 | You must solve it in O(n) time complexity. 10 | 11 | 12 | 13 | Example 1: 14 | 15 | Input: nums = [3,2,1,5,6,4], k = 2 16 | Output: 5 17 | Example 2: 18 | 19 | Input: nums = [3,2,3,1,2,4,5,5,6], k = 4 20 | Output: 4 21 | 22 | 23 | Constraints: 24 | 25 | 1 <= k <= nums.length <= 105 26 | -104 <= nums[i] <= 104 27 | 28 | 29 | */ 30 | 31 | import java.util.Random; 32 | class KthLargestElementInTheArrayUsingQuickSelect { 33 | int [] nums; 34 | 35 | public void swap(int a, int b) { 36 | int tmp = this.nums[a]; 37 | this.nums[a] = this.nums[b]; 38 | this.nums[b] = tmp; 39 | } 40 | 41 | 42 | public int partition(int left, int right, int pivot_index) { 43 | int pivot = this.nums[pivot_index]; 44 | // 1. move pivot to end 45 | swap(pivot_index, right); 46 | int store_index = left; 47 | 48 | // 2. move all smaller elements to the left 49 | for (int i = left; i <= right; i++) { 50 | if (this.nums[i] < pivot) { 51 | swap(store_index, i); 52 | store_index++; 53 | } 54 | } 55 | 56 | // 3. move pivot to its final place 57 | swap(store_index, right); 58 | 59 | return store_index; 60 | } 61 | 62 | public int quickselect(int left, int right, int k_smallest) { 63 | /* 64 | Returns the k-th smallest element of list within left..right. 65 | */ 66 | 67 | if (left == right) // If the list contains only one element, 68 | return this.nums[left]; // return that element 69 | 70 | // select a random pivot_index 71 | Random random_num = new Random(); 72 | int pivot_index = left + random_num.nextInt(right - left); 73 | 74 | pivot_index = partition(left, right, pivot_index); 75 | 76 | // the pivot is on (N - k)th smallest position 77 | if (k_smallest == pivot_index) 78 | return this.nums[k_smallest]; 79 | // go left side 80 | else if (k_smallest < pivot_index) 81 | return quickselect(left, pivot_index - 1, k_smallest); 82 | // go right side 83 | return quickselect(pivot_index + 1, right, k_smallest); 84 | } 85 | 86 | public int findKthLargest(int[] nums, int k) { 87 | this.nums = nums; 88 | int size = nums.length; 89 | // kth largest is (N - k)th smallest 90 | return quickselect(0, size - 1, size - k); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /TwoSum/Two Sum2WithSortedInputArray.java: -------------------------------------------------------------------------------- 1 | /** 2 | Two Sum II - Input Array Is Sorted 3 | 4 | Given a 1-indexed array of integers numbers that is already sorted in non-decreasing order, find two numbers such that they add up to a specific target number. Let these two numbers be numbers[index1] and numbers[index2] where 1 <= index1 < index2 <= numbers.length. 5 | 6 | Return the indices of the two numbers, index1 and index2, added by one as an integer array [index1, index2] of length 2. 7 | 8 | The tests are generated such that there is exactly one solution. You may not use the same element twice. 9 | 10 | Your solution must use only constant extra space. 11 | 12 | 13 | 14 | Example 1: 15 | 16 | Input: numbers = [2,7,11,15], target = 9 17 | Output: [1,2] 18 | Explanation: The sum of 2 and 7 is 9. Therefore, index1 = 1, index2 = 2. We return [1, 2]. 19 | Example 2: 20 | 21 | Input: numbers = [2,3,4], target = 6 22 | Output: [1,3] 23 | Explanation: The sum of 2 and 4 is 6. Therefore index1 = 1, index2 = 3. We return [1, 3]. 24 | Example 3: 25 | 26 | Input: numbers = [-1,0], target = -1 27 | Output: [1,2] 28 | Explanation: The sum of -1 and 0 is -1. Therefore index1 = 1, index2 = 2. We return [1, 2]. 29 | 30 | 31 | Constraints: 32 | 33 | 2 <= numbers.length <= 3 * 104 34 | -1000 <= numbers[i] <= 1000 35 | numbers is sorted in non-decreasing order. 36 | -1000 <= target <= 1000 37 | The tests are generated such that there is exactly one solution. 38 | 39 | 40 | 41 | 42 | */ 43 | 44 | class Solution { 45 | 46 | public int[] twoSum(int[] nums, int target) { 47 | 48 | int left = 0; 49 | int midValue = nums[nums.length/2]; 50 | 51 | /** 52 | - if the target is less than the mid value and the input array length is 53 | greater than 2 (since the minimum size to have a mid element is 3), then set the 54 | value of the right variable to the index of the middle. 55 | - Else, use the right-most index for the right pointer. 56 | - This will possibly halve the running time if the 57 | 58 | */ 59 | int right = (target < midValue && nums.length > 2) ? nums.length/2 : nums.length - 1; 60 | 61 | 62 | // Move the left and right pointer closer to the middle of the array 63 | // unitl their values are equals to the target 64 | while (nums[left] + nums[right] != target) { 65 | //System.out.println(nums[left] + " " + nums[right] ); 66 | if (nums[left] + nums[right] < target) left++; 67 | else right--; 68 | } 69 | 70 | // Adding 1 to left and right variables since the requirement asks 71 | // for the ordinal position (index+1) and not actual index 72 | return new int[] {left+1, right+1}; 73 | 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Arrays/Kth Element In The Array/KthSmallestElementInSortedMatrixUsingMaxHeap.java: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Given an n x n matrix where each of the rows and columns is sorted in ascending order, return the kth smallest element in the matrix. 4 | 5 | Note that it is the kth smallest element in the sorted order, not the kth distinct element. 6 | 7 | You must find a solution with a memory complexity better than O(n2). 8 | 9 | 10 | 11 | Example 1: 12 | 13 | Input: matrix = [[1,5,9],[10,11,13],[12,13,15]], k = 8 14 | Output: 13 15 | Explanation: The elements in the matrix are [1,5,9,10,11,12,13,13,15], and the 8th smallest number is 13 16 | Example 2: 17 | 18 | Input: matrix = [[-5]], k = 1 19 | Output: -5 20 | 21 | 22 | Constraints: 23 | 24 | n == matrix.length == matrix[i].length 25 | 1 <= n <= 300 26 | -109 <= matrix[i][j] <= 109 27 | All the rows and columns of matrix are guaranteed to be sorted in non-decreasing order. 28 | 1 <= k <= n2 29 | 30 | 31 | Follow up: 32 | 33 | Could you solve the problem with a constant memory (i.e., O(1) memory complexity)? 34 | Could you solve the problem in O(n) time complexity? The solution may be too advanced for an interview but you may find reading this paper fun: http://www.cse.yorku.ca/~andy/pubs/X+Y.pdf 35 | 36 | */ 37 | 38 | class KthSmallestElementInSortedMatrixUsingMaxHeap { 39 | 40 | /** 41 | * Returns the ordinal "Kth" smallest element in a given two-dimentional array (2D Array) 42 | 43 | Approach: 44 | - Iterate over all the elements of the 2D array 45 | - Use a min heap with the size of the target, which is represented by the variable "k" 46 | 47 | 48 | 49 | */ 50 | public int kthSmallest(int[][] matrix, int k) { 51 | 52 | // Create a Max Heap where the root always contains the largest number 53 | // The Max Heap data structure is represented in an array where the index (0) contains the largest number. 54 | PriorityQueue maxHeap = new PriorityQueue<>(Comparator.reverseOrder()); 55 | 56 | for (int row=0; row < matrix.length; row++){ 57 | for (int col=0; col < matrix[row].length; col++){ 58 | maxHeap.add(matrix[row][col]); 59 | 60 | if (maxHeap.size() > k){ 61 | // delete the first element which contains the LARGEST element, 62 | // which leave us with the 2nd or 3rd or 4th or the Kth Largest element 63 | maxHeap.poll(); 64 | 65 | } 66 | // System.out.print(matrix[row][col]+ " "); 67 | } 68 | System.out.println(maxHeap); 69 | System.out.println(); 70 | } 71 | 72 | // Get the head (also known as root, or the first element) from the max heap 73 | 74 | return maxHeap.peek(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Anagram/GroupedAnagrams.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | GroupedAnagrams 4 | 5 | Given an array of strings strs, group the anagrams together. You can return the answer in any order. 6 | 7 | An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, 8 | typically using all the original letters exactly once. 9 | 10 | 11 | 12 | Example 1: 13 | 14 | Input: strs = ["eat","tea","tan","ate","nat","bat"] 15 | Output: [["bat"],["nat","tan"],["ate","eat","tea"]] 16 | 17 | Example 2: 18 | 19 | Input: strs = [""] 20 | Output: [[""]] 21 | 22 | Example 3: 23 | 24 | Input: strs = ["a"] 25 | Output: [["a"]] 26 | 27 | 28 | Constraints: 29 | 30 | 1 <= strs.length <= 104 31 | 0 <= strs[i].length <= 100 32 | strs[i] consists of lowercase English letters. 33 | 34 | */ 35 | 36 | import java.util.Map; 37 | 38 | import java.util.HashMap; 39 | import java.util.List; 40 | import java.util.ArrayList; 41 | import java.util.Arrays; 42 | 43 | public class GroupedAnagrams 44 | { 45 | public static void main(String[] args) { 46 | System.out.println("Welcome to Online IDE!! Happy Coding :)"); 47 | //List> test1 = groupAnagrams(new String[]{"eat","tea","tan","ate","nat","bat"}); 48 | 49 | List> test1 = groupAnagrams(new String[]{"eat","tea","tan","ate","nat","bat"}); 50 | System.out.println(test1 + "\tNumber of Groups: " + test1.size()); // has 2 groups of anagrams out of 3 groups. 51 | 52 | List> test2 = groupAnagrams(new String[]{"jon","bonso"}); 53 | System.out.println(test2 + "\tNumber of Groups: " + test2.size()); 54 | 55 | List> test3 = groupAnagrams(new String[]{"kaliwa","wakali"}); 56 | System.out.println(test3 + "\tNumber of Groups: " + test3.size()); 57 | 58 | 59 | List> test4 = groupAnagrams(new String[]{"sakalam","malakas", "petmalu","malupet", "noypi", "pinoy", "manila" }); 60 | System.out.println(test4 + "\tNumber of Groups: " + test4.size()); 61 | 62 | 63 | } 64 | 65 | public static List> groupAnagrams(String[] input){ 66 | 67 | List> result = new ArrayList<>(); 68 | Map> map = new HashMap<>(); 69 | 70 | for (String current : input){ 71 | 72 | // sort the letters of the word in alphabetical order 73 | char[] currentCharArray = current.toCharArray(); 74 | Arrays.sort(currentCharArray); 75 | String sortedString = new String(currentCharArray); 76 | 77 | // Populate the key 78 | if (!map.containsKey(sortedString)){ 79 | map.put(sortedString, new ArrayList<>()); 80 | } 81 | 82 | map.get(sortedString).add(current); 83 | 84 | } 85 | 86 | result.addAll(map.values()); 87 | 88 | return result; 89 | 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Traversals/InorderPreorderPostorderRecursive.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Depth-First Search (DFS) Inorder, Preorder and Postorder demo using an Iterative method 4 | */ 5 | 6 | import java.util.*; 7 | 8 | class Node{ 9 | int value; 10 | Node left, right; 11 | 12 | Node(int value){ 13 | this.value = value; 14 | this.left = this.right = null; 15 | } 16 | 17 | Node(int value, Node left, Node right){ 18 | this.value = value; 19 | this.left = left; 20 | this.right = right; 21 | } 22 | 23 | } 24 | 25 | class BinarySearchTree{ 26 | 27 | Node root; 28 | 29 | BinarySearchTree(){ 30 | this.root = null; 31 | } 32 | 33 | 34 | BinarySearchTree(int value){ 35 | this.root = new Node(value); 36 | } 37 | 38 | 39 | void insertNode(int value){ 40 | this.root = insert(root, value); 41 | } 42 | 43 | Node insert(Node root, int value){ 44 | 45 | if (root == null) return new Node(value); 46 | else if (value < root.value) root.left = insert(root.left, value); 47 | else if (value > root.value) root.right = insert(root.right, value); 48 | 49 | return root; 50 | } 51 | void inorder(){ 52 | inorder(this.root); 53 | } 54 | 55 | void inorder(Node root) { 56 | if (root == null) return; 57 | inorder(root.left); 58 | System.out.print(root.value + " "); 59 | inorder(root.right); 60 | 61 | 62 | } 63 | 64 | void preorder() { 65 | preorder(root); 66 | } 67 | /** 68 | * 69 | */ 70 | void preorder(Node node) { 71 | 72 | if (root == null) return; 73 | 74 | System.out.print(root.value + " "); 75 | inorder(root.left); 76 | inorder(root.right); 77 | 78 | 79 | } 80 | 81 | void postorder() { 82 | postorder(root); 83 | } 84 | /** 85 | * 86 | */ 87 | void postorder(Node node) { 88 | if (root == null) return; 89 | inorder(root.left); 90 | inorder(root.right); 91 | System.out.print(root.value + " "); 92 | } 93 | 94 | } 95 | 96 | 97 | public class InorderPreorderPostorderRecursive 98 | { 99 | public static void main(String[] args) { 100 | 101 | 102 | BinarySearchTree bst = new BinarySearchTree(); 103 | a 104 | /* Create the following tree structure 105 | Order of Insertion: 5 , 3 , 7 , 1, 4, 6, 9 106 | 107 | 5 108 | / \ 109 | 3 7 110 | / \ / \ 111 | 1 4 6 9 112 | */ 113 | bst.insertNode(5); 114 | bst.insertNode(3); 115 | bst.insertNode(7); 116 | bst.insertNode(1); 117 | bst.insertNode(4); 118 | bst.insertNode(6); 119 | bst.insertNode(9); 120 | 121 | System.out.println("In order..."); 122 | bst.inorder(); 123 | 124 | System.out.println("\nPre order..."); 125 | bst.preorder(); 126 | 127 | System.out.println("\nPost order..."); 128 | bst.postorder(); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /Anagram/GroupsAnagramsWithNotes.java: -------------------------------------------------------------------------------- 1 | import java.util.Map; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | 8 | class GroupsAnagramsWithNotes { 9 | 10 | /** 11 | 12 | Returns a list of a list of Anagram Strings 13 | https://github.com/jsbonso/algorithms 14 | Input: ["eat","tea","tan","ate","nat","bat"] 15 | Output: [ ["bat"], 16 | ["nat","tan"], 17 | ["ate","eat","tea"]] 18 | 19 | INSIGHTS: 20 | - An anagram is just another word that has exactly the same characters 21 | of the original word but in different arrangement 22 | 23 | Example: 24 | eat = tea 25 | star = rats 26 | 27 | - If your rearranged the characters of the two anagram words in alphabetical order, 28 | the output should be exactly the same. 29 | 30 | Example: 31 | 32 | "eat" and "tea" are anagrams: 33 | 34 | "eat" is "aet" in alphabetical order 35 | "tea" is "aet" in alphabetical order 36 | 37 | "aet" = "aet" are the same, thus, the words "eat" and "tea" are indeed anagrams 38 | 39 | 40 | 41 | APPROACH: 42 | - Convert the string into a character array 43 | - Sort the character array into alphabetical order 44 | - Use 45 | 46 | CONSTRAINTS: 47 | - All letters are in lowercase 48 | - The words don't have whitespaces 49 | 50 | TIME/SPACE COMPLEXITY: 51 | - TIME: O(n k log k) 52 | - Summation of O(n) for the iteration and O(k log k) for the sorting 53 | – since we only iterate through the string array once O(n) 54 | - Sorting the characters of a string is (k log k) since Arrays.sort is using a custom 55 | timsort algorithm which is a combination of mergesort and insertion sort 56 | 57 | - SPACE: O(nk) 58 | 59 | WHERE: 60 | n is the number of elements 61 | k is the maximum length of string 62 | 63 | 64 | */ 65 | public List> groupAnagrams(String[] strs) { 66 | 67 | List> result = new ArrayList<>(); 68 | 69 | // A hashmap containing a list of strings 70 | // where the key is the sorted characters of the input 71 | // and the value is the list of String anagram words 72 | Map> map = new HashMap<>(); 73 | 74 | // iterate the input 75 | for (String current : strs){ 76 | 77 | // Rearrange the characters of the current word in alphabetical order 78 | char[] currentCharArray = current.toCharArray(); 79 | Arrays.sort(currentCharArray); 80 | String sortedString = String.valueOf(currentCharArray); 81 | 82 | // Populate the key with an empty String Array if not existing yet 83 | if(!map.containsKey(sortedString)){ 84 | map.put(sortedString, new ArrayList<>()); 85 | } 86 | 87 | // Add the current word (which is not rearranged/sorted) 88 | // in the map 89 | map.get(sortedString).add(current); 90 | 91 | } 92 | 93 | result.addAll(map.values()); 94 | 95 | 96 | 97 | return result; 98 | 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Sorting and Searching/KthLargestElementInAnArraySimple.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | An overly simply solution for the Kth Largest Element in Array Problem 4 | using Arrays.sort 5 | */ 6 | 7 | import java.util.Arrays; 8 | public class Main 9 | { 10 | public static void main(String[] args) { 11 | System.out.println("Welcome to Online IDE!! Happy Coding :)"); 12 | 13 | /** 14 | * TEST SET 1 15 | * 16 | * {3, 2, 1, 5, 6, 4} 17 | * 18 | * 1st Largest = 6 19 | * 2nd Largest = 5 20 | * 3rd Largest = 4 21 | * 22 | */ 23 | 24 | int[] inputSet1 = new int[]{3, 2, 1, 5, 6, 4}; 25 | int KthLargestElementTest1 = 1; // Get the 1st Largest Element of the array 26 | System.out.println(KthLargestElementInAnArraySimpleSort(inputSet1, KthLargestElementTest1)); 27 | 28 | int KthLargestElementTest2 = 2; // Get the 2nd Largest Element of the array 29 | System.out.println(KthLargestElementInAnArraySimpleSort(inputSet1, KthLargestElementTest2)); 30 | 31 | int KthLargestElementTest3 = 3; // Get the 3rd Largest Element of the array 32 | System.out.println(KthLargestElementInAnArraySimpleSort(inputSet1, KthLargestElementTest3)); 33 | 34 | /** 35 | * TEST SET 2 36 | * {60, 20, 10, 80, 100, 50, 40, 90} 37 | * 38 | * 1st Largest = 100 39 | * 2nd Largest = 90 40 | * 3rd Largest = 80 41 | * 4th Largest = 60 42 | */ 43 | 44 | int[] inputSet2 = new int[]{60, 20, 10, 80, 100, 50, 40, 90}; 45 | 46 | int KthLargestElementTest4 = 2; // Get the 2nd Largest Element of the array 47 | System.out.println(KthLargestElementInAnArraySimpleSort(inputSet2, KthLargestElementTest4)); 48 | 49 | int KthLargestElementTest5 = 3; // Get the 3rd Largest Element of the array 50 | System.out.println(KthLargestElementInAnArraySimpleSort(inputSet2, KthLargestElementTest5)); 51 | 52 | int KthLargestElementTest6 = 4; // Get the 4th Largest Element of the array 53 | System.out.println(KthLargestElementInAnArraySimpleSort(inputSet2, KthLargestElementTest6)); 54 | 55 | } 56 | 57 | /** 58 | Returns the Kth Largest Element of a given array, where "K" is the ordinal position 59 | (e.g. 2 = 2nd largest element 60 | 3 = 3rd largest element 61 | 62 | Examples: 63 | 64 | INPUT: {3, 2, 1, 5, 6, 4} KthLargestElement = 2 65 | OUTPUT: 6 66 | 67 | INPUT: {3, 2, 1, 5, 6, 4} KthLargestElement = 3 68 | OUTPUT: 4 69 | 70 | INPUT: {3, 2, 1, 5, 6, 4} KthLargestElement = 1 71 | OUTPUT: 6 72 | 73 | INSIGHT: 74 | - Sort the input array from smallest to largest number 75 | - Return the element with "array length - kth" as the index 76 | 77 | CONSTRAINTS: 78 | - The input array is a set of non-repeating integgers 79 | 80 | PERFORMANCE: 81 | Time Complexity : Summation of O(n log n) + O(1) 82 | - Sorting: O(n log n) 83 | - Constant time for direct access to array O(1) via index 84 | 85 | Space Complexity : O (n) 86 | - Arrays.sort is using a custom timsort (mergesort + insertion sort combo) with O (n) space complexity 87 | 88 | */ 89 | 90 | static int KthLargestElementInAnArraySimpleSort(int[] input, int KthLargestElement){ 91 | 92 | Arrays.sort(input); 93 | return input[input.length-KthLargestElement]; 94 | 95 | } 96 | } 97 | 98 | -------------------------------------------------------------------------------- /Palindrome/ValidPalindromWithTestCases.java: -------------------------------------------------------------------------------- 1 | 2 | import java.util.*; 3 | import java.lang.Character; 4 | 5 | public class ValidPalindromWithTestCases 6 | { 7 | public static void main(String[] args) { 8 | 9 | String input = "ababa"; 10 | String input1 = "mom"; 11 | String input2 = "nono"; 12 | String input3 = "A man, a plan, a canal: Panama!"; 13 | String input4 = "Dammit I'm mad."; 14 | String input5 = "Philippines"; 15 | 16 | boolean test1 = isPalindrome(input); 17 | System.out.println("Is the input: `" + input + "` a palindrome? " + test1 + " " + ((test1 == true) ? "\n ✅ PASS " : "\n❌FAILED" )); 18 | System.out.println(); 19 | 20 | boolean test2 = isPalindrome(input1); 21 | System.out.println("Is the input: `" + input1 + "` a palindrome? " + test2 + " " + ((test2 == true) ? "\n ✅ PASS " : "\n❌FAILED" )); 22 | System.out.println(); 23 | 24 | boolean test3 = isPalindrome(input2); 25 | System.out.println("Is the input: `" + input2 + "` a palindrome? " + test3 + " " + ((test3 == false) ? "\n ✅ PASS " : "\n❌FAILED" )); 26 | System.out.println(); 27 | 28 | boolean test4 = isPalindrome(input3); 29 | System.out.println("Is the input: `" + input3 + "` a palindrome? " + test4 + " " + ((test4 == true) ? "\n ✅ PASS " : "\n❌FAILED" )); 30 | System.out.println(); 31 | 32 | boolean test5 = isPalindrome(input4); 33 | System.out.println("Is the input: `" + input4 + "` a palindrome? " + test5 + " " + ((test5 == true) ? "\n ✅ PASS " : "\n❌FAILED" )); 34 | System.out.println(); 35 | 36 | boolean test6 = isPalindrome(input5); 37 | System.out.println("Is the input: `" + input5 + "` a palindrome? " + test6 + " " + ((test6 == false) ? "\n ✅ PASS " : "\n❌FAILED" )); 38 | System.out.println(); 39 | 40 | } 41 | 42 | /** 43 | * Checks if a given string is a palindrome. 44 | * 45 | * Essentially, a palindrome is simply a string that is the same when reversed. 46 | * 47 | * e.g: 48 | * ababa = ababa 49 | * mom = mom 50 | * noon = noon 51 | * 52 | * Approach: 53 | * 54 | * - Use two pointers: "left" on the beginning of the array and "right" at the end of the array, 55 | * - Move the "left" and "right" pointers of the array one set inwards the center of the array, comparing their values. 56 | * - The input is not a palindrome if the two pointers are not same. Else, the input is a palindrome 57 | */ 58 | public static boolean isPalindrome(String input){ 59 | 60 | System.out.println("Input: " + input); 61 | System.out.println("Number of characters: " + input.length()); 62 | 63 | // Format the input to only include numbers and letters 64 | String formattedInput = ""; 65 | for (char ch : input.toCharArray()){ 66 | if (Character.isDigit(ch)|| Character.isLetter(ch)){ 67 | formattedInput += ch; 68 | } 69 | } 70 | formattedInput = formattedInput.toLowerCase(); 71 | 72 | // Use two pointers that starts from the outer boundaries of the array and traverse inwards towards the middle. 73 | int left = 0; 74 | int right = formattedInput.length() - 1; 75 | int steps =0; 76 | while (left < (formattedInput.length()/2)){ 77 | 78 | steps++; // Not related to the algorightm. Only used for counting the steps to determine the Time Complexity 79 | 80 | if (formattedInput.charAt(left) != formattedInput.charAt(right) ){ 81 | System.out.println("Number of Steps: " + steps); 82 | return false; 83 | } 84 | left++; 85 | right--; 86 | 87 | 88 | } 89 | 90 | System.out.println("Number of Steps: " + steps); 91 | return true; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Palindrome/MinimumStepsRequiredToConvertBinaryStringToPalindrome.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | You are given a binary string, s, consisting of characters '0' and '1'. 4 | Transform this string into a palindrome by performing some operations. 5 | In one operation, swap any two characters, s[i] and s[j] 6 | 7 | Determine the minimum number of swaps required to make the string a palindrom. 8 | If it is impossible to do so, then return -1. 9 | 10 | Note: 11 | A palindrome is a string that reads the same backward as forward, for example, strings "0", 12 | "111" 010 10101 are palindromes, but strings 001 10 11101 are not. 13 | 14 | 15 | Example: 16 | 17 | Let string s = "0100101". 18 | The following shows the minimum number of steps required. It uses 1-based indexing. 19 | 20 | 1. Swap characters with indices (4,5) 21 | 2. Swap characters with indices (1,2) 22 | 23 | Now, the binary string is now palindromic. 24 | The answer is 2 swaps. 25 | 26 | 27 | 28 | */ 29 | 30 | public class Main 31 | { 32 | public static void main(String[] args) { 33 | System.out.println("Welcome to Online IDE!! Happy Coding :)"); 34 | 35 | System.out.println(minSwapsRequired("0100101") == 2 ? "Test Passed ✅ " : "Test Failed ❌/"); 36 | System.out.println(minSwapsRequired("letelt") == 2 ? "Test Passed ✅ " : "Test Failed ❌/"); 37 | System.out.println(minSwapsRequired("aabb") == 2 ? "Test Passed ✅ " : "Test Failed ❌/"); 38 | System.out.println(minSwapsRequired("10011") == 1 ? "Test Passed ✅ " : "Test Failed ❌/"); 39 | System.out.println(minSwapsRequired("abba") == 0 ? "Test Passed ✅ " : "Test Failed ❌/"); 40 | System.out.println(minSwapsRequired("ababa") == 0 ? "Test Passed ✅ " : "Test Failed ❌/"); 41 | 42 | System.out.println(minSwapsRequired("dammitimmad") == 0 ? "Test Passed ✅ " : "Test Failed ❌/"); 43 | System.out.println(minSwapsRequired("dammmtiimad") == 4 ? "Test Passed ✅ " : "Test Failed ❌/"); 44 | System.out.println(minSwapsRequired("ddmmitimmaa") == 16 ? "Test Passed ✅ " : "Test Failed ❌/"); 45 | 46 | // not palindrome 47 | 48 | System.out.println(minSwapsRequired("ddmmitimmaaxcve") == 5 ? "Test Passed ✅ " : "Test Failed ❌/"); 49 | 50 | 51 | } 52 | 53 | /** 54 | * Returns the minimum number of swaps required to make the given string a Palindrom. 55 | * If the result is... 56 | * 0 - then the given string is already a palindrome 57 | * 1 - it takes one swap to make the string a palindrome 58 | */ 59 | public static int minSwapsRequired(String s){ 60 | int count = 0; 61 | StringBuilder sb = new StringBuilder(s); 62 | 63 | while(sb.length() > 2) { 64 | char left = sb.charAt(0); 65 | int len = sb.length(); 66 | char right = sb.charAt(len - 1); 67 | 68 | if (left == right) { 69 | sb.deleteCharAt(len - 1); 70 | sb.deleteCharAt(0); 71 | // System.out.println("SB match: " + sb); 72 | } else { 73 | int id1 = sb.lastIndexOf(Character.toString(left)); 74 | int id2 = sb.indexOf(Character.toString(right)); 75 | 76 | int steps1 = len - id1 - 1; 77 | int steps2 = id2; 78 | 79 | if (steps1 > steps2) { // keep last char, move char at id2 80 | count += steps2; 81 | sb.deleteCharAt(id2); 82 | sb.deleteCharAt(sb.length() - 1); 83 | 84 | // System.out.println("SB not match IF: " + sb); 85 | 86 | } else {// keep first char, move char at id1 87 | count += steps1; 88 | sb.deleteCharAt(id1); 89 | sb.deleteCharAt(0); 90 | // System.out.println("SB not match Else: " + sb); 91 | } 92 | 93 | 94 | } 95 | } 96 | 97 | //System.out.println("SB : " + sb); 98 | System.out.println("Input: " + s + " Result: " + count); 99 | return count; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /TwoSum/TwoSumUsingHashMapSinglePass.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | Two Sum Solution #2 - Using a HashMap and iterates the array in a single pass approach 4 | 5 | Author: Jon Bonso 6 | 7 | Goal: Get the two indices from the array that sums up to the value of the given target 8 | 9 | MATH THEORY: 10 | 11 | - The sum is composed to two or more "addends" which has the following formula: 12 | sum = number1 + number2 13 | 14 | - In this problem set, the sum is called the "target" so... 15 | target = number1 + number2 16 | 17 | - There are different equations that can be derived from the above formula 18 | (e.g): 19 | target = number1 + number2 20 | number1 = target - number2 21 | number2 = target - number1 22 | 23 | - We will use the (number2 = target - number1) equation since 24 | its standard formula (sum = number1 + number2) is running on a slow quadractic time O(n^2) 25 | 26 | APPROACH 27 | - Instead of just using the "target = number1 + number2" condition, we can utilize one of the addends by using the 28 | "number2 = target - number1" equation instead, to identify the value of the other addend. 29 | - We will store the elements in a hashmap, where the key is the index of the array and the value is the array elements. 30 | - For every element, we will run the "number2 = target - number1" equation, where the number1 is the current Integer 31 | in the loop and the number2 variable is the missing addend that must match, in order to get the correct sum. 32 | 33 | 34 | COMPLEXITY 35 | - Time complexity: Linear time – O(n) where n is the size of the array. 36 | - Space complexity: Linear time – O(n) where n is the size of the array. 37 | 38 | */ 39 | 40 | import java.util.Map; 41 | import java.util.HashMap; 42 | import java.util.Arrays; 43 | 44 | class TwoSumUsingHashMapSinglePass { 45 | 46 | public static void main(String args[]){ 47 | int nums[] = {7,11,15,2,10,12,34,100}; 48 | int target = 9; 49 | System.out.println("Target: " + target); 50 | int indices[] = twoSum(nums,target); 51 | System.out.println("Indices" + Arrays.toString(indices)); 52 | System.out.println("The sum of : " + nums[indices[0]] + " + " + nums[indices[1]] + " is " + target ); 53 | } 54 | 55 | public static int[] twoSum(int[] nums, int target) { 56 | 57 | Map map = new HashMap(); 58 | 59 | for (int i=0; i < nums.length ;i++){ 60 | 61 | /** the "addend" variable signifies the other part of the sum equation 62 | In theory: 63 | target = addend1 + addend2 64 | target = 9 65 | 66 | addend1 = 9 - nums[i] 67 | The added2 is equivalent to the current nums[i] value 68 | 69 | Formula: a = target = nums[i] 70 | 71 | Loop 1: a = 9 - 7 (the addend must be 2) 72 | Loop 2: a = 9 - 11 (the addend must be -2) 73 | Loop 3: a = 9 - 15 (the addend must be -6) 74 | Loop 4: a = 9 - 2 (the addend must be 7, which we actually have on Loop 1) 75 | */ 76 | 77 | 78 | int addend = target - nums[i]; 79 | 80 | // checks if the item is already in the map 81 | /** 82 | * 83 | * Remember that we only need to return the index. 84 | * KEY, VALUE 85 | * 7 0 86 | * 11 1 87 | * 15 2 88 | * 2 3 89 | */ 90 | System.out.println("Looking for " + addend); 91 | 92 | // We are using the "containsKey" method since the key contains the array number. 93 | if (map.containsKey(addend)){ 94 | 95 | // We have found a match! No need to traverse other succeeding elements. 96 | // The added and the current item has a sum that is equivalent to the target 97 | // return the indices from the map and the variable iterator of this for loop ("i") 98 | 99 | return new int[]{ map.get(addend) , i }; 100 | } 101 | System.out.println("Adding to the hashmap: " + nums[i] + " " + i); 102 | map.put(nums[i], i); 103 | 104 | } 105 | 106 | // returns an empty array if no match found 107 | System.out.println("No match found. Returning an empty int array."); 108 | return new int[]{}; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Traversals/InorderPreorderPostorderIterative.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Depth-First Search (DFS) Inorder, Preorder and Postorder demo using an Iterative method 4 | */ 5 | 6 | import java.util.*; 7 | 8 | class Node{ 9 | int value; 10 | Node left, right; 11 | 12 | Node(int value){ 13 | this.value = value; 14 | this.left = this.right = null; 15 | } 16 | 17 | Node(int value, Node left, Node right){ 18 | this.value = value; 19 | this.left = left; 20 | this.right = right; 21 | } 22 | 23 | } 24 | 25 | class BinarySearchTree{ 26 | 27 | Node root; 28 | 29 | BinarySearchTree(){ 30 | this.root = null; 31 | } 32 | 33 | 34 | BinarySearchTree(int value){ 35 | this.root = new Node(value); 36 | } 37 | 38 | search(int value){ 39 | 40 | } 41 | 42 | void insertNode(int value){ 43 | this.root = insert(root, value); 44 | } 45 | 46 | Node insert(Node root, int value){ 47 | 48 | if (root == null) return new Node(value); 49 | else if (value < root.value) root.left = insert(root.left, value); 50 | else if (value > root.value) root.right = insert(root.right, value); 51 | 52 | return root; 53 | } 54 | void inorder() { 55 | if (root == null) return; 56 | 57 | 58 | Stack stack = new Stack(); 59 | Node current = root; 60 | 61 | // traverse the tree 62 | while (current != null || stack.size() > 0) 63 | { 64 | 65 | /* Reach the left most Node of the 66 | curr Node */ 67 | while (current != null) 68 | { 69 | /* place pointer to a tree node on 70 | the stack before traversing 71 | the node's left subtree */ 72 | stack.push(current); 73 | current = current.left; 74 | } 75 | 76 | // Current must be NULL at this point 77 | current = stack.pop(); 78 | 79 | System.out.print(current.value + " "); 80 | 81 | /* we have visited the node and its 82 | left subtree. Now, it's right 83 | subtree's turn */ 84 | current = current.right; 85 | } 86 | } 87 | 88 | void preorder() { 89 | preorder(root); 90 | } 91 | /** 92 | * 93 | */ 94 | void preorder(Node node) { 95 | 96 | if (node == null) return; 97 | 98 | // Create an empty stack and push root to it 99 | Stack stack = new Stack(); 100 | stack.push(root); 101 | 102 | /* Pop all items one by one. Do following for every popped item 103 | a) print it 104 | b) push its right child 105 | c) push its left child 106 | Note that right child is pushed first so that left is processed first */ 107 | while (!stack.empty()) { 108 | 109 | // Pop the top item from stack and print it 110 | Node mynode = stack.peek(); 111 | System.out.print(mynode.value + " "); 112 | stack.pop(); 113 | 114 | // Push right and left children of the popped node to stack 115 | if (mynode.right != null) stack.push(mynode.right); 116 | if (mynode.left != null) stack.push(mynode.left); 117 | 118 | } 119 | } 120 | 121 | void postorder() { 122 | postorder(root); 123 | } 124 | /** 125 | * 126 | */ 127 | void postorder(Node node) { 128 | // create another stack to store postorder traversal 129 | LinkedList result = new LinkedList<>(); 130 | 131 | Stack stack = new Stack<>(); 132 | if (root == null) return; 133 | 134 | stack.push(root); 135 | 136 | while (!stack.isEmpty()) { 137 | Node current = stack.pop(); 138 | result.push(current.value); 139 | if (current.left != null) stack.push(current.left); 140 | if (current.right != null) stack.push(current.right); 141 | 142 | } 143 | 144 | for (Integer p : result){ 145 | 146 | System.out.print(p + " "); 147 | } 148 | } 149 | 150 | 151 | 152 | 153 | 154 | 155 | } 156 | 157 | 158 | public class InorderPreorderPostorderIterative 159 | { 160 | public static void main(String[] args) { 161 | 162 | 163 | BinarySearchTree bst = new BinarySearchTree(); 164 | 165 | /* Create the following tree structure 166 | Order of Insertion: 5 , 3 , 7 , 1, 4, 6, 9 167 | 168 | 5 169 | / \ 170 | 3 7 171 | / \ / \ 172 | 1 4 6 9 173 | */ 174 | bst.insertNode(5); 175 | bst.insertNode(3); 176 | bst.insertNode(7); 177 | bst.insertNode(1); 178 | bst.insertNode(4); 179 | bst.insertNode(6); 180 | bst.insertNode(9); 181 | 182 | System.out.println("In order..."); 183 | bst.inorder(); 184 | 185 | System.out.println("\nPre order..."); 186 | bst.preorder(); 187 | 188 | System.out.println("\nPost order..."); 189 | bst.postorder(); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /TwoSum/TwoSumMethodsPerformanceChecks.java: -------------------------------------------------------------------------------- 1 | /** 2 | This tracks the Elapsed Time for the 2 Solutions for the Classic Two Sum Problem 3 | 4 | You will discover how immensely better an (O)n solution is (twoSumOptimized) 5 | than a brute force (O)n^2 solution (twoSumBruteForce) by checking the start and end 6 | times of both methods 7 | */ 8 | 9 | 10 | import java.util.Map; 11 | import java.util.HashMap; 12 | import java.util.Arrays; 13 | 14 | public class TwoSumMethodsPerformanceChecks 15 | { 16 | public static long optimizedElapsedTime = 0L; 17 | public static long bruteForceElapsedTime = 0L; 18 | 19 | public static void main(String[] args) { 20 | 21 | int arr[] = { 15, 10, 4, 12, 11, 8, 6, 5 }; 22 | int target = 10; 23 | 24 | // Expected Result: [2, 6] 25 | // ( arr[2] = 4 ) + ( arr[4] = 6 ) 26 | 27 | System.out.println("Brute Force Method Result: " + Arrays.toString(twoSumBruteForce(arr, target))); 28 | System.out.println(); 29 | System.out.println("Optimized Method Result: " + Arrays.toString(twoSumOptimized(arr, target))); 30 | System.out.println(); 31 | System.out.println("Brute Force Elapsed Time: " + bruteForceElapsedTime + " milliseconds"); 32 | System.out.println("Optimized Elapsed Time: " + optimizedElapsedTime + " milliseconds"); 33 | System.out.println(); 34 | long perfDiff = (bruteForceElapsedTime / optimizedElapsedTime); 35 | System.out.println("The Optimized Method is " + perfDiff + "% faster than the Brute Force Method"); 36 | 37 | 38 | 39 | 40 | } 41 | 42 | /** 43 | * An optimized method of getting the indices of two numbers 44 | * in an array whose sum is equals to the given target. 45 | * 46 | * Time Complexity: Linear Time (O)n 47 | * Space Complexity: Constant Time (O)1 since no other data structure was used. 48 | * 49 | */ 50 | public static int[] twoSumOptimized(int num[], int target){ 51 | 52 | long startTime = System.currentTimeMillis(); 53 | System.out.println("Optimized Method START: " + System.currentTimeMillis()); 54 | 55 | // Create a Hashmap with the key = number input; value = index 56 | 57 | Map map = new HashMap(); 58 | 59 | // Loop the array and populate the map. 60 | for (int i = 0; i < num.length; i++){ 61 | 62 | /** target = num1 + num2 63 | * num1 = target - num2 64 | * -5 = 10 - 15 65 | * 0 = 10 - 10 66 | * 6 = 10 - 4 67 | */ 68 | 69 | int addend = target - num[i]; 70 | 71 | // Check if the addend is in the map 72 | if (map.containsKey(addend)){ 73 | // we found a match! return the indices 74 | 75 | optimizedElapsedTime = System.currentTimeMillis() - startTime; 76 | 77 | System.out.println("Optimized Method END : " + System.currentTimeMillis()); 78 | return new int[]{map.get(addend),i}; 79 | } 80 | // Add the array number as the key, and the index as the value 81 | map.put(num[i],i); 82 | 83 | } 84 | System.out.println("Optimized Method END : " + System.currentTimeMillis()); 85 | optimizedElapsedTime = System.currentTimeMillis() - startTime; 86 | // return empty array 87 | return new int[]{}; 88 | 89 | } 90 | 91 | /** 92 | * A brute force method to get the indices of two numbers 93 | * in an array whose sum is equals to the given target. 94 | * 95 | * Time Complexity: Quadratic Time (O)n^2 96 | * Space Complexity: Linear Time (O)n since no other data structure was used. 97 | * 98 | */ 99 | public static int[] twoSumBruteForce(int num[], int target){ 100 | 101 | long startTime = System.currentTimeMillis(); 102 | System.out.println("Brute Force START: " + System.currentTimeMillis()); 103 | 104 | 105 | // input: 15, 10, 4, 12, 11, 8, 6, 5 106 | // target: 10 107 | 108 | /** 109 | * 1: outer loop - 15 (compare all 8 numbers below) 110 | * inner loop - 15, 10, 4, 12, 11, 8, 6, 5 111 | * 112 | * 2: outer loop - 10 (compare all 8 numbers below) 113 | * inner loop - 15, 10, 4, 12, 11, 8, 6, 5 114 | * 115 | * 3: outer loop - 4 (compare to all 8 numbers below) 116 | * inner loop - 15, 10, 4, 12, 11, 8, 6, 5 117 | */ 118 | 119 | 120 | for (int i = 0; i n1 n2 n3 n... 40 | 41 | if "n" is letter, then the log is a Letter log. Else, it is a digit log. 42 | 43 | APPROACH 44 | - Create a Comparator and sort the input 45 | - The comparator has the following implementation: 46 | - The two inputs would be split in to two parts: 47 | 1. identifier 48 | 2. content 49 | 50 | Example: 51 | "let2 own kit dig" -> "let2", "own kit dig" 52 | "dig1 8 1 5 1" -> "dig1", "8 1 5 1" 53 | 54 | */ 55 | public String[] reorderLogFiles(String[] logs) { 56 | 57 | /** 58 | * 59 | INSIGHTS: 60 | - letter logs are always LESS than the Digit Logs 61 | - "LESS" in this case, means it should go on the left-hand side of the array, 62 | where the letter logs are meant to be placed. 63 | 64 | 65 | 66 | This Comparator returns: 67 | 0 = if the two inputs are the same 68 | -1 = if the first input is less than the second input 69 | = (goes to the LEFT of the array) 70 | 1 = if the first input is greater than the former 71 | = (goes to the RIGHT of the array) 72 | 73 | If the input is: 74 | (letter-log, digit-log) = -1 75 | (digit-log, letter-log) = 1 76 | 77 | */ 78 | Comparator logComparator = new Comparator() { 79 | @Override 80 | public int compare(String log1, String log2) { 81 | 82 | int firstInputIsSmaller = -1; 83 | int firstInputIsBigger = 1; 84 | int bothInputsAreEqual = 0; 85 | 86 | // split each log into two parts: 87 | String[] logSplit1 = log1.split(" ", 2); 88 | String[] logSplit2 = log2.split(" ", 2); 89 | 90 | String log1identifier = logSplit1[0]; 91 | String log1Content = logSplit1[1]; 92 | 93 | String log2identifier = logSplit2[0]; 94 | String log2Content = logSplit2[1]; 95 | 96 | boolean isLetterLog1 = Character.isLetter(log1Content.charAt(0)); 97 | boolean isLetterLog2 = Character.isLetter(log2Content.charAt(0)); 98 | 99 | // This first if block has two outcomes: 100 | 101 | // - If both inputs are letter-logs, compare the content 102 | // - if the inputs are the same, compare the identifiers 103 | 104 | if (isLetterLog1 && isLetterLog2) { 105 | 106 | System.out.println("Both input are Letter Logs"); 107 | 108 | // Compare the content of the two Input. 109 | 110 | // The compareTo function also returns: 111 | // 0 : if the two inputs are equal (bothInputsAreEqual) 112 | // -1 : if the first input is smaller 113 | // 1 : if the first input is bigger 114 | 115 | int compareContentResult = log1Content.compareTo(log2Content); 116 | 117 | // if the logs have the same content, compare the identifiers 118 | if (compareContentResult == bothInputsAreEqual){ 119 | return log1identifier.compareTo(log2identifier); 120 | } 121 | 122 | return compareContentResult; 123 | } 124 | 125 | // The first input is a digit log but the second is a letter log 126 | // The letter log always comes first so the 127 | // first input is considered bigger than the second input 128 | else if (!isLetterLog1 && isLetterLog2){ 129 | 130 | System.out.println("The first input is a Digit Log"); 131 | return firstInputIsBigger; 132 | } 133 | 134 | // The second input is a digit log but the first one is a letter log 135 | // The letter log always comes first, or considered smaller than the latter input. 136 | else if (isLetterLog1 && !isLetterLog2){ 137 | 138 | System.out.println("The first input is a Letter Log"); 139 | return firstInputIsSmaller; 140 | } 141 | 142 | // Both logs are digit logs, so no ordering needed. 143 | else{ 144 | 145 | System.out.println("Both input are the same"); 146 | return bothInputsAreEqual; 147 | } 148 | } 149 | }; 150 | 151 | // Sort the input 152 | Arrays.sort(logs, logComparator); 153 | return logs; 154 | 155 | } 156 | 157 | 158 | } 159 | --------------------------------------------------------------------------------