├── .gitattributes ├── .github ├── FUNDING.yml └── workflows │ └── pages.yml ├── .gitignore ├── .idea ├── .gitignore ├── AceTheJavaCodingInterview.iml ├── aws.xml ├── codeStyles │ └── codeStyleConfig.xml ├── codestream.xml ├── compiler.xml ├── git_toolbox_prj.xml ├── google-java-format.xml ├── gradle.xml ├── inspectionProfiles │ └── Project_Default.xml ├── jarRepositories.xml ├── misc.xml ├── uiDesigner.xml ├── vcs.xml └── workspace.xml ├── README.md ├── app ├── build.gradle └── src │ ├── main │ └── java │ │ └── AceTheJavaCodingInterview │ │ ├── App.java │ │ ├── module1_big_o_notation │ │ ├── BigONestedLoopWithAddition.java │ │ ├── BigONestedLoopWithMultiplication.java │ │ ├── BigONestedLoopWithSubtraction.java │ │ ├── _big_o_notation_formulae.md │ │ └── problem_sets │ │ │ ├── ProblemSet1.java │ │ │ └── ProblemSet2.java │ │ └── module2_data_structures │ │ ├── ClassTemplate.java │ │ ├── arrays │ │ ├── FindMaximumInSlidingWindow.java │ │ ├── FindTheSmallestCommonNumber.java │ │ ├── MaximumSumSubarrayOfSizeK.java │ │ ├── MergeAnArrayWithOverlappingIntervals.java │ │ ├── OneDimensionalArrays.java │ │ ├── PairWithTargetSum.java │ │ ├── Permutations.java │ │ ├── SmallestSubarrayWithAGreaterSum.java │ │ ├── SquaringASortedArray.java │ │ ├── SubArraysWithProductLessThanTarget.java │ │ ├── Subset.java │ │ ├── SubsetsWithDuplicates.java │ │ ├── TripletSumCloseToTarget.java │ │ ├── TripletSumToZero.java │ │ ├── TripletsWithSmallerSum_ReturnCount.java │ │ ├── TripletsWithSmallerSum_ReturnList.java │ │ ├── TwoDimensionalArrays.java │ │ ├── _arrays.md │ │ ├── binary_search │ │ │ ├── BinarySearchOnSortedArray_Iterative.java │ │ │ ├── BinarySearchOnSortedArray_Recursive.java │ │ │ ├── BitonicArrayMaximum.java │ │ │ ├── FindLowOrHighIndexOfAnElementInSortedArray.java │ │ │ ├── MoveAllZerosToTheBeginningOfTheArray.java │ │ │ ├── OrderAgnosticBinarySearch.java │ │ │ ├── SearchRotatedArray_Iteratively.java │ │ │ ├── SearchRotatedArray_Recursive.java │ │ │ └── StockBuySellToMaximizeProfit.java │ │ ├── challenges │ │ │ ├── CH10_RearrangeSortedArrayInMaxOrMinForm_SOL_1.java │ │ │ ├── CH10_RearrangeSortedArrayInMaxOrMinForm_SOL_2.java │ │ │ ├── CH11_FindTheSumOfMaximumSumSubarray.java │ │ │ ├── CH1_RemoveEvenFromArray.java │ │ │ ├── CH2_MergeTwoSortedArrays.java │ │ │ ├── CH3_FindTwoNoAddingUpToN_Sol_1.java │ │ │ ├── CH3_FindTwoNoAddingUpToN_Sol_2.java │ │ │ ├── CH4_ArrayOFProductsOfAllElementsExceptItself.java │ │ │ ├── CH5_FindMinimumValueInArray.java │ │ │ ├── CH6_FindFirstNonRepeatingIntegerInArray.java │ │ │ ├── CH7_FindSecondMaximumValueInArray_Sol_1.java │ │ │ ├── CH7_FindSecondMaximumValueInArray_Sol_2.java │ │ │ ├── CH8_RightRotateTheArrayByOneIndex.java │ │ │ ├── CH9_ReArrangePositiveAndNegativeValues_SOL_1.java │ │ │ └── CH9_ReArrangePositiveAndNegativeValues_SOL_2.java │ │ └── sorting │ │ │ ├── CyclicSortEasy.java │ │ │ └── QuicksortAlgorithm.java │ │ ├── hash_tables │ │ ├── PairWithTargetSum.java │ │ └── _hash_tables.md │ │ ├── stacks_and_queues │ │ └── _stacks_and_queues.md │ │ ├── tuples │ │ ├── Interval.java │ │ ├── Tuple.java │ │ └── _tuples.md │ │ └── utils │ │ └── DataStructuresUtils.java │ └── test │ └── java │ └── AceTheJavaCodingInterview │ └── AppTest.java ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # These are explicitly windows files and should use crlf 5 | *.bat text eol=crlf 6 | 7 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: david-kariuki # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: davidkariuki # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/workflows/pages.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a Jekyll site to GitHub Pages 2 | name: Deploy Jekyll with GitHub Pages dependencies preinstalled 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["master"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow one concurrent deployment 19 | concurrency: 20 | group: "pages" 21 | cancel-in-progress: true 22 | 23 | jobs: 24 | # Build job 25 | build: 26 | runs-on: ubuntu-latest 27 | steps: 28 | 29 | - name: Checkout 30 | uses: actions/checkout@v3 31 | - name: Setup Pages 32 | uses: actions/configure-pages@v1 33 | - name: Build with Jekyll 34 | uses: actions/jekyll-build-pages@v1 35 | with: 36 | source: ./ 37 | destination: ./_site 38 | - name: Upload artifact 39 | uses: actions/upload-pages-artifact@v1 40 | - name: Close Stale Issues 41 | uses: actions/stale@v5.1.1 42 | - name: Setup Node.js environment 43 | uses: actions/setup-node@v3.4.1 44 | - name: Setup Go environment 45 | uses: actions/setup-go@v3.3.0 46 | - name: SonarCloud Scan 47 | # You may pin to the exact commit or the version. 48 | # uses: SonarSource/sonarcloud-github-action@de2e56b42aa84d0b1c5b622644ac17e505c9a049 49 | uses: SonarSource/sonarcloud-github-action@v1.6 50 | - name: HashiCorp's Link Checker 51 | # You may pin to the exact commit or the version. 52 | # uses: hashicorp/gh-action-check-broken-links@9da9ec2d83f88fe981a856c3f03aca64e68af90c 53 | uses: hashicorp/gh-action-check-broken-links@v1 54 | - name: Cache 55 | uses: actions/cache@v3.0.8 56 | 57 | 58 | # Deployment job 59 | deploy: 60 | environment: 61 | name: github-pages 62 | url: ${{ steps.deployment.outputs.page_url }} 63 | runs-on: ubuntu-latest 64 | needs: build 65 | steps: 66 | - name: Deploy to GitHub Pages 67 | id: deployment 68 | uses: actions/deploy-pages@v1 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Gradle project-specific cache directory 2 | .gradle 3 | 4 | # Ignore Gradle build output directory 5 | build 6 | /.idea/uiDesigner.xml 7 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # CodeStream ignored files 7 | /../../AceTheJavaCodingInterview\.idea/codestream.xml 8 | # Datasource local storage ignored files 9 | /dataSources/ 10 | /dataSources.local.xml 11 | # Zeppelin ignored files 12 | /ZeppelinRemoteNotebooks/ 13 | -------------------------------------------------------------------------------- /.idea/AceTheJavaCodingInterview.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/aws.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/codestream.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/git_toolbox_prj.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/google-java-format.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ace The Java Coding Interview 2 | Java project to learn advanced Data Structures and Algorithms 3 | 4 |
5 | 6 | ![GitHub issues](https://img.shields.io/github/issues/david-kariuki/AceTheJavaCodingInterview?&labelColor=black&color=eb3b5a&label=Issues&logo=issues&logoColor=black&style=for-the-badge)   7 | ![GitHub Contributions](https://img.shields.io/github/contributors/david-kariuki/AceTheJavaCodingInterview?&labelColor=black&color=8854d0&style=for-the-badge)   8 | ![repo size](https://img.shields.io/github/repo-size/david-kariuki/AceTheJavaCodingInterview?label=Repo%20Size&style=for-the-badge&labelColor=black&color=20bf6b)   9 | ![GitHub forks](https://img.shields.io/github/forks/david-kariuki/AceTheJavaCodingInterview?&labelColor=black&color=0fb9b1&style=for-the-badge)   10 | ![GitHub stars](https://img.shields.io/github/stars/david-kariuki/AceTheJavaCodingInterview?&labelColor=black&color=f7b731&style=for-the-badge)   11 | ![GitHub LastCommit](https://img.shields.io/github/last-commit/david-kariuki/AceTheJavaCodingInterview?logo=github&labelColor=black&color=d1d8e0&style=for-the-badge)   12 | 13 | 14 | # Project Contents 15 | 16 | 17 |
18 | 19 | ## 1. Complexity Problems
20 | - Introduction to Asymptotic Analysis and Big O 21 | - Challenge 1: Big (O) of Nested Loop with Addition 22 | - Challenge 2: Big (O) of Nested Loop with Subtraction 23 | - Challenge 3: Big O of Nested Loop with Multiplication 24 | - Challenge 4: Nested Loop with Multiplication (Basic) 25 | - Challenge 5: Nested Loop with Multiplication (Intermediate) 26 | - Challenge 6: Nested Loop with Multiplication (Advanced) 27 | - Challenge 7: Nested Loop with Multiplication (Pro) 28 | - Problem Sets 29 | - Complexity Interview Questions 30 | - Cheat Sheet 31 | 32 |

33 | ## 2. DATA STRUCTURES 34 | 35 | a. ARRAYS 36 | 37 | . Two Dimensional Arrays. 38 | . Challenge 1: Remove Even Integers from an Array 39 | . Challenge 2: Merge Two Sorted Arrays 40 | . Challenge 3: Find Two Numbers that Add up to "n" 41 | . Challenge 4: Array of Products of All Elements Except Itself 42 | . Challenge 5: Find Minimum Value in Array 43 | . Challenge 6: First Non-Repeating Integer in an Array 44 | . Challenge 7: Find Second Maximum Value in an Array 45 | . Challenge 8: Right Rotate the Array by One Index 46 | . Challenge 9: Re-arrange Positive & Negative Values 47 | . Challenge 10: Rearrange Sorted Array in Max/Min Form 48 | . Challenge 11: Find the Sum of Maximum Sum Subarray 49 | . Implement Binary Search on a Sorted Array 50 | . Find Maximum in Sliding Window 51 | . Search a Rotated Array 52 | . Find the Smallest Common Number 53 | . Find Low/High Index of an Element in a Sorted Array 54 | . Move All Zeros to the Beginning of the Array 55 | . Stock Buy Sell to Maximize Profit 56 | . Merge an Array With Overlapping Intervals 57 | . Sort an Array Using Quicksort Algorithm 58 | . Cyclic Sort (easy) 59 | . Maximum Sum Subarray of Size K (easy) 60 | . Smallest Subarray With a Greater Sum (easy) 61 | . Squaring a Sorted Array (easy) 62 | . Subset (easy) 63 | . Subsets With Duplicates (easy) 64 | . Order-agnostic Binary Search (easy) 65 | . Bitonic Array Maximum (easy) 66 | . 67 | 68 | 69 | b. LINKED LISTS 70 | 71 | . Introduction to Linked Lists 72 | . Basic Linked List Operations 73 | . Insertion in a Singly Linked List 74 | . Challenge 1: Insertion in a Singly Linked List (insert at End) 75 | . Solution Review: Insertion in a Singly Linked List(insert at End) 76 | . Challenge 2: Search in Singly Linked List 77 | . Solution Review: Search in a Singly Linked List 78 | . Challenge 3: Deletion in Singly Linked List(Delete by Value) 79 | . Solution Review: Deletion in Singly Linked List 80 | . Linked Lists vs. Arrays 81 | . What is a Doubly Linked List (DLL)? 82 | . Linked List with Tail 83 | . Challenge 4: Find the Length of a Linked List 84 | . Solution Review: Find the Length of a Linked List 85 | . Challenge 5: Reverse a Linked List 86 | . Solution Review: Reverse a Linked List 87 | . Challenge 6: Detect Loop in a Linked List 88 | . Solution Review: Detect Loop in a Linked List 89 | . Challenge 7: Find the Middle Node of a Linked List 90 | . Solution Review: Find the Middle Node of a Linked List 91 | . Challenge 8: Remove Duplicates from a Linked List 92 | . Solution Review: Remove Duplicate from a Linked List 93 | . Challenge 9: Union and Intersection of Lists 94 | . Solution Review: Union & Intersection of Lists 95 | . Challenge 10: Return the Nth node from End 96 | . Solution Review: Return the Nth node from End 97 | . Challenge 11: Find if Doubly Linked-list is a Palindrome 98 | . Solution: Find if a Doubly Linked-list is a Palindrome 99 | . Implementation of Linked List 100 | . Intersection Point of Two Lists 101 | . Rotate a Linked List 102 | . Reverse Alternative K Node in a Singly Linked List 103 | . Add Two Integers Represented by Linked Lists 104 | . Reverse a Sub-list (medium) 105 | . Reverse every K-element Sub-list (medium) 106 | . Merge K Sorted Lists (medium) 107 | . Kth Smallest Number in M Sorted Lists (medium) 108 | . Linked list Interview Questions 109 | 110 | 111 | c. STRINGS 112 | 113 | . String: Common Methods & Operations 114 | . Reverse Words in a Sentence 115 | . Remove Duplicates from a String 116 | . Remove White Spaces from a String 117 | . Word Break Problem 118 | . XML to Tree 119 | . Find all Palindrome Substrings 120 | . Regular Expression Matching in String 121 | . Longest Palindromic Substring 122 | . Longest Palindromic Subsequence 123 | . Count of Palindromic Substrings 124 | . Minimum Deletions in a String to make it a Palindrome 125 | . Palindromic Partitioning 126 | . Longest Common Substring 127 | . Longest Common Subsequence 128 | . Minimum Deletions & Insertions to Transform a String into another 129 | . Fruits into Baskets (medium) 130 | . Longest Substring with maximum K Distinct Characters (medium) 131 | . String Permutations by changing case (medium) 132 | . Balanced Parentheses (hard) 133 | . Unique Generalized Abbreviations (hard) 134 | . Longest Substring with Distinct Characters (hard) 135 | . Longest Substring with Same Letters after Replacement (hard) 136 | . Boggle 137 | . Generate all Combinations of Balanced Parentheses 138 | 139 | 140 | d. STACKS and QUEUES 141 | 142 | . Introduction to Stacks & Queues 143 | . Stack (Implementation) 144 | . Queue (Implementation) 145 | . Implement Queue Using Stacks 146 | . Implement Stack Using Queues 147 | . Challenge 1: Generate Binary Numbers from 1 to n using a Queue 148 | . Solution Review: Generate Binary Numbers from 1 to n using Queue 149 | . Challenge 2: Implement Two Stacks using one Array 150 | . Solution Review: Implement Two Stacks using one Array 151 | . Challenge 3: Reversing the First k Elements of a Queue 152 | . Solution Review: Reversing the First k Elements of a Queue 153 | . Challenge 4: Implement Queue using Stack 154 | . Solution Review: Implement Queue using Stack 155 | . Challenge 5: Sort the Values in a Stack 156 | . Solution Review: Sort the Values in a Stack 157 | . Challenge 6: Evaluate Postfix Expressions using Stacks 158 | . Solution Review: Evaluate Postfix Expressions using Stacks 159 | . Challenge 7: Next Greater Element using Stack 160 | . Solution Review: Next Greater Element using Stack 161 | . Challenge 8: Solve a Celebrity Problem using a Stack 162 | . Solution Review: Solve a Celebrity Problem using a Stack 163 | . Challenge 9: Check for Balanced Parentheses using a Stack 164 | . Solution Review: Check for Balanced Parentheses using a Stack 165 | . Challenge 10: Create Stack where min() gives minimum in O(1) 166 | . Solution Review: Create Stack where min() gives minimum in O(1) 167 | . Stack/Queue Interview Questions 168 | 169 | 170 | e. TREES 171 | 172 | . Introduction to Trees 173 | . Implementation of Binary Tree 174 | . Check if Two Binary Trees are Identical 175 | . Write an In-Order Iterator for a Binary Tree 176 | . Iterative In-order Traversal of Binary Tree 177 | . In-order Successor of Binary Search Tree 178 | . In-order Successor Binary Search Tree With Parent Pointers 179 | . Level Order Traversal of Binary Tree 180 | . Is a Binary Search Tree Valid? 181 | . Convert Binary Tree to Doubly Linked List 182 | . Print Tree Perimeter 183 | . Connect Same Level Siblings of a Binary Tree 184 | . Connect All Siblings of a Binary Tree 185 | . Serialize/Deserialize Binary Tree 186 | . Nth Highest Number in Binary Search Tree 187 | . Mirror Binary Tree Nodes 188 | . Delete Zero Sum Sub-Trees 189 | . Convert N-ary Tree to Binary Tree 190 | 191 | 192 | f. TRIE 193 | 194 | . Introduction to Tries 195 | . Insertion in a Trie 196 | . Search in a Trie 197 | . Deletion in a Trie 198 | . The Structure of a Trie 199 | . Challenge 1: Total Number of Words in a Trie 200 | . Solution Review: Total Number of Words in a Trie 201 | . Challenge 2: Find All of the Words in a Trie 202 | . Solution Review: Find All of the Words in a Trie 203 | . Challenge 3: Sort the Elements of an Array using a Trie. 204 | . Solution Review: Sort the Elements of an Array using a Trie. 205 | . Challenge 4: Word Formation from a Given Dictionary using a Trie 206 | . Solution Review: Word Formation from Given Dictionary using Trie 207 | . Trie Interview Questions 208 | 209 | 210 | g. HEAPS 211 | 212 | . Introduction to Heaps 213 | . Heap Representation in Arrays 214 | . Max Heap: Introduction 215 | . Max Heap (Implementation) 216 | . Min Heap: An Introduction 217 | . Min Heap (Implementation) 218 | . Challenge 1: Convert a Max-Heap to a Min-Heap 219 | . Solution Review: Convert a Max-Heap to a Min-Heap 220 | . Challenge 2: Find the k Smallest Elements in an Array 221 | . Solution Review: Find the k Smallest Elements in an Array 222 | . Challenge 3: Find the k Largest Elements in an Array 223 | . Solution Review: Find the k Largest Elements in an Array 224 | . Heap Interview Questions 225 | 226 | 227 | h. HASH TABLES 228 | 229 | . Introduction to Hash Tables 230 | . Trie vs Hash Table 231 | . HashMap vs HashSet 232 | . Challenge 1: Find whether an array is a subset of another array 233 | . Solution Review: Find whether an array is a subset of another array 234 | . Challenge 2: Check if the given arrays are disjoint 235 | . Solution Review: Check if the given arrays are disjoint 236 | . Challenge 3: Find symmetric pairs in an Array 237 | . Solution Review: Find symmetric pairs in an Array 238 | . Challenge 4: Trace the complete path of a journey 239 | . Solution Review: Trace the complete path of a journey 240 | . Challenge 5: Find two pairs in an Array such that a+b = c+d 241 | . Solution Review: Find two pairs in an Array such that a+b = c+d 242 | . Challenge 6: Find If a Subarray with a Sum Equal to 0 Exists 243 | . Solution Review: Find if a subarray with a sum equal to 0 exists. 244 | . Challenge 7: First Non-Repeating Integer in an Array 245 | . Solution Review: First Non-Repeating Integer in an Array 246 | . Challenge 8: Remove Duplicate from a Linked List using Hashing 247 | . Solution Review: Remove Duplicate from Linked List using Hashing 248 | . Challenge 9: Union and Intersection of Lists using Hashing 249 | . Solution Review: Union and Intersection of Lists using Hashing 250 | . Challenge 10: Find Two Numbers that Add up to "n" 251 | . Solution Review: Find Two Numbers that Add up to "n" 252 | . Hashing Interview Questions 253 | 254 | 255 | i. GRAPHS 256 | 257 | . Introduction to Graphs 258 | . Graph Implementation 259 | . What is a Bipartite Graph? 260 | . Challenge 1: Implement Breadth First Search 261 | . Solution Review: Implement Breadth First Search 262 | . Challenge 2: Implement Depth First Search 263 | . Solution Review: Implement Depth First Search 264 | . Challenge 3: Cycle Detection in a Directed Graph 265 | . Solution Review: Cycle Detection in a Directed Graph 266 | . Challenge 4: Find "Mother Vertex" in a Directed Graph 267 | . Solution Review: Find "Mother Vertex" in a Directed Graph 268 | . Challenge 5: Count the Number of Edges in an Undirected Graph 269 | . Solution Review: Count the number of Edges in an Undirected Graph 270 | . Challenge 6: Check if a Path Exists Between Two Vertices 271 | . Solution Review: Check if a Path Exists Between Two Vertices 272 | . Challenge 7: Check if a Directed Graph is Tree or not 273 | . Solution Review: Check if a Directed Graph is Tree or not 274 | . Challenge 8: Find Length of Shortest Path between Two Vertices 275 | . Solution Review: Find the Shortest Path between Two Vertices 276 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * This generated file contains a sample Java application project to get you started. 5 | * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle 6 | * User Manual available at https://docs.gradle.org/7.4/userguide/building_java_projects.html 7 | * This project uses @Incubating APIs which are subject to change. 8 | */ 9 | 10 | plugins { 11 | // Apply the application plugin to add support for building a CLI application in Java. 12 | id 'application' 13 | } 14 | 15 | repositories { 16 | // Use Maven Central for resolving dependencies. 17 | mavenCentral() 18 | } 19 | 20 | dependencies { 21 | // This dependency is used by the application. 22 | implementation 'com.google.guava:guava:30.1.1-jre' 23 | } 24 | 25 | testing { 26 | suites { 27 | // Configure the built-in test suite 28 | test { 29 | // Use JUnit Jupiter test framework 30 | useJUnitJupiter('5.8.1') 31 | } 32 | } 33 | } 34 | 35 | application { 36 | // Define the main class for the application. 37 | mainClass = 'AceTheJavaCodingInterview.App' 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/App.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This Java source file was generated by the Gradle 'init' task. 3 | */ 4 | package AceTheJavaCodingInterview; 5 | 6 | public class App { 7 | public String getGreeting() { 8 | return "Hello World!"; 9 | } 10 | 11 | public static void main(String[] args) { 12 | System.out.println(new App().getGreeting()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module1_big_o_notation/BigONestedLoopWithAddition.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Big (O) of Nested Loop With Addition 3 | * Compute the Big O complexity of the code snippet given below. 4 | * 5 | * @authr David Kariuki 6 | * @since 10/8/2022 7 | */ 8 | 9 | package AceTheJavaCodingInterview.module1_big_o_notation; 10 | 11 | public class BigONestedLoopWithAddition { 12 | 13 | public static void main(String[] args) { 14 | int n = 10; // 1 step - Initializing a variable is a basic operation that costs one unit. 15 | int sum = 0; // 1 step - Initializing a variable is a basic operation that costs one unit. 16 | double pie = 3.14; // 1 step - Initializing a variable is a basic operation that costs one unit. 17 | 18 | /* 19 | * int var = 0; - Initializing a variable is a basic operation that costs one unit. 20 | * 21 | * var < n; 22 | * This condition executes in steps of 3,i.e., initially var = 0, and hence var is less than n. 23 | * In the next step var is 3 --> still less than n. Then var = 6 -> still less than n var = 9 --> still less 24 | * than n. But when var = 12, it is greater than n,loop breaks here.From this example notice that the loop 25 | * runs n/3 times and 1 time extra this condition is executed for breaking the loop. 26 | */ 27 | for (int var = 0; var < n; var = var + 3) { // n/3 steps 28 | 29 | // The outer-loop runs n/3 times so the print statement is executed n/3 times. 30 | System.out.println("\nFor loop at " + var + " Pie: " + pie); 31 | 32 | /* 33 | * int j = 0 itself is executed in 1 unit of time. 34 | * However, this statement is executed n/3 times due to outer for-loop. 35 | * 36 | * j < n; 37 | * The outer loop runs n/3 times.The statement j < n executes in steps of 2 due to the inner loop. 38 | * In each iteration of the inner loop 2 is added to j. Therefore, this statement runs (n/2 + 1) times due 39 | * to inner loop,and in turn executes n/3(n/2 + 1) due to outer loop. 40 | */ 41 | for (int j = 0; j < n; j = j + 2) { // (n/3 * n/2) steps 42 | 43 | // (n/3 * n/2) steps - The outer loop runs n/3 times, and the inner loop runs n/2 times.Therefore, 44 | // sum++ is executed n/3(n/2) times. 45 | sum++; 46 | 47 | System.out.println("When var : " + var + " and j : " + j + " Sum : " + sum + " and n " + n); // 48 | // (n/3 * n/2) steps 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module1_big_o_notation/BigONestedLoopWithMultiplication.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Big (O) of Nested Loop With Multiplication 3 | * Compute the Big O complexity of the code snippet given below. 4 | * 5 | * @authr David Kariuki 6 | * @since 12/8/2022 7 | */ 8 | 9 | package AceTheJavaCodingInterview.module1_big_o_notation; 10 | 11 | @SuppressWarnings("ALL") 12 | public class BigONestedLoopWithMultiplication { 13 | 14 | public static void main(String[] args) { 15 | withMultiplicationBasic1(); 16 | withMultiplicationBasic2(); 17 | withMultiplicationIntermediate(); 18 | withMultiplicationAdvanced(); 19 | } 20 | 21 | /** 22 | * @note Nested Loop with Multiplication (Basic) 1 23 | * Compute the Big O complexity of the code snippet given below. 24 | */ 25 | public static void withMultiplicationBasic1() { 26 | 27 | System.out.println("\n\n Starting Simple"); 28 | 29 | int n = 16; // O(time complexity of the called function) 30 | int sum = 0; // O(1) 31 | double pie = 3.14; // O(1) 32 | int var = 1; // O(1 33 | 34 | 35 | while (var < n) { // O(log n) 36 | 37 | System.out.println("Pie: " + pie); // O(log n) 38 | 39 | for (int j = 0; // O(log n) 40 | j < var; j++) { // 2n 41 | sum++; // (2n-1) 42 | } 43 | var *= 2; // O(log n) 44 | } //end of while loop 45 | 46 | System.out.println("Sum: " + sum); //O(1) 47 | 48 | // Answer -> O(n) 49 | } 50 | 51 | /** 52 | * @note Nested Loop with Multiplication (Basic) 2 53 | * Compute the Big O complexity of the code snippet given below. 54 | */ 55 | public static void withMultiplicationBasic2() { 56 | 57 | System.out.println("\n\n Starting Basic"); 58 | 59 | int n = 10; // O(time complexity of the called function) 60 | int sum = 0; //O(1) 61 | double pie = 3.14; //O(1) 62 | int var = 1; 63 | 64 | 65 | while (var < n) { // O(log3 n) 66 | System.out.println("Pie: " + pie); // O(log3 n) 67 | 68 | for (int j = 1; // O(log3 n) 69 | // The inner loop is executed n/2 times. This condition is however, checked 1 more time for breaking 70 | // the loop.The outer loop is executed log3(n) times. Therefore, this statement is executed 71 | // log3(n) x (n/2 + 1) times 72 | j < n; 73 | 74 | // The inner loop is executed n/2 times. The outer loop is executed log3(n) times. Therefore, this 75 | // statement is executed log3(n) x (n/2) times 76 | j = j + 2) { // O((log3 n)* (n/2)) 77 | 78 | sum++; // O((log3 n)* (n/2) * 2) 79 | } 80 | var *= 3; // O(log3 n) 81 | } //end of while loop 82 | System.out.println("Sum: " + sum); //O(1) 83 | 84 | // Answer -> O(nlog2(n)) 85 | } 86 | 87 | /** 88 | * @note Nested Loop with Multiplication (Intermediate) 89 | * Compute the Big O complexity of the code snippet given below. 90 | */ 91 | public static void withMultiplicationIntermediate() { 92 | 93 | System.out.println("\n\n Starting Intermediate 1"); 94 | 95 | int n = 10; //O(1) 96 | int sum = 0; //O(1) 97 | int j = 1; //O(1) 98 | double pie = 3.14; //O(1) 99 | 100 | //O(?) 101 | for ( 102 | int var = 1; // O(1) 103 | var < n; // n/3 + 1 104 | var += 3 // n/3 105 | ) { 106 | 107 | System.out.println("Pie: " + pie); // n/3 108 | j = 1; // n/3 109 | while (j < n) { //O(?) 110 | sum += 1; // (log_3(n) + 1 ) * n/3 111 | j *= 3; // log_3(n) * n/3 112 | } 113 | } 114 | 115 | System.out.println("Sum: " + sum); //O(1) 116 | 117 | // Answer -> O(nlog(n)) 118 | } 119 | 120 | /** 121 | * @note Nested Loop with Multiplication (Advanced) 122 | * Compute the Big O complexity of the code snippet given below. 123 | */ 124 | public static void withMultiplicationAdvanced() { 125 | int n = 10; //O(1) 126 | int sum = 0; //O(1) 127 | double pie = 3.14; //O(1) 128 | 129 | for (int var = 0; var < n; var++) { //O(n) 130 | int j = 1; //O(n) 131 | System.out.println("Pie: " + pie); //O(n) 132 | while(j < var) { // O((n) * (log2 var)) 133 | sum += 1; // O((n) * (log2 var)) 134 | j *= 2; // O((n) * (log2 var)) 135 | } 136 | } 137 | 138 | System.out.println("Sum: " + sum); //O(1) 139 | 140 | // Answer -> O(nlog2(n)) 141 | } 142 | 143 | /** 144 | * @note Nested Loop with Multiplication (Pro) 145 | * Compute the Big O complexity of the code snippet given below. 146 | */ 147 | public static void withMultiplicationPro() { 148 | 149 | int n = 10; // O(1) 150 | int sum = 0; // O(1) 151 | int j = 1; // O(1) 152 | double pie = 3.14; // O(1) 153 | 154 | for (int var = 0; var < n; var++) { // 0(n) 155 | 156 | System.out.println("Pie: " + pie); // 0(n) 157 | while(j < var) { // 0(n) 158 | sum += 1; // 0(n) 159 | j *= 2; // 0(n) 160 | } 161 | } 162 | 163 | System.out.println("Sum: " + sum); // O(1) 164 | 165 | // Answer O(n) 166 | } 167 | } -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module1_big_o_notation/BigONestedLoopWithSubtraction.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Big (O) of Nested Loop With Subtraction 3 | * Compute the Big O complexity of the code snippet given below. 4 | * 5 | * @authr David Kariuki 6 | * @since 11/8/2022 7 | */ 8 | 9 | package AceTheJavaCodingInterview.module1_big_o_notation; 10 | 11 | public class BigONestedLoopWithSubtraction { 12 | 13 | public static void main(String[] args) { 14 | int n = 10; // O(time complexity of the called function) 15 | int sum = 0; //O(1) 16 | double pie = 3.14; //O(1) 17 | 18 | for (int var = n; var >= 1; var = var - 3) { // O(n/3) 19 | System.out.println("Pie: " + pie); // O(n/3) 20 | 21 | /* 22 | * j >= 0 is executed n + 2 times due to the inner loop. For example if n = 10. 23 | * Then j can have values10, 9, 8, ..., 2, 1, 0. This means that j >= 0 will execute n + 1times 24 | * successfully and another +1 for the loop breaking condition. Total n + 2However, due to the outer loop 25 | * this statement is executed a further n/3 times.Therefore, running time of this statement is n/3(n + 2). 26 | * */ 27 | for (int j = n; j >= 0; j = j - 1) { // O((n/3)*(n+1)) 28 | sum++; // O((n/3)*(n+1)) 29 | } 30 | } //end of outer for loop 31 | System.out.println("Sum: " + sum);//O(1) 32 | } //end of main 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module1_big_o_notation/_big_o_notation_formulae.md: -------------------------------------------------------------------------------- 1 | # Saved concepts and formulae 2 | 3 | ## Big O Notation 4 | 5 |
1. A function `f(n)`, is considered `O(g(n))` (read as big oh of `g(n)`) if there exists some positive real constant `c` and an integer `n_0 > 0`, such that the following inequality holds for all n >= n_0
6 | `f(n) <= cg(n)` 7 | 8 |
2. People tend to write `f(n) = O(g(n))`, which isn’t technically accurate. A lot of functions can satisfy the `O(g(n))` conditions. Therefore, `O(g(n))` is a set of functions, and it is okay to say that `f(n)` belongs to `O(g(n))`. 9 | 10 |
3. `f(n)` will grow no faster than a constant multiple of `g(n)`. Put yet another way, the rate of growth of `f(n)` is within constant factors of that of `g(n)`. 11 | 12 |
4. Suppose algorithms `A` and `B` have running time of `O(n)` and `O(n^2)`, respectively. For sufficiently large input sizes, algorithm `A` will run faster than algorithm `B`. That does not mean that algorithm `A` will always run faster than algorithm `B`. 13 | Algorithm A and B both have running time `O(n)`. The execution time for these algorithms for very large input sizes, will be within constant factors of each other. For all practical purposes, they are considered equally good. 14 | 15 |
5. Simplified asymptotic analysis 16 | Once we have obtained the time complexity of an algorithm by counting the number of primitive operations, we can arrive at the Big O notation for the algorithm simply by: 17 | 18 | - Dropping the multiplicative constants with all terms. 19 | - Dropping all but the highest order term. 20 | - Therefore, `n^2 + 2n + 1` is `O(n^2)` while `n^5 + 4n^3 + 2n + 43` is `O(n^5)`. 21 | 22 | The constant coefficients have become insignificant in the Big O notation. Recall that these constants represent the number of primitive operations on a given line of code. This means that, while analyzing code, counting a line of code 23 | as contributing 4 primitive operations is as good as counting it as 1 primitive operation. What matters is correctly counting the number of times each line of code is repeated. 24 | 25 |

6. A comparison of some common functions 26 | It is easy to work with simple polynomials in n, but when the time complexity involves other types of functions like log(), you may find it hard to identify the “highest order term”. The following table lists some commonly encountered 27 | functions in ascending order of rate of growth. Any function can be given as a Big O of any other function that appears later in this table. 28 | 29 | | # | Name | Function | 30 | |-|-|-| 31 | | 1. | Any constant | Constant | 32 | | 2. | logn | Logarithmic | 33 | | 3. | $${log^2n}$$ | Log-square | 34 | | 4. | $$\sqrt{n}$$ | Root-n | 35 | | 5. | n | Linear | 36 | | 6. | nlogn | Linearithmic | 37 | | 7. | $${n^2}$$ | Quadratic | 38 | | 8. | $${n^3}$$ | Cubic | 39 | | 9. | $${n^4}$$ | Quartic | 40 | | 10. | $${2^n}$$ | Exponential | 41 | | 11. | $${e^n}$$ | Exponential | 42 | | 12. | n! | n-Factorial | 43 | |||| 44 | 45 |

7. General Tips 46 | 47 | - Every time a list or array gets iterated over `c×length` times, it is most likely in `O(n)` time. 48 | - When you see a problem where the number of elements in the problem space gets halved each time, it will most probably be in `O(log n)` runtime. 49 | - Whenever you have a single nested loop, the problem is most likely in quadratic time. `O(n2)`. 50 | - A loop statement that multiplies/divides the loop variable by a constant takes log_k(n) time because the loop runs that many times. 51 | - We don’t always add the time complexity of the inner loop. It depends. If the inner loop depends on the outer loop, then the complexity is added, and if the inner loop does not depend on the outer loop, then we multiply it. 52 | - `log(a)` + `log(b)` = `log(ab)` 53 | - An algorithm is said to be constant time (also written as `O(1)}` time) if the value of `T(n)` is bounded by a value that does not depend on the size of the input. For example, accessing any single element in an array takes constant time as only one operation has to be performed to locate it. In a similar manner, finding the minimal value in an array sorted in ascending order; it is the first element. However, finding the minimal value in an unordered array is not a constant time operation as scanning over each element in the array is needed in order to determine the minimal value. Hence it is a linear time operation, taking {\textstyle O(n)}{\textstyle O(n)} time. If the number of elements is known in advance and does not change, however, such an algorithm can still be said to run in constant time. 54 | - An algorithm is said to take logarithmic time when `T(n) =O(log n)`. Since `log_a(n)` `log_b(n)` are related by a constant multiplier, and such a multiplier is irrelevant to `big O` classification, the standard usage for logarithmic-time algorithms is `O(log n)` regardless of the base of the logarithm appearing in the expression of T. 55 | Algorithms taking logarithmic time are commonly found in operations on binary trees or when using binary search. 56 | 57 |
58 |
59 |
60 |
61 | 62 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module1_big_o_notation/problem_sets/ProblemSet1.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Problem set 1 3 | * @author David Kariuki 4 | * @since 14/8/2022 5 | */ 6 | 7 | package AceTheJavaCodingInterview.module1_big_o_notation.problem_sets; 8 | 9 | @SuppressWarnings("unused") 10 | public class ProblemSet1 { 11 | 12 | /** 13 | * Following is another implementation of insertion sort. If we feed an already sorted array to the following 14 | * snippet will the algorithm execute a linear number of instructions? Insertion sort’s best-case running time 15 | * is linear (think running a single loop) and not quadratic. 16 | */ 17 | public void sort(int[] input) { 18 | 19 | for (int i = 1; i < input.length; i++) { 20 | int key = input[i]; 21 | for (int j = i - 1; j >= 0; j--) { 22 | if (input[j] > key) { 23 | int tmp = input[j]; 24 | input[j] = key; 25 | input[j + 1] = tmp; 26 | } 27 | } 28 | } 29 | 30 | /* 31 | * Answer - No 32 | * 33 | * The algorithm represents insertion sort. However, the way the code is written, there’s no short-circuiting 34 | * for the nested loop when the values are already sorted so even in the best case, i.e. when the array is 35 | * sorted the inner loops run from the start of the array to the end. Unlike the implementation of insertion 36 | * sort in the lesson, the short-circuiting would never make the inner loop run when the input array is already 37 | * sorted. The best-case time would be linear and not quadratic. However, for the above snippet, the best case 38 | * would still be quadratic. The point to drive home is to exercise caution as slight implementation changes 39 | * can change complexities for the same algorithm. 40 | */ 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module1_big_o_notation/problem_sets/ProblemSet2.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Problem set 2 3 | * @author David Kariuki 4 | * @since 14/8/2022 5 | */ 6 | 7 | package AceTheJavaCodingInterview.module1_big_o_notation.problem_sets; 8 | 9 | 10 | /** 11 | *

12 | * @note Question 1 13 | * Suppose your friend discovers a new algorithm and in his excitement tells you that his algorithm has a lower 14 | * bound of O(n2). Can you explain why your friend's statement makes no sense? 15 | * 16 | *

17 | * Answer 18 | * Big O notation denotes an upper bound but is silent about the lower bound. Treat it like a cap on the worst 19 | * that can happen. So when someone says that an algorithm has a lower bound of O(n2) that translates into saying 20 | * the lower bound can at worst be quadratic in complexity. By definition, the lower bound is the best an algorithm 21 | * can perform. Combine the two statements and your friend is saying the algorithm he found in the best case can 22 | * perform in quadratic time or better. It can also perform in linear time or constant time, we just don't know. 23 | * So your friend is effectively not telling you anything about the lower bound on the performance of his new-found 24 | * algorithm. 25 | * 26 | *

27 | * @note Question 2 28 | * Does O^(22n) equal O^(2n) ? 29 | * 30 | *

31 | * @note Question 3 32 | * Give an example of an algorithm whose best case is equal to its worst case? 33 | * Counting Sort and Radix Sort are two algorithms which have the same best, worst and average case complexities. 34 | * 35 | *

36 | * @question Question 4 - Time complexity - Work out the time complexity for the avarager method below 37 | * @see #averager(int[]) 38 | * 39 | *

40 | * @question Question 5 - What is the complexity of the below snippet 41 | * @see #question5(int[]) 42 | * 43 | *

44 | * @question Question 6 - Consider the following snippet of code and determine its running time complexity - 45 | * @see #question6(int[]) 46 | * 47 | *

48 | * @question Question 7 - Determine the time complexity for the following snippet of code 49 | * @see #question7(int, int) 50 | * 51 | *

52 | * @question Question 8 - Determine the time complexity for the following snippet of code 53 | * @see #question8(int) 54 | * 55 | *

56 | * @question Question 9 - Determine the time complexity for the following snippet of code 57 | * @see #question9(int, int) 58 | */ 59 | 60 | @SuppressWarnings({"unused", "StatementWithEmptyBody"}) 61 | public class ProblemSet2 { 62 | 63 | /** 64 | * Question 4 65 | * @param A - int[] 66 | */ 67 | void averager(int[] A) { 68 | 69 | float avg = 0.0f; 70 | int j, count; 71 | 72 | for (j = 0; j < A.length; j++) { 73 | avg += A[j]; 74 | } 75 | 76 | avg = avg / A.length; 77 | count = j = 0; 78 | 79 | do { 80 | 81 | while (j < A.length && A[j] != avg) { 82 | j++; 83 | } 84 | 85 | if (j < A.length) { 86 | A[j++] = 0; 87 | count++; 88 | } 89 | } while (j < A.length); 90 | } 91 | 92 | /** 93 | * Question 5 94 | */ 95 | public void question5(int[] array) { 96 | 97 | for( int i=0; i m then m%n will equal m, so now the inner loop will run for m times, 145 | // giving us a total complexity of O(m*n). The last case is when n < m then m%n will equal values ranging from 146 | // 1 to n-1. So the inner loop in the worst case would run for n-1 times. The complexity in the last case would 147 | // then be O(n*(n-1)) which is O(n2). 148 | 149 | // Note that O(m*n) is a tighter bound for the second case, but since we are talking in big O terms, we can 150 | // say for the second case, when n > m, then O(m*n) < O(n2) so for the second case, we can say the complexity 151 | // will be O(n2). So in the worst case, the complexity would be O(n2). 152 | } 153 | 154 | /** 155 | * Question 8 156 | * @param n - int 157 | */ 158 | public void question8(int n) { 159 | 160 | /* Commenting due to duplicate int i declaration 161 | for (int j = 0; j < n; j++) { 162 | for (int i = 0; i < 3; i++) { 163 | for (int i = 0; i < n; i++) { 164 | System.out.println("I have 3 loops"); 165 | } 166 | } 167 | } 168 | */ 169 | 170 | // It may seem that the complexity of the snippet is cubic since we have 3 loops. But the second loop runs 171 | // for a constant number of times. One way to think about the above snippet is to unroll the second loop. 172 | // We can say the above code is equivalent to the following. The output of both the snippets would be the same. 173 | // From the unrolling, it is evident that the three inner loops contribute n + n + n = 3n = O(n) and the 174 | // out most loop runs for n too therefore the overall complexity is O(n2). 175 | } 176 | 177 | /** 178 | * Question 8 179 | * @param n - int 180 | * @param m - int 181 | */ 182 | public void question9(int n, int m) { 183 | for (int j = 0; j < n; j++) { 184 | for (int i = 0; i < m; i++) { 185 | System.out.println("I have 2 loops"); 186 | } 187 | } 188 | 189 | // The above snippet is a traditional example of nested loops. Whenever you get nested loops, each running for 190 | // a variable number of times, the complexity of the entire snippet is the product of the variables 191 | // controlling the repetition of each loop. The string message would be printed for a total of (m * n) 192 | // times and thus the overall, complexity will be O(mn) 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/ClassTemplate.java: -------------------------------------------------------------------------------- 1 | /** 2 | * ClassTemplate Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement - 7 | * @example 8 | * @note Solution - 9 | * @note Time Complexity - 10 | * @note Space Complexity - 11 | * @author David Kariuki 12 | * @since /8/2022 13 | */ 14 | package AceTheJavaCodingInterview.module2_data_structures; 15 | 16 | public class ClassTemplate { 17 | 18 | /** 19 | * Main method 20 | * 21 | * @param args - String[] 22 | */ 23 | public static void main(String[] args) {} 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/FindMaximumInSlidingWindow.java: -------------------------------------------------------------------------------- 1 | /** 2 | * FindMaximumInSlidingWindow Class 3 | * 4 | *

5 | * 6 | * @question Given an array of integers, find the maximum value in a window. Given an integer array 7 | * and a window of size w, find the current maximum value in the window as it slides through the 8 | * entire array. 9 | * @note If the window size is greater than the array size, we will consider the entire array as a 10 | * single window. 11 | * @author David Kariuki 12 | * @since 17/8/2022 13 | */ 14 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 15 | 16 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 17 | 18 | import java.util.ArrayDeque; 19 | import java.util.Deque; 20 | 21 | public class FindMaximumInSlidingWindow { 22 | 23 | /** 24 | * Main method 25 | * 26 | * @param args - String[] 27 | */ 28 | public static void main(String[] args) { 29 | 30 | int[] targetList = {3, 2, 1, 2}; 31 | int[][] numsList = { 32 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 33 | {10, 6, 9, -3, 23, -1, 34, 56, 67, -1, -4, -8, -2, 9, 10, 34, 67}, 34 | {4, 5, 6, 1, 2, 3}, 35 | {9, 5, 3, 1, 6, 3} 36 | }; 37 | 38 | for (int i = 0; i < targetList.length; i++) { 39 | 40 | System.out.println( 41 | (i + 1) + ". Original list:\t" + DataStructuresUtils.arrayToString(numsList[i])); 42 | System.out.println(" Window size:\t\t" + targetList[i]); 43 | 44 | ArrayDeque ouput = findMaxSlidingWindow(numsList[i], targetList[i]); 45 | 46 | System.out.println(" Max:\t\t\t" + ouput); 47 | System.out.println("------------------------------------------------\n"); 48 | } 49 | } 50 | 51 | /** 52 | * Method to find max sliding window 53 | * 54 | *

55 | * 56 | * @note Time complexity - The time complexity of this solution is O(n) O(n). 57 | * @note Every element is pushed and popped from the deque only once in a single traversal. 58 | * @note Space complexity - The space complexity of this solution is O(w), where w is the window 59 | * size in this case. 60 | * @param arr - int[] 61 | * @return ArrayDeque 62 | */ 63 | @SuppressWarnings("ConstantConditions") 64 | public static ArrayDeque findMaxSlidingWindow(int[] arr, int windowSize) { 65 | 66 | // ArrayDeque for storing values 67 | ArrayDeque result = new ArrayDeque<>(); 68 | Deque list = new ArrayDeque<>(); // Create a LinkedList 69 | 70 | if (arr.length > 0) { 71 | 72 | // If window_size is greater than the array size, 73 | // set the window_size to arr.size() 74 | if (arr.length < windowSize) { 75 | windowSize = arr.length; 76 | } 77 | 78 | for (int i = 0; i < windowSize; ++i) { 79 | // Removing last smallest element index 80 | while (!list.isEmpty() && arr[i] >= arr[list.peekLast()]) { 81 | list.removeLast(); 82 | } 83 | 84 | // Adding newly picked element index 85 | list.addLast(i); 86 | } 87 | for (int i = windowSize; i < arr.length; ++i) { 88 | result.add(arr[list.peek()]); 89 | 90 | // Removing all the elements indexes which are not in the current window 91 | while ((!list.isEmpty()) && list.peek() <= i - windowSize) list.removeFirst(); 92 | 93 | // Removing the smaller elements indexes which are not required 94 | while ((!list.isEmpty()) && arr[i] >= arr[list.peekLast()]) list.removeLast(); 95 | 96 | // Adding newly picked element index 97 | list.addLast(i); 98 | } 99 | 100 | // Adding the max number of the current window in the result 101 | result.add(arr[list.peek()]); 102 | } 103 | 104 | return result; // returning result 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/FindTheSmallestCommonNumber.java: -------------------------------------------------------------------------------- 1 | /** 2 | * FindTheSmallestCommonNumber Class 3 | * 4 | *

5 | * 6 | * @question Given three integer arrays sorted in ascending order, return the smallest number found 7 | * in all three arrays. 8 | * @author David Kariuki 9 | * @since 18/8/2022 10 | */ 11 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 12 | 13 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 14 | 15 | public class FindTheSmallestCommonNumber { 16 | 17 | /** 18 | * Main method 19 | * 20 | * @param args - String[] 21 | */ 22 | public static void main(String[] args) { 23 | 24 | int[] v1 = new int[] {6, 7, 10, 25, 30, 63, 64}; 25 | int[] v2 = new int[] {0, 4, 5, 6, 7, 8, 50}; 26 | int[] v3 = new int[] {1, 6, 10, 14}; 27 | System.out.println("Array 1: " + DataStructuresUtils.arrayToString(v1)); 28 | System.out.println("Array 2: " + DataStructuresUtils.arrayToString(v2)); 29 | System.out.println("Array 3: " + DataStructuresUtils.arrayToString(v3)); 30 | 31 | Integer result = findLeastCommonNumber(v1, v2, v3); 32 | System.out.println("Least Common Number: " + result); 33 | } 34 | 35 | /** 36 | * Method to find the least common number 37 | * 38 | *

39 | * 40 | * @note Time complexity - The time complexity of the solution is linear, O (n). 41 | * @note Space complexity - The space complexity of the solution is constant, O(1) . 42 | * @param arr1 - int[] 43 | * @param arr2 - int[] 44 | * @param arr3 - int[] 45 | * @return Integer 46 | */ 47 | static Integer findLeastCommonNumber(int[] arr1, int[] arr2, int[] arr3) { 48 | 49 | // Initialize starting indexes for arr1, arr2 and arr3 50 | int i = 0, j = 0, k = 0; 51 | 52 | while (i < arr1.length && j < arr2.length && k < arr3.length) { 53 | 54 | // Finding the smallest common number 55 | if (arr1[i] == arr2[j] && arr2[j] == arr3[k]) { 56 | return arr1[i]; 57 | } 58 | 59 | // Increment iterator for the smallest value 60 | if (arr1[i] <= arr2[j] && arr1[i] <= arr3[k]) { 61 | i++; 62 | } else if (arr2[j] <= arr1[i] && arr2[j] <= arr3[k]) { 63 | j++; 64 | } else if (arr3[k] <= arr1[i] && arr3[k] <= arr2[j]) { 65 | k++; 66 | } 67 | } 68 | 69 | return -1; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/MaximumSumSubarrayOfSizeK.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MaximumSumSubarrayOfSizeK Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement - Given an array of positive numbers and a positive number ‘k,’ find 7 | * the maximum sum of any contiguous subarray of size ‘k’. 8 | *

9 | * @note Solution - If you observe closely, you will realize that to calculate the sum of a 10 | * contiguous subarray, we can utilize the sum of the previous subarray. For this, consider each 11 | * subarray as a Sliding Window of size ‘k.’ To calculate the sum of the next subarray, we need 12 | * to slide the window ahead by one element. So to slide the window forward and calculate the 13 | * sum of the new position of the sliding window, we need to do two things: 14 | *

Subtract the element going out of the sliding window, i.e., subtract the first element of 15 | * the window. 16 | *

Add the new element getting included in the sliding window, i.e ., the element coming 17 | * right after the end of the window. This approach will save us from re-calculating the sum of 18 | * the overlapping part of the sliding window. 19 | *

20 | * @note Time Complexity - The time complexity of the above algorithm will be O(N) . 21 | * @note Space Complexity - The algorithm runs in constant space O(1). 22 | * @author David Kariuki 23 | * @since 23/8/2022 24 | */ 25 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 26 | 27 | public class MaximumSumSubarrayOfSizeK { 28 | 29 | /** 30 | * Main method 31 | * 32 | * @param args - String[] 33 | */ 34 | public static void main(String[] args) { 35 | 36 | System.out.println( 37 | "Maximum sum of a subarray of size K: " 38 | + findMaxSumSubArray(3, new int[] {2, 1, 5, 1, 3, 2})); 39 | System.out.println( 40 | "Maximum sum of a subarray of size K: " + findMaxSumSubArray(2, new int[] {2, 3, 4, 1, 5})); 41 | } 42 | 43 | /** Method to find max sum sub array */ 44 | public static int findMaxSumSubArray(int k, int[] arr) { 45 | 46 | int windowSum = 0; 47 | int maxSum = 0; 48 | int windowStart = 0; 49 | 50 | for (int windowEnd = 0; windowEnd < arr.length; windowEnd++) { 51 | 52 | windowSum += arr[windowEnd]; // Add the next element 53 | 54 | // Slide the window, we don't need to slide if we've no hit the 55 | // required window size of k 56 | if (windowEnd >= k - 1) { 57 | maxSum = Math.max(maxSum, windowSum); 58 | windowSum -= arr[windowStart]; // subtract the element going out 59 | windowStart++; // slide the window ahead 60 | } 61 | } 62 | 63 | return maxSum; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/MergeAnArrayWithOverlappingIntervals.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MergeAnArrayWithOverlappingIntervals Class 3 | * 4 | *

5 | * 6 | * @question We’re given an array of interval pairs as input where each interval has a start and end 7 | * timestamp. The input array is sorted by starting timestamps. Merge the overlapping intervals 8 | * and return a new output array. 9 | *

10 | * @note Solution - This problem can be solved in a simple linear scan algorithm. We know that the 11 | * input is sorted by starting timestamps. Here is the approach we are following: 12 | *

Using the given list of input intervals, we keep merged intervals in the output list. 13 | *

For each interval in the input list: If the input interval is overlapping with the last 14 | * interval in the output list, then we merge these two intervals and update the last interval 15 | * of the output list with the merged interval. 16 | *

Otherwise, we add an input interval to the output list. 17 | * @author David Kariuki 18 | * @since 22/8/2022 19 | */ 20 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 21 | 22 | import AceTheJavaCodingInterview.module2_data_structures.tuples.Interval; 23 | 24 | import java.util.ArrayList; 25 | import java.util.Arrays; 26 | 27 | @SuppressWarnings("StringConcatenationInLoop") 28 | public class MergeAnArrayWithOverlappingIntervals { 29 | 30 | /** 31 | * Main method 32 | * 33 | * @param args - String[] 34 | */ 35 | public static void main(String[] args) { 36 | 37 | Interval[] v1 = {new Interval(1, 5), new Interval(3, 7), new Interval(4, 6)}; 38 | 39 | Interval[] v2 = { 40 | new Interval(1, 5), new Interval(4, 6), new Interval(6, 8), new Interval(11, 15) 41 | }; 42 | 43 | Interval[] v3 = { 44 | new Interval(3, 7), new Interval(6, 8), new Interval(10, 12), new Interval(11, 15) 45 | }; 46 | 47 | Interval[] v4 = {new Interval(1, 5)}; 48 | 49 | Interval[][] vList = {v1, v2, v3, v4}; 50 | 51 | for (int i = 0; i < vList.length; i++) { 52 | 53 | ArrayList v = new ArrayList<>(Arrays.asList(vList[i])); 54 | System.out.print(i + 1); 55 | printIntervalList(v); 56 | 57 | ArrayList result = mergeIntervals(v); 58 | String result_str = ""; 59 | 60 | for (int j = 0; j < result.size(); j++) { 61 | result_str += "[" + result.get(j).first + ", " + result.get(j).second + "] "; 62 | } 63 | 64 | System.out.println(" Merged intervals:\t" + result_str); 65 | System.out.println("------------------------------\n"); 66 | } 67 | } 68 | 69 | /** 70 | * Method to merge intervals 71 | * 72 | * @note Time complexity - The time complexity of this solution is linear, O(n). 73 | * @note Space complexity - The space complexity of this solution is linear, O(n). 74 | * @param arrayList - ArrayList 75 | * @return ArrayList 76 | */ 77 | public static ArrayList mergeIntervals(ArrayList arrayList) { 78 | 79 | // If the list is empty 80 | if (arrayList == null || arrayList.size() == 0) { 81 | return null; 82 | } 83 | 84 | ArrayList result = new ArrayList<>(); 85 | 86 | // Adding interval in the result list 87 | result.add(new Interval(arrayList.get(0).first, arrayList.get(0).second)); 88 | 89 | for (int i = 1; i < arrayList.size(); i++) { 90 | 91 | // Getting the recent added interval in the result list 92 | Interval recentAddedInterval = result.get(result.size() - 1); 93 | 94 | // Getting and initializing input interval 95 | int currentStart = arrayList.get(i).first; 96 | int currentEnd = arrayList.get(i).second; 97 | 98 | // Getting and initializing previous end recently added interval from 99 | // result list 100 | int previousEnd = recentAddedInterval.second; 101 | 102 | // Overlapping condition 103 | if (previousEnd >= currentStart) { 104 | recentAddedInterval.second = Math.max(currentEnd, previousEnd); 105 | } 106 | 107 | // No overlapping 108 | else { 109 | result.add(new Interval(currentStart, currentEnd)); 110 | } 111 | } 112 | 113 | return result; 114 | } 115 | 116 | /** 117 | * Method to print the list of intervals 118 | * 119 | * @param list - ArrayList 120 | */ 121 | public static void printIntervalList(ArrayList list) { 122 | 123 | String resultStr = ""; 124 | 125 | for (int i = 0; i < list.size(); i++) { 126 | 127 | Interval p = list.get(i); 128 | 129 | resultStr += "[" + p.first + ", " + p.second + "]"; 130 | 131 | if (i != list.size() - 1) { 132 | resultStr += ","; 133 | } 134 | } 135 | 136 | System.out.println(". Intervals to merge:\t" + resultStr); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/OneDimensionalArrays.java: -------------------------------------------------------------------------------- 1 | /** 2 | * OneDimensionalArrays Class 3 | * 4 | *

5 | * 6 | * @note 7 | * @author David Kariuki 8 | * @since 14/8/2022 9 | */ 10 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 11 | 12 | @SuppressWarnings({"ForLoopReplaceableByForEach", "SameParameterValue"}) 13 | public class OneDimensionalArrays { 14 | 15 | public static final int[] myArray = new int[4]; // Array declaration 16 | 17 | public static void main(String[] args) { 18 | 19 | initArray(); // Array initialization 20 | showArrayElements(); 21 | updateArrayElement(2, 50); 22 | showArrayElements(); 23 | } 24 | 25 | /** 26 | * Method to initialize array 27 | */ 28 | public static void initArray() { 29 | 30 | // Adding elements in an array 31 | myArray[0] = 10; 32 | myArray[1] = 20; 33 | myArray[2] = 30; 34 | myArray[3] = 40; 35 | } 36 | 37 | /** 38 | * Method to update array element 39 | * 40 | */ 41 | public static void updateArrayElement(final int index, final int value) { 42 | myArray[index] = value; 43 | } 44 | 45 | /** Method to show array elements */ 46 | public static void showArrayElements() { 47 | 48 | System.out.println("\nPrinting array elements\n"); 49 | 50 | // Accessing elements in an array 51 | for (int i = 0; i < myArray.length; i++) { 52 | System.out.println(myArray[i]); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/PairWithTargetSum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * PairWithTargetSum Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement - Given an array of sorted numbers and a target sum, find a pair in 7 | * the array whose sum is equal to the given target. 8 | *

Write a function to return the indices of the two numbers (i.e. the pair) such that they 9 | * add up to the given target. 10 | * @note Example 1: 11 | *

Input: [1, 2, 3, 4, 6], target=6 Output: [1, 3] Explanation: The numbers at index 1 and 3 12 | * add up to 6: 2 + 4 = 6 13 | * @note Example 2: 14 | *

Input: [2, 5, 9, 11], target=11 Output: [0, 2] Explanation: The numbers at index 0 and 2 15 | * add up to 11: 2 + 9 = 11 16 | * @note Solution - Since the given array is sorted, a brute-force solution could be to iterate 17 | * through the array, taking one number at a time and searching for the second number through 18 | * Binary Search. The time complexity of this algorithm will be O(N*logN). Can we do better than 19 | * this? 20 | *

21 | *

We can follow the Two Pointers approach. We will start with one pointer pointing to the 22 | * beginning of the array and another pointing at the end. At every step, we will see if the 23 | * numbers pointed by the two pointers add up to the target sum. If they do, we have found our 24 | * pair; otherwise, we will do one of two things: 25 | *

1. If the sum of the two numbers pointed by the two pointers is greater than the target 26 | * sum, this means that we need a pair with a smaller sum. So, to try more pairs, we can 27 | * decrement the end-pointer. 28 | *

2. If the sum of the two numbers pointed by the two pointers is smaller than the target 29 | * sum, this means that we need a pair with a larger sum. So, to try more pairs, we can 30 | * increment the start-pointer. 31 | *

32 | * @note Time Complexity - The time complexity of the above algorithm will be O(N), where N is the 33 | * total number of elements in the given array. 34 | * @note Space Complexity - The space complexity will also be O(N), as, in the worst case, we will 35 | * be pushing N numbers in the HashTable. 36 | * @author David Kariuki 37 | * @since 24/8/2022 38 | */ 39 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 40 | 41 | public class PairWithTargetSum { 42 | 43 | /** 44 | * Main method 45 | * 46 | * @param args - String[] 47 | */ 48 | public static void main(String[] args) { 49 | 50 | int[] result = PairWithTargetSum.search(new int[] {1, 2, 3, 4, 6}, 6); 51 | System.out.println("Pair with target sum: [" + result[0] + ", " + result[1] + "]"); 52 | 53 | result = PairWithTargetSum.search(new int[] {2, 5, 9, 11}, 11); 54 | System.out.println("Pair with target sum: [" + result[0] + ", " + result[1] + "]"); 55 | } 56 | 57 | /** 58 | * Method to search array 59 | * 60 | * @param arr - int[] 61 | * @param targetSum - 62 | * @return int[] 63 | */ 64 | public static int[] search(int[] arr, int targetSum) { 65 | 66 | int left = 0; 67 | int right = arr.length - 1; 68 | 69 | while (left < right) { 70 | 71 | int currentSum = arr[left] + arr[right]; 72 | 73 | // Check if current sum equals target sum 74 | if (currentSum == targetSum) { 75 | return new int[] {left, right}; 76 | } 77 | 78 | // Compare current and target sum 79 | if (currentSum > targetSum) { 80 | right--; // We need a pair with a smaller sum 81 | } else { 82 | left++; // We need a pair with a bigger sum 83 | } 84 | } 85 | 86 | return new int[] {-1, -1}; // Return int pair with -1 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/Permutations.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Permutations Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement# Given a set of distinct numbers, find all of its permutations. 7 | *

Permutation is defined as the re-arranging of the elements of the set. 8 | * @note Example, {1, 2, 3} has the following six permutations: 9 | *

{1, 2, 3} {1, 3, 2} {2, 1, 3} {2, 3, 1} {3, 1, 2} {3, 2, 1} 10 | *

If a set has n distinct elements it will have n! n! permutations. 11 | * @note Solution This problem follows the Subsets pattern ({@link 12 | * AceTheJavaCodingInterview.module2_data_structures.arrays.Subset}) and, we can follow a 13 | * similar Breadth First Search (BFS) approach. However, unlike Subsets, every permutation must 14 | * contain all the numbers. 15 | *

Let’s take the example-1 mentioned above to generate all the permutations. Following a BFS 16 | * approach, we will consider one number at a time: 17 | *

1. If the given set is empty then we have only an empty permutation set: [] 18 | *

2. Let’s add the first element (1), the permutations will be: [1] 19 | *

3. Let’s add the second element (3), the permutations will be: [3,1], [1,3] 20 | *

4. Let’s add the third element (5), the permutations will be: [5,3, 1], [3,5,1], [3,1,5], 21 | * [5,1,3], [1,5,3], [1,3,5] 22 | *

23 | *

Let’s analyze the permutations in the 3rd and 4th steps. How can we generate permutations 24 | * in the 4th step from the permutations of the 3rd step? 25 | *

If we look closely, we will realize that when we add a new number (5), we take each 26 | * permutation of the previous step and insert the new number in every position to generate the 27 | * new permutations. For example, inserting 5 in different positions of [3,1] will give us the 28 | * following permutations: 29 | *

Inserting 5 before 3: [5,3,1] 30 | *

Inserting 5 between 3 and 1: [3,5,1] 31 | *

Inserting 5 after 1: [3,1,5] 32 | *

33 | * @note Time complexity - We know that there are a total of N! permutations of a set with N 34 | * numbers. In the algorithm above, we are iterating through all of these permutations with the 35 | * help of the two for loops. In each iteration, we go through all the current permutations to 36 | * insert a new number in them. To insert a number into a permutation of size N will take O(N), 37 | * which makes the overall time complexity of our algorithm O(N*N!). 38 | * @note Space complexity - All the additional space used by our algorithm is for the result list 39 | * and the queue to store the intermediate permutations. If you see closely, at any time, we 40 | * don’t have more than N! permutations between the result list and the queue. Therefore, the 41 | * overall space complexity to store N! permutations each containing N elements will be O(N*N!). 42 | * @see AceTheJavaCodingInterview.module2_data_structures.arrays.Subset 43 | * @see AceTheJavaCodingInterview.module2_data_structures.arrays.SubsetsWithDuplicates 44 | * @author David Kariuki 45 | * @since 24/8/2022 46 | */ 47 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 48 | 49 | import java.util.ArrayList; 50 | import java.util.LinkedList; 51 | import java.util.List; 52 | import java.util.Queue; 53 | 54 | public class Permutations { 55 | 56 | /** 57 | * Main method 58 | * 59 | * @param args - String[] 60 | */ 61 | public static void main(String[] args) { 62 | 63 | List> result = Permutations.findPermutations(new int[] {1, 3, 5}); 64 | System.out.print("Here are all the permutations: " + result); 65 | } 66 | 67 | /** 68 | * Method to find permutation of an array 69 | * 70 | * @param nums - int[] 71 | * @return List> 72 | */ 73 | @SuppressWarnings("ConstantConditions") 74 | public static List> findPermutations(int[] nums) { 75 | 76 | List> result = new ArrayList<>(); 77 | Queue> permutations = new LinkedList<>(); 78 | permutations.add(new ArrayList<>()); 79 | 80 | for (int currentNumber : nums) { 81 | 82 | // Take all existing permutations and add the current number to create new 83 | // permutations 84 | int n = permutations.size(); 85 | 86 | for (int i = 0; i < n; i++) { 87 | List oldPermutation = permutations.poll(); 88 | 89 | // create a new permutation by adding the current number at every position 90 | for (int j = 0; j <= oldPermutation.size(); j++) { 91 | 92 | List newPermutation = new ArrayList<>(oldPermutation); 93 | newPermutation.add(j, currentNumber); 94 | 95 | if (newPermutation.size() == nums.length) { 96 | result.add(newPermutation); 97 | } else { 98 | permutations.add(newPermutation); 99 | } 100 | } 101 | } 102 | } 103 | return result; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/SmallestSubarrayWithAGreaterSum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SmallestSubarrayWithAGreaterSum Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement Given an array of positive numbers and a positive number ‘S,’ find 7 | * the length of the smallest contiguous subarray whose sum is greater than or equal to ‘S’. 8 | * Return 0 if no such subarray exists. 9 | *

10 | * @note Solution - This problem follows the Sliding Window pattern. In this problem, the sliding 11 | * window size is not fixed. Here is how we will solve this problem: 12 | *

First, we will add-up elements from the beginning of the array until their sum becomes 13 | * greater than or equal to ‘S.’ 14 | *

These elements will constitute our sliding window. We are asked to find the smallest such 15 | * window having a sum greater than or equal to ‘S.’ We will remember the length of this window 16 | * as the smallest window so far. 17 | *

After this, we will keep adding one element in the sliding window (i.e., slide the window 18 | * ahead) in a stepwise fashion. 19 | *

In each step, we will also try to shrink the window from the beginning. We will shrink the 20 | * window until the window’s sum is smaller than ‘S’ again. This is needed as we intend to find 21 | * the smallest window. This shrinking will also happen in multiple steps; in each step, we will 22 | * do two things: - Check if the current window length is the smallest so far, and if so, 23 | * remember its length. -Subtract the first element of the window from the running sum to shrink 24 | * the sliding window. 25 | *

26 | * @note Time Complexity - The time complexity of the above algorithm will be O(N) . The outer for 27 | * loop runs for all elements, and the inner while loop processes each element only once; 28 | * therefore, the time complexity of the algorithm will be O(N+N), which is asymptotically 29 | * equivalent to O(N) . 30 | * @note Space Complexity - The algorithm runs in constant space O(1) . 31 | * @author David Kariuki 32 | * @since 23/8/2022 33 | */ 34 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 35 | 36 | public class SmallestSubarrayWithAGreaterSum { 37 | 38 | /** 39 | * Main method 40 | * 41 | * @param args - String[] 42 | */ 43 | public static void main(String[] args) { 44 | 45 | int result = findMinSubArray(7, new int[] {2, 1, 5, 2, 3, 2}); 46 | System.out.println("Smallest subarray length: " + result); 47 | result = findMinSubArray(7, new int[] {2, 1, 5, 2, 8}); 48 | System.out.println("Smallest subarray length: " + result); 49 | result = findMinSubArray(8, new int[] {3, 4, 1, 1, 6}); 50 | System.out.println("Smallest subarray length: " + result); 51 | } 52 | 53 | /** Method to find min sub array */ 54 | public static int findMinSubArray(int S, int[] arr) { 55 | 56 | int windowSum = 0, minLength = Integer.MAX_VALUE; 57 | int windowStart = 0; 58 | for (int windowEnd = 0; windowEnd < arr.length; windowEnd++) { 59 | windowSum += arr[windowEnd]; // add the next element 60 | // shrink the window as small as possible until the 'windowSum' is smaller than 'S' 61 | while (windowSum >= S) { 62 | minLength = Math.min(minLength, windowEnd - windowStart + 1); 63 | windowSum -= arr[windowStart]; // subtract the element going out 64 | windowStart++; // slide the window ahead 65 | } 66 | } 67 | 68 | return minLength == Integer.MAX_VALUE ? 0 : minLength; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/SquaringASortedArray.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SquaringASortedArray Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement - Given a sorted array, create a new array containing squares of all 7 | * the numbers of the input array in the sorted order. 8 | *

9 | * @note Solution - use two-pointers starting at both ends of the input array. At any step, 10 | * whichever pointer gives us the bigger square, we add it to the result array and move to the 11 | * next/previous number according to the pointer. 12 | *

13 | * @note Time complexity - The above algorithm’s time complexity will be O(N) O(N) as we are 14 | * iterating the input array only once. 15 | *

16 | * @note Space complexity - The above algorithm’s space complexity will also be O(N) O(N) ; this 17 | * space will be used for the output array. 18 | * @author David Kariuki 19 | * @since 23/8/2022 20 | */ 21 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 22 | 23 | public class SquaringASortedArray { 24 | 25 | /** 26 | * Main method 27 | * 28 | * @param args - String[] 29 | */ 30 | public static void main(String[] args) { 31 | int[] result = SquaringASortedArray.makeSquares(new int[] {-2, -1, 0, 2, 3}); 32 | for (int num : result) System.out.print(num + " "); 33 | System.out.println(); 34 | 35 | result = SquaringASortedArray.makeSquares(new int[] {-3, -1, 0, 1, 2}); 36 | for (int num : result) System.out.print(num + " "); 37 | System.out.println(); 38 | } 39 | 40 | /** 41 | * Method to make squares 42 | * 43 | * @param arr - int[] 44 | * @return int[] 45 | */ 46 | public static int[] makeSquares(int[] arr) { 47 | 48 | int n = arr.length; 49 | int[] squares = new int[n]; 50 | 51 | int highestSquareIdx = n - 1; 52 | 53 | int left = 0; 54 | int right = arr.length - 1; 55 | 56 | while (left <= right) { 57 | 58 | int leftSquare = arr[left] * arr[left]; 59 | int rightSquare = arr[right] * arr[right]; 60 | 61 | if (leftSquare > rightSquare) { 62 | squares[highestSquareIdx--] = leftSquare; 63 | left++; 64 | } else { 65 | squares[highestSquareIdx--] = rightSquare; 66 | right--; 67 | } 68 | } 69 | 70 | return squares; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/SubArraysWithProductLessThanTarget.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SubArraysWithProductLessThanTarget Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement - Given an array with positive numbers and a positive target number, 7 | * find all of its contiguous sub-arrays whose product is less than the target number. 8 | * @example Example 1: 9 | *

Input: [2, 5, 3, 10], target=30 Output: [2], [5], [2, 5], [3], [5, 3], [10] Explanation: 10 | * There are six contiguous sub-arrays whose product is less than the target. 11 | * @example Example 2: 12 | *

Input: [8, 2, 6, 5], target=50 Output: [8], [2], [8, 2], [6], [2, 6], [5], [6, 5] 13 | * Explanation: There are seven contiguous sub-arrays whose product is less than the target. 14 | * @note Solution - This problem follows the Sliding Window and the Two Pointers pattern and shares 15 | * similarities with Triplets with Smaller Sum 16 | *

({@link 17 | * AceTheJavaCodingInterview.module2_data_structures.arrays.TripletsWithSmallerSum_ReturnCount}, 18 | * {@link 19 | * AceTheJavaCodingInterview.module2_data_structures.arrays.TripletsWithSmallerSum_ReturnList}) 20 | * with two differences: 21 | *

In this problem, the input array is not sorted. Instead of finding triplets with sum less 22 | * than a target, we need to find all sub-arrays having a product less than the target. The 23 | * implementation will be quite similar to Triplets with Smaller Sum. 24 | * @note Time Complexity - 25 | * @note Space Complexity - 26 | * @author David Kariuki 27 | * @since 26/8/2022 28 | * @see AceTheJavaCodingInterview.module2_data_structures.arrays.TripletsWithSmallerSum_ReturnCount 29 | * @see AceTheJavaCodingInterview.module2_data_structures.arrays.TripletsWithSmallerSum_ReturnList 30 | */ 31 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 32 | 33 | import java.util.ArrayList; 34 | import java.util.LinkedList; 35 | import java.util.List; 36 | 37 | public class SubArraysWithProductLessThanTarget { 38 | 39 | /** 40 | * Main method 41 | * 42 | * @param args - String[] 43 | */ 44 | public static void main(String[] args) { 45 | System.out.println( 46 | SubArraysWithProductLessThanTarget.findSubArrays(new int[] {2, 5, 3, 10}, 30)); 47 | System.out.println( 48 | SubArraysWithProductLessThanTarget.findSubArrays(new int[] {8, 2, 6, 5}, 50)); 49 | } 50 | 51 | /** 52 | * Method to find sub arrays 53 | * 54 | * @param arr - int[] 55 | * @param target - int 56 | * @return List> 57 | */ 58 | public static List> findSubArrays(int[] arr, int target) { 59 | 60 | List> result = new ArrayList<>(); 61 | 62 | double product = 1; 63 | int left = 0; 64 | 65 | // Traverse array 66 | for (int right = 0; right < arr.length; right++) { 67 | 68 | product *= arr[right]; 69 | 70 | while (product >= target && left < arr.length) { 71 | product /= arr[left++]; 72 | } 73 | 74 | // Since the product of all numbers from left to right is less than the 75 | // target therefore, all sub-arrays from left to right will have a 76 | // product less than the target too; to avoid duplicates, we will start 77 | // with a sub-array containing only arr[right] and then extend it. 78 | List tempList = new LinkedList<>(); 79 | 80 | for (int i = right; i >= left; i--) { 81 | tempList.add(0, arr[i]); 82 | result.add(new ArrayList<>(tempList)); 83 | } 84 | } 85 | 86 | return result; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/Subset.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Subset Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement - Given a set with distinct elements, find all of its distinct 7 | * subsets. 8 | *

9 | * @note Solution - To generate all subsets of the given set, we can use the Breadth First Search 10 | * (BFS) approach. We can start with an empty set, iterate through all numbers one-by-one, and 11 | * add them to existing sets to create new subsets. 12 | *

Let’s take the example-2 mentioned above to go through each step of our algorithm: 13 | *

Given set: [1, 5, 3] 14 | *

Start with an empty set: [[]] Add the first number (1) to all the existing subsets to 15 | * create new subsets: [[], [1]]; Add the second number (5) to all the existing subsets: [[], 16 | * [1], [5], [1,5]]; Add the third number (3) to all the existing subsets: [[], [1], [5], [1,5], 17 | * [3], [1,3], [5,3], [1,5,3]]. 18 | *

19 | * @note Time complexity - Since, in each step, the number of subsets doubles as we add each element 20 | * to all the existing subsets, therefore, we will have a total of O(2^N) subsets, where ‘N’ is 21 | * the total number of elements in the input set. And since we construct a new subset from an 22 | * existing set, therefore, the time complexity of the above algorithm will be O(N*2^N). 23 | *

24 | * @note Space complexity - All the additional space used by our algorithm is for the output list. 25 | * Since we will have a total of O(2^N) O(2 N ) subsets, and each subset can take up to O(N) 26 | * space, therefore, the space complexity of our algorithm will be O(N*2^N). 27 | *

28 | * @author David Kariuki 29 | * @since 23/8/2022 30 | */ 31 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 32 | 33 | import java.util.ArrayList; 34 | import java.util.List; 35 | 36 | public class Subset { 37 | 38 | /** 39 | * Main method 40 | * 41 | * @param args - String[] 42 | */ 43 | public static void main(String[] args) { 44 | 45 | List> result = Subset.findSubsets(new int[] {1, 3}); 46 | System.out.println("Here is the list of subsets: " + result); 47 | 48 | result = Subset.findSubsets(new int[] {1, 5, 3}); 49 | System.out.println("Here is the list of subsets: " + result); 50 | } 51 | 52 | /** 53 | * Method to find subset 54 | * 55 | * @param nums - int[] 56 | * @return List> 57 | */ 58 | public static List> findSubsets(int[] nums) { 59 | 60 | List> subsets = new ArrayList<>(); 61 | 62 | // Start by adding the empty subset 63 | subsets.add(new ArrayList<>()); 64 | 65 | System.out.println("Adding empty to subset."); 66 | 67 | for (int currentNumber : nums) { 68 | 69 | System.out.println(); 70 | 71 | // Take all existing subsets and insert the current number in them to 72 | // create new subsets 73 | int n = subsets.size(); 74 | 75 | for (int i = 0; i < n; i++) { 76 | 77 | // Create a new subset from the existing subsets and insert the 78 | // current element to it 79 | List set = new ArrayList<>(subsets.get(i)); 80 | System.out.println("Adding current number : " + currentNumber + " to " + "set : " + set); 81 | set.add(currentNumber); 82 | System.out.println("Adding set : " + set + " to subset : " + subsets); 83 | subsets.add(set); 84 | } 85 | } 86 | 87 | return subsets; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/SubsetsWithDuplicates.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SubsetsWithDuplicates Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement - Given a set of numbers that might contain duplicates, find all of 7 | * its distinct subsets. 8 | * @note Solution - This problem follows the Subsets pattern and we can follow a similar Breadth 9 | * First Search (BFS) approach. The only additional thing we need to do is handle duplicates. 10 | * Since the given set can have duplicate numbers, if we follow the same approach discussed in 11 | * Subsets, we will end up with duplicate subsets, which is not acceptable. To handle this, we 12 | * will do two extra things: 13 | *

Sort all numbers of the given set. This will ensure that all duplicate numbers are next to 14 | * each other. Follow the same BFS approach but whenever we are about to process a duplicate 15 | * (i.e., when the current and the previous numbers are same), instead of adding the current 16 | * number (which is a duplicate) to all the existing subsets, only add it to the subsets which 17 | * were created in the previous step. 18 | *

19 | * @note Example 20 | *

Given set: [1, 5, 3, 3] Sorted set: [1, 3, 3, 5] 21 | *

Start with an empty set: [[]] 22 | *

Add the first number (1) to all the existing subsets to create new subsets: [[], [1]]; 23 | *

Add the second number (3) to all the existing subsets: [[], [1], [3], [1,3]]. 24 | *

The next number (3) is a duplicate. If we add it to all existing subsets we will get: 25 | *

[[], [1], [3], [1,3], [3], [1,3], [3,3], [1,3,3]] 26 | *

We got two duplicate subsets: [3], [1,3] Whereas we only needed the new subsets: [3,3], 27 | * [1,3,3] 28 | *

To handle this instead of adding (3) to all the existing subsets, we only add it to the 29 | * new subsets which were created in the previous (3rd) step: 30 | *

[[], [1], [3], [1,3], [3,3], [1,3,3]] 31 | *

Finally, add the forth number (5) to all the existing subsets: 32 | *

[[], [1], [3], [1,3], [3,3], [1,3,3], [5], [1,5], [3,5], [1,3, 5], [3, 3,5], [1,3,3,5]] 33 | *

34 | * @note Time complexity - Since, in each step, the number of subsets doubles (if not duplicate) as 35 | * we add each element to all the existing subsets, therefore, we will have a total of O(2^N) 36 | * subsets, where ‘N’ is the total number of elements in the input set. And since we construct a 37 | * new subset from an existing set, therefore, the time complexity of the above algorithm will 38 | * be O(N*2^N) O(N∗2 N ) . 39 | *

Space complexity# All the additional space used by our algorithm is for the output list. 40 | * Since, at most, we will have a total of O(2^N) subsets, and each subset can take up to O(N) 41 | * space, therefore, the space complexity of our algorithm will be O(N*2^N). 42 | * @author David Kariuki 43 | * @since 24/8/2022 44 | */ 45 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 46 | 47 | import java.util.ArrayList; 48 | import java.util.Arrays; 49 | import java.util.List; 50 | 51 | @SuppressWarnings("SameParameterValue") 52 | public class SubsetsWithDuplicates { 53 | 54 | /** 55 | * Main method 56 | * 57 | * @param args - String[] 58 | */ 59 | public static void main(String[] args) { 60 | 61 | List> result = SubsetsWithDuplicates.findSubsets(new int[] {1, 3, 3}); 62 | System.out.println("Here is the list of subsets: " + result); 63 | 64 | result = SubsetsWithDuplicates.findSubsets(new int[] {1, 5, 3, 3}); 65 | System.out.println("Here is the list of subsets: " + result); 66 | } 67 | 68 | /** 69 | * Method to find subsets 70 | * 71 | * @param nums - int[] 72 | * @return List> 73 | */ 74 | @SuppressWarnings("UnusedAssignment") 75 | public static List> findSubsets(int[] nums) { 76 | 77 | // Sort numbers to handle duplicates 78 | Arrays.sort(nums); 79 | List> subsets = new ArrayList<>(); 80 | subsets.add(new ArrayList<>()); 81 | 82 | int startIndex = 0; 83 | int endIndex = 0; 84 | 85 | for (int i = 0; i < nums.length; i++) { 86 | 87 | startIndex = 0; 88 | 89 | // If the current and previous elements are the same, create new 90 | // subsets only from the subsets added in the previous step 91 | if (i > 0 && nums[i] == nums[i - 1]) { 92 | startIndex = endIndex + 1; 93 | } 94 | 95 | endIndex = subsets.size() - 1; 96 | 97 | for (int j = startIndex; j <= endIndex; j++) { 98 | 99 | // Create a new subset from the existing subset and add the current 100 | // element to it 101 | List set = new ArrayList<>(subsets.get(j)); 102 | set.add(nums[i]); 103 | subsets.add(set); 104 | } 105 | } 106 | 107 | return subsets; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/TripletSumCloseToTarget.java: -------------------------------------------------------------------------------- 1 | /** 2 | * TripletSumCloseToTarget Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement# Given an array of unsorted numbers and a target number, find a 7 | * triplet in the array whose sum is as close to the target number as possible, return the sum 8 | * of the triplet. If there are more than one such triplet, return the sum of the triplet with 9 | * the smallest sum. 10 | * @note Solution - This problem follows the Two Pointers pattern and is quite similar to Triplet 11 | * Sum to Zero({@link 12 | * AceTheJavaCodingInterview.module2_data_structures.arrays.TripletSumToZero}). 13 | *

We can follow a similar approach to iterate through the array, taking one number at a 14 | * time. At every step, we will save the difference between the triplet and the target number, 15 | * so that in the end, we can return the triplet with the closest sum. 16 | * @note Time Complexity - Sorting the array will take O(N * logN). Overall, the function will take 17 | * O(N * logN + N^2), which is asymptotically equivalent to O(N^2). 18 | * @note Space Complexity - The above algorithm’s space complexity will be O(N), which is required 19 | * for sorting. 20 | * @author David Kariuki 21 | * @since 25/8/2022 22 | * @see AceTheJavaCodingInterview.module2_data_structures.arrays.TripletSumToZero 23 | */ 24 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 25 | 26 | import java.util.Arrays; 27 | 28 | public class TripletSumCloseToTarget { 29 | 30 | /** 31 | * Main method 32 | * 33 | * @param args - String[] 34 | */ 35 | public static void main(String[] args) { 36 | 37 | System.out.println(TripletSumCloseToTarget.searchTriplet(new int[] {-2, 0, 1, 2}, 2)); 38 | System.out.println(TripletSumCloseToTarget.searchTriplet(new int[] {-3, -1, 1, 2}, 1)); 39 | System.out.println(TripletSumCloseToTarget.searchTriplet(new int[] {1, 0, 1, 1}, 100)); 40 | } 41 | 42 | /** 43 | * Method to search for triplet 44 | * 45 | * @param arr - int[] 46 | * @param targetSum - int 47 | */ 48 | public static int searchTriplet(int[] arr, int targetSum) { 49 | 50 | if (arr == null || arr.length < 3) { 51 | throw new IllegalArgumentException(); 52 | } 53 | 54 | Arrays.sort(arr); 55 | 56 | int smallestDifference = Integer.MAX_VALUE; 57 | 58 | for (int i = 0; i < arr.length - 2; i++) { 59 | 60 | int left = i + 1; 61 | int right = arr.length - 1; 62 | 63 | while (left < right) { 64 | 65 | // Comparing sum of 3 numbers to the targetSum can cause overflow so, 66 | // try to find a target difference 67 | int targetDiff = targetSum - arr[i] - arr[left] - arr[right]; 68 | 69 | if (targetDiff == 0) { 70 | // Found triplet with exact sum thus return sum of all the numbers 71 | return targetSum; 72 | } 73 | 74 | // the second part of the above 'if' is to handle the smallest sum when we have more than 75 | // one solution 76 | if (Math.abs(targetDiff) < Math.abs(smallestDifference) 77 | || (Math.abs(targetDiff) == Math.abs(smallestDifference) 78 | && targetDiff > smallestDifference)) 79 | smallestDifference = targetDiff; // save the closest and the biggest difference 80 | 81 | if (targetDiff > 0) { 82 | left++; // we need a triplet with a bigger sum 83 | } else { 84 | right--; // we need a triplet with a smaller sum 85 | } 86 | } 87 | } 88 | 89 | return targetSum - smallestDifference; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/TripletSumToZero.java: -------------------------------------------------------------------------------- 1 | /** 2 | * TripletSumToZero Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement - Given an array of unsorted numbers, find all unique triplets in it 7 | * that add up to zero. 8 | *

9 | * @example Example 1: 10 | *

Input: [-3, 0, 1, 2, -1, 1, -2] Output: [-3, 1, 2], [-2, 0, 2], [-2, 1, 1], [-1, 0, 1] 11 | * Explanation: There are four unique triplets whose sum is equal to zero. 12 | * @example Example 2: 13 | *

Input: [-5, 2, -1, -2, 3] Output: [[-5, 2, 3], [-2, -1, 3]] Explanation: There are two 14 | * unique triplets whose sum is equal to zero. 15 | * @solution Solution - This problem follows the Two Pointers pattern and shares similarities with 16 | * Pair with Target Sum ({@link 17 | * AceTheJavaCodingInterview.module2_data_structures.arrays.PairWithTargetSum}). A couple of 18 | * differences are that the input array is not sorted and instead of a pair we need to find 19 | * triplets with a target sum of zero. 20 | *

To follow a similar approach, first, we will sort the array and then iterate through it 21 | * taking one number at a time. Let’s say during our iteration we are at number ‘X’, so we need 22 | * to find ‘Y’ and ‘Z’ such that X + Y + Z == 0. At this stage, our problem translates into 23 | * finding a pair whose sum is equal to -X (as from the above equation Y + Z == -X). 24 | *

25 | *

Another difference from Pair with Target Sum({@link 26 | * AceTheJavaCodingInterview.module2_data_structures.arrays.PairWithTargetSum}) is that we need 27 | * to find all the unique triplets. To handle this, we have to skip any duplicate number. Since 28 | * we will be sorting the array, so all the duplicate numbers will be next to each other and are 29 | * easier to skip. 30 | * @note Time complexity - Sorting the array will take O(N * logN). The searchPair() function will 31 | * take O(N). As we are calling searchPair() for every number in the input array, this means 32 | * that overall searchTriplets() will take O(N * logN + N^2), which is asymptotically equivalent 33 | * to O(N^2). 34 | * @note Space complexity - Ignoring the space required for the output array, the space complexity 35 | * of the above algorithm will be O(N) which is required for sorting. 36 | * @see AceTheJavaCodingInterview.module2_data_structures.arrays.PairWithTargetSum 37 | * @see AceTheJavaCodingInterview.module2_data_structures.hash_tables.PairWithTargetSum 38 | * @author David Kariuki 39 | * @since 25/8/2022 40 | */ 41 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 42 | 43 | import java.util.ArrayList; 44 | import java.util.Arrays; 45 | import java.util.List; 46 | 47 | public class TripletSumToZero { 48 | 49 | /** 50 | * Main method 51 | * 52 | * @param args - String[] 53 | */ 54 | public static void main(String[] args) { 55 | 56 | System.out.println(TripletSumToZero.searchTriplets(new int[] {-3, 0, 1, 2, -1, 1, -2})); 57 | System.out.println(TripletSumToZero.searchTriplets(new int[] {-5, 2, -1, -2, 3})); 58 | } 59 | 60 | /** 61 | * Method to search for triplets 62 | * 63 | * @param arr - int[] 64 | * @return List> 65 | */ 66 | public static List> searchTriplets(int[] arr) { 67 | 68 | Arrays.sort(arr); // Sort array 69 | 70 | List> triplets = new ArrayList<>(); 71 | 72 | // Traverse array 73 | for (int i = 0; i < arr.length - 2; i++) { 74 | if (i > 0 && arr[i] == arr[i - 1]) { 75 | continue; // Skip element to avoid duplicate triplets 76 | } 77 | 78 | searchPair(arr, -arr[i], i + 1, triplets); // Search pair 79 | } 80 | 81 | return triplets; 82 | } 83 | 84 | /** 85 | * Method to search for triplets 86 | * 87 | * @param arr - int[] 88 | * @param targetSum - int 89 | * @param left - int 90 | * @param triplets - List> 91 | */ 92 | public static void searchPair(int[] arr, int targetSum, int left, List> triplets) { 93 | 94 | int right = arr.length - 1; 95 | 96 | while (left < right) { 97 | 98 | int currentSum = arr[left] + arr[right]; 99 | 100 | if (currentSum == targetSum) { 101 | 102 | // Found the triplet 103 | triplets.add(Arrays.asList(-targetSum, arr[left], arr[right])); 104 | left++; 105 | right--; 106 | 107 | while (left < right && arr[left] == arr[left - 1]) { 108 | left++; // Skip same element to avoid duplicate triplets 109 | } 110 | 111 | while (left < right && arr[right] == arr[right + 1]) { 112 | right--; // Skip same element to avoid duplicate triplets 113 | } 114 | } else if (targetSum > currentSum) { 115 | left++; // Pair with a bigger sum 116 | } else { 117 | right--; // Pair with a smaller sum 118 | } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/TripletsWithSmallerSum_ReturnCount.java: -------------------------------------------------------------------------------- 1 | /** 2 | * TripletsWithSmallerSum_ReturnCount Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement - Write a function to return the list of all such triplets instead of 7 | * the count. How will the time complexity change in this case? 8 | * @note Solution - Following a similar approach we can create a list containing all the triplets. 9 | * Another simpler approach could be to check every triplet of the array with three nested loops 10 | * and create a list of triplets that meet the required condition. 11 | * @note Time Complexity - Sorting the array will take O(N * logN). The searchPair(), in this case, 12 | * will take O(N^2). The main while loop will run in O(N)but the nested for loop can also take 13 | * O(N) - this will happen when the target sum is bigger than every triplet in the array. 14 | *

So, overall searchTriplets() will take O(N * logN + N^3), which is asymptotically 15 | * equivalent to O(N^3). 16 | * @note Space Complexity - Ignoring the space required for the output array, the space complexity 17 | * of the above algorithm will be O(N) which is required for sorting. 18 | * @author David Kariuki 19 | * @since 26/8/2022 20 | * @see AceTheJavaCodingInterview.module2_data_structures.arrays.TripletSumToZero 21 | */ 22 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 23 | 24 | import java.util.ArrayList; 25 | import java.util.Arrays; 26 | import java.util.List; 27 | 28 | public class TripletsWithSmallerSum_ReturnCount { 29 | 30 | /** 31 | * Main method 32 | * 33 | * @param args - String[] 34 | */ 35 | public static void main(String[] args) { 36 | System.out.println( 37 | TripletsWithSmallerSum_ReturnCount.searchTriplets(new int[] {-1, 0, 2, 3}, 3)); 38 | System.out.println( 39 | TripletsWithSmallerSum_ReturnCount.searchTriplets(new int[] {-1, 4, 2, 1, 3}, 5)); 40 | } 41 | 42 | /** 43 | * Method to search for triplets 44 | * 45 | * @param arr - int[] 46 | * @param target - int 47 | * @return List> 48 | */ 49 | public static List> searchTriplets(int[] arr, int target) { 50 | 51 | Arrays.sort(arr); // Sort array 52 | 53 | List> triplets = new ArrayList<>(); 54 | 55 | for (int i = 0; i < arr.length - 2; i++) { 56 | searchPair(arr, target - arr[i], i, triplets); 57 | } 58 | 59 | return triplets; 60 | } 61 | 62 | /** 63 | * Method to search for pairs 64 | * 65 | * @param arr - int[] 66 | * @param targetSum - int 67 | * @param first - int 68 | * @param triplets - List> 69 | */ 70 | public static void searchPair(int[] arr, int targetSum, int first, List> triplets) { 71 | 72 | int left = first + 1; 73 | int right = arr.length - 1; 74 | 75 | while (left < right) { 76 | 77 | if (arr[left] + arr[right] < targetSum) { 78 | // Found the triplet. Since arr[right] >= arr[left], therefore, we can 79 | // replace arr[right] by any number between left and right to get a sum 80 | // less than the target sum 81 | 82 | for (int i = right; i > left; i--) { 83 | triplets.add(Arrays.asList(arr[first], arr[left], arr[i])); 84 | } 85 | 86 | left++; 87 | 88 | } else { 89 | right--; // Need a pair with a smaller sum 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/TripletsWithSmallerSum_ReturnList.java: -------------------------------------------------------------------------------- 1 | /** 2 | * TripletsWithSmallerSum_ReturnList Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement - Given an array arr of unsorted numbers and a target sum, count all 7 | * triplets in it such that arr[i] + arr[j] + arr[k] < target where i, j, and k are three 8 | * different indices. Write a function to return the count of such triplets. 9 | * @example Example 1: 10 | *

Input: [-1, 0, 2, 3], target=3 Output: 2 Explanation: There are two triplets whose sum is 11 | * less than the target: [-1, 0, 3], [-1, 0, 2] 12 | * @example Example 2: 13 | *

Input: [-1, 4, 2, 1, 3], target=5 Output: 4 Explanation: There are four triplets whose sum 14 | * is less than the target: [-1, 1, 4], [-1, 1, 3], [-1, 1, 2], [-1, 2, 3] 15 | * @note Solution - This problem follows the Two Pointers pattern and shares similarities with 16 | * Triplet Sum to Zero ({@link 17 | * AceTheJavaCodingInterview.module2_data_structures.arrays.TripletSumToZero}). The only 18 | * difference is that, in this problem, we need to find the triplets whose sum is less than the 19 | * given target. To meet the condition i != j != k we need to make sure that each number is not 20 | * used more than once. 21 | *

Following a similar approach, first, we can sort the array and then iterate through it, 22 | * taking one number at a time. Let’s say during our iteration we are at number ‘X’, so we need 23 | * to find ‘Y’ and ‘Z’ such that X + Y + Z < target X+Y+Z= arr[left], therefore, we can 89 | // replace arr[right] by any number between left and right to get a sum 90 | // less than the target sum 91 | count += right - left; 92 | left++; 93 | } else { 94 | right--; // Need a pair with a smaller sum 95 | } 96 | } 97 | 98 | return count; // Return count 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/TwoDimensionalArrays.java: -------------------------------------------------------------------------------- 1 | /** 2 | * TwoDimensionalArrays Class 3 | * 4 | *

5 | * 6 | * @note 2D Arrays 7 | * @author David Kariuki 8 | * @since 14/8/2022 9 | */ 10 | package AceTheJavaCodingInterview.module2_data_structures.arrays; 11 | 12 | @SuppressWarnings("SameParameterValue") 13 | public class TwoDimensionalArrays { 14 | 15 | static int[][] twoDArray; 16 | 17 | public static void main(String[] args) { 18 | 19 | twoDArray = create2DArray(3, 4); // Create 2D array 20 | 21 | init2DArray(0, 1, 10); // Adding 10 at Row 0 Column 1 22 | } 23 | 24 | /** 25 | * Method to create 2D array 26 | * 27 | * @param rows - int 28 | * @param columns - int 29 | */ 30 | public static int[][] create2DArray(int rows, int columns) { 31 | 32 | return new int[rows][columns]; // Create array 33 | } 34 | 35 | public static void init2DArray(int row, int column, int value) { 36 | twoDArray[row][column] = value; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/_arrays.md: -------------------------------------------------------------------------------- 1 | # Arrays 2 | 3 | ### Array Indexing 4 | 5 | Each data element is assigned a numerical value called the index, which corresponds to the position of that item in the array. It is important to note that the value of the index is non-negative and always starts from zero. So the first 6 | element of an array will be stored at index 0 and the last one at index size-1. 7 | 8 | An index makes it possible to access the contents of the array directly. Otherwise, we would have to traverse through the whole array to access a single element. 9 | 10 | ### Types of Arrays# 11 | 12 | Arrays can store **primitive** data-type values (e.g., `int`, `char`, `floats`, `boolean`, `byte`, `short`, `long`, etc.), **non-primitive** data-type values (e.g., Java Objects, etc.) or it can even hold references of other arrays. That 13 | divides the arrays into two categories: 14 | 15 | - One Dimensional Array. 16 | - Multi-Dimensional Array. 17 | 18 |
19 | 20 | ### Notes 21 | 22 | 1. If the size and the values of an array are known in advance, we can use the array literal for adding elements in an array. 23 | - datatype[] arrayName = {Comma Separated list of values}; 24 | 2. In Java, arrays are dynamically allocated. Arrays are stored in the memory using a reference pointer, which points to the first element. 25 | 3. Pointers - References are used to explicitly store memory locations that hold a value or an object. 26 | 4. A Two Dimensional Array is an array of references that holds references to other arrays. 27 | 5. In 2D arrays, all values must have the same data type. This means that you can’t store an array of integers next to an array of strings and vice versa. For example, if one array is declared of type int, then its pointer can’t point to 28 | the string type array. Each element must be of the same data type. 29 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/binary_search/BinarySearchOnSortedArray_Iterative.java: -------------------------------------------------------------------------------- 1 | /** 2 | * BinarySearchOnSortedArray_Iterative Class 3 | * 4 | *

5 | * 6 | * @question We are given an array of integers, nums, sorted in ascending order, and an integer 7 | * value, target. If the target exists in the array, return its index. If the target does not 8 | * exist, then return -1. This class uses Iteration. 9 | * @author David Kariuki 10 | * @since 17/8/2022 11 | */ 12 | package AceTheJavaCodingInterview.module2_data_structures.arrays.binary_search; 13 | 14 | public class BinarySearchOnSortedArray_Iterative { 15 | 16 | /** 17 | * Main method 18 | * 19 | * @param args - String[] 20 | */ 21 | public static void main(String[] args) { 22 | 23 | int[] nums = new int[] {1, 3, 9, 10, 12}; 24 | int target = 9; 25 | } 26 | 27 | /** 28 | * Method to perform binary search 29 | * 30 | *

31 | * 32 | * @note Time complexity - The time complexity of this solution is logarithmic, O(log n) 33 | * @note Space complexity - The space complexity of this solution is logarithmic, O(log n) because 34 | * the recursive approach consumes memory on the stack. 35 | * @param nums - int[] 36 | * @param target - int 37 | * @return int 38 | */ 39 | static int binarySearch(int[] nums, int target) { 40 | 41 | // Set start 42 | int start = 0; 43 | int end = nums.length - 1; 44 | 45 | for (int i = 0; i < nums.length; i++) { 46 | 47 | // Finding the mid using floor division 48 | // Using this method to prevent an overflow 49 | int mid = start + ((end - start) / 2); 50 | 51 | // Target value is present at the middle of the array 52 | if (nums[mid] == target) { 53 | return nums[mid]; 54 | 55 | // Target value is present in the low subarray 56 | } else if (nums[mid] > target) { 57 | end = mid - 1; 58 | 59 | // Target value is present in the high subarray 60 | } else if (target > nums[mid]) { 61 | start = mid + 1; 62 | } 63 | } 64 | 65 | return -1; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/binary_search/BinarySearchOnSortedArray_Recursive.java: -------------------------------------------------------------------------------- 1 | /** 2 | * BinarySearchOnSortedArray_Recursive Class 3 | * 4 | *

5 | * 6 | * @question We are given an array of integers, nums, sorted in ascending order, and an integer * 7 | * value, target. If the target exists in the array, return its index. If the target does not * 8 | * exist, then return -1. 9 | * This class uses Recursion. 10 | * @author David Kariuki 11 | * @since 17/8/2022 12 | */ 13 | package AceTheJavaCodingInterview.module2_data_structures.arrays.binary_search; 14 | 15 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 16 | 17 | public class BinarySearchOnSortedArray_Recursive { 18 | 19 | /** 20 | * Main method 21 | * 22 | * @param args - String[] 23 | */ 24 | public static void main(String[] args) { 25 | 26 | int[][] numsLists = {{}, {0, 1}, {1, 2, 3}, {-1, 0, 3, 5, 9, 12}, {-1, 0, 3, 5, 9, 12}}; 27 | int[] targetList = {12, 1, 3, 9, 2}; 28 | 29 | for (int i = 0; i < numsLists.length; i++) { 30 | 31 | int[] nums = numsLists[i]; 32 | int target = targetList[i]; 33 | int index = binarySearch(nums, target); 34 | 35 | System.out.println(i + 1 + ". Array to search: " + DataStructuresUtils.arrayToString(nums)); 36 | System.out.println(" Target: " + targetList[i]); 37 | 38 | if (index != -1) { 39 | System.out.println(" " + target + " exists in the array and its index is " + index); 40 | } else { 41 | System.out.println( 42 | " " + target + " does not exist in the array so the return value is " + index); 43 | } 44 | } 45 | } 46 | 47 | /** 48 | * Method to perform binary search 49 | * 50 | *

51 | * 52 | * @note Time complexity - The time complexity of this solution is logarithmic, O(log n) 53 | * @note Space complexity - The space complexity of this solution is constant, O(1). 54 | * @param nums - int[] 55 | * @param target - int 56 | * @return int 57 | */ 58 | public static int binarySearch(int[] nums, int target) { 59 | return binarySearchRecursive(nums, target, 0, nums.length - 1); 60 | } 61 | 62 | /** 63 | * Method to perform binary search 64 | * 65 | *

66 | * 67 | * @note Time complexity - The time complexity of this solution is logarithmic, O(log n) 68 | * @note Space complexity - The space complexity of this solution is constant, O(1). 69 | * @param nums - int[] 70 | * @param target - int 71 | * @param low - int 72 | * @param high - int 73 | * @return int 74 | */ 75 | public static int binarySearchRecursive(int[] nums, int target, int low, int high) { 76 | 77 | if (low > high) { 78 | return -1; 79 | } 80 | 81 | // Finding the mid using floor division 82 | int mid = low + ((high - low) / 2); 83 | 84 | // Target value is present at the middle of the array 85 | if (nums[mid] == target) { 86 | return mid; 87 | } 88 | 89 | // Target value is present in the low subarray 90 | else if (target < nums[mid]) { 91 | binarySearchRecursive(nums, target, low, mid - 1); 92 | 93 | // Target value is present in the high subarray 94 | } else if (target > nums[mid]) { 95 | binarySearchRecursive(nums, target, mid + 1, high); 96 | } 97 | 98 | // Target value is not present in the array 99 | return -1; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/binary_search/BitonicArrayMaximum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * BitonicArrayMaximum Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement - Find the maximum value in a given Bitonic array. An array is 7 | * considered bitonic if it is monotonically increasing and then monotonically decreasing. 8 | * Monotonically increasing or decreasing means that for any index i in the array arr[i] != 9 | * arr[i+1]. 10 | * @note Example 11 | *

Input: [1, 3, 8, 12, 4, 2] Output: 12 Explanation: The maximum number in the input bitonic 12 | * array is 12. 13 | * @note Solution 14 | *

A bitonic array is a sorted array; the only difference is that its first part is sorted in 15 | * ascending order and the second part is sorted in descending order. We can use a similar 16 | * approach as discussed in Order-agnostic Binary Search. 17 | *

Since no two consecutive numbers are same (as the array is monotonically increasing or 18 | * decreasing), whenever we calculate the middle, we can compare the numbers pointed out by the 19 | * index middle and middle+1 to find if we are in the ascending or the descending part. So: 20 | *

f arr[middle] > arr[middle + 1], we are in the second (descending) part of the bitonic 21 | * array. Therefore, our required number could either be pointed out by middle or will be before 22 | * middle. This means we will be doing: end = middle. 23 | *

If arr[middle] < arr[middle + 1], we are in the first (ascending) part of the bitonic 24 | * array. Therefore, the required number will be after middle. This means we will be doing: 25 | * start = middle + 1. 26 | *

We can break when start == end. Due to the two points mentioned above, both start and end 27 | * will be pointing at the maximum number of the bitonic array. 28 | * @note Time complexity - Since we are reducing the search range by half at every step, this means 29 | * that the time complexity of our algorithm will be O(logN) where N is the total elements in 30 | * the given array. 31 | *

32 | * @note Space complexity - The algorithm runs in constant space O(1). 33 | * @author David Kariuki 34 | * @since 24/8/2022 35 | */ 36 | package AceTheJavaCodingInterview.module2_data_structures.arrays.binary_search; 37 | 38 | public class BitonicArrayMaximum { 39 | 40 | /** 41 | * Main method 42 | * 43 | * @param args - String[] 44 | */ 45 | public static void main(String[] args) { 46 | 47 | System.out.println(BitonicArrayMaximum.findMax(new int[] {1, 3, 8, 12, 4, 2})); 48 | System.out.println(BitonicArrayMaximum.findMax(new int[] {3, 8, 3, 1})); 49 | System.out.println(BitonicArrayMaximum.findMax(new int[] {1, 3, 8, 12})); 50 | System.out.println(BitonicArrayMaximum.findMax(new int[] {10, 9, 8})); 51 | } 52 | 53 | /** 54 | * Method to find max in a bitonic array 55 | * 56 | * @param nums - int[] 57 | * @return int 58 | */ 59 | public static int findMax(int[] nums) { 60 | 61 | int start = 0; 62 | int end = nums.length - 1; 63 | 64 | while (start < end) { 65 | 66 | int mid = start + ((end - start) / 2); // Calculate mid point 67 | 68 | if (nums[mid] > nums[mid + 1]) { 69 | end = mid; 70 | } else if (nums[mid] < nums[mid + 1]) { 71 | start = mid + 1; 72 | } 73 | } 74 | 75 | // At the end of the while loop, 'start == end' 76 | return nums[start]; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/binary_search/FindLowOrHighIndexOfAnElementInSortedArray.java: -------------------------------------------------------------------------------- 1 | /** 2 | * FindLowOrHighIndexOfAnElementInSortedArray Class 3 | * 4 | *

5 | * 6 | * @question We’re given a sorted array of integers, nums, and an integer value, target. Return the 7 | * low and high index of the given target element. If the indexes are not found, return -1. 8 | * @note The array can contain multiple duplicates with length in millions. 9 | * @example int array -> {1, 2, 5, 5, 5, 5, 5, 5, 5, 5, 20} 10 | *

For target= 1: low = 0 and high = 0 11 | *

For target= 2: low = 1 and high = 1 12 | *

For target= 5: low = 2 and high = 9 13 | *

14 | *

Linearly scanning the sorted array for low and high indices is highly inefficient since 15 | * our array size can be in the millions. Instead, we will use a slightly modified binary search 16 | * to find the low and high indices of a given target. 17 | * @author David Kariuki 18 | * @since /8/2022 19 | */ 20 | package AceTheJavaCodingInterview.module2_data_structures.arrays.binary_search; 21 | 22 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 23 | 24 | @SuppressWarnings("ALL") 25 | public class FindLowOrHighIndexOfAnElementInSortedArray { 26 | 27 | /** 28 | * Main method 29 | * 30 | * @param args - String[] 31 | */ 32 | public static void main(String[] args) { 33 | 34 | int[] arr = 35 | new int[] {1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 6, 6, 9}; 36 | 37 | int target = 5; 38 | 39 | DataStructuresUtils.printOutArray(arr); 40 | 41 | System.out.println( 42 | "The low index of target : " + target + " is : " + findLowIndex(arr, target)); 43 | System.out.println(); 44 | 45 | System.out.println( 46 | "The high index of target : " + target + " is : " + findHighIndex(arr, target)); 47 | System.out.println(); 48 | } 49 | 50 | /** 51 | * Method to find low index 52 | * 53 | *

54 | * 55 | * @note Time complexity - Since we are using binary search, the time complexity is logarithmic, 56 | * O(logn). Even though we do the binary search twice, the asymptotic time complexity is still 57 | * O(logn). 58 | *

59 | * @note Space complexity - The space complexity is constant, O(1) O (1) , since no extra storage 60 | * is used. 61 | * @param nums - int[] 62 | * @param target - int 63 | * @return int 64 | */ 65 | static int findLowIndex(int[] nums, int target) { 66 | int low = 0; 67 | int high = nums.length - 1; 68 | int mid = high / 2; 69 | 70 | while (low <= high) { 71 | int midElem = nums[mid]; 72 | 73 | // Target value is less than the middle value 74 | if (midElem < target) { 75 | low = mid + 1; 76 | } 77 | 78 | // Target value is greater than or equal to the middle value 79 | else { 80 | high = mid - 1; 81 | } 82 | 83 | // Updating the mid value 84 | mid = low + (high - low) / 2; 85 | } 86 | 87 | if (low < nums.length && nums[low] == target) { 88 | return low; 89 | } 90 | 91 | return -1; 92 | } 93 | 94 | /** 95 | * Method to find high index 96 | * 97 | *

98 | * 99 | * @note Time complexity - Since we are using binary search, the time complexity is logarithmic, 100 | * O(logn). Even though we do the binary search twice, the asymptotic time complexity is still 101 | * O(logn). 102 | *

103 | * @note Space complexity - The space complexity is constant, O(1) O (1) , since no extra storage 104 | * is used. 105 | * @param nums - int[] 106 | * @param target - int 107 | * @return int 108 | */ 109 | static int findHighIndex(int[] nums, int target) { 110 | int low = 0; 111 | int high = nums.length - 1; 112 | int mid = high / 2; 113 | 114 | while (low <= high) { 115 | 116 | int midElem = nums[mid]; 117 | 118 | // Target value is less than or equal to the middle value 119 | if (midElem <= target) { 120 | low = mid + 1; 121 | } 122 | 123 | // Target value is greater than the middle value 124 | else { 125 | high = mid - 1; 126 | } 127 | 128 | // Updating the mid value 129 | mid = low + (high - low) / 2; 130 | } 131 | 132 | if (high == -1) { 133 | return high; 134 | } 135 | 136 | if (high < nums.length && nums[high] == target) { 137 | return high; 138 | } 139 | 140 | return -1; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/binary_search/MoveAllZerosToTheBeginningOfTheArray.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MoveAllZerosToTheBeginningOfTheArray Class 3 | * 4 | *

5 | * 6 | * @question Move all zeros to the left of an array while maintaining its order. 7 | * @author David Kariuki 8 | * @since 18/8/2022 9 | */ 10 | package AceTheJavaCodingInterview.module2_data_structures.arrays.binary_search; 11 | 12 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 13 | 14 | public class MoveAllZerosToTheBeginningOfTheArray { 15 | 16 | /** 17 | * Main method 18 | * 19 | * @param args - String[] 20 | */ 21 | public static void main(String[] args) { 22 | 23 | int[][] numsList = { 24 | {1, 10, 20, 0, 59, 63, 0, 88, 0}, 25 | {1, 0, 2, 3, 0}, 26 | {0}, 27 | {-1, 0, 0, -2, 9}, 28 | {1, 2, 3, 4, 5}, 29 | {2} 30 | }; 31 | 32 | for (int i = 0; i < numsList.length; i++) { 33 | DataStructuresUtils.printOutArray(numsList[i], (i + 1) + ". Before list: "); 34 | moveZerosToLeft(numsList[i]); 35 | DataStructuresUtils.printOutArray(numsList[i], "After list:\t"); 36 | System.out.println("-------------------------\n"); 37 | } 38 | } 39 | 40 | /** 41 | * @explanation - Solution. We will use Read and Write pointers and start by pointing them to the 42 | * end of the array. 43 | *

While moving the Read pointer towards the start of the array: 44 | *

If the value at the Read pointer is 0, decrement the Read pointer. If the value at the 45 | * Read pointer is non-zero, set the value at the - Write pointer equal to the value at the 46 | * Read pointer, and decrement the - Write and Read pointers. Once, the Read pointer reaches 47 | * the 0th index, start assigning zeros to all the values from the - Write pointer back to the 48 | * 0th index. 49 | * @note Time complexity - The time complexity of this solution is O(n). 50 | *

51 | * @note Space complexity - The space complexity of this solution is O(1). 52 | */ 53 | static void moveZerosToLeft(int[] nums) { 54 | 55 | // Initialize markers 56 | int writeIndex = nums.length - 1; 57 | int readIndex = nums.length - 1; 58 | 59 | // Iterate readIndex marker till the index is less than or equal to zero 60 | while (readIndex >= 0) { 61 | // Replacing write_index value with read_index value. This step moves 62 | // the next non-zero value "back" in the array, making space for the 63 | // zero at the head of the array 64 | if (nums[readIndex] != 0) { 65 | nums[writeIndex] = nums[readIndex]; 66 | writeIndex--; 67 | } 68 | 69 | readIndex--; 70 | } 71 | 72 | // Replacing initial values with zeroes 73 | while (writeIndex >= 0) { 74 | nums[writeIndex] = 0; 75 | writeIndex--; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/binary_search/OrderAgnosticBinarySearch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * OrderAgnosticBinarySearch Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement - Given a sorted array of numbers, find if a given number ‘key’ is 7 | * present in the array. Though we know that the array is sorted, we don’t know if it’s sorted 8 | * in ascending or descending order. You should assume that the array can have duplicates. 9 | *

Write a function to return the index of the ‘key’ if it is present in the array, otherwise 10 | * return -1. 11 | * @note Solution - To make things simple, let’s first solve this problem assuming that the input 12 | * array is sorted in ascending order. Here are the set of steps for Binary Search: 13 | *

Let’s assume start is pointing to the first index and end is pointing to the last index of 14 | * the input array (let’s call it arr). 15 | *

This means: int start = 0; int end = arr.length - 1; 16 | *

First, we will find the middle. middle = start + ((end - start) / 2) 17 | *

Next, we will see if the ‘key’ is equal to the number at index middle. If it is equal we 18 | * return middle as the required index. If ‘key’ is not equal to number at index middle, we have 19 | * to check two things: 20 | *

If (key < arr[middle]), then we can conclude that the key will be smaller than all the 21 | * numbers after index middle as the array is sorted in the ascending order. Hence, we can 22 | * reduce our search to end = mid - 1. 23 | *

If (key > arr[middle]), then we can conclude that the key will be greater than all numbers 24 | * before index middle as the array is sorted in the ascending order. Hence, we can reduce our 25 | * search to start = mid + 1. 26 | *

We will repeat steps 2-4 with new ranges of start to end. If at any time start becomes 27 | * greater than end, this means that we can’t find the ‘key’ in the input array and we must 28 | * return ‘-1’. 29 | *

30 | *

If the array is sorted in the descending order, we have to update the step 4 above as: 31 | *

If key > arr[middle], then we can conclude that the key will be greater than all numbers 32 | * after index middle as the array is sorted in the descending order. Hence, we can reduce our 33 | * search to end = mid - 1. 34 | *

If key < arr[middle], then we can conclude that the key will be smaller than all the 35 | * numbers before index middle as the array is sorted in the descending order. Hence, we can 36 | * reduce our search to start = mid + 1. 37 | *

Finally, how can we figure out the sort order of the input array? We can compare the 38 | * numbers pointed out by start and end index to find the sort order. If arr[start] < arr[end], 39 | * it means that the numbers are sorted in ascending order otherwise they are sorted in the 40 | * descending order. 41 | *

42 | * @note Time complexity - Since, we are reducing the search range by half at every step, this means 43 | * that the time complexity of our algorithm will be O(logN) where N is the total elements in 44 | * the given array. 45 | *

46 | * @note Space complexity - The algorithm runs in constant space O(1). 47 | * @author David Kariuki 48 | * @since 24/8/2022 49 | */ 50 | package AceTheJavaCodingInterview.module2_data_structures.arrays.binary_search; 51 | 52 | public class OrderAgnosticBinarySearch { 53 | 54 | /** 55 | * Main method 56 | * 57 | * @param args - String[] 58 | */ 59 | public static void main(String[] args) { 60 | 61 | System.out.println(OrderAgnosticBinarySearch.search(new int[] {4, 6, 10}, 10)); 62 | System.out.println(OrderAgnosticBinarySearch.search(new int[] {1, 2, 3, 4, 5, 6, 7}, 5)); 63 | System.out.println(OrderAgnosticBinarySearch.search(new int[] {10, 6, 4}, 10)); 64 | System.out.println(OrderAgnosticBinarySearch.search(new int[] {10, 6, 4}, 4)); 65 | } 66 | 67 | /** Method to search array and return index of key */ 68 | public static int search(int[] nums, int key) { 69 | 70 | int start = 0; // Initialize start 71 | int end = nums.length - 1; // Initialize end 72 | 73 | // Check if array is ascending or descending 74 | boolean arrayIsAscending = nums[start] < nums[end]; 75 | 76 | // Traverse array 77 | while (start <= end) { 78 | 79 | int mid = start + ((end - start) / 2); 80 | 81 | // Check if key is at the midpoint 82 | if (nums[mid] == key) { 83 | return mid; 84 | } 85 | 86 | if (arrayIsAscending) { // ascending order 87 | 88 | if (nums[mid] > key) { 89 | end = mid - 1; // The key can be in the first half 90 | } else if (nums[mid] < key) { 91 | start = mid + 1; // The key can be in the second half 92 | } 93 | 94 | } else { // Descending order 95 | if (nums[mid] > key) { 96 | start = mid + 1; 97 | } else if (nums[mid] < key) { 98 | end = mid - 1; 99 | } 100 | } 101 | } 102 | 103 | return -1; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/binary_search/SearchRotatedArray_Iteratively.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SearchRotatedArray_Iteratively Class 3 | * 4 | *

5 | * 6 | * @question Search for a given number in a sorted array that has been rotated by some arbitrary 7 | * number. We're given a sorted integer array, nums and an integer value, target. The array is 8 | * rotated by some arbitrary number. Search the target in this array. If the target does not 9 | * exist then return -1. 10 | * @author David Kariuki 11 | * @since 18/8/2022 12 | */ 13 | package AceTheJavaCodingInterview.module2_data_structures.arrays.binary_search; 14 | 15 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 16 | 17 | public class SearchRotatedArray_Iteratively { 18 | 19 | /** 20 | * Main method 21 | * 22 | * @param args - String[] 23 | */ 24 | public static void main(String[] args) { 25 | 26 | int[] targetList = {3, 6, 3, 6}; 27 | int[][] numsList = { 28 | {6, 7, 1, 2, 3, 4, 5}, 29 | {6, 7, 1, 2, 3, 4, 5}, 30 | {4, 5, 6, 1, 2, 3}, 31 | {4, 5, 6, 1, 2, 3} 32 | }; 33 | 34 | for (int i = 0; i < targetList.length; i++) { 35 | 36 | System.out.println((i + 1) + ". Rotated array: " 37 | + DataStructuresUtils.arrayToString(numsList[i])); 38 | System.out.println(" target " + targetList[i] + " found at index " 39 | + binarySearchRotated(numsList[i], targetList[i])); 40 | System.out.println("--------------------------\n"); 41 | } 42 | } 43 | 44 | /** 45 | * Method to perform binary search 46 | * 47 | *

48 | * 49 | * @note Time complexity - The time complexity of this solution is O(log n). 50 | * @note Space complexity - The space complexity of this solution is constant, O(1). 51 | * @param nums - int[] 52 | * @param target - int 53 | */ 54 | public static int binarySearchRotated(int[] nums, int target) { 55 | 56 | int start = 0; 57 | int end = nums.length - 1; 58 | 59 | if (start > end) { 60 | return -1; 61 | } 62 | 63 | while (start <= end) { 64 | 65 | int mid = start + ((end - start) / 2); 66 | 67 | // Target value is present at the middle of the array 68 | if (target == nums[mid]) { 69 | return mid; 70 | } 71 | 72 | // Start to mid is sorted 73 | if (nums[start] <= nums[mid]) { 74 | if (nums[start] <= target && target < nums[mid]) { 75 | end = mid - 1; 76 | } else { 77 | start = mid + 1; 78 | } 79 | } 80 | 81 | // Mid to end is sorted 82 | else { 83 | if (nums[mid] < target && target <= nums[end]) { 84 | start = mid + 1; 85 | } else { 86 | end = mid - 1; 87 | } 88 | } 89 | } 90 | return -1; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/binary_search/SearchRotatedArray_Recursive.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SearchRotatedArray_Recursive Class 3 | * 4 | *

5 | * 6 | * @question Search for a given number in a sorted array that has been rotated by some arbitrary 7 | * number. We're given a sorted integer array, nums and an integer value, target. The array is 8 | * rotated by some arbitrary number. Search the target in this array. If the target does not 9 | * exist then return -1. 10 | * @author David Kariuki 11 | * @since 18/8/2022 12 | */ 13 | package AceTheJavaCodingInterview.module2_data_structures.arrays.binary_search; 14 | 15 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 16 | 17 | public class SearchRotatedArray_Recursive { 18 | 19 | /** 20 | * Main method 21 | * 22 | * @param args - String[] 23 | */ 24 | public static void main(String[] args) { 25 | 26 | int[] targetList = {3, 6, 3, 6}; 27 | int[][] numsList = { 28 | {6, 7, 1, 2, 3, 4, 5}, {6, 7, 1, 2, 3, 4, 5}, {4, 5, 6, 1, 2, 3}, {4, 5, 6, 1, 2, 3} 29 | }; 30 | 31 | for (int i = 0; i < targetList.length; i++) { 32 | 33 | System.out.println( 34 | (i + 1) + ". Rotated array: " + DataStructuresUtils.arrayToString(numsList[i])); 35 | System.out.println( 36 | " target " 37 | + targetList[i] 38 | + " found at index " 39 | + binarySearchRotated(numsList[i], targetList[i])); 40 | System.out.println("------------------\n"); 41 | } 42 | } 43 | 44 | /** 45 | * Method to perform binary search 46 | * 47 | * @param nums - int[] 48 | * @param target - int 49 | */ 50 | static int binarySearchRotated(int[] nums, int target) { 51 | return binarySearch(nums, 0, nums.length - 1, target); 52 | } 53 | 54 | /** 55 | * Method to perform binary search 56 | * 57 | *

58 | * 59 | * @note Time complexity - The time complexity of this solution is O(log n). 60 | * @note Space complexity - The space complexity of this solution is logarithmic, O(log n) . 61 | * @param nums - int[] 62 | * @param start - int 63 | * @param end - int 64 | * @param target - int 65 | */ 66 | public static int binarySearch(int[] nums, int start, int end, int target) { 67 | 68 | if (start > end) { 69 | return -1; 70 | } 71 | 72 | int mid = start + ((end - start) / 2); 73 | 74 | // Target value is present at the middle of the array 75 | if (target == nums[mid]) { 76 | return mid; 77 | } 78 | 79 | // Start to mid is sorted 80 | if (nums[start] <= nums[mid]) { 81 | if (nums[start] <= target && target < nums[mid]) { 82 | binarySearch(nums, start, mid - 1, target); 83 | } else { 84 | binarySearch(nums, mid + 1, end, target); 85 | } 86 | } 87 | 88 | // Mid to end is sorted 89 | else { 90 | if (nums[mid] < target && target <= nums[end]) { 91 | binarySearch(nums, mid + 1, end, target); 92 | } else { 93 | binarySearch(nums, start, mid - 1, target); 94 | } 95 | } 96 | 97 | return -1; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/binary_search/StockBuySellToMaximizeProfit.java: -------------------------------------------------------------------------------- 1 | /** 2 | * StockBuySellToMaximizeProfit Class 3 | * 4 | *

5 | * 6 | * @question Given a list of stock prices, find the maximum profit with a single buy or sell 7 | * activity. 8 | *

We’re given an array of daily stock prices (integers for simplicity). Return the buying 9 | * and selling prices for making the maximum profit. 10 | *

The values in the array represent the cost of stock each day. As we can buy and sell the 11 | * stock only once, we need to find the best buy and sell prices that maximize profit (or 12 | * minimized loss) over a given span of time. 13 | *

We need to maximize the profit from a single buy and sell. If we can’t make any profit, 14 | * we’ll try to minimize the loss. 15 | * @author David Kariuki 16 | * @since 18/8/2022 17 | */ 18 | package AceTheJavaCodingInterview.module2_data_structures.arrays.binary_search; 19 | 20 | import AceTheJavaCodingInterview.module2_data_structures.tuples.Tuple; 21 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 22 | 23 | @SuppressWarnings("UnusedAssignment") 24 | public class StockBuySellToMaximizeProfit { 25 | 26 | /** 27 | * Main method 28 | * 29 | * @param args - String[] 30 | */ 31 | public static void main(String[] args) { 32 | 33 | int[][] stockNums = { 34 | {1, 2, 3, 4, 3, 2, 1, 2, 5}, {8, 6, 5, 4, 3, 2, 1}, {12, 30, 40, 90, 110}, {2} 35 | }; 36 | 37 | for (int i = 0; i < stockNums.length; i++) { 38 | Tuple result = findBuySellStockPrices(stockNums[i]); 39 | System.out.println( 40 | (i + 1) + ". Day stocks: " + DataStructuresUtils.arrayToString(stockNums[i])); 41 | if (result != null) { 42 | System.out.println(" Buy Price: " + result.x + ", Sell Price: " + result.y); 43 | } else { 44 | System.out.println(" Buy Price: null, Sell Price: null"); 45 | } 46 | System.out.println("----------------------------\n"); 47 | } 48 | } 49 | 50 | /** 51 | * Method to find buy and sell stock prices 52 | * 53 | *

54 | * 55 | * @note Time complexity - The time complexity of this solution is O(n). 56 | * @note Space complexity - The space complexity of this algorithm is O(1). 57 | */ 58 | @SuppressWarnings("Convert2Diamond") 59 | public static Tuple findBuySellStockPrices(int[] stockNums) { 60 | // Return None when stock list is empty or less than 2 61 | if (stockNums == null || stockNums.length < 2) { 62 | return null; 63 | } 64 | 65 | // Initializations 66 | int current_buy = stockNums[0]; 67 | int global_sell = stockNums[1]; 68 | 69 | // Calculating the global profit 70 | int global_profit = global_sell - current_buy; 71 | 72 | // Initializing current_profit with minimum value 73 | int current_profit = Integer.MIN_VALUE; 74 | 75 | // Looping over stocks to find best buy and selling price 76 | for (int i = 1; i < stockNums.length; i++) { 77 | // Calculating the current profit 78 | current_profit = stockNums[i] - current_buy; 79 | 80 | // Current profit is greater than the global profit 81 | if (current_profit > global_profit) { 82 | global_profit = current_profit; 83 | global_sell = stockNums[i]; 84 | } 85 | 86 | // We will always maximise margin relative to the lowest stock price we can find 87 | // So whenever we find a stock price lower than the current buying price, 88 | // we adopt it as the current buying price 89 | if (current_buy > stockNums[i]) { 90 | current_buy = stockNums[i]; 91 | } 92 | } 93 | 94 | // Tuple having buy price and sell price 95 | return new Tuple(global_sell - global_profit, global_sell); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/challenges/CH10_RearrangeSortedArrayInMaxOrMinForm_SOL_1.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CH10_RearrangeSortedArrayInMaxOrMinForm_SOL_1 Class 3 | * 4 | *

5 | * 6 | * @note Given an array, can you re-arrange the elements such that the first position will have the 7 | * largest number, the second will have the smallest, the third will have the second-largest, 8 | * and so on. 9 | * @author David Kariuki 10 | * @since 16/8/2022 11 | */ 12 | package AceTheJavaCodingInterview.module2_data_structures.arrays.challenges; 13 | 14 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 15 | 16 | public class CH10_RearrangeSortedArrayInMaxOrMinForm_SOL_1 { 17 | 18 | /** 19 | * Main method 20 | * 21 | * @param args - String[] 22 | */ 23 | public static void main(String[] args) { 24 | int[] arr = {1, 2, 3, 4, 5, 6}; 25 | System.out.print("Array before min/max: "); 26 | 27 | System.out.print(DataStructuresUtils.arrayToString(arr)); 28 | System.out.println(); 29 | 30 | maxMin(arr); 31 | 32 | System.out.print("Array after min/max: "); 33 | for (int i = 0; i < arr.length; i++) System.out.print(arr[i] + " "); 34 | System.out.println(); 35 | } 36 | 37 | /** 38 | * Method to find max/min 39 | * 40 | *

41 | * 42 | * @note Time Complexity - The time complexity of this problem is O(n) 43 | * as the array is iterated over once. 44 | * @param arr - int[] 45 | */ 46 | @SuppressWarnings("ManualArrayCopy") 47 | static void maxMin(int[] arr) { 48 | 49 | // Create a result array to hold re-arranged version of given arr 50 | int[] result = new int[arr.length]; 51 | 52 | int pointerSmall = 0; // PointerSmall => Start of arr 53 | int pointerLarge = arr.length - 1; // PointerLarge => End of arr 54 | 55 | // Flag which will help in switching between two pointers 56 | boolean switchPointer = true; 57 | 58 | for (int i = 0; i < arr.length; i++) { 59 | 60 | if (switchPointer) { 61 | result[i] = arr[pointerLarge--]; // Copy large values 62 | } else { 63 | result[i] = arr[pointerSmall++]; // Copy small values 64 | } 65 | 66 | switchPointer = !switchPointer; // Switching between small and large 67 | } 68 | 69 | // Copy new array into old array 70 | for (int j = 0; j < arr.length; j++) { 71 | arr[j] = result[j]; // Copying to original array 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/challenges/CH10_RearrangeSortedArrayInMaxOrMinForm_SOL_2.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CH10_RearrangeSortedArrayInMaxOrMinForm_SOL_2 Class 3 | * 4 | *

5 | * 6 | * @note Given an array, can you re-arrange the elements such that the first position will have the 7 | * largest number, the second will have the smallest, the third will have the second-largest, 8 | * and so on. 9 | * @author David Kariuki 10 | * @since 16/8/2022 11 | */ 12 | package AceTheJavaCodingInterview.module2_data_structures.arrays.challenges; 13 | 14 | public class CH10_RearrangeSortedArrayInMaxOrMinForm_SOL_2 { 15 | 16 | /** 17 | * Main method 18 | * 19 | * @param args - String[] 20 | */ 21 | public static void main(String[] args) { 22 | 23 | int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 24 | System.out.print("Array before min/max: "); 25 | for (int i = 0; i < arr.length; i++) System.out.print(arr[i] + " "); 26 | System.out.println(); 27 | 28 | maxMin(arr); 29 | 30 | System.out.print("Array after min/max: "); 31 | for (int i = 0; i < arr.length; i++) System.out.print(arr[i] + " "); 32 | System.out.println(); 33 | } 34 | 35 | /** 36 | * Method to find max/min 37 | * 38 | *

39 | * 40 | * @note Time Complexity - The time complexity of this solution is in O(n). The space complexity 41 | * is constant. 42 | * @param arr - int[] 43 | */ 44 | static void maxMin(int[] arr) { 45 | 46 | int maxIdx = arr.length - 1; 47 | int minIdx = 0; 48 | 49 | // Store any element that is greater than the maximum element in the array 50 | int maxElem = arr[maxIdx] + 1; 51 | 52 | // Traverse array 53 | for (int i = 0; i < arr.length; i++) { 54 | 55 | // at even indices we will store maximum elements 56 | if (i % 2 == 0) { 57 | 58 | arr[i] += (arr[maxIdx] % maxElem) * maxElem; 59 | maxIdx -= 1; 60 | 61 | } else { // at odd indices we will store minimum elements 62 | 63 | arr[i] += (arr[minIdx] % maxElem) * maxElem; 64 | minIdx += 1; 65 | } 66 | } 67 | // dividing with maxElem to get original values. 68 | for (int i = 0; i < arr.length; i++) { 69 | arr[i] = arr[i] / maxElem; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/challenges/CH11_FindTheSumOfMaximumSumSubarray.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CH11_FindTheSumOfMaximumSumSubarray Class 3 | * 4 | *

5 | * 6 | * @note Given an array, find the sum of contiguous subarray with the largest sum. Given an unsorted 7 | * array A, the maximum sum sub-array is the sub-array (contiguous elements) from A, for which 8 | * the sum of the elements is maximum. In this challenge, we want to find the sum of the maximum 9 | * sum sub-array. The array might have negative integers in any position, so we have to cater to 10 | * those negative integers while choosing the contiguous subarray with the largest positive 11 | * values. 12 | *

13 | * @note Kadane's Algorithm - The basic idea of Kadane’s algorithm is to scan the entire array and 14 | * at each position find the maximum sum of the subarray ending there. This is achieved by 15 | * keeping a currMax for the current array index and a globalMax. 16 | * @author David Kariuki 17 | * @since 17/8/2022 18 | */ 19 | package AceTheJavaCodingInterview.module2_data_structures.arrays.challenges; 20 | 21 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 22 | 23 | public class CH11_FindTheSumOfMaximumSumSubarray { 24 | 25 | /** 26 | * Main method 27 | * 28 | * @param args - String[] 29 | */ 30 | public static void main(String[] args) { 31 | 32 | int[] arr1 = {1, 7, -2, -5, 10, -1}; 33 | 34 | System.out.println("Array: " + DataStructuresUtils.arrayToString(arr1)); 35 | System.out.println("Sum: " + findMaxSumSubArray(arr1)); 36 | } 37 | 38 | /** 39 | * Method to find the sum of maximum sum subarray 40 | * 41 | *

42 | * 43 | * @note Runtime complexity - The runtime complexity of this solution is linear, O(n). 44 | *

45 | * @note Space complexity - The space complexity of this solution is constant, O(1). 46 | * @param arr - int[] 47 | */ 48 | public static int findMaxSumSubArray(int[] arr) { 49 | 50 | if (arr.length < 1) { 51 | return 0; 52 | } 53 | 54 | int currMax = arr[0]; 55 | int globalMax = arr[0]; 56 | 57 | // Traverse array 58 | for (int i = 1; i < arr.length; i++) { 59 | 60 | // Check if current max is less than 0 to re-assign 61 | if (currMax < 0) { 62 | currMax = arr[i]; // Re-assign with current element at i 63 | } else { 64 | currMax += arr[i]; // Increment 65 | } 66 | 67 | // Check if global max is less that current max 68 | if (globalMax < currMax) { 69 | globalMax = currMax; 70 | } 71 | } 72 | return globalMax; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/challenges/CH1_RemoveEvenFromArray.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CH1_RemoveEvenFromArray Class 3 | * 4 | *

5 | * 6 | * @note Challenge 1: Remove Even Integers from an Array. 7 | * Given an array of size n, remove all even integers from it. 8 | * @author David Kariuki 9 | * @since 14/8/2022 10 | */ 11 | package AceTheJavaCodingInterview.module2_data_structures.arrays.challenges; 12 | 13 | public class CH1_RemoveEvenFromArray { 14 | 15 | /** 16 | * Method to remove even numbers from array 17 | * 18 | * @param arr - int[] 19 | */ 20 | public static int[] removeEven(int[] arr) { 21 | int oddElements = 0; 22 | 23 | // Find number of odd elements in arr 24 | for (int i = 0; i < arr.length; i++) { 25 | if (arr[i] % 2 != 0) { 26 | oddElements++; 27 | } 28 | } 29 | 30 | // Create result array with the size equal to the number of odd elements in arr 31 | int[] result = new int[oddElements]; 32 | int result_index = 0; 33 | 34 | // Put odd values from arr to the resulted array 35 | for (int i = 0; i < arr.length; i++) { 36 | if (arr[i] % 2 != 0) { 37 | result[result_index++] = arr[i]; 38 | } 39 | } // end of for loop 40 | 41 | return result; 42 | } // end of removeEven 43 | 44 | /** 45 | * Main method 46 | * 47 | * @param args - String[] 48 | */ 49 | public static void main(String[] args) { 50 | 51 | int size = 10; 52 | int[] arr = new int[size]; // declaration and instantiation 53 | 54 | System.out.print("Before removing Even Numbers: "); 55 | for (int i = 0; i < arr.length; i++) { 56 | 57 | arr[i] = i; // assigning values 58 | System.out.print(arr[i] + " "); 59 | } 60 | 61 | System.out.println(); 62 | 63 | int[] newArr = removeEven(arr); // calling removeEven 64 | 65 | System.out.print("After removing Even Numbers: "); 66 | for (int i = 0; i < newArr.length; i++) { 67 | System.out.print(newArr[i] + " "); // Prinitng array 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/challenges/CH2_MergeTwoSortedArrays.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CH2_MergeTwoSortedArrays Class 3 | * 4 | *

5 | * 6 | * @note Challenge 2: Merge Two Sorted Arrays 7 | * Given two sorted arrays, merge them into one array, which should also 8 | * be sorted. 9 | * @author David Kariuki 10 | * @since 14/8/2022 11 | */ 12 | package AceTheJavaCodingInterview.module2_data_structures.arrays.challenges; 13 | 14 | public class CH2_MergeTwoSortedArrays { 15 | 16 | /** 17 | * Main method 18 | * 19 | * @param args - String[] 20 | */ 21 | public static void main(String[] args) { 22 | 23 | int[] arr1 = {1, 12, 14, 17, 23}; 24 | int[] arr2 = {11, 19, 27}; 25 | 26 | int[] resultantArray = mergeArrays(arr1, arr2); // calling mergeArrays 27 | 28 | System.out.print("Arrays after merging: "); 29 | for (int i = 0; i < arr1.length + arr2.length; i++) { 30 | System.out.print(resultantArray[i] + " "); 31 | } 32 | } 33 | 34 | /** 35 | * Method to remove even numbers from array 36 | * 37 | *

The time complexity for this algorithm is O(n+m), where n and m are the * sizes of arr1 and 38 | * arr2, respectively. This is because both arrays are iterated over once. 39 | * 40 | * @param arr1 - Array1 41 | * @param arr2 - Array2 42 | */ 43 | public static int[] mergeArrays(int[] arr1, int[] arr2) { 44 | 45 | int arr1Length = arr1.length; 46 | int arr2Length = arr2.length; 47 | 48 | int[] mergedArray = new int[(arr1Length + arr2Length)]; 49 | 50 | int i = 0, j = 0, k = 0; 51 | 52 | // Traverse both arrays 53 | while (i < arr1Length && j < arr2Length) { 54 | 55 | // Check if current element of first array is smaller than current 56 | // element of second array. If yes, store first array element and 57 | // increment first array index. Otherwise, do same with second array 58 | if (arr1[i] < arr2[j]) { 59 | mergedArray[k++] = arr1[i++]; // Add element from array 1 60 | } else if (arr2[j] < arr1[i]) { 61 | mergedArray[k++] = arr2[j++]; // Add element from array 2 62 | } 63 | } 64 | 65 | // Store the remaining elements of 1st array 66 | while (i < arr1Length) { 67 | mergedArray[k++] = arr1[i++]; 68 | } 69 | 70 | // Store the remaining elements of 2nd array 71 | while (j < arr2Length) { 72 | mergedArray[k++] = arr2[j++]; 73 | } 74 | 75 | return mergedArray; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/challenges/CH3_FindTwoNoAddingUpToN_Sol_1.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CH3_FindTwoNoAddingUpToN_Sol_1 Class 3 | * 4 | *

5 | * 6 | * @note Challenge 2: Merge Two Sorted Arrays 7 | * Given an array and a number "n", find two numbers from the array that 8 | * sums up to "n". 9 | * @author David Kariuki 10 | * @since 14/8/2022 11 | */ 12 | package AceTheJavaCodingInterview.module2_data_structures.arrays.challenges; 13 | 14 | public class CH3_FindTwoNoAddingUpToN_Sol_1 { 15 | 16 | /** 17 | * Main method 18 | * 19 | * @param args - String[] 20 | */ 21 | public static void main(String[] args) { 22 | 23 | int n = 9; 24 | int[] arr1 = {2, 4, 5, 7, 8}; 25 | 26 | int[] arr2 = findSum(arr1, n); 27 | int num1 = arr2[0]; 28 | int num2 = arr2[1]; 29 | 30 | if ((num1 + num2) != n) System.out.println("Not Found"); 31 | else { 32 | System.out.println("Number 1 = " + num1); 33 | System.out.println("Number 2 = " + num2); 34 | System.out.println("Sum = " + (n)); 35 | } 36 | } 37 | 38 | /** 39 | * Method to find the sum of two index elements adding up to n and the elements 40 | * 41 | * @param arr - int[] 42 | * @param n - Target sum 43 | */ 44 | public static int[] findSum(int[] arr, int n) { 45 | 46 | int[] result = new int[2]; // to store the pair of values. 47 | 48 | for (int i = 0; i < arr.length; i++) { // traverse arr 49 | for (int j = i + 1; j < arr.length; j++) { // traverse arr again 50 | if (arr[i] + arr[j] == n) { // find where sum is equal to n 51 | result[0] = arr[i]; 52 | result[1] = arr[j]; 53 | return result; // return the pair of numbers 54 | } 55 | } 56 | } 57 | return arr; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/challenges/CH3_FindTwoNoAddingUpToN_Sol_2.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CH3_FindTwoNoAddingUpToN_Sol_2 Class 3 | * 4 | *

5 | * 6 | * @note Challenge 2: Merge Two Sorted Arrays 7 | * Given an array and a number "n", find two numbers from the array that 8 | * sums up to "n". 9 | * @author David Kariuki 10 | * @since 14/8/2022 11 | */ 12 | package AceTheJavaCodingInterview.module2_data_structures.arrays.challenges; 13 | 14 | public class CH3_FindTwoNoAddingUpToN_Sol_2 { 15 | 16 | /** 17 | * Helper Function to sort given Array (Quick Sort) 18 | * 19 | * @param arr - int[] 20 | * @param low - int 21 | * @param high - int 22 | */ 23 | public static int partition(int[] arr, int low, int high) { 24 | int pivot = arr[high]; 25 | int i = (low - 1); // index of smaller element 26 | for (int j = low; j < high; j++) { 27 | // If current element is <= to pivot 28 | if (arr[j] <= pivot) { 29 | i++; 30 | 31 | // swap arr[i] and arr[j] 32 | int temp = arr[i]; 33 | arr[i] = arr[j]; 34 | arr[j] = temp; 35 | } 36 | } 37 | 38 | // swap arr[i+1] and arr[high] (or pivot) 39 | int temp = arr[i + 1]; 40 | arr[i + 1] = arr[high]; 41 | arr[high] = temp; 42 | 43 | return i + 1; 44 | } 45 | 46 | /** 47 | * @param arr - int[] 48 | * @param low - int 49 | * @param high - high 50 | */ 51 | public static void sort(int[] arr, int low, int high) { 52 | if (low < high) { 53 | int pi = partition(arr, low, high); 54 | sort(arr, low, pi - 1); 55 | sort(arr, pi + 1, high); 56 | } 57 | } 58 | 59 | /** 60 | * Return 2 elements of arr that sum to the given value 61 | * 62 | * @param arr - int[] 63 | * @param n n 64 | */ 65 | public static int[] findSum(int[] arr, int n) { 66 | 67 | // Helper sort function that uses the Quicksort Algorithm 68 | sort(arr, 0, arr.length - 1); // Sort the array in Ascending Order 69 | 70 | int Pointer1 = 0; // Pointer 1 -> At Start 71 | int Pointer2 = arr.length - 1; // Pointer 2 -> At End 72 | 73 | int[] result = new int[2]; 74 | int sum; 75 | 76 | while (Pointer1 != Pointer2) { 77 | 78 | sum = arr[Pointer1] + arr[Pointer2]; // Calulate Sum of Pointer 1 and 2 79 | 80 | if (sum < n) Pointer1++; // if sum is less than given value => Move Pointer 1 to Right 81 | else if (sum > n) Pointer2--; 82 | else { 83 | result[0] = arr[Pointer1]; 84 | result[1] = arr[Pointer2]; 85 | return result; // containing 2 number 86 | } 87 | } 88 | return arr; 89 | } 90 | 91 | /** 92 | * Main method 93 | * 94 | * @param args - String[] 95 | */ 96 | public static void main(String[] args) { 97 | 98 | int n = 9; 99 | int[] arr1 = {1, 2, 3, 4, 5}; 100 | int[] arr2 = findSum(arr1, n); 101 | int num1 = arr2[0]; 102 | int num2 = arr2[1]; 103 | 104 | if ((num1 + num2) != n) System.out.println("Not Found"); 105 | else { 106 | System.out.println("Number 1 = " + num1); 107 | System.out.println("Number 2 = " + num2); 108 | System.out.println("Sum = " + (n)); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/challenges/CH4_ArrayOFProductsOfAllElementsExceptItself.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CH4_ArrayOFProductsOfAllElementsExceptItself Class 3 | * 4 | *

5 | * 6 | * @note Given an array, return an array where each index stores the product of all numbers except 7 | * the number on the index itself. 8 | * @author David Kariuki 9 | * @since 16/8/2022 10 | */ 11 | package AceTheJavaCodingInterview.module2_data_structures.arrays.challenges; 12 | 13 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 14 | 15 | public class CH4_ArrayOFProductsOfAllElementsExceptItself { 16 | 17 | /** 18 | * Main method 19 | * 20 | * @param args - String[] 21 | */ 22 | public static void main(String[] args) { 23 | 24 | int[] arr = {-1, 2, -3, 4, -5}; 25 | 26 | System.out.println("Array before product: " + DataStructuresUtils.arrayToString(arr)); 27 | 28 | int[] prodArray = findProduct(arr); 29 | 30 | System.out.println("Array after product: " + DataStructuresUtils.arrayToString(prodArray)); 31 | } 32 | 33 | /** 34 | * Find product 35 | * 36 | *

Time complexity is O(n) Space complexity is O(n) Auxiliary Space Used is O(1) 37 | * 38 | * @param arr - int[] 39 | */ 40 | public static int[] findProduct(int[] arr) { 41 | 42 | int n = arr.length; 43 | int i, temp = 1; 44 | 45 | // Allocation of result array 46 | int[] result = new int[n]; 47 | 48 | // Product of elements on left side excluding arr[i] 49 | for (i = 0; i < n; i++) { 50 | System.out.println( 51 | "1.--- i : " 52 | + i 53 | + " temp : " 54 | + temp 55 | + " arr[i] :" 56 | + " " 57 | + arr[i] 58 | + " result[i] : " 59 | + result[i]); 60 | result[i] = temp; 61 | temp *= arr[i]; 62 | } 63 | 64 | System.out.println("\n"); 65 | 66 | // Initializing temp to 1 for product on right side 67 | temp = 1; 68 | 69 | // Product of elements on right side excluding arr[i] 70 | for (i = n - 1; i >= 0; i--) { 71 | System.out.println( 72 | "2.--- i : " 73 | + i 74 | + " temp : " 75 | + temp 76 | + " arr[i] :" 77 | + " " 78 | + arr[i] 79 | + " result[i] : " 80 | + result[i]); 81 | result[i] *= temp; 82 | temp *= arr[i]; 83 | } 84 | 85 | return result; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/challenges/CH5_FindMinimumValueInArray.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CH5_FindMinimumValueInArray Class 3 | * 4 | *

5 | * 6 | * @note Given an array of size "n", can you find the minimum value in the array? 7 | * @author David Kariuki 8 | * @since 16/8/2022 9 | */ 10 | package AceTheJavaCodingInterview.module2_data_structures.arrays.challenges; 11 | 12 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 13 | 14 | public class CH5_FindMinimumValueInArray { 15 | 16 | /** 17 | * Main method 18 | * 19 | * @param args - String[] 20 | */ 21 | public static void main(String[] args) { 22 | 23 | int[] arr = new int[] {30, 43, 55, 32, 12, 23, 4, 21, 21, 55, 67, 90, 32, 21}; 24 | 25 | System.out.println( 26 | "Minimum in array : " 27 | + DataStructuresUtils.arrayToString(arr) 28 | + " " 29 | + "is : " 30 | + findMinimum(arr)); 31 | } 32 | 33 | /** 34 | * Method to find minimum 35 | * 36 | *

37 | * 38 | * @note Time Complexity - Since the entire list is iterated over once, this algorithm is in 39 | * linear time - O(n) 40 | * @param arr - int[] 41 | */ 42 | public static int findMinimum(int[] arr) { 43 | 44 | int minimum = arr[0]; 45 | 46 | // At every Index compare its value with minimum and if it is less, then 47 | // make that index value new minimum value 48 | for (int i = 0; i < arr.length; i++) { 49 | // Check if element at current index is smaller than set minimum 50 | if (arr[i] < minimum) { 51 | minimum = arr[i]; // Assign new minimum 52 | } 53 | } 54 | 55 | return minimum; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/challenges/CH6_FindFirstNonRepeatingIntegerInArray.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CH6_FindFirstNonRepeatingIntegerInArray Class 3 | * 4 | *

5 | * 6 | * @note Given an array, find the first integer, which is unique in the array. 7 | * Unique means the number does not repeat and appears only once in the 8 | * whole array. 9 | * @author David Kariuki 10 | * @since 16/8/2022 11 | */ 12 | package AceTheJavaCodingInterview.module2_data_structures.arrays.challenges; 13 | 14 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 15 | 16 | public class CH6_FindFirstNonRepeatingIntegerInArray { 17 | 18 | /** 19 | * Main method 20 | * 21 | * @param args - String[] 22 | */ 23 | public static void main(String[] args) { 24 | 25 | int[] arr = {2, 54, 7, 2, 6, 54}; 26 | 27 | System.out.println("Array: " + DataStructuresUtils.arrayToString(arr)); 28 | 29 | int unique = findFirstUnique(arr); 30 | System.out.print("First Unique in an Array: " + unique); 31 | } 32 | 33 | /** 34 | * Method to find first unique element 35 | * 36 | *

37 | * 38 | * @note The time complexity of this solution is O(n^2) since the entire list is iterated for each 39 | * element n*n times. 40 | * @param arr - int[] 41 | */ 42 | public static int findFirstUnique(int[] arr) { 43 | 44 | // Inside Inner Loop Check Each index of outerLoop If it is repeated in 45 | // array. If it's not repeated then return this as first unique Integer 46 | boolean numRepeated = false; 47 | 48 | // Traverse array 49 | for (int i = 0; i < arr.length; i++) { 50 | 51 | // Traverse array 52 | for (int j = 0; j < arr.length; j++) { 53 | 54 | if (i != j) { 55 | if (arr[i] == arr[j]) { 56 | numRepeated = true; 57 | break; 58 | } else { 59 | numRepeated = false; 60 | } 61 | } 62 | } 63 | 64 | if (!numRepeated) { 65 | return arr[i]; 66 | } 67 | } 68 | 69 | return -1; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/challenges/CH7_FindSecondMaximumValueInArray_Sol_1.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CH7_FindSecondMaximumValueInArray_Sol_1 Class 3 | * 4 | *

5 | * 6 | * @note Given an array of size n, can you find the second maximum element in the array? 7 | * @author David Kariuki 8 | * @since 16/8/2022 9 | */ 10 | package AceTheJavaCodingInterview.module2_data_structures.arrays.challenges; 11 | 12 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 13 | 14 | public class CH7_FindSecondMaximumValueInArray_Sol_1 { 15 | 16 | /** 17 | * Main method 18 | * 19 | * @param args - String[] 20 | */ 21 | public static void main(String[] args) { 22 | 23 | int[] arr = {-2, -33, -10, -456}; 24 | 25 | System.out.println("Array: " + DataStructuresUtils.arrayToString(arr)); 26 | 27 | int secMax = findSecondMaximum(arr); 28 | 29 | System.out.println("Second maximum: " + secMax); 30 | } 31 | 32 | /** 33 | * Method to find second maximum number in an int[] arr 34 | * 35 | *

36 | * 37 | * @note We traverse the array twice. In the first traversal, we find the maximum element. In the 38 | * second traversal, find the greatest element less than the element obtained in the first 39 | * traversal. 40 | *

41 | * @note Time Complexity - The time complexity of the solution is in O(n) 42 | * since the array is traversed twice but in separate loops. Which means 43 | * O(n+ n) => O(n) 44 | * @param arr - int[] arr 45 | */ 46 | public static int findSecondMaximum(int[] arr) { 47 | 48 | int max = Integer.MIN_VALUE; 49 | int secondMax = Integer.MIN_VALUE; 50 | 51 | // Find the maximum value in the array by comparing each index with max 52 | // If an element is greater than max then update max to be equal to it 53 | for (int i = 0; i < arr.length; i++) { 54 | if (arr[i] > max) { 55 | max = arr[i]; 56 | } 57 | } 58 | 59 | // Find the second maximum value by comparing each index with secondmax 60 | // If an element is greater than secondmax and not equal to previously 61 | // calculated max, then update secondmax to be equal to that element. 62 | for (int i = 0; i < arr.length; i++) { 63 | if ((arr[i] > secondMax) && (arr[i] < max)) { 64 | secondMax = arr[i]; 65 | } 66 | } 67 | 68 | return secondMax; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/challenges/CH7_FindSecondMaximumValueInArray_Sol_2.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CH7_FindSecondMaximumValueInArray_Sol_2 Class 3 | * 4 | *

5 | * 6 | * @note Given an array of size n, can you find the second maximum element in the array? 7 | * @author David Kariuki 8 | * @since 16/8/2022 9 | */ 10 | package AceTheJavaCodingInterview.module2_data_structures.arrays.challenges; 11 | 12 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 13 | 14 | public class CH7_FindSecondMaximumValueInArray_Sol_2 { 15 | 16 | /** 17 | * Main method 18 | * 19 | * @param args - String[] 20 | */ 21 | public static void main(String[] args) { 22 | 23 | int[] arr = {-2, -33, -10, -456}; 24 | 25 | System.out.println("Array: " + DataStructuresUtils.arrayToString(arr)); 26 | 27 | int secMax = findSecondMaximum(arr); 28 | 29 | System.out.println("Second maximum: " + secMax); 30 | } 31 | 32 | /** 33 | * Method to find second maximum number in an int[] arr 34 | * 35 | *

36 | * 37 | * @note Time Complexity - This solution is in O(n) since the list is traversed once only. 38 | * @param arr - int[] arr 39 | */ 40 | public static int findSecondMaximum(int[] arr) { 41 | 42 | int max = Integer.MIN_VALUE; 43 | int secondMax = Integer.MIN_VALUE; 44 | 45 | // Keep track of Maximum value, whenever the value at an array index is greater 46 | // than current Maximum value then make that max value 2nd max value and 47 | // make that index value maximum value 48 | for (int i = 0; i < arr.length; i++) { 49 | if (arr[i] > max) { 50 | secondMax = max; 51 | max = arr[i]; 52 | } else if (arr[i] > secondMax && arr[i] != max) { 53 | secondMax = arr[i]; 54 | } 55 | } 56 | 57 | return secondMax; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/challenges/CH8_RightRotateTheArrayByOneIndex.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CH8_RightRotateTheArrayByOneIndex Class 3 | * 4 | *

5 | * 6 | * @note Given an array, can you rotate its elements once from right to left? 7 | * @author David Kariuki 8 | * @since 16/8/2022 9 | */ 10 | package AceTheJavaCodingInterview.module2_data_structures.arrays.challenges; 11 | 12 | public class CH8_RightRotateTheArrayByOneIndex { 13 | 14 | /** 15 | * Main method 16 | * 17 | * @param args - String[] 18 | */ 19 | public static void main(String[] args) { 20 | int[] arr = {3, 6, 1, 8, 4, 2}; 21 | 22 | System.out.print("Array before rotation: "); 23 | for (int i = 0; i < arr.length; i++) { 24 | System.out.print(arr[i] + " "); 25 | } 26 | System.out.println(); 27 | 28 | rotateArray(arr); 29 | 30 | System.out.print("Array after rotation: "); 31 | for (int i = 0; i < arr.length; i++) { 32 | System.out.print(arr[i] + " "); 33 | } 34 | } 35 | 36 | /** 37 | * Method to rotate an int array 38 | * 39 | *

40 | * 41 | * @note Time Complexity# Since the entire array is iterated over once, the time complexity of 42 | * this solution is O(n). 43 | * @param arr - int[] 44 | */ 45 | @SuppressWarnings("ManualArrayCopy") 46 | public static void rotateArray(int[] arr) { 47 | 48 | int lastElement = arr[arr.length - 1]; // get last element 49 | 50 | for (int i = arr.length - 1; i > 0; i--) { 51 | arr[i] = arr[i - 1]; 52 | } 53 | 54 | arr[0] = lastElement; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/challenges/CH9_ReArrangePositiveAndNegativeValues_SOL_1.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CH9_ReArrangePositiveAndNegativeValues_SOL_1 Class 3 | * 4 | *

5 | * 6 | * @note 7 | * @author David Kariuki 8 | * @since 16/8/2022 9 | */ 10 | package AceTheJavaCodingInterview.module2_data_structures.arrays.challenges; 11 | 12 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 13 | 14 | public class CH9_ReArrangePositiveAndNegativeValues_SOL_1 { 15 | 16 | /** 17 | * Main method 18 | * 19 | * @param args - String[] 20 | */ 21 | public static void main(String[] args) { 22 | 23 | int[] arr = {10, -1, 20, 4, 5, -9, -6}; 24 | 25 | System.out.println("Array before re-arranging : " 26 | + DataStructuresUtils.arrayToString(arr)); 27 | 28 | arr = reArrange(arr); 29 | 30 | System.out.println("Array after re-arranging : " 31 | + DataStructuresUtils.arrayToString(arr)); 32 | } 33 | 34 | static int[] reArrange(int[] arr) { 35 | 36 | int[] newArray = new int[arr.length]; 37 | 38 | int j = 0; 39 | // Loop to get negatives 40 | for (int i = 0; i < arr.length; i++) { 41 | if (arr[i] < 0) { 42 | newArray[j++] = arr[i]; 43 | } 44 | } 45 | 46 | // Loop to get positives 47 | for (int i = 0; i < arr.length; i++) { 48 | if (arr[i] > 0) { 49 | newArray[j++] = arr[i]; 50 | } 51 | } 52 | 53 | return newArray; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/challenges/CH9_ReArrangePositiveAndNegativeValues_SOL_2.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CH9_ReArrangePositiveAndNegativeValues_SOL_2 Class 3 | * 4 | *

5 | * 6 | * @note 7 | * @author David Kariuki 8 | * @since 16/8/2022 9 | */ 10 | package AceTheJavaCodingInterview.module2_data_structures.arrays.challenges; 11 | 12 | import AceTheJavaCodingInterview.module2_data_structures.utils.DataStructuresUtils; 13 | 14 | public class CH9_ReArrangePositiveAndNegativeValues_SOL_2 { 15 | 16 | /** 17 | * Main method 18 | * 19 | * @param args - String[] 20 | */ 21 | public static void main(String[] args) { 22 | 23 | int[] arr = {-50, -1, 20, 4, 5, -9, -6}; 24 | 25 | System.out.println("Array before re-arranging : " 26 | + DataStructuresUtils.arrayToString(arr)); 27 | 28 | reArrange(arr); 29 | 30 | System.out.println("Array after re-arranging : " 31 | + DataStructuresUtils.arrayToString(arr)); 32 | } 33 | 34 | static void reArrange(int[] arr) { 35 | 36 | int j = 0; 37 | for (int i = 0; i < arr.length; i++) { 38 | if (arr[i] < 0) { // if negative number found 39 | if (i != j) { 40 | int temp = arr[i]; 41 | arr[i] = arr[j]; // Swapping with leftmost positive 42 | arr[j] = temp; 43 | } 44 | j++; 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/sorting/CyclicSortEasy.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CyclicSortEasy Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement - We are given an array containing n objects. Each object, when 7 | * created, was assigned a unique number from the range 1 to n based on their creation sequence. 8 | * This means that the object with sequence number 3 was created just before the object with 9 | * sequence number 4. 10 | *

Write a function to sort the objects in-place on their creation sequence number in O(n) 11 | * and without using any extra space. For simplicity, let’s assume we are passed an integer 12 | * array containing only the sequence numbers, though each number is actually an object. 13 | *

14 | * @note Solution - As we know, the input array contains numbers from the range 1 to n. We can use 15 | * this fact to devise an efficient way to sort the numbers. Since all numbers are unique, we 16 | * can try placing each number at its correct place, i.e., placing 1 at index ‘0’, placing 2 at 17 | * index ‘1’, and so on. 18 | *

To place a number (or an object in general) at its correct index, we first need to find 19 | * that number. If we first find a number and then place it at its correct place, it will take 20 | * us O(N^2), which is not acceptable. 21 | *

Instead, what if we iterate the array one number at a time, and if the current number we 22 | * are iterating is not at the correct index, we swap it with the number at its correct index. 23 | * This way, we will go through all numbers and place them at their correct indices, hence, 24 | * sorting the whole array. 25 | *

26 | * @note Time complexity - The time complexity of the below algorithm is O(n). Although we are not 27 | * incrementing the index i when swapping the numbers, this will result in more than n 28 | * iterations of the loop, but in the worst-case scenario, the while loop will swap a total of 29 | * n-1 numbers, and once a number is at its correct index, we will move on to the next number by 30 | * incrementing i. So overall, our algorithm will take O(n) + O(n-1) which is asymptotically 31 | * equivalent to O(n). 32 | *

33 | * @note Space complexity - The algorithm runs in constant space O(1). 34 | * @author David Kariuki 35 | * @since 23/8/2022 36 | */ 37 | package AceTheJavaCodingInterview.module2_data_structures.arrays.sorting; 38 | 39 | public class CyclicSortEasy { 40 | 41 | /** 42 | * Main method 43 | * 44 | * @param args - String[] 45 | */ 46 | public static void main(String[] args) { 47 | 48 | int[] arr = new int[] {3, 1, 5, 4, 2}; 49 | CyclicSortEasy.sort(arr); 50 | for (int num : arr) System.out.print(num + " "); 51 | System.out.println(); 52 | 53 | arr = new int[] {2, 6, 4, 3, 1, 5}; 54 | CyclicSortEasy.sort(arr); 55 | for (int num : arr) System.out.print(num + " "); 56 | System.out.println(); 57 | 58 | arr = new int[] {1, 5, 6, 4, 3, 2}; 59 | CyclicSortEasy.sort(arr); 60 | for (int num : arr) System.out.print(num + " "); 61 | System.out.println(); 62 | } 63 | 64 | /** 65 | * Method to sort int[] 66 | * 67 | * @param nums - int[] 68 | */ 69 | public static void sort(int[] nums) { 70 | 71 | int i = 0; 72 | 73 | while (i < nums.length) { 74 | int j = nums[i] - 1; 75 | 76 | if (nums[i] != nums[j]) { 77 | swap(nums, i, j); 78 | } else { 79 | i++; 80 | } 81 | } 82 | } 83 | 84 | /** 85 | * Methods to swap array elements 86 | * 87 | * @param arr - int[] 88 | * @param i - int 89 | * @param j - int 90 | */ 91 | public static void swap(int[] arr, int i, int j) { 92 | int temp = arr[i]; 93 | arr[i] = arr[j]; 94 | arr[j] = temp; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/arrays/sorting/QuicksortAlgorithm.java: -------------------------------------------------------------------------------- 1 | /** 2 | * QuicksortAlgorithm Class 3 | * 4 | *

5 | * 6 | * @question Given an integer array, sort it in ascending order using quicksort. 7 | * @note Solution Here is an overview of how the quicksort algorithm works: 8 | *

Select a pivot element from the array to divide it into two parts. We pick the first 9 | * element as the pivot if we follow Hoare’s algorithm. Another common approach is to select a 10 | * random element as the pivot. 11 | *

Reorder the array by comparing elements with the pivot element such that smaller values 12 | * end up on the left side and larger values end up on the right side of the pivot. 13 | *

Now, the pivot element is in its correct sorted position. By applying the above steps, we 14 | * can recursively sort the sublists on the right and left sides of the pivot. 15 | * @note Time complexity - The time complexity of this solution is linearithmic, O(n logn). 16 | * @note Space complexity - The space complexity of this solution is logarithmic, O(logn), because 17 | * it consumes memory on the stack. 18 | * @author David Kariuki 19 | * @since 23/8/2022 20 | */ 21 | package AceTheJavaCodingInterview.module2_data_structures.arrays.sorting; 22 | 23 | import java.util.Arrays; 24 | 25 | public class QuicksortAlgorithm { 26 | 27 | /** 28 | * Main method 29 | * 30 | * @param args - String[] 31 | */ 32 | public static void main(String[] args) { 33 | 34 | int[][] numsList = { 35 | {55, 23, 26, 2, 18, 78, 23, 8, 2, 3}, {1}, {9, 8, 7, 2, 3, 1}, {10, 20, 30, -1, -2} 36 | }; 37 | 38 | for (int i = 0; i < numsList.length; i++) { 39 | 40 | System.out.println((i + 1) + ". Before Sorting"); 41 | System.out.println(" " + Arrays.toString(numsList[i])); 42 | 43 | quickSort(numsList[i]); 44 | 45 | System.out.println(" After Sorting"); 46 | System.out.println(" " + Arrays.toString(numsList[i])); 47 | System.out.println("------------------------------------------------\n"); 48 | } 49 | } 50 | 51 | /** 52 | * Method to perform quick sort using Hoare's partitioning scheme 53 | * 54 | * @param arr - int[] 55 | * @param low - int 56 | * @param high - int 57 | */ 58 | static int partition(int[] arr, int low, int high) { 59 | 60 | // [55, 23, 26, 2, 25] 61 | 62 | // Initializing pivot's index to low 63 | int pivotValue = arr[low]; 64 | int i = low; 65 | int j = high; 66 | 67 | // Loop until i pointer crosses j pointer 68 | while (i < j) { 69 | 70 | // Increment the 'i' pointer till it finds an element greater than pivot 71 | while (i <= high && arr[i] <= pivotValue) { 72 | i++; 73 | } 74 | 75 | // Decrement the 'j' pointer till it finds an element less than pivot 76 | while (arr[j] > pivotValue) { 77 | j--; 78 | } 79 | 80 | // Swap the numbers on i and j 81 | if (i < j) { 82 | // Swap arr[i] and arr[j] 83 | int temp = arr[i]; 84 | arr[i] = arr[j]; 85 | arr[j] = temp; 86 | } 87 | } 88 | 89 | // Swap pivot element with element on j pointer 90 | arr[low] = arr[j]; 91 | arr[j] = pivotValue; 92 | 93 | return j; // return the pivot index 94 | } 95 | 96 | /** 97 | * Recursive function to implement QuickSort 98 | * 99 | * @param arr - int[] 100 | * @param low - int 101 | * @param high - int 102 | */ 103 | static void quickSortRec(int[] arr, int low, int high) { 104 | 105 | if (high > low) { 106 | 107 | // Pivot index is the partitioning index 108 | int pivotIndex = partition(arr, low, high); 109 | 110 | // Sort elements before partition 111 | quickSortRec(arr, low, pivotIndex - 1); 112 | 113 | // Sort elements after partition 114 | quickSortRec(arr, pivotIndex + 1, high); 115 | } 116 | } 117 | 118 | /** 119 | * Method to perform quicksort 120 | * 121 | * @param arr - int[] 122 | */ 123 | static void quickSort(int[] arr) { 124 | quickSortRec(arr, 0, arr.length - 1); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/hash_tables/PairWithTargetSum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * PairWithTargetSum Class 3 | * 4 | *

5 | * 6 | * @question Problem Statement - Given an array of sorted numbers and a target sum, find a pair in 7 | * the array whose sum is equal to the given target. 8 | *

Write a function to return the indices of the two numbers (i.e. the pair) such that they 9 | * add up to the given target. 10 | * @note Example 1: 11 | *

Input: [1, 2, 3, 4, 6], target=6 Output: [1, 3] Explanation: The numbers at index 1 and 3 12 | * add up to 6: 2 + 4 = 6 13 | * @note Example 2: 14 | *

Input: [2, 5, 9, 11], target=11 Output: [0, 2] Explanation: The numbers at index 0 and 2 15 | * add up to 11: 2 + 9 = 11 16 | * @note Solution - we can utilize a HashTable to search for the required pair. We can iterate 17 | * through the array one number at a time. Let’s say during our iteration we are at number ‘X’, 18 | * so we need to find ‘Y’ such that “X + Y == Target”. We will do two things here: 19 | *

Search for ‘Y’ (which is equivalent to “Target - X Target−X ”) in the HashTable. If it is 20 | * there, we have found the required pair. Otherwise, insert “X” in the HashTable, so that we 21 | * can search it for the latter numbers. 22 | *

23 | * @note Time Complexity - The time complexity of the above algorithm will be O(N), where N is the 24 | * total number of elements in the given array. 25 | * @note Space Complexity - The algorithm runs in constant space O(1). 26 | * @author David Kariuki 27 | * @since 24/8/2022 28 | */ 29 | package AceTheJavaCodingInterview.module2_data_structures.hash_tables; 30 | 31 | import java.util.HashMap; 32 | 33 | public class PairWithTargetSum { 34 | 35 | /** 36 | * Main method 37 | * 38 | * @param args - String[] 39 | */ 40 | public static void main(String[] args) { 41 | 42 | int[] result = PairWithTargetSum.search(new int[] {1, 2, 3, 4, 6}, 6); 43 | System.out.println("Pair with target sum: [" + result[0] + ", " + result[1] + "]"); 44 | result = PairWithTargetSum.search(new int[] {2, 5, 9, 11}, 11); 45 | System.out.println("Pair with target sum: [" + result[0] + ", " + result[1] + "]"); 46 | } 47 | 48 | /** 49 | * Method to search array 50 | * 51 | * @param arr - int[] 52 | * @param targetSum - 53 | * @return int[] 54 | */ 55 | public static int[] search(int[] arr, int targetSum) { 56 | 57 | // HashMap to store numbers and their indices 58 | HashMap nums = new HashMap<>(); 59 | 60 | // Traverse array 61 | for (int i = 0; i < arr.length; i++) { 62 | 63 | if (nums.containsKey(targetSum - arr[i])) { 64 | return new int[] {nums.get(targetSum - arr[i]), i}; 65 | } else { 66 | nums.put(arr[i], i); // put the number and its index in the map 67 | } 68 | } 69 | 70 | return new int[] {-1, -1}; // Pair not found 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/hash_tables/_hash_tables.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-kariuki/ace-the-java-coding-interview/fe026ca84495b00873262a13665b5cebc1dc1174/app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/hash_tables/_hash_tables.md -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/stacks_and_queues/_stacks_and_queues.md: -------------------------------------------------------------------------------- 1 | ## Stacks and Queues 2 | 3 | A collection designed for holding elements prior to processing. Besides, basic Collection operations, queues provide additional insertion, extraction, and inspection operations. Each of these methods exists in two forms: one throws an 4 | exception if the operation fails, the other returns a special value (either null or false, depending on the operation). The latter form of the insert operation is designed specifically for use with capacity-restricted Queue implementations; 5 | in most implementations, insert operations cannot fail. 6 | 7 | | # | Action | Method <>(Throws Exception) | Method (Returns special value) | 8 | |-|-|-|-| 9 | | 1. | Insert | add(e) | offer(e) | 10 | | 2. | Remove | remove() | poll() | 11 | | 3. | Examine | element() | peek() | 12 | ||||| 13 | 14 | `Queues` typically, but do not necessarily, order elements in a `FIFO`(first-in-first-out) manner. Among the exceptions are priority queues, which order elements according to a supplied comparator, or the elements' natural ordering, 15 | and`LIFO`queues (or stacks) which order the elements`LIFO` (last-in-first-out). Whatever the ordering used, the head of the queue is that element which would be removed by a call to remove() or poll(). In a FIFO queue, all new elements are 16 | inserted at the tail of the queue. Other kinds of queues may use different placement rules. Every Queue implementation must specify its ordering properties. 17 | 18 | The offer method inserts an element if possible, otherwise returning false. This differs from the Collection.add method, which can fail to add an element only by throwing an unchecked exception. The offer method is designed for use when 19 | failure is a normal, rather than exceptional occurrence, for example, in fixed-capacity (or "bounded") queues. 20 | 21 | The `remove()` and `poll()` methods remove and return the head of the queue. Exactly which element is removed from the queue is a function of the queue's ordering policy, which differs from implementation to implementation. The `remove()` 22 | and `poll()` methods differ only in their behavior when the queue is empty: the `remove()` method throws an exception, while the `poll()` method returns null. 23 | 24 | The `element()` and `peek()` methods return, but do not remove, the head of the queue. 25 | 26 | The Queue interface does not define the blocking queue methods, which are common in concurrent programming. These methods, which wait for elements to appear or for space to become available, are defined in 27 | the `java.util.concurrent.BlockingQueue` interface, which extends this interface. 28 | 29 | Queue implementations generally do not allow insertion of null elements, although some implementations, such as LinkedList, do not prohibit insertion of null. Even in the implementations that permit it, null should not be inserted into a 30 | Queue, as null is also used as a special return value by the poll method to indicate that the queue contains no elements. 31 | 32 | Queue implementations generally do not define element-based versions of methods `equals` and `hashCode` but instead inherit the identity based versions from class Object, because element-based equality is not always well-defined for queues 33 | with the same elements but different ordering properties. 34 | 35 | #### public interface Queue extends Collection 36 | 37 | Inserts the specified element into this queue if it is possible to do so immediately without violating capacity restrictions, returning true upon success and throwing an `IllegalStateException` if no space is currently available. 38 | 39 | Params: 40 | **e** – the element to add 41 | **Returns**: true (as specified by Collection.add) 42 | **Throws**: 43 | . `IllegalStateException` – if the element cannot be added at this time due to capacity restrictions 44 | . `ClassCastException` – if the class of the specified element prevents it from being added to this queue 45 | . `NullPointerException` – if the specified element is null and this queue does not permit null elements 46 | . `IllegalArgumentException` – if some property of this element prevents it from being added to this queue 47 | 48 | `boolean offer(E e);` 49 | Retrieves and removes the head of this queue. This method differs from `poll()` only in that it throws an exception if this queue is empty. 50 | . **return**: the head of this queue 51 | . **throws** `NoSuchElementException` if this queue is empty. 52 | 53 | `E remove();` 54 | Retrieves and removes the head of this queue, or returns null if this queue is empty. 55 | . **return**: the head of this queue, or `null` if this queue is empty. 56 | 57 | `E poll();` 58 | Retrieves, but does not remove, the head of this queue. This method differs from `peek()` only in that it throws an exception if this queue is empty. 59 | . **return**: the head of this queue 60 | . **throws**: `NoSuchElementException` if this queue is empty. 61 | 62 | `E element();` 63 | Retrieves, but does not remove, the head of this queue, or returns `null` if this queue is empty. 64 | . **return**: the head of this queue, or `null` if this queue is empty. 65 | 66 | `E peek();` -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/tuples/Interval.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Interval Tuple Class 3 | * 4 | *

5 | * 6 | * @implNote Creating a tuple class as java does not support returning multiple arguments 7 | * @author David Kariuki 8 | * @since 22/8/2022 9 | */ 10 | package AceTheJavaCodingInterview.module2_data_structures.tuples; 11 | 12 | public class Interval { 13 | 14 | public int first; 15 | public int second; 16 | 17 | /** 18 | * Class constructor 19 | * 20 | * @param x - X 21 | * @param y - Y 22 | */ 23 | public Interval(int x, int y) { 24 | this.first = x; 25 | this.second = y; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/tuples/Tuple.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tuple Class 3 | * 4 | *

5 | * 6 | * @implNote Creating a tuple class as java does not support returning multiple arguments 7 | * @author David Kariuki 8 | * @since 18/8/2022 9 | */ 10 | package AceTheJavaCodingInterview.module2_data_structures.tuples; 11 | 12 | public class Tuple { 13 | 14 | public X x; 15 | public Y y; 16 | 17 | /** 18 | * Class constructor 19 | * 20 | * @param x - X 21 | * @param y - Y 22 | */ 23 | public Tuple(X x, Y y) { 24 | this.x = x; 25 | this.y = y; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/tuples/_tuples.md: -------------------------------------------------------------------------------- 1 | # Tuples 2 | 3 | -------------------------------------------------------------------------------- /app/src/main/java/AceTheJavaCodingInterview/module2_data_structures/utils/DataStructuresUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Class with shared data structures utils 3 | * 4 | * @author David Kariuki 5 | * @since 16/8/2022 6 | */ 7 | package AceTheJavaCodingInterview.module2_data_structures.utils; 8 | 9 | public class DataStructuresUtils { 10 | 11 | /** 12 | * Method to convert array to string 13 | * 14 | * @param arr - int[] 15 | */ 16 | @SuppressWarnings("StringConcatenationInLoop") 17 | public static String arrayToString(final int[] arr) { 18 | if (arr.length > 0) { 19 | String result = "["; 20 | for (int i = 0; i < arr.length; i++) { 21 | if (i != arr.length - 1) { 22 | result += arr[i] + ", "; 23 | } else { 24 | result += arr[i]; 25 | } 26 | } 27 | return result + "]"; 28 | } else { 29 | return "Empty Array!"; 30 | } 31 | } 32 | 33 | /** 34 | * Method to print out array elements 35 | * 36 | * @param arr - int[] 37 | */ 38 | public static void printOutArray(final int[] arr) { 39 | System.out.println(arrayToString(arr) + "\n"); 40 | } 41 | 42 | /** 43 | * Method to print out array elements 44 | * 45 | * @param arr - int[] 46 | */ 47 | public static void printOutArray(final int[] arr, final String message) { 48 | System.out.println(message + arrayToString(arr) + "\n"); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/test/java/AceTheJavaCodingInterview/AppTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This Java source file was generated by the Gradle 'init' task. 3 | */ 4 | package AceTheJavaCodingInterview; 5 | 6 | import org.junit.jupiter.api.Test; 7 | import static org.junit.jupiter.api.Assertions.*; 8 | 9 | class AppTest { 10 | @Test void appHasAGreeting() { 11 | App classUnderTest = new App(); 12 | assertNotNull(classUnderTest.getGreeting(), "app should have a greeting"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | } 4 | 5 | group 'com.dk' 6 | version '1.0-SNAPSHOT' 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | test { 13 | 14 | testLogging { 15 | events "started", "passed", "skipped", "failed" 16 | showStandardStreams = true 17 | exceptionFormat = "full" 18 | } 19 | 20 | 21 | useJUnitPlatform() 22 | 23 | //testLogging.showStandardStreams = true 24 | //testLogging.exceptionFormat = 'full' 25 | } 26 | 27 | dependencies { 28 | 29 | // Implementation 30 | implementation group: 'eu.benschroeder', name: 'mockito-extension', version: '4.3.0' 31 | implementation 'org.apache.logging.log4j:log4j-api:2.18.0' 32 | 33 | 34 | // Test Implementation 35 | testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.9.0' 36 | testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-params', version: '5.9.0' 37 | testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.9.0' 38 | testImplementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.18.0' 39 | testImplementation 'org.assertj:assertj-core:3.23.1' 40 | testImplementation 'org.hamcrest:hamcrest:2.2' 41 | testImplementation 'org.skyscreamer:jsonassert:1.5.1' 42 | //testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-migrationsupport', version: '5.9.0' 43 | // testImplementation group: 'org.mockito', name: 'mockito-junit-jupiter', version: '4.6.1' 44 | // testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.6.1' 45 | 46 | compileOnly 'org.projectlombok:lombok:1.18.24' 47 | 48 | // Test RuntimeOnly 49 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' 50 | } 51 | 52 | test { 53 | useJUnitPlatform() 54 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-kariuki/ace-the-java-coding-interview/fe026ca84495b00873262a13665b5cebc1dc1174/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * 6 | * Detailed information about configuring a multi-project build in Gradle can be found 7 | * in the user manual at https://docs.gradle.org/7.4/userguide/multi_project_builds.html 8 | * This project uses @Incubating APIs which are subject to change. 9 | */ 10 | 11 | rootProject.name = 'AceTheJavaCodingInterview' 12 | include('app') 13 | --------------------------------------------------------------------------------