{"id":19840309,"url":"https://github.com/rajneesh069/dsa-in-java","last_synced_at":"2025-09-05T02:40:21.377Z","repository":{"id":236044683,"uuid":"782627985","full_name":"rajneesh069/DSA-in-Java","owner":"rajneesh069","description":null,"archived":false,"fork":false,"pushed_at":"2024-09-01T06:22:31.000Z","size":498,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-12T12:36:54.363Z","etag":null,"topics":["dsa","dsa-java","dsa-practice","java"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rajneesh069.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-04-05T17:25:55.000Z","updated_at":"2024-10-22T05:11:42.000Z","dependencies_parsed_at":"2024-04-28T14:27:53.983Z","dependency_job_id":"c1aa30d7-bb2c-4575-8901-178a2a5b5282","html_url":"https://github.com/rajneesh069/DSA-in-Java","commit_stats":null,"previous_names":["rajneesh069/dsa","rajneesh069/dsa-in-java"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rajneesh069/DSA-in-Java","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajneesh069%2FDSA-in-Java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajneesh069%2FDSA-in-Java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajneesh069%2FDSA-in-Java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajneesh069%2FDSA-in-Java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rajneesh069","download_url":"https://codeload.github.com/rajneesh069/DSA-in-Java/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajneesh069%2FDSA-in-Java/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273703308,"owners_count":25152999,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-05T02:00:09.113Z","response_time":402,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dsa","dsa-java","dsa-practice","java"],"created_at":"2024-11-12T12:26:18.000Z","updated_at":"2025-09-05T02:40:16.363Z","avatar_url":"https://github.com/rajneesh069.png","language":"Java","readme":"# Notes\n\n## !!!Some important things!!!\n\n### - Always use pen and paper and dry run it!\n\n#### - `char to int conversion : char - '0'`\n\n#### - `number of digits in a number(say, a) = (int)(Math.log(a)) + 1`\n\n#### - Once you identify that the question is from a certain algo, stick to it and tweak it as per needs.\n\n### Linear Search Recursion\n\nLinear Search program in which the list has not been passed as an argument, it contains a very important concept that the function call returns finally to the place where it was called:\n\n```java\nstatic ArrayList\u003cInteger\u003e search(int[] arr, int target, int start) {\n        ArrayList\u003cInteger\u003e list = new ArrayList\u003cInteger\u003e();\n        if (start == arr.length) {\n            return list;\n        }\n        if (arr[start] == target) {\n            list.add(start);\n        }\n\n        ArrayList\u003cInteger\u003e ansFromBelow = search(arr, target, ++start); // very clever line!\n        list.addAll(ansFromBelow);\n\n        return list;\n    }\n```\n\n## Binary Search tid-bits\n\n1. You find target when start = end = target.\n2. Create an `ans` variable to store the potential answer.\n3. To find the last occurence of a repeated element in a sorted array, use `start = mid+1` in the `else` statement to break the loop and make sure you're storing the answer in that only.\n4. To find the first occurence, use `end = mid-1` to break the loop.\n5. If asked for searching in a sorted array(or `if sorted array mentioned`) then `think of Binary Search.` Or the time complexity of O(log(N)) is required.\n\n#### Following example illustrates those useful insights :\n\n```java\n    public class BSTidBits{\n        public static void main(String[] args){\n\n        }\n\n        static int binarySearch(int[] arr, int target){\n            int ans = -1;\n            int start = 0;\n            int end = arr.length-1;\n            while(start\u003c=end){\n                int mid = start + (end - start)/2;\n                if(arr[mid] \u003c target){\n                    start = mid+1;\n                }else if(arr[mid] \u003e target){\n                    end = mid-1;\n                }else{\n                    start = mid+1;\n                    //gives the last occurence of the repeated element, and of course\n                    //helps in breaking the loop as start will exceed end.\n                    ans = mid;\n                }\n            }\n        }\n    }\n\n```\n\n### Cyclic sort\n\n1. Array contains elements from (1,n) or (0, n) then you can think of cyclic sort.\n2. Could be the case that some element is missing in between the range, then also cyclic sort could be applied.\n\n## Recursion\n\n### It helps breaking large problems into smaller ones and then solve them.\n\n- Divide the problem into smaller chunks and solve them to reach the answer/goal.\n\n### Do not overthink. Overthink about recursion after solving the problem.\n\n#### Function calls return finally to the place they were called.\n\n### Basic Concept of recursion\n\n```java\npackage javaPlayground.revision1.recursion;\n\npublic class Main {\n    public static void main(String[] args) {\n        message(0);\n        message2(0);\n    }\n\n    private static void message(int n) {\n        if (n == 5) { // base condition\n            return;\n        }\n        System.out.println(\"Hello this is the message function.\\s\" + n); // prints the message\n        message(++n); // calls itself till its 5\n    }\n\n    private static void message2(int n) {\n        if (n == 5) { // base condition\n            return;\n        }\n        message2(n+1); // calls itself till its 5\n        System.out.println(\"Hello this is the message function.\\s\" + n); // prints the message\n    }\n}\n\n```\n\n### !!! Important !!!\n\n```java\npublic class Main{\n    public static void main(String[] args){\n        int ans = someFunction();\n        System.out.println(\"ans: \"+ans);\n    }\n\n    static int someFunction(){\n        return 69;\n    }\n}\n```\n\nAfter execution of `someFunction()`, it'll return(69 here) to that line(`int a = someFunction()`) defined above and ans will be assigned the return value of `someFunction()`.\n\n1. `Identify if problem could be broken down into smaller problems.`\n2. Write recurrence relation if needed.\n3. Draw the recursion tree.\n4. About the tree :\n\n   a. See the flow of the functions, and how they are called.\n\n   b. Identify and focus on left tree calls (firstly left side will be evaluated (in fibo(n-1)+fibo(n-2), fibo(n-1) will be called first)) and right tree calls.\n\n   c. Until the left tree call completes, right side won't be called.\n\n   d. See how the values are returned 'at each step'!\n\n   e. See where the function call comes out.\n\n#### Types of recurrence relations\n\n1. Linear : (fibo(n-1) + fibo(n-2))\n2. Divide and Conquer (e.g. Binary Search) :\n   f(n) = O(1) + f(n/2) -\u003e Recurrence Relation for Binary Search, O(1) denotes some constant time comparison/operation and since the search space is reduced by a factor(of 2 here), it is very fast.\n\n#### Variables in Recursion\n\n1. Arguments (updated value is passed from previous function to the current function) -\u003e think about it\n2. Return type -\u003e easy to figure out\n3. Body of the function (variable's value doesn't persist and is re-calculated each time) -\u003e think about it\n\nHere's the example of Binary Search :\n\nThis is the starting code, following code snippets will be updated to show the thinking process according to the points that follow through.\n\n```java\npublic class BinarySearch{\n    public static void main(String[] args){\n\n    }\n\n    //we'll return the index, so return type is int.\n    static int search(int[] arr, int target){\n    }\n}\n\n```\n\nIn the above code snippet we can clearly see that return type is easy to figure out. Now we'll try to think about the arguments, i.e., what arguments to pass and what should be their data type.\n\nNow in the body of the function we'll need three varibles of `int` type which are : `start`, `end` and `mid`, and the next function call will require the `start` and `end` of the previous call hence we'll need to pass them in the arguments of the function as well (`mid` would be evaluated in the body itself, so needs not to be passed).\n\n`Whatever you'll put in the arguments is going to go in the next function call, remember that!`\n\nAnd since we want to divide the array in half(see the recurrence relation) then obviously we'll need the previous `end` and `start` and the only way to get it is : through arguments!\n\n`mid` here is the variable which will be in the body of the function because it will be specific(based on `start` and `end`) for each function.\n\n#### Whichever variable is needed in the future function calls pass them as arguments/parameters of the function and whichever are specific to a function call should be kept in the body.\n\n```java\npublic class BinarySearch{\n    public static void main(String[] args){\n\n    }\n\n    //start and end are required in the future function calls hence they are provided in the argument itself.\n    static int search(int[] arr, int target, int start, int end){\n        if(start \u003e end){\n            return -1;\n        }\n\n        int mid = start + (end - start) / 2; //body variable\n        if(arr[mid] ==  target){\n            return mid;\n        }else if(target \u003c arr[mid]){\n            end = mid-1;\n            search(arr, target, start, end); //function call made with updated end variable\n        }else{\n            start = mid+1;\n            search(arr, target, start, end); //function call made with updated start variable\n        }\n\n    }\n}\n\n```\n\n#### But there's an error in the above code, can you spot it?\n\n### It is that whenever we call the function we don't return anything and `whenever you have a return type always return the function`.\n\n##### Final code :\n\n```java\npublic class BinarySearch{\n    public static void main(String[] args){\n\n    }\n\n    //start and end are required in the future function calls hence they are provided in the argument itself.\n    static int search(int[] arr, int target, int start, int end){\n        if(start \u003e end){\n            return -1;\n        }\n\n        int mid = start + (end - start) / 2; //body variable\n        if(arr[mid] ==  target){\n            return mid;\n        }else if(target \u003c arr[mid]){\n            end = mid-1;\n           return search(arr, target, start, end);\n           //function call made with updated end variable and added the return statement\n        }else{\n            start = mid+1;\n           return search(arr, target, start, end);\n           //function call made with updated start variable and added the return statement\n        }\n\n    }\n}\n\n```\n\n### Some standard approaches/problems in recursion\n\n#### Sum of digits of a number\n\n```java\npackage javaPlayground.revision1.recursion;\n\npublic class SumOfDigits {\n    /*\n     * Approach to hold answers from previous recursion calls and then\n     * add/concatenate them to the current one.\n     */\n    public static void main(String[] args) {\n        System.out.println(digitSum(12345));\n        System.out.println(digitSum(12345, 0));\n    }\n\n    static int digitSum(int num) {\n        return num == 0 ? 0 : (num % 10) + digitSum(num / 10);\n        // return in every function call is : digit + digitSum(num/10);\n        // except when num==0 then its 0.\n\n        /*\n         * Recursive tree :\n         * Call 1: 5 + digitSum(1234); --\u003e 5 + 10 = 15 \u003c-- eventually returns this\n         * Call 2: 4 + digitSum(123); --\u003e 4 + 6 = 10\n         * Call 3: 3 + digitSum(12); --\u003e 3 + 3 = 6\n         * Call 4: 2 + digitSum(1); --\u003e 2 + 1 = 3\n         * Call 5: 1 + digitSum(0); --\u003e 1 + 0 = 1\n         * Call 6: return 0;\n         *\n         */\n\n        // Then it traces back the recursion adding the answer from the previous\n        // function call to the current one eventually returning from Call 1 as 15.\n    }\n\n    static int digitSum(int num, int sum) {\n        // Pretty self explanatory, we maintained a sum across the function calls and\n        // then returned it in the base condition as an answer\n        if (num == 0) {\n            return sum;\n        }\n        int digit = num % 10;\n        sum += digit;\n        return digitSum(num / 10, sum);\n    }\n\n    // This is the analogy of recursive method to the iterative method.\n    static int iterativeMethodDigitSum(int num) {\n        int sum = 0; // sum maintained across the loop by being created outside its scope\n        while (num != 0) { // base condition to exit\n            int digit = num % 10; // variable which needs not to be maintained\n            sum += digit;\n            num /= 10;\n        }\n        return sum; // return the final answer\n    }\n\n    /*\n     * 1. since sum is maintained across the loop calls, hence put in function\n     * parameters\n     * 2. digit needs not to be maintained so its in the loop body.\n     * 3. num==0 exits the loop hence the base condition in function body\n     */\n}\n\n```\n\n#### Counting Zeroes in a number\n\n```java\npackage javaPlayground.revision1.recursion;\n\npublic class CountZeroes {\n    public static void main(String[] args) {\n\n    }\n\n    // Approach 1 -\u003e maintaining the count across the function calls by\n    // parameterizing it\n\n    static int countZeroes(int num, int count) {\n        if (num == 0) {\n            return count;\n        }\n        int digit = num % 10;\n        if (digit == 0) {\n            count++;\n        }\n        return countZeroes(num / 10, count);\n    }\n\n    /*\n     * Working :-\n     * let num = 1020, count =0;\n     * Call 1: countZeroes(1020, 0)\n     * Call 2: countZeroes(102, 1)\n     * Call 3: countZeroes(10, 1)\n     * Call 4: countZeroes(1, 2)\n     * Call 5: countZeroes(0, 2)\n     * Call 6: countZeroes(0, 2) -\u003e returns count, i.e, 2;\n     * Since every function call's return statement exited at line number 19, i.e.,\n     * at this statement : return countZeroes(num / 10, count); -\u003e the last line\n     * hence the calls before 6 will also go back at that line return the value from\n     * previous calls and simply exit the function, and we'll get 2.\n     *\n     */\n\n    // Approach 2 : adding the count from previous calls while holding the current\n    // one\n    static int countZeroes(int num) {\n        int currentCount = 0;\n        if (num == 0) {\n            return currentCount;\n        }\n        int digit = num % 10;\n        if (digit == 0) {\n            currentCount++;\n        }\n        int previousCount = countZeroes(num / 10); // every function call before last one\n        // will come back to this line, then go below add both the variables and return.\n        return currentCount + previousCount;\n    }\n    // Approach 2 has already been discussed in sum of digits question.\n}\n\n```\n\n#### Fibonacci Sequence using recursion\n\n```java\npackage javaPlayground.revision1.recursion;\n\npublic class FibonacciSequence {\n    public static void main(String[] args) {\n        System.out.println(fibo(3));\n    }\n\n    private static int fibo(int n) {\n        if (n \u003c= 1) {\n            return n;\n        }\n        return fibo(n - 1) + fibo(n - 2);\n    }\n}\n\n```\n\n#### Rotated Binary Search using Recursion\n\n```java\npackage recursion;\n\npublic class RotatedBinarySearch {\n    public static void main(String[] args) {\n        int[] arr = { 1, 2, 3, 4, 5 };\n        System.out.println(pivotElementWithDuplicateElementsIndex(arr, 0, arr.length - 1));\n    }\n\n    static int pivotElementWithDuplicateElementsIndex(int[] arr, int start, int end) {\n        if (start \u003e end) {\n            return start - 1;\n        }\n        int mid = start + (end - start) / 2;\n        if (mid \u003c arr.length - 1 \u0026\u0026 arr[mid] \u003e arr[mid + 1]) {\n            return mid;\n        } else if (mid \u003e= 1 \u0026\u0026 arr[mid - 1] \u003e arr[mid]) {\n            return mid - 1;\n        } else if (arr[mid] \u003c arr[start]) {\n            end = mid - 1;\n            return pivotElementWithDuplicateElementsIndex(arr, start, end);\n        } else if (arr[mid] == arr[end] \u0026\u0026 arr[mid] == arr[start]) {\n            if (start \u003c end \u0026\u0026 arr[start] \u003e arr[start + 1]) {\n                return start;\n            }\n            start++;\n            end--;\n            return pivotElementWithDuplicateElementsIndex(arr, start, end);\n        } else {\n            start = mid + 1;\n            return pivotElementWithDuplicateElementsIndex(arr, start, end);\n        }\n    }\n\n    // Second approach\n    /*\n     * static int pivotElementWithDuplicateElementsIndex(int[] arr, int start, int end) {\n        if (start \u003e end) {\n            return start - 1;\n        }\n        int mid = start + (end - start) / 2;\n        if (mid \u003c arr.length - 1 \u0026\u0026 arr[mid] \u003e arr[mid + 1]) {\n            return mid;\n        } else if (mid \u003e= 1 \u0026\u0026 arr[mid - 1] \u003e arr[mid]) {\n            return mid - 1;\n        } else if (arr[mid] \u003e arr[start]) {\n            start = mid + 1;\n            return pivotElementWithDuplicateElementsIndex(arr, start, end);\n        } else if (arr[start] == arr[mid] \u0026\u0026 arr[mid] != arr[end]) {\n            start = mid + 1;\n            return pivotElementWithDuplicateElementsIndex(arr, start, end);\n        } else if (arr[mid] == arr[end] \u0026\u0026 arr[mid] == arr[start]) {\n            if (start \u003c end \u0026\u0026 arr[start] \u003e arr[start + 1]) {\n                return start;\n            }\n            start++;\n            end--;\n            return pivotElementWithDuplicateElementsIndex(arr, start, end);\n        } else {\n            end = mid - 1;\n            return pivotElementWithDuplicateElementsIndex(arr, start, end);\n        }\n    }\n     */\n}\n\n```\n\n#### Remove A Character from string\n\n```java\npackage javaPlayground.revision1.recursion;\n\npublic class RemoveACharacter {\n    public static void main(String[] args) {\n        String up = new String(\"baccd\");\n        System.out.println(removeAChar(up));\n\n    }\n\n    static String removeAChar(String up) {\n        if (up.isEmpty()) {\n            return \"\";\n        }\n        if (up.charAt(0) == 'c') {\n            return removeAChar(up.substring(1));\n        }\n        return up.charAt(0) + removeAChar(up.substring(1)); // holding the answer of\n        // current call and then adding to it when the previous calls return the\n        // answer\n    }\n}\n\n```\n\n### Subsequences of a string : Processed(p) and Unprocessed(up) Strings Approach\n\n```java\npackage javaPlayground.revision1.recursion;\n\nimport java.util.ArrayList;\n\npublic class SubSequence {\n    // For subsequences, its always processed(p) and unprocessed(up) strings\n    public static void main(String[] args) {\n        String up = \"abc\";\n        String p = \"\";\n        // subsequences(up, p);\n        // ArrayList\u003cString\u003e ans = subsequences(up, p, new ArrayList\u003cString\u003e());\n        // System.out.println(ans);\n        System.out.println(subsequencesList(up, p));\n    }\n\n    // Approach 1\n    static void subsequences(String up, String p) {\n        if (up.isEmpty()) {\n            System.out.println(p);\n            return;\n        }\n        char ch = up.charAt(0);\n        subsequences(up.substring(1), p + (ch));\n        subsequences(up.substring(1), p);\n    }\n\n    // Approach 2\n    static ArrayList\u003cString\u003e subsequences(String up, String p, ArrayList\u003cString\u003e list) {\n        if (up.isEmpty()) { // You get the answer when the \"up\" is empty.\n            if (!p.isEmpty())\n                list.add(p); // add it to the list and return it\n            return list;\n        }\n        char ch = up.charAt(0);\n        subsequences(up.substring(1), p + (ch), list);\n        subsequences(up.substring(1), p, list);\n        return list;\n    }\n\n    // Approach 3\n    static ArrayList\u003cString\u003e subsequencesList(String up, String p) {\n        ArrayList\u003cString\u003e current = new ArrayList\u003c\u003e();\n        if (up.isEmpty()) {\n            current.add(p);\n            return current;\n        }\n        char ch = up.charAt(0);\n        ArrayList\u003cString\u003e left = subsequencesList(up.substring(1), p + (ch));\n        ArrayList\u003cString\u003e right = subsequencesList(up.substring(1), p);\n        left.addAll(right);\n        return left;\n    }\n}\n\n```\n\n### Subsets of an array with unique elements : Recursive Approach - Recommended\n\n- Always have an index 'i' in the parameter for array in recursion.\n\n```java\nimport java.util.*;\npublic class Subsets{\npublic List\u003cList\u003cInteger\u003e\u003e subsets(int[] arr) {\n        List\u003cList\u003cInteger\u003e\u003e ans = new ArrayList\u003c\u003e();\n        findSubsets(arr, 0, ans, new ArrayList\u003c\u003e());\n        return ans;\n    }\n\n    private static void findSubsets(int[] arr, int i, List\u003cList\u003cInteger\u003e\u003e ans, List\u003cInteger\u003e ds){\n        if(i==arr.length){\n            ans.add(new ArrayList\u003c\u003e(ds));\n            return;\n        }\n\n        ds.add(arr[i]);\n        findSubsets(arr, i+1, ans, ds);\n        ds.removeLast();\n\n        findSubsets(arr, i+1, ans, ds);\n    }\n}\n```\n\n### Subsets of an array `without` duplicate elements : Iterative Approach\n\n```java\npackage javaPlayground.revision1.recursion;\n\nimport java.util.ArrayList;\n\npublic class SubsetsOfAnArrayWithUniqueElements {\n    public static void main(String[] args) {\n        int[] arr = { 1, 2 };\n        // subsets : {}, {1}, {2}, {1,2}\n        System.out.println(subsetsOfAnArray(arr));\n    }\n    // we use iterative approach in this case as the recursive one needs\n    // backtracking and is less intuitive as well\n\n    static ArrayList\u003cArrayList\u003cInteger\u003e\u003e subsetsOfAnArray(int[] arr) {\n        ArrayList\u003cArrayList\u003cInteger\u003e\u003e outerList = new ArrayList\u003c\u003e();\n        outerList.add(new ArrayList\u003c\u003e()); // [ [] ]\n        for (int i = 0; i \u003c arr.length; i++) {\n            int n = outerList.size();\n            for (int j = 0; j \u003c n; j++) {\n                ArrayList\u003cInteger\u003e innerList = new ArrayList\u003c\u003e(outerList.get(j)); // copy of the outer list elements\n                innerList.add(arr[i]);\n                outerList.add(innerList);\n            }\n        }\n        return outerList;\n    }\n}\n\n```\n\n### Subsets of an array with duplicate elements : Recursive Approach - RECOMMENDED\n\n- Always use an index 'i' to traverse through the array in recursion.\n- The for loop intuition came from the Combinaton Sum II problem, as we have to remove duplicates.\n\n```java\nimport java.util.*;\nclass Solution {\n    public List\u003cList\u003cInteger\u003e\u003e subsetsWithDup(int[] arr) {\n        Arrays.sort(arr);\n        List\u003cList\u003cInteger\u003e\u003e ans = new ArrayList\u003c\u003e();\n        findSubsets(arr, 0, new ArrayList\u003c\u003e(), ans);\n        return ans;\n    }\n\n    private static void findSubsets(int[] arr, int ind, List\u003cInteger\u003e ds, List\u003cList\u003cInteger\u003e\u003e ans){\n        ans.add(new ArrayList\u003c\u003e(ds)); // creating a new array list each time\n\n        for(int i = ind; i\u003carr.length; i++){\n            if(i\u003eind \u0026\u0026 arr[i]==arr[i-1]) continue;\n            ds.add(arr[i]);\n            findSubsets(arr, i+1, ds, ans);\n            ds.removeLast();\n        }\n    }\n}\n```\n\n### Subsets of an array with duplicate elements : Iterative Approach\n\n```java\npackage javaPlayground.revision1.recursion;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\n\npublic class SubsetsOfAnArrayWithDuplicateElements {\n    public static void main(String[] args) {\n        int[] arr = { 1, 2, 2 };\n        System.out.println(subsets(arr));\n    }\n\n    static ArrayList\u003cArrayList\u003cInteger\u003e\u003e subsets(int[] arr) {\n        Arrays.sort(arr); // sort the array first\n        ArrayList\u003cArrayList\u003cInteger\u003e\u003e outerList = new ArrayList\u003c\u003e();\n        outerList.add(new ArrayList\u003c\u003e());\n        int start = 0, end = outerList.size() - 1;\n        for (int i = 0; i \u003c arr.length; i++) {\n            start = 0;\n            if (start \u003c end \u0026\u0026 i \u003e 0 \u0026\u0026 arr[i] == arr[i - 1]) {\n                start = end + 1;\n            }\n            end = outerList.size() - 1;\n            // int n = outerList.size();\n            for (int j = start; j \u003c= end; j++) {\n                ArrayList\u003cInteger\u003e innerList = new ArrayList\u003c\u003e(outerList.get(j));\n                innerList.add(arr[i]);\n                outerList.add(innerList);\n            }\n        }\n        return outerList;\n    }\n}\n```\n\n### Permutations of a string : Processed and Unprocessed Strings Approach\n\n```java\npackage javaPlayground.revision1.recursion;\n\npublic class Permuatations {\n    public static void main(String[] args) {\n        String up = new String(\"abc\");\n        String p = new String(\"\");\n        permuatations(up, p);\n    }\n\n    static void permuatations(String up, String p) {\n        // since there will be variable function(recursive) calls at each step\n        // hence we'll use loops to handle them\n        if (up.isEmpty()) {\n            System.out.println(p);\n            return;\n        }\n\n        char ch = up.charAt(0);\n        for (int i = 0; i \u003c= p.length(); i++) { // loop to fill spaces\n            String f = p.substring(0, i);\n            String s = p.substring(i, p.length());\n            permuatations(up.substring(1), f + ch + s);\n        }\n    }\n}\n\n```\n\n### Permutations of an array with No duplicate elements - Recursive - RECOMMENDED\n\n```java\npackage recursion.permutations;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class ArrayPermutations {\n    public List\u003cList\u003cInteger\u003e\u003e permute(int[] nums) {\n        boolean[] map = new boolean[nums.length];\n        List\u003cList\u003cInteger\u003e\u003e ans = new ArrayList\u003c\u003e();\n        findPermutations(nums, map, ans, new ArrayList\u003cInteger\u003e());\n        return ans;\n    }\n\n    private static void findPermutations(int[] nums, boolean[] map, List\u003cList\u003cInteger\u003e\u003e ans, List\u003cInteger\u003e ds) {\n        if (ds.size() == nums.length) {\n            ans.add(new ArrayList\u003c\u003e(ds));\n            return;\n        }\n\n        for (int i = 0; i \u003c nums.length; i++) {\n            if (map[i]==true) {\n               continue;\n            }\n            map[i] = true;\n            ds.add(nums[i]);\n            findPermutations(nums, map, ans, ds);\n            ds.removeLast();\n            map[i] = false;\n        }\n    }\n}\n\n```\n\n### Array Subsequences : Recursive Approach\n\n- Never modify the original array and always take an index 'i' to traverse through it.\n\n```java\npackage leetcode;\n\nimport java.util.*;\n\npublic class $39_CombinationSum {\n    public static void main(String[] args) {\n\n    }\n\n    static void findCombinations(int[] nums, ArrayList\u003cInteger\u003e ds, int i, int target) {\n        if (i == nums.length) {\n            if (target == 0) {\n                System.out.println(ds);\n            }\n\n            return;\n        }\n\n        if (nums[i] \u003c= target) {\n            ds.add(nums[i]);\n            findCombinations(nums, ds, i + 1, target - nums[i]);\n            ds.removeLast();\n        }\n\n        findCombinations(nums, ds, i + 1, target);\n\n    }\n}\n\n```\n\n### Array Subsequences with NO DUPLICATE ELEMENTS IN THE FINAL ARRAY\n\n```java\npackage leetcode;\n\nimport java.util.*;\n@SuppressWarnings(\"unused\")\npublic class $40_CombinationSum2 {\n    public static void main(String[] args) {\n\n    }\n\n    private static void findCombinations(int ind, int target, ArrayList\u003cArrayList\u003cInteger\u003e\u003e ans, ArrayList\u003cInteger\u003e ds,\n            int[] arr) {\n            // sort the array in the main function\n            if (target == 0) {\n                ans.add(new ArrayList\u003c\u003e(ds));\n                return;\n            }\n\n\n        for (int i = ind; i \u003c arr.length; i++) {\n            if (i \u003e ind \u0026\u0026 arr[i] == arr[i - 1])\n                continue;\n            if (arr[i] \u003e target)\n                break;\n\n            ds.add(arr[i]);\n            findCombinations(i + 1, target - arr[i], ans, ds, arr);\n            ds.removeLast();\n        }\n        }\n}\n\n```\n\n### Dice Roll Problem using Processed and Unprocessed Strings Approach\n\n```java\npackage javaPlayground.revision1.recursion;\n\nimport java.util.ArrayList;\n\npublic class Dice {\n    public static void main(String[] args) {\n        System.out.println(diceList(3, \"\"));\n    }\n\n    static void dice(int target, String p) {\n        if (target == 0) {\n            System.out.println(p);\n            return;\n        }\n\n        for (int i = 1; i \u003c= 6 \u0026\u0026 i \u003c= target; i++) { // loop for other combinations\n            dice(target - i, p + i);\n        }\n    }\n\n    // Another approach to hold the answer in prev and then add it to the current\n    // array list\n    static ArrayList\u003cString\u003e diceList(int target, String p) {\n        ArrayList\u003cString\u003e current = new ArrayList\u003c\u003e();\n        if (target == 0) {\n            current.add(p);\n            return current;\n        }\n        for (int i = 1; i \u003c= 6 \u0026\u0026 i \u003c= target; i++) {\n            ArrayList\u003cString\u003e prev = diceList(target - i, p + i);\n            current.addAll(prev);\n        }\n\n        return current;\n    }\n}\n\n```\n\n### Phone Pad Problem using Processed and Unprocessed Strings Approach\n\n```java\npackage javaPlayground.revision1.recursion;\n\nimport java.util.ArrayList;\n\npublic class PhonePad {\n    public static void main(String[] args) {\n        String up = new String(\"234\");\n        String p = new String(\"\");\n        phonePadCombinations(p, up);\n    }\n\n    static void phonePadCombinations(String p, String up) {\n        if (up.isEmpty()) {\n            System.out.println(p);\n            return;\n        }\n        int n = (int) (up.charAt(0) - '0');\n        if (n == 7) {\n            for (int i = 3 * (n - 2); i \u003c 3 * (n - 1) + 1; i++) {\n                char ch = (char) ('a' + i);\n                String f = p.substring(0, p.length());\n                phonePadCombinations(f + ch, up.substring(1));\n            }\n        } else if (n == 8) {\n            for (int i = 3 * (n - 2) + 1; i \u003c 3 * (n - 1) + 1; i++) {\n                char ch = (char) ('a' + i);\n                String f = p.substring(0, p.length());\n                phonePadCombinations(f + ch, up.substring(1));\n            }\n        } else if (n == 9) {\n            for (int i = 3 * (n - 2) + 1; i \u003c 3 * (n - 1) + 1; i++) {\n                char ch = (char) ('a' + i);\n                String f = p.substring(0, p.length());\n                phonePadCombinations(f + ch, up.substring(1));\n            }\n        } else {\n            for (int i = 3 * (n - 2); i \u003c 3 * (n - 1); i++) {\n                char ch = (char) ('a' + i);\n                String f = p.substring(0, p.length());\n                phonePadCombinations(f + ch, up.substring(1));\n            }\n        }\n    }\n\n    static ArrayList\u003cString\u003e phonePadCombinationsList(String p, String up) {\n        ArrayList\u003cString\u003e currentList = new ArrayList\u003c\u003e();\n        if (up.isEmpty()) {\n            currentList.add(p);\n            return currentList;\n        }\n        int n = (int) (up.charAt(0) - '0');\n        if (n == 7) {\n            for (int i = 3 * (n - 2); i \u003c 3 * (n - 1) + 1; i++) {\n                char ch = (char) ('a' + i);\n                String f = p.substring(0, p.length());\n                ArrayList\u003cString\u003e prev = phonePadCombinationsList(f + ch, up.substring(1));\n                currentList.addAll(prev);\n            }\n        } else if (n == 8) {\n            for (int i = 3 * (n - 2) + 1; i \u003c 3 * (n - 1) + 1; i++) {\n                char ch = (char) ('a' + i);\n                String f = p.substring(0, p.length());\n                ArrayList\u003cString\u003e prev = phonePadCombinationsList(f + ch, up.substring(1));\n                currentList.addAll(prev);\n            }\n        } else if (n == 9) {\n            for (int i = 3 * (n - 2) + 1; i \u003c 3 * (n - 1) + 2; i++) {\n                char ch = (char) ('a' + i);\n                String f = p.substring(0, p.length());\n                ArrayList\u003cString\u003e prev = phonePadCombinationsList(f + ch, up.substring(1));\n                currentList.addAll(prev);\n            }\n        } else {\n            for (int i = 3 * (n - 2); i \u003c 3 * (n - 1); i++) {\n                char ch = (char) ('a' + i);\n                String f = p.substring(0, p.length());\n                ArrayList\u003cString\u003e prev = phonePadCombinationsList(f + ch, up.substring(1));\n                currentList.addAll(prev);\n            }\n        }\n        return currentList;\n    }\n\n}\n\n```\n\n- Backtracking in Recursion\n\n- Backtracking is simply used to maintain the state of recursion, i.e., for the same function when the recursion comes back up to it from the stack then the variable's in the body/parameters need to be same.\n\n- For example, when we pass some string/array using reference then the actual string/array is being modified in each function call hence when the recursion comes back up in the tree to run some code below the call then the actual string/array for that function would have been modified which would result in unexpected behavior. So to reset it to the original state, i.e., to the state in which the recursion started for that string/array we revert the changes.\n\nThis preserves the actual state of the recursion and allows us to traverse through the recursive tree properly.\n\n- Maze traversal is the best example for this.\n\n- Or when we pass some array/string/variable and we need to come back up in the function to perform some operation on it then we might need to use backtracking if the operations are needed to be performed on the previous version of the variable, i.e., the one with which the recursion was called.\n\n- It's nothing different from recursion, just a fancy name.\n\n## Backtracking\n\n- We revert back the changes while returning to the original function calls in recursion.\n\n### Some standard problems to better understand the concept\n\n### Maze Traversal with Down and Right Paths\n\n```java\npackage javaPlayground.revision1.backtracking;\n\nimport java.util.ArrayList;\n\npublic class Maze {\n    public static void main(String[] args) {\n        // mazeTraversal(0, 0, \"\");\n        System.out.println(mazeTraversalList(0, 0, \"\"));\n    }\n\n    static void mazeTraversal(int row, int col, String p) {\n        if (row == 2 \u0026\u0026 col == 2) {\n            System.out.println(p);\n            return;\n        }\n\n        /*\n         * You cannot stand at row == 2 || col == 2 because then one of the\n         * if conditions would be satisfied and you'll make a move but rather\n         * once you reach at 2, the further moves in that direction are blocked!\n         */\n\n        if (row \u003c 2) {\n            // p = p+ 'D'; Don't do this as it changes 'p' for the whole body.\n            mazeTraversal(row + 1, col, p + 'D');\n        }\n\n        if (col \u003c 2) {\n            // p = p + 'R'; Don't do this as it changes 'p' for the whole body.\n            mazeTraversal(row, col + 1, p + 'R');\n        }\n    }\n\n    static ArrayList\u003cString\u003e mazeTraversalList(int row, int col, String p) {\n        ArrayList\u003cString\u003e current = new ArrayList\u003c\u003e();\n        if (row == 2 \u0026\u0026 col == 2) {\n            current.add(p);\n            return current;\n        }\n\n        // Here left and right refer to the calls in recursion tree and not paths.\n        if (row \u003c 2) {\n            ArrayList\u003cString\u003e left = mazeTraversalList(row + 1, col, p + 'D');\n            current.addAll(left);\n        }\n\n        if (col \u003c 2) {\n            ArrayList\u003cString\u003e right = mazeTraversalList(row, col + 1, p + 'R');\n            current.addAll(right);\n        }\n\n        return current;\n    }\n}\n\n```\n\n### Maze Traversal with Down, Right and Diagonal Paths\n\n```java\npackage javaPlayground.revision1.backtracking;\n\nimport java.util.ArrayList;\n\npublic class MazeWithDiagonal {\n    public static void main(String[] args) {\n        // mazeTraversal(2, 2, \"\");\n        System.out.println(mazeTraversalArrayList(2, 2, \"\"));\n    }\n\n    static void mazeTraversal(int row, int col, String p) {\n        if (row == 0 \u0026\u0026 col == 0) {\n            System.out.println(p);\n            return;\n        }\n\n        /*\n         * You cannot stand at row == 0 || col == 0 because then one of the\n         * if conditions would be satisfied and you'll make a move but rather\n         * once you reach at 0, the further moves in that direction are blocked!\n         */\n\n        if (row \u003e 0 \u0026\u0026 col \u003e 0) {\n            mazeTraversal(row - 1, col - 1, p + 'D'); // D : Diagonal\n        }\n\n        if (row \u003e 0) {\n            mazeTraversal(row - 1, col, p + 'V'); // V : Vertically down\n        }\n\n        if (col \u003e 0) {\n            mazeTraversal(row, col - 1, p + 'R'); // R : Right\n        }\n\n    }\n\n    static ArrayList\u003cString\u003e mazeTraversalArrayList(int row, int col, String p) {\n        ArrayList\u003cString\u003e currentPaths = new ArrayList\u003c\u003e();\n        if (row == 0 \u0026\u0026 col == 0) {\n            currentPaths.add(p);\n            return currentPaths;\n        }\n\n        if (row \u003e 0 \u0026\u0026 col \u003e 0) {\n            ArrayList\u003cString\u003e diagonalPath = mazeTraversalArrayList(row - 1, col - 1, p + 'D');\n            currentPaths.addAll(diagonalPath);\n        }\n\n        if (row \u003e 0) {\n            ArrayList\u003cString\u003e downPath = mazeTraversalArrayList(row - 1, col, p + 'V');\n            currentPaths.addAll(downPath);\n        }\n        if (col \u003e 0) {\n            ArrayList\u003cString\u003e rightPath = mazeTraversalArrayList(row, col - 1, p + 'R');\n            currentPaths.addAll(rightPath);\n        }\n\n        return currentPaths;\n    }\n}\n\n```\n\n### Maze Traversal with obstacles in the path\n\n```java\npackage javaPlayground.revision1.backtracking;\n\nimport java.util.ArrayList;\n\npublic class MazeWithObstacles {\n    public static void main(String[] args) {\n        // mazeWithObstacles(2, 2, \"\");\n        System.out.println(mazeWithObstaclesArrayList(2, 2, \"\"));\n    }\n\n    static void mazeWithObstacles(int row, int col, String p) {\n        if (row == 0 \u0026\u0026 col == 0) {\n            System.out.println(p);\n            return;\n        }\n\n        if (row == 1 \u0026\u0026 col == 1) { // obstacle at (1,1)\n            return;\n        }\n\n        if (row \u003e 0 \u0026\u0026 col \u003e 0) {\n            mazeWithObstacles(row - 1, col - 1, p + \"D\");\n        }\n\n        if (row \u003e 0) {\n            mazeWithObstacles(row - 1, col, p + 'V');\n        }\n\n        if (col \u003e 0) {\n            mazeWithObstacles(row, col - 1, p + 'R');\n        }\n    }\n\n    static ArrayList\u003cString\u003e mazeWithObstaclesArrayList(int row, int col, String p) {\n        ArrayList\u003cString\u003e current = new ArrayList\u003c\u003e();\n        if (row == 0 \u0026\u0026 col == 0) {\n            current.add(p);\n            return current;\n        }\n\n        if (row == 1 \u0026\u0026 col == 1) {\n            return current;\n        }\n        if (row \u003e 0 \u0026\u0026 col \u003e 0) {\n            ArrayList\u003cString\u003e diagonal = mazeWithObstaclesArrayList(row - 1, col - 1, p + 'D');\n            current.addAll(diagonal);\n        }\n        if (row \u003e 0) {\n            ArrayList\u003cString\u003e down = mazeWithObstaclesArrayList(row - 1, col, p + 'V');\n            current.addAll(down);\n        }\n        if (col \u003e 0) {\n            ArrayList\u003cString\u003e right = mazeWithObstaclesArrayList(row, col - 1, p + 'R');\n            current.addAll(right);\n        }\n        return current;\n    }\n}\n\n```\n\n### Maze Traversal with all paths allowed, i.e., Up, Down, Left and Right\n\n```java\npackage javaPlayground.revision1.backtracking;\n\nimport java.util.ArrayList;\n\npublic class MazeWithAllPathsAllowed {\n    public static void main(String[] args) {\n        boolean[][] path = new boolean[3][3];\n        mazeTraversalWithAllPaths(2, 2, \"\", path);\n        System.out.println(mazeTraversalWithAllPathsList(2, 2, \"\", path));\n    }\n\n    static void mazeTraversalWithAllPaths(int row, int col, String p, boolean[][] path) {\n        if (row == 0 \u0026\u0026 col == 0) {\n            path[row][col] = false;\n            System.out.println(p);\n            return;\n        }\n        if (path[row][col] == true) { // return if already visited so that you don't get into infinite loop\n            return;\n        }\n\n        path[row][col] = true; // as soon as you visit the cell, mark it true\n        if (row \u003e 0) {\n            mazeTraversalWithAllPaths(row - 1, col, p + 'D', path);\n\n        }\n        if (row \u003c 2) {\n            mazeTraversalWithAllPaths(row + 1, col, p + 'U', path);\n        }\n        if (col \u003e 0) {\n            mazeTraversalWithAllPaths(row, col - 1, p + 'R', path);\n        }\n        if (col \u003c 2) {\n            mazeTraversalWithAllPaths(row, col + 1, p + 'L', path);\n        }\n        path[row][col] = false; // backtrack, i.e., revert the changes you made for the future calls\n    }\n\n    static ArrayList\u003cString\u003e mazeTraversalWithAllPathsList(int row, int col, String p, boolean[][] path) {\n        ArrayList\u003cString\u003e current = new ArrayList\u003c\u003e();\n        if (row == 0 \u0026\u0026 col == 0) {\n            path[row][col] = false;\n            current.add(p);\n            return current;\n        }\n        if (path[row][col] == true) { // return if already visited so that you don't get into infinite loop\n            return current;\n        }\n\n        path[row][col] = true; // as soon as you visit the cell, mark it true\n        if (row \u003e 0) {\n            ArrayList\u003cString\u003e down = mazeTraversalWithAllPathsList(row - 1, col, p + 'D', path);\n            current.addAll(down);\n        }\n        if (row \u003c 2) {\n            ArrayList\u003cString\u003e up = mazeTraversalWithAllPathsList(row + 1, col, p + 'U', path);\n            current.addAll(up);\n        }\n        if (col \u003e 0) {\n            ArrayList\u003cString\u003e right = mazeTraversalWithAllPathsList(row, col - 1, p + 'R', path);\n            current.addAll(right);\n        }\n        if (col \u003c 2) {\n            ArrayList\u003cString\u003e left = mazeTraversalWithAllPathsList(row, col + 1, p + 'L', path);\n            current.addAll(left);\n        }\n        path[row][col] = false; // backtrack, i.e., revert the changes you made for the future calls\n        return current;\n    }\n}\n```\n\n## Time Complexity\n\n### Time Complexity != Time Taken\n\n#### It is actually how (in what fashion) the time increases as the input size increases.\n\n1. Constants and less power terms are ignored(only degree terms are kept) while writing the function in the big O notation. We are not interested in actual time, but how does it grow when `dataset increases and becomes large`.\n2. Always look for the worst case time complexity.\n\n#### General trend : O(1) \u003c O(log(n)) \u003c O(n) \u003c O(n\u003csup\u003e2\u003c/sup\u003e) \u003c O(2\u003csup\u003en\u003c/sup\u003e)\n\nOther time complexities like `nlog(n)` exist too, we'll have to figure out the trend accordingly if asked to compare.\nExponential time complexity is the worst as even for the small amount of data the time grows exponentially.\n\n#### Big-O notation gives the upper bound, i.e., the time complexity won't exceed the function inside it.\n\nFor example, O(N\u003csup\u003e3\u003c/sup\u003e) means that the algorithm could have time complexities of the order of 1, N\u003csup\u003e2\u003c/sup\u003e, NlogN, logN but shouldn't exceed N\u003csup\u003e3\u003c/sup\u003e.\n\nf(N) = O(g(N))\nlim (N -\u003e inf) f(N)/g(N) \u003c inf\n\n#### Big-Omega gives the lower bound, i.e., the time complexity should be atleast the function inside it.\n\nOpposite of Big-O\n\nf(N) = O(g(N))\nlim (N -\u003e inf) f(N)/g(N) \u003e 0\n\n#### Theta Notation gives the upper and lower bound both, like if the upper and lower bound both are N\u003csup\u003e2\u003c/sup\u003e for an alogrithm then Theta(N\u003csup\u003e2\u003c/sup\u003e) will represent that.\n\nTheta(N\u003csup\u003e2\u003c/sup\u003e)\ninf \u003e lim (N -\u003e inf) f(N)/g(N) \u003e 0\n\n##### Little O Notation gives the loose upper bound, not strict like Big O.\n\nLittle O is the less than and Big O is less than or equal to.\n\n#### Little omega gives the loose lower bound, not strict like Big Omega.\n\nLittle omega is less than and Big Omega is less than or equal to.\n\n## Space Complexity\n\nIt is the `input` space and the `auxiliary` space. In interviews we can't do anything about the input space hence we care about `auxiliary` space.\n\n### Recursive Algorithms\n\nSpace complexity = Height of the recursion tree, and remember that the interlinked function calls will be in the stack at the same time and NOT the unlinked ones!\n\nFor fibonacci, the space complexity is O(n).\n\nTypes of Recurrence relations :\n\n1. Linear\n2. Divide and Conquer\n\nRecursions have recurrence relations, i.e., can be represented in the form of an equation.\n\n#### Divide and Conquer Recurrence Relation :\n\n##### Form : T(x) = a1*T(b1*x+e1*(x)) + a2*T(b2*x+e2*(x)) +....+ak*T(bk*x+ek\\*(x)) + g(x);\n\nFor binary search : a1 = 1, b1 = 1/2, e1(x) = 0, g(x) = c\n\n## Bitwise Operators and Bit Manipulation\n\n1. n \u0026 (-n) gives us the position right most set bit.\n2. XOR from 0 to a :\n   1. a % 4 == 0 : a\n   2. a % 4 == 1 : 1\n   3. a % 4 == 2 : a + 1\n   4. a % 4 == 3 : 0\n3. bit ^ 1 = flipped bit\n4. `To find ith set bit in 'n', do (1\u003c\u003c(i-1)) \u0026 (n), if i is 1-based, if it is 0-based just put i: This is masking and is used at many places.`\n- XOR(L to R)=XOR(0 to R)⊕XOR(0 to L−1), both are inclusive.\n\n### AND(\u0026)\n\n1. If you do '\u0026' operation with 1, then the bits remain same.\n   1 \u0026 a = a\n\n### XOR(^)\n\n1. If you do '^' operation with 1, it gives the complement of that number.\n2. a ^ a = 0\n3. a ^ 0 = a\n\n### Left shift operator(\u003c\u003c)\n\n1. a\u003c\u003c1 = a*2 -\u003e a \u003c\u003c b = a * 2\u003csup\u003eb\u003c/sup\u003e(generally true unless there's an overflow).\n\n   Multiplies by 2.\n\n   Add 0 when you need an extra bit\n\n   Eg. 1010 \u003c\u003c 1 = 10100 which is 20 in decimal.\n\n2. 1 \u003c\u003c (n-1) = 1 \\* 2\u003csup\u003e(n-1)\u003c/sup\u003e\n\n### Right shift operator(\u003e\u003e)\n\n1. a\u003e\u003eb = a/(2\u003csup\u003eb\u003c/sup\u003e), divides by 2.(always true)\n   1010 \u003e\u003e 1 = 0101, which is 5 in decimal.\n\n   Leading zeroes are ignored in every number system.\n\nExamples :\n\n1. a\u003csup\u003eb\u003c/sup\u003e in O(log(b)) time complexity using right shift operator\n\n   ```java\n   // O(log(b)) -\u003e time complexity\n\n    public static int pow(int base, int index) {\n       int ans = 1;\n       while (index != 0) {\n           if ((index \u0026 1) != 0) {\n               ans = ans * base;\n           }\n           base *= base;\n           index = index \u003e\u003e 1;\n       }\n       return ans;\n   }\n   ```\n\n2. Find ith bit in a number\n   Ans. Use masking.\n\n   \"110101, find the 3rd bit(from right obviously)\n\n   110101 \u0026 (1\u003c\u003c2) = 1.\n\n   1 \u003c\u003c (n-1) -\u003e and with this value, and here n = 3;\n\n   0110101\n   \u0026000100\n\n   This will give 1.\n\n3. Set ith bit\n\n   110101, set the 4th bit.\n\n   OR it with the proper mask, i.e., (1\u003c\u003c3) OR 110101\n\n4. Reset ith bit\n\n   110101, reset the 5th bit.\n\n   AND it with the complement of the mask, i.e., !(1\u003c\u003c4) \u0026 110101\n\n#### Time complexity of Sieve Of Eratostheneses = O(N\\*log(logN))\n\n## Modulo Properties\n\n1. (a+b)%m = ((a%m) + (b%m))%m\n2. (a-b)%m = ((a%m) - (b%m)+m)%m\n3. (a\\*b)%m = ((a%m)\\*(b%m))%m\n4. (a/b)%m = ((a%m)\\*((b\u003csup\u003e-1\u003c/sup\u003e)%m))%m\n\n   (b\u003csup\u003e-1\u003c/sup\u003e)%m is known as multiplicative modulo inverse.\n   It also means that `b` and `m` are co-primes.\n\n5. (a%m)%m = a % m\n6. m\u003csup\u003ex\u003c/sup\u003e % m = 0, for all x \u003e 0.\n7. If p is a prime number which is not a divisor of b then ab\u003csup\u003ep-1\u003c/sup\u003e%p = a%p, due to Fermat's little theorem.\n\n## GCD/HCF\n\nDefinition : HCF of 2 numbers(say, a and b) is the `minimum positive` value of the equation `ax+by`, where `x and y are integers`.\n\nWhatever HCF you'll get will be `common`.\n\nSo, suppose 3x + 9y = 18, then the GCD of 3 and 9 will be 3 and will come out as `common`, so the equation reduces to x+3y = 6, i.e., 18 is divisible by 3. That gives us the solution to die-hard problem that yes using 3L and 9L bucket we can form 18L of water, because 3 came out as common and gave us an integer so combination of x and y will be there.\n\nFor, 2x+4y = 5 however, we can't do it, as 2 will be HCF and come out as common from the equation which won't divide 5 hence no combination of x and y will ever result in 5 as an answer.\n\nIf GCD is 1, then you can form any type RHS from the combination of x and y.\npackage bitwiseManipulation;\n\n### Euclid's algorithm : gcd(a,b) = gcd(rem(b,a),a)\n\n```java\npublic class GCD {\n    public static void main(String[] args) {\n        System.out.println(HCF(4, 8));\n    }\n\n    static int HCF(int a, int b) {\n        if (a == 0) {\n            return b;\n        }\n        return HCF(b % a, a);\n    }\n}\n```\n\n## LCM\n\nDefinition : Minimum number dvisible by both the numbers.\n\nHCF \\* LCM = Product of 2 numbers\n\n```java\npackage bitwiseManipulation;\n\npublic class FindLCMOfTwoNumbers {\n    public static void main(String[] args) {\n        System.out.println(LCM(33, 11));\n    }\n\n    static int LCM(int a, int b) {\n        return a * b / GCD(a, b);\n    }\n\n    static int GCD(int a, int b) { // Euclid's algo\n        if (a == 0) {\n            return b;\n        }\n        return GCD(b % a, a);\n    }\n}\n```\n\n- Sum of divisors from 1 to N\n  E.g. for n = 3, the answer is : (1*3) + (2*1) + (3\\*1)\n\n```java\nclass Solution{\n    static long sumOfDivisors(int N){\n        long finalSum =0;\n        for(int i=1; i\u003c=N;i++){\n            finalSum+= i*(N/i);\n        }\n        return finalSum;\n    }\n}\n```\n\n## Linked List\n\nA linked list is a linear data structure in which elements, known as nodes, are stored in a sequential manner. Each node contains two parts:\n\n1. Data: The value or data stored in the node.\n2. Reference (or Pointer): A reference or pointer to the next node in the sequence.\n\n### Singly Linked List without Tail\n\n```java\npackage javaPlayground.revision1.linkedList;\n\npublic class SinglyLinkedList {\n    public static void main(String[] args) {\n        SinglyLinkedList list = new SinglyLinkedList();\n        for (int i = 1; i \u003c 10; i++) {\n            list.add(i);\n        }\n        list.display();\n    }\n\n    private class Node {\n        private int val;\n        private Node next;\n\n        private Node(int val) {\n            this.val = val;\n        }\n    }\n\n    private Node head = null;\n    private int size = 0;\n\n    public void add(int val) {\n        head = add(head, val);\n    }\n\n    private Node add(Node head, int val) {\n        if (head == null) {\n            Node newNode = new Node(val);\n            this.size++;\n            head = newNode;\n            return head;\n        }\n        Node temp = head;\n        while (temp.next != null) {\n            /*\n             * we need to stop right at the tail when temp = tail,\n             * hence temp.next!=null.\n             */\n            temp = temp.next;\n        }\n        Node newNode = new Node(val);\n        temp.next = newNode;\n        newNode.next = null;\n        this.size++;\n        return head;\n    }\n\n    public void display() {\n        display(head);\n    }\n\n    private void display(Node head) {\n        if (head == null) {\n            System.out.println(\"Linkedlist is empty.\" + \" Size: \" + this.size);\n            return;\n        }\n        Node temp = head;\n        while (temp != null) {\n            /*\n             * this loop prints the value hence it needs to run for the tail\n             * but it will stop at tail and come out as temp = tail,\n             * and since we need it to run for the tail to print its value,\n             * hence temp!=null condition is there.\n             */\n            System.out.print(temp.val + \" -\u003e \");\n            temp = temp.next;\n        }\n        System.out.print(\"NULL\\n\");\n        System.out.println(\"Size: \" + this.size);\n    }\n\n    public void insertAfter(int index, int val) {\n        head = insertAfter(head, index, val);\n    }\n\n    private Node insertAfter(Node head, int index, int val) {\n        if (head == null) {\n            System.out.println(\"Linked list is empty. Consider adding an element first.\");\n            return null;\n        } else if (index \u003c 0 \u0026\u0026 index \u003e= size) {\n            System.out.println(\"Index out of bounds.\");\n            return head;\n        } else if (index == size) {\n            head = add(head, val);\n            this.size++;\n            return head;\n        }\n\n        Node newNode = new Node(val);\n        Node temp = head;\n        for (int i = 0; i \u003c index; i++) {\n            temp = temp.next;\n        }\n        newNode.next = temp.next;\n        temp.next = newNode;\n        this.size++;\n        return head;\n    }\n\n    public void remove(int index) {\n        head = remove(head, index);\n    }\n\n    private Node remove(Node head, int index) {\n        if (head == null) {\n            System.out.println(\"Linked list is empty, cannot remove.\");\n            return null;\n        } else if (index \u003c 0 || index \u003e= size) {\n            System.out.println(\"Invalid index, cannot remove.\");\n            return head;\n        } else if (index == 0) {\n            head = head.next;\n            this.size--;\n            return head;\n        }\n        Node temp = head;\n        for (int i = 0; i \u003c index - 1; i++) {\n            temp = temp.next;\n        }\n        if (temp.next != null) {\n            temp.next = temp.next.next;\n        }\n        this.size--;\n        return head;\n    }\n}\n\n```\n\n### Singly Linked List With Tail\n\n```java\npackage linkedList;\n\npublic class SinglyLinkedList {\n    public static void main(String[] args) {\n        SinglyLinkedList list = new SinglyLinkedList();\n        int[] array = { 1, 2, 3, 4, 5 };\n        list.addRecursively(array);\n        list.display();\n    }\n\n    private class Node {\n        private int value;\n        private Node next;\n\n        private Node(int value) {\n            this.value = value;\n        }\n\n    }\n\n    private Node head; // head is initially null\n    private Node tail; // tail is initially null\n    private int size;\n\n    public SinglyLinkedList() {\n        this.size = 0;\n    }\n\n    public void add(int value) { // 18 -\u003e 7\n        Node newNode = new Node(value);\n        this.size += 1;\n        if (head == null) {\n            head = newNode;\n            tail = head;\n            return; // neat way of initializing the first node\n        }\n        tail.next = newNode;\n        tail = newNode;\n\n    }\n\n    public void add(int value, int index) {\n        Node node = new Node(value);\n        Node temp = head;\n        this.size++;\n        if (index == 0) {\n            node.next = head;\n            head = node;\n            return;\n        }\n\n        else if (index == size) {\n            tail.next = node;\n            tail = node;\n            return;\n        }\n        for (int i = 0; i \u003c index; i++) {\n            if (i == index - 1) {\n                Node preserveNextNode = temp.next;\n                temp.next = node;\n                node.next = preserveNextNode;\n                break;\n            }\n            temp = temp.next;\n        }\n    }\n\n    public void delete(int index) {\n        this.size--;\n        if (index == 0) {\n            head = head.next;\n            return;\n        }\n        Node temp = head;\n        for (int i = 0; i \u003c index; i++) {\n            if (i == index - 1) {\n                Node node = temp.next;\n                temp.next = node.next;\n                return;\n            }\n            temp = temp.next;\n        }\n        if (head == null) {\n            tail = null;\n        }\n    }\n\n    public Node nodeAtIndex(int index) { // a utility function for getting node at a particular index\n        Node temp = head;\n        for (int i = 0; i \u003c index; i++) {\n            temp = temp.next;\n        }\n        return temp;\n    }\n\n    public void insertFirst(int value) {\n        Node newNode = new Node(value);\n        this.size += 1;\n        newNode.next = head;\n        head = newNode;\n        if (tail == null) {\n            tail = head;\n        }\n    }\n\n    public Node find(int value) {\n        Node temp = head;\n        for (int i = 0; i \u003c size; i++) {\n            if (temp.value == value) {\n                return temp;\n            }\n            temp = temp.next;\n        }\n        return null;\n    }\n\n    public void display() {\n        Node temp = head;\n        while (temp != null) {\n            System.out.print(temp.value + \" -\u003e \");\n            temp = temp.next;\n        }\n        System.out.print(\"END\\n\");\n        System.out.println(\"Size: \" + this.size);\n    }\n\n    // add using recursion\n    public void addRecursively(int[] array) {\n        for (int i = 0; i \u003c array.length; i++) {\n            head = addRecursively(head, array[i]);\n        }\n    }\n\n    private Node addRecursively(Node node, int value) {\n        if (node == null) {\n            Node newNode = new Node(value);\n            newNode.next = null;\n            this.size++;\n            return newNode;\n        }\n\n        node.next = addRecursively(node.next, value);\n        tail = node;\n        return node;\n    }\n\n    // insert with recursion\n    public void insert(int value, int index) {\n        head = insert(head, value, index);\n    }\n\n    private Node insert(Node node, int value, int index) {\n        if (index == 0) {\n            Node newNode = new Node(value);\n            newNode.next = node.next;\n            this.size++;\n            return newNode;\n        }\n        node.next = insert(node.next, value, index - 1);\n        return node;\n    }\n\n}\n```\n\n### Doubly Linked List\n\n```java\npackage linkedList;\n\npublic class DoublyLinkedList {\n    public static void main(String[] args) {\n        DoublyLinkedList list = new DoublyLinkedList();\n        list.insert(0, 0);\n        list.add(1);\n        list.display();\n    }\n\n    private class Node {\n        private int value;\n        private Node next = null;\n        private Node previous = null;\n\n        private Node(int value) {\n            this.value = value;\n        }\n    }\n\n    private Node head;\n    private Node tail;\n    private int size = 0;\n\n    public DoublyLinkedList() {\n        this.size = 0;\n    }\n\n    public void add(int value) {\n        Node newNode = new Node(value);\n        this.size++;\n        if (head == null) { // for the first node, we don't need to update the head ever\n            head = newNode;\n            tail = newNode;\n            return;\n        }\n\n        newNode.previous = tail;\n        tail.next = newNode;\n        tail = newNode;\n    }\n\n    public void insertFirst(int value) {\n        Node newNode = new Node(value);\n        this.size++;\n        if (tail == null) { // for the first node, we don't need to update the tail ever again\n            head = newNode;\n            tail = newNode;\n            return;\n        }\n\n        newNode.next = head;\n        head.previous = newNode;\n        head = newNode;\n\n    }\n\n    public void display() {\n        Node temp = head;\n        while (temp != null) {\n            System.out.print(temp.value + \" -\u003e \");\n            temp = temp.next;\n        }\n        System.out.print(\"NULL\\n\");\n        System.out.println(\"Size: \" + this.size);\n        return;\n    }\n\n    public void displayInverted() {\n        Node temp = tail;\n        while (temp != null) {\n            System.out.print(temp.value + \" -\u003e \");\n            temp = temp.previous;\n        }\n        System.out.print(\"NULL\\n\");\n        System.out.println(\"Size: \" + this.size);\n    }\n\n    public Node getNodeAtIndex(int index) {\n        Node temp = head;\n        for (int i = 0; i \u003c index; i++) {\n            temp = temp.next;\n        }\n        return temp;\n    }\n\n    public void delete(int index) {\n        if (index \u003c 0 || index \u003e= size) {\n            System.out.println(\"Cannot be deleted. Index out of bounds.\");\n            return;\n        }\n\n        this.size--; // size is at least 1\n        Node nodeToBeDeleted = getNodeAtIndex(index);\n\n        if (nodeToBeDeleted == head) {\n            if (head.next != null) { // head.next will be null if there's only one element\n                head = head.next;\n                head.previous = null;\n            } else {\n                head = null;\n                tail = null;\n            }\n            return;\n        } else if (nodeToBeDeleted == tail) {\n            if (tail.previous != null) {\n                tail = tail.previous;\n                tail.next = null;\n            } else { // tail.previous will be null if and only there's one element\n                head = null;\n                tail = null;\n            }\n            return;\n        }\n\n        nodeToBeDeleted.previous.next = nodeToBeDeleted.next;\n        nodeToBeDeleted.next.previous = nodeToBeDeleted.previous;\n    }\n\n    public void insert(int value, int index) {\n        if (index \u003c 0) {\n            System.out.println(\"Index out of bounds.\");\n            return;\n        }\n        Node newNode = new Node(value);\n        Node nodeAtThatIndex = getNodeAtIndex(index);\n        if (nodeAtThatIndex != null \u0026\u0026 nodeAtThatIndex == head) {\n            this.size++;\n            newNode.next = head;\n            head.previous = newNode;\n            head = newNode;\n            head.previous = null;\n        } else if (nodeAtThatIndex != null \u0026\u0026 nodeAtThatIndex != tail) {\n            this.size++;\n            newNode.previous = nodeAtThatIndex;\n            newNode.next = nodeAtThatIndex.next;\n            nodeAtThatIndex.next.previous = newNode;\n            nodeAtThatIndex.next = newNode;\n        } else {\n            this.add(value);\n            return;\n        }\n    }\n\n}\n\n```\n\n### Circular Linked List\n\n- Demonstrates the implementation without tail and how to traverse through the list.\n\n```java\npackage javaPlayground;\n\npublic class j8 {\n    public static void main(String[] args) {\n        j8 CLL = new j8();\n        for (int i = 0; i \u003c 10; i++) {\n            CLL.add(i);\n        }\n        CLL.display();\n        CLL.insertAfter(9, 33);\n        CLL.display();\n    }\n\n    private class Node {\n        private int value;\n        private Node next;\n\n        private Node(int value) {\n            this.value = value;\n        }\n    }\n\n    private int size;\n    private Node head;\n\n    /*\n     * To reach the node just before the head\n     * Node temp = head;\n     * do{\n     * temp = temp.next;\n     * }while(temp.next!=head);\n     * Now temp, just before head and obviously since temp.next == head, hence for\n     * that last node the do{} block won't run obviously.\n     */\n\n    public void add(int value) {\n        if (head == null) {\n            Node headNode = new Node(value);\n            head = headNode;\n            headNode.next = head;\n            this.size++;\n            return;\n        }\n\n        Node newNode = new Node(value);\n        Node temp = head;\n        do {\n            temp = temp.next;\n        } while (temp.next != head);\n        temp.next = newNode;\n        newNode.next = head;\n        this.size++;\n        return;\n    }\n\n    public void insertFirst(int value) {\n        if (head == null) {\n            Node headNode = new Node(value);\n            head = headNode;\n            headNode.next = head;\n            this.size++;\n            return;\n        }\n\n        Node temp = head;\n        Node newNode = new Node(value);\n        newNode.next = head;\n\n        do {\n            temp = temp.next;\n        } while (temp.next != head);\n\n        temp.next = newNode;\n        head = newNode;\n        this.size++;\n    }\n\n    public void insertAfter(int index, int value) {\n        if (index \u003c 0 || index \u003e= size) {\n            System.out.println(\"Index out of bounds, cannot insert.\");\n            return;\n        } else if (index == size - 1) {\n            this.add(value);\n            this.size++;\n        } else {\n            Node newNode = new Node(value);\n            Node temp = head;\n            int i = 0;\n            do {\n                temp = temp.next;\n                i++;\n            } while (temp.next != head \u0026\u0026 i \u003c index);\n            newNode.next = temp.next;\n            temp.next = newNode;\n            this.size++;\n            return;\n        }\n    }\n\n    public void display() {\n        display(head);\n    }\n\n    private void display(Node node) {\n        if (node == null) {\n            System.out.println(\"Linked list is empty.\");\n            return;\n        }\n\n        Node temp = node;\n        do {\n            System.out.print(temp.value + \" -\u003e \");\n            temp = temp.next;\n        } while (temp != head); // keep this in mind, we have to go till head\n        System.out.print(\"HEAD\\n\");\n        System.out.println(\"Size: \" + size);\n    }\n\n}\n\n```\n\n## Stack\n\nA stack is a linear data structure that follows the Last In, First Out (LIFO) principle. This means that the last element added to the stack will be the first one to be removed. Stacks are used in various applications such as expression evaluation, function call management in recursion, and backtracking algorithms.\n\nKey Operations:\n\n1. Push: Add an element to the top of the stack.\n2. Pop: Remove and return the top element from the stack.\n3. Peek (or Top): Return the top element without removing it.\n4. isEmpty: Check if the stack is empty.\n5. Size: Get the number of elements in the stack.\n\n### Custom Stack\n\n```java\npackage stackAndQueues;\npublic class Stack {\n    public static void main(String[] args) {\n        Stack stack = new Stack(15);\n        for (int i = 0; i \u003c 10; i++) {\n            stack.push(i);\n        }\n        for (int i = 0; i \u003c 10; i++) {\n            int val = stack.pop();\n            System.out.println(val);\n        }\n    }\n\n    private int[] data;\n    private int top = -1;\n    private static final int DEFAULT_SIZE = 10;\n\n    public Stack() {\n        // data = new int[DEFAULT_SIZE];\n        this(DEFAULT_SIZE); // calls the appropriate constructor\n    }\n\n    public Stack(int size) {\n        data = new int[size];\n    }\n\n    public boolean push(int value) {\n        if (isFull()) {\n            System.out.println(\"Cannot add to a full stack.\");\n            return false;\n        }\n        data[++this.top] = value;\n        return true;\n    }\n\n    public int pop() {\n        if (isEmpty()) {\n            System.out.println(\"Cannot remove from an empty stack.\");\n            return -1;\n        }\n        return data[this.top--];\n    }\n\n    public int peek() {\n        if (isEmpty()) {\n            System.out.println(\"Cannot peek in an empty stack.\");\n            return -1;\n        }\n        return data[top];\n    }\n\n    private boolean isFull() {\n        return top == data.length - 1;\n    }\n\n    private boolean isEmpty() {\n        return top == -1;\n    }\n\n}\n\n```\n\n### Dynamic Stack\n\n```java\npackage stackAndQueues;\n\npublic class DynamicStack {\n    public static void main(String[] args) {\n        DynamicStack stack = new DynamicStack();\n        for (int i = 0; i \u003c 15; i++) {\n            stack.push(i);\n        }\n        System.out.println(stack.peek());\n\n    }\n\n    private int top = -1;\n    private static final int DEFAULT_SIZE = 10;\n    private int[] data;\n\n    public DynamicStack() {\n        this.data = new int[DEFAULT_SIZE];\n    }\n\n    public boolean push(int value) {\n        if (isFull()) {\n            resize();\n        }\n        data[++this.top] = value;\n        return true;\n    }\n\n    public int pop() {\n        if (isEmpty()) {\n            System.out.println(\"Cannot pop from an empty stack.\");\n            return -1;\n        }\n        return data[top--];\n    }\n\n    public int peek() {\n        return data[top];\n    }\n\n    private boolean isFull() {\n        return top == data.length - 1;\n    }\n\n    private boolean isEmpty() {\n        return top == -1;\n    }\n\n    private void resize() {\n        int[] temp = new int[data.length * 2];\n        for (int i = 0; i \u003c data.length; i++) {\n            temp[i] = data[i];\n        }\n        this.data = temp; // very important line\n    }\n\n}\n\n```\n\n## Queue\n\nDefinition of Queue\nA queue is a linear data structure that follows the First In, First Out (FIFO) principle. This means that the first element added to the queue will be the first one to be removed. Queues are used in various applications such as task scheduling, handling requests in a server, and breadth-first search (BFS) in graphs.\n\nKey Operations:\n\n1. Enqueue (or Offer): Add an element to the end of the queue.\n2. Dequeue (or Poll): Remove and return the front element from the queue.\n3. Peek (or Front): Return the front element without removing it.\n4. isEmpty: Check if the queue is empty.\n5. Size: Get the number of elements in the queue.\n\n### Queue Methods\n\n| Method       | Action                     | Empty Queue Behavior            | Exception Thrown         |\n| ------------ | -------------------------- | ------------------------------- | ------------------------ |\n| `add(E e)`   | Inserts element            | Throws `IllegalStateException`  | `IllegalStateException`  |\n| `offer(E e)` | Inserts element            | Returns `false`                 | None                     |\n| `peek()`     | Retrieves head (no remove) | Returns `null`                  | None                     |\n| `element()`  | Retrieves head (no remove) | Throws `NoSuchElementException` | `NoSuchElementException` |\n| `poll()`     | Retrieves and removes head | Returns `null`                  | None                     |\n| `remove()`   | Retrieves and removes head | Throws `NoSuchElementException` | `NoSuchElementException` |\n\n```java\npackage stackAndQueues;\n\npublic class Queue {\n    public static void main(String[] args) {\n        Queue queue = new Queue();\n        for (int i = 0; i \u003c 15; i++) {\n            queue.add(i);\n        }\n        System.out.println(queue.remove());\n        System.out.println(queue.remove());\n    }\n\n    private int[] data;\n    private int first = 0;\n    private int current = -1;\n    private static final int DEFAULT_SIZE = 10;\n\n    public Queue() {\n        this(DEFAULT_SIZE);\n    }\n\n    public Queue(int size) {\n        this.data = new int[size];\n    }\n\n    public boolean add(int value) {\n        if (isFull()) {\n            System.out.println(\"Cannot add to a full queue.\");\n            return false;\n        }\n        data[++this.current] = value;\n        return true;\n    }\n\n    public int remove() {\n        if (isEmpty()) {\n            System.out.println(\"Cannot remove from an empty queue.\");\n            return -1;\n        }\n        return data[this.first++];\n    }\n\n    private boolean isFull() {\n        return this.current == data.length - 1;\n    }\n\n    private boolean isEmpty() {\n        return this.current == -1;\n    }\n\n}\n\n```\n\n### Queue with One Pointer\n\n```java\npackage stackAndQueues;\n\n\npublic class QueueWithOnePointer {\n    public static void main(String[] args) {\n        QueueWithOnePointer queue = new QueueWithOnePointer();\n        for (int i = 0; i \u003c 10; i++) {\n            queue.add(i);\n        }\n        queue.remove();\n        queue.remove();\n        queue.display();\n    }\n\n    private int ptr = -1;\n    private int[] data;\n    private static final int DEFAULT_SIZE = 10;\n\n    public QueueWithOnePointer() {\n        this(DEFAULT_SIZE);\n    }\n\n    public QueueWithOnePointer(int size) {\n        this.data = new int[size];\n    }\n\n    public boolean add(int value) {\n        if (isFull()) {\n            System.out.println(\"Cannot add to a full queue.\");\n            return false;\n        }\n        data[++ptr] = value;\n        return true;\n    }\n\n    public int remove() {\n        if (isEmpty()) {\n            System.out.println(\"Cannot remove from an empty queue.\");\n            return -1;\n        }\n        int deletedValue = data[0];\n        for (int i = 0; i \u003c data.length - 1; i++) { // left shifting the array by 1\n            data[i] = data[i + 1];\n        }\n        this.ptr--;\n        return deletedValue;\n    }\n\n    public void display() {\n        for (int i = 0; i \u003c= ptr; i++) {\n            System.out.print(data[i] + \" \u003c-\\s\");\n        }\n        System.out.print(\"END\");\n    }\n\n    private boolean isEmpty() {\n        return ptr == -1;\n    }\n\n    private boolean isFull() {\n        return ptr == data.length - 1;\n    }\n}\n```\n\n### Dynamic Queue\n\n```java\npackage stackAndQueues;\n\npublic class DynamicQueue {\n    public static void main(String[] args) {\n        DynamicQueue queue = new DynamicQueue();\n\n        queue.add(1);\n        queue.add(2);\n        queue.display();\n\n        queue.remove();\n        queue.display();\n    }\n\n    private int[] data;\n    private int first = 0;\n    private int last = 0;\n    private int size = 0;\n    private static final int DEFAULT_SIZE = 10;\n\n    public DynamicQueue() {\n        this(DEFAULT_SIZE);\n    }\n\n    public DynamicQueue(int initialSize) {\n        this.data = new int[initialSize];\n    }\n\n    private boolean isFull() {\n        return size == data.length;\n    }\n\n    private boolean isEmpty() {\n        return size == 0;\n    }\n\n    private boolean resize() {\n        int[] temp = new int[2 * data.length];\n        for (int i = first; i \u003c size; i++) {\n            temp[i] = data[i];\n        }\n        data = temp;\n        return true;\n    }\n\n    public boolean add(int value) {\n        if (isFull()) {\n            resize();\n        }\n        data[this.last] = value;\n        last = last + 1;\n        this.size++;\n        return true;\n    }\n\n    public int remove() {\n        if (isEmpty()) {\n            System.out.println(\"Cannot remove from an empty queue.\");\n            return -1;\n        }\n\n        int value = data[this.first];\n        first = first + 1;\n        this.size--;\n        return value;\n    }\n\n    public void display() {\n        if (isEmpty()) {\n            System.out.println(\"Queue is empty.\");\n            return;\n        }\n        for (int i = first; i \u003c last; i++) {\n            System.out.print(data[i] + \" -\u003e \");\n        }\n        System.out.print(\"END\\n\");\n    }\n\n```\n\n## Circular Queue\n\n```java\npackage stackAndQueues;\n\npublic class CircularQueue {\n    public static void main(String[] args) {\n        CircularQueue queue = new CircularQueue();\n        for (int i = 0; i \u003c 10; i++) {\n            queue.add(i);\n        }\n        queue.remove();\n        queue.add(99);\n        queue.display();\n        // for (int i = 0; i \u003c 10; i++) {\n        // System.out.println(queue.remove());\n        // }\n    }\n\n    private int first = 0;\n    private int last = 0;\n    private int[] data;\n    private int size;\n    private final static int DEFAULT_SIZE = 10;\n\n    public CircularQueue() {\n        this(DEFAULT_SIZE);\n    }\n\n    public CircularQueue(int size) {\n        this.data = new int[size];\n    }\n\n    public boolean add(int value) {\n        if (isFull()) {\n            System.out.println(\"Cannot add to a full circular queue.\");\n            return false;\n        }\n        data[last] = value;\n        this.last = this.last + 1;\n        this.last = (this.last) % data.length;\n        this.size++;\n        return true;\n    }\n\n    public int remove() {\n        if (isEmpty()) {\n            System.out.println(\"Cannot remove from an empty circular queue.\");\n            return -1;\n        }\n        int value = data[this.first];\n        this.first = this.first + 1;\n        this.first = (this.first) % data.length;\n        this.size--;\n        return value;\n    }\n\n    public int peek() {\n        if (isEmpty()) {\n            System.out.println(\"Cannot peek in an empty circular queue.\");\n            return -1;\n        }\n        return data[first];\n    }\n\n    public void display() {\n        if (isEmpty()) {\n            System.out.println(\"Queue is empty.\");\n            return;\n        }\n\n        int i = first;\n        do {\n            System.out.print(data[i] + \" -\u003e \");\n            i = (i + 1) % data.length;\n        } while (i != last);\n        System.out.print(\"END\");\n    }\n\n    private boolean isEmpty() {\n        return size == 0;\n    }\n\n    private boolean isFull() {\n        return size == data.length;\n    }\n}\n```\n\n### Dynamic Circular Queue\n\n```java\npackage stackAndQueues;\n\npublic class DynamicCircularQueue {\n    public static void main(String[] args) {\n        DynamicCircularQueue queue = new DynamicCircularQueue();\n        for (int i = 0; i \u003c 20; i++) {\n            queue.add(i);\n        }\n        queue.remove();\n        queue.display();\n    }\n\n    private int[] data;\n    private int size;\n    private int first;\n    private int last;\n    private final static int DEFAULT_SIZE = 10;\n\n    public DynamicCircularQueue() {\n        this(DEFAULT_SIZE);\n    }\n\n    public DynamicCircularQueue(int initialSize) {\n        this.data = new int[initialSize];\n    }\n\n    private boolean resize() {\n        int[] temp = new int[data.length * 2];\n        int i = 0;\n        do {\n            temp[i] = data[(first + i) % data.length];\n            ++i;\n        } while (i != data.length);\n        first = 0;\n        last = data.length;\n        data = temp;\n        return true;\n    }\n\n    private boolean isFull() {\n        return size == data.length;\n    }\n\n    private boolean isEmpty() {\n        return size == 0;\n    }\n\n    public boolean add(int value) {\n        if (isFull()) {\n            resize();\n        }\n        data[last] = value;\n        last = (last + 1) % data.length;\n        this.size++;\n        return true;\n    }\n\n    public int remove() {\n        if (isEmpty()) {\n            System.out.println(\"Cannot remove from an empty queue.\");\n            return -1;\n        }\n\n        int value = data[first];\n        first = (first + 1) % data.length;\n        this.size--;\n        return value;\n    }\n\n    public int peek() {\n        if (isEmpty()) {\n            System.out.println(\"Cannot peak in an empty queue.\");\n            return -1;\n        }\n        return data[first];\n    }\n\n    public void display() {\n        if (isEmpty()) {\n            System.out.println(\"Queue is empty.\");\n            return;\n        }\n        int i = first;\n        do {\n            System.out.print(data[i] + \" -\u003e \");\n            i = (i + 1) % data.length;\n        } while (i != last);\n        System.out.print(\"END\");\n    }\n}\n\n```\n\n## Trees\n\n1. It consists of nodes. In case of a binary tree, they are atmost 2 in number.\n2. Nodes \u0026rarr; root , internal, leaf.\n3. Leaf : They have no children.\n4. Root : Topmost node is root.\n5. Internal : Nodes with atleast 1 child.\n6. `Height of a tree =  Max(height(leftSubtree), height(rightSubtree)).`\n7. `Height of a node is Max number of edges from that node to the leaf node.`\n8. Level of a node = Height of root - Height of the node.\n\n#### `Time complexity while inserting, removing or traversing a binary tree(balanced) is O(log(N)).`\n\n```java\nimport java.util.Scanner;\n\npublic class BinaryTree {\n    private Node root; // intially null\n\n    private static class Node {\n        int value;\n        Node left;\n        Node right;\n\n        public Node(int value) {\n            this.value = value;\n        }\n\n    }\n\n    public void populate(Scanner scanner) {\n        System.out.println(\"Input the value of root node: \");\n        root = new Node(scanner.nextInt());\n        populate(scanner, root);\n    }\n\n    private void populate(Scanner scanner, Node node) {\n        System.out.print(\"Do you want to add a left node to  \" + node.value + \": \");\n        boolean left = scanner.nextBoolean();\n        if (left) {\n            System.out.print(\"Enter the value of the left node: \");\n            int val = scanner.nextInt();\n            node.left = new Node(val);\n            populate(scanner, node.left);\n        }\n\n        System.out.print(\"Do you want to add a right node to \" + node.value + \": \");\n        boolean right = scanner.nextBoolean();\n        if (right) {\n            System.out.print(\"Enter the value of the right node: \");\n            int val = scanner.nextInt();\n            node.right = new Node(val);\n            populate(scanner, node.right);\n        }\n    }\n\n    public void display() {\n        display(this.root, \"\");\n    }\n\n    private void display(Node node, String indent) {\n        if (node == null) {\n            return;\n        }\n        System.out.println(indent + node.value);\n        display(node.left, \"\\t\");\n        display(node.right, \"\\t\");\n    }\n\n}\n\n```\n\n### Calculating height of a node in a binary tree\n\n```java\npackage binaryTrees;\n\n@SuppressWarnings(\"unused\")\npublic class HeightOfANode {\n    private class Node {\n        private int value;\n        private Node left;\n        private Node right;\n    }\n\n    private Node root;\n\n    private int height(Node node) {\n        if (node == null) {\n            return 0;\n        }\n\n        int left = height(node.left);\n        int right = height(node.right);\n\n        return Math.max(left, right) + 1;\n\n    }\n}\n\n```\n\n### Finding a Node in a binary tree\n\n```java\nprivate Node findNode(Node root, Node node, int x) {\n\n        if (root == node) {\n            return node;\n        }\n\n        if (node == null) {\n            return null;\n        }\n\n        if (node.value == x) {\n            return node;\n        }\n\n        Node left = findNode(root, node.left, x);\n        if (left != null) {\n            return left;\n        }\n        return findNode(root, node.right, x);\n\n    }\n```\n\n### Finding level of a node in a binary tree\n\n```java\npackage binaryTrees;\n\n@SuppressWarnings(\"unused\")\npublic class LevelOfNodes {\n    // We'll find the level of nodes.\n    private class Node {\n        private int value;\n        private Node left;\n        private Node right;\n\n        private Node(int value) {\n            this.value = value;\n        }\n    }\n\n    private Node root;\n\n    private int findLevel(Node node, Node x, int level) {\n        if (root == null) {\n            return -1;\n        }\n\n        if (node == null) {\n            return 0;\n        }\n\n        if (node == x) {\n            return level;\n        }\n\n        int left = findLevel(node.left, x, level + 1);\n        if (left != 0) {\n            return left;\n        }\n        return findLevel(node.right, x, level + 1);\n\n    }\n}\n\n```\n\n## Traversal Methods in [Depth First Search](#depth-first-search)\n\n#### The traversal methods are for Binary Trees in general.\n\n#### Pre-order : N \u0026rarr; L \u0026rarr; R\n\n- Can be seen as \"top-to bottom\"\n- Used for evaluating mathematical expressions or making a copy.\n- Convert string/array in a Binary Tree or serialize data.\n\n```java\nprivate void preOrder(Node node){\n    if(node==null){\n        return;\n    }\n\n    System.out.println(node.value +\"\\s\");\n    preOrder(node.left);\n    preOrder(node.right);\n}\n```\n\n#### In-order : L \u0026rarr; N \u0026rarr; R\n\n- For sorted order traversal in a Binary Tree, we can use this.\n\n```java\nprivate void inOrder(Node node){\n    if(node==null){\n        return;\n    }\n\n    inOrder(node.left);\n    System.out.println(node.value +\"\\s\");\n    inOrder(node.right);\n}\n```\n\n#### Post-order : L \u0026rarr; R \u0026rarr; N\n\n- Can be seen as \"bottom-to-top\"\n- To delete something from the Binary Tree.\n- When we perform bottom-up calculation(like calculating the height or diameter of a tree), then we can use it.\n\n```java\nprivate void postOrder(Node node){\n    if(node==null){\n        return;\n    }\n\n    postOrder(node.left);\n    postOrder(node.right);\n    System.out.println(node.value +\"\\s\");\n}\n```\n\n## Binary Search Trees\n\n- The left child node always contains value less than the parent node.\n- The right child node always contains value greater than the parent node.\n- BSTs are helpful while traversing, inserting or removing elements as they follow above constraints and have a time complexity of O(log(N)).\n\n### What are Balanced Binary Search Trees?\n\n#### Height(Left Subtree) - Height(Right Subtree) \u003c=1.\n\n### Why Balanced Binary Search Trees?\n\n#### Because, in unbalanced the time complexity of worst case rises upto O(N).\n\n```java\npublic class BST {\n    public BST() {\n\n    }\n\n    private Node root;\n\n    private class Node {\n        private int value;\n        private int height;\n        private Node right;\n        private Node left;\n\n        public Node(int value) {\n            this.value = value;\n        }\n\n    }\n\n    public void populate(int[] nums) {\n        for (int i = 0; i \u003c nums.length; i++) {\n            insert(nums[i]);\n        }\n    }\n\n    public boolean isEmpty() {\n        return root == null;\n    }\n\n    public int height(Node node) {\n        if (node == null) {\n            return -1;\n        }\n        return node.height;\n    }\n\n    public void insert(int value) {\n        root = insert(root, value);\n    }\n\n    private Node insert(Node node, int value) {\n        if (node == null) {\n            node = new Node(value);\n            return node;\n        }\n\n        if (value \u003c node.value) {\n            node.left = insert(node.left, value);\n        }\n\n        else if (value \u003e node.value) {\n            node.right = insert(node.right, value);\n        }\n\n        node.height = Math.max(height(node.left), height(node.right)) + 1;\n\n        return node;\n\n    }\n\n    public void display() {\n        display(root, \"Root Value is : \");\n    }\n\n    private void display(Node node, String details) {\n        if (node == null) {\n            return;\n        }\n        System.out.println(details + node.value);\n        display(node.left, \"Left node value of \" + node.value + \" is: \");\n        display(node.right, \"Right node value of \" + node.value + \" is: \");\n    }\n\n    public boolean isBalanced() {\n        return isBalanced(root);\n    }\n\n    private boolean isBalanced(Node node) {\n        if (node == null) {\n            return true;\n        }\n        return Math.abs(height(node.left) - height(node.right)) \u003c= 1 \u0026\u0026 isBalanced(node.left) \u0026\u0026 isBalanced(node.right);\n    }\n\n    public void populateSorted(int[] nums, int start, int end) {\n        if (start \u003e= end) {\n            return;\n        }\n\n        int mid = start + (end - start) / 2;\n        this.insert(nums[mid]);\n        populateSorted(nums, start, mid);\n        populateSorted(nums, mid + 1, end);\n\n    }\n\n}\n\n```\n\nSome self balancing binary search trees are : AVL trees, Red Black Tree etc.\n\n## AVL tree\n\n1. Insert the node normally.\n2. From `bottom-up` check for the unbalanced node(p).\n3. Then according to the following `4 cases`, rotate the tree while leaving the balanced part of the tree.\n\n- `Time Complexity  : O(log(N))`\n\n- Parent unbalanced Node : p\n- Child Node : c\n- Node which is displaced : t\n\n1. Left Rotate :\n\n```java\nprivate Node leftRotate(Node c) {\n        Node p = c.right;\n        Node t = p.left;\n\n        c.right = t;\n        p.left = c;\n\n        p.height = Math.max(height(p.left), height(p.right)) + 1;\n        c.height = Math.max(height(c.left), height(c.right)) + 1;\n\n        return p;\n    }\n```\n\n2. Right Rotate :\n\n```java\nprivate Node rightRotate(Node p) {\n\n        Node c = p.left;\n        Node t = c.left;\n\n        c.right = p;\n        p.left = t;\n\n        p.height = Math.max(height(p.left), height(p.right)) + 1;\n        c.height = Math.max(height(c.left), height(c.right)) + 1;\n\n        return c;\n    }\n\n```\n\n- Case 1 : Left - Left : Right rotate the unbalanced node(p).\n- Case 2 : Left - Right : Left rotate the child node(c) of the unbalanced node(p) and then right rotate the unbalanced node(p).\n- Case 3 : Right - Right : Left rotate the unbalanced node(p).\n- Case 4 : Right - Left : Right rotate the child node(c) of the unbalanced node(p) and then left rotate the unbalanced node(p).\n\n### Code of AVL Tree\n\n```java\npublic class AVL {\n    private class Node {\n        private int value;\n        private int height;\n        private Node left;\n        private Node right;\n\n        private Node(int value) {\n            this.value = value;\n        }\n    }\n\n    private Node root;\n\n    public void insert(int value) {\n        root = insert(root, value);\n    }\n\n    private int height(Node node) {\n        if (node == null) {\n            return -1;\n        }\n\n        return node.height;\n    }\n\n    private Node insert(Node node, int value) {\n        if (node == null) {\n            node = new Node(value);\n            return node;\n        }\n\n        if (value \u003e node.value) {\n            node.right = insert(node.right, value);\n        }\n        if (value \u003c node.value) {\n            node.left = insert(node.left, value);\n        }\n\n        node.height = Math.max(height(node.left), height(node.right)) + 1;\n\n        return rotate(node);\n\n    }\n\n    private Node rotate(Node node) {\n        if (height(node.left) - height(node.right) \u003e 1) {\n            // left heavy\n            if (height(node.left.left) - height(node.left.right) \u003e 0) {\n                // left-left case\n                return rightRotate(node);\n            }\n            if (height(node.left.left) - height(node.left.right) \u003c 0) {\n                // left-right case\n                node.left = leftRotate(node.left);\n                return rightRotate(node);\n            }\n        }\n        if (height(node.left) - height(node.right) \u003c -1) {\n            // right heavy\n            if (height(node.right.left) - height(node.right.right) \u003c 0) {\n                // right-right\n                return leftRotate(node);\n            }\n            if (height(node.right.left) - height(node.right.right) \u003e 0) {\n                // right-left case\n                node.right = rightRotate(node.right);\n                return leftRotate(node);\n            }\n        }\n        return node;\n    }\n\n    private Node leftRotate(Node c) {\n        Node p = c.right;\n        Node t = p.left;\n\n        c.right = t;\n        p.left = c;\n\n        p.height = Math.max(height(p.left), height(p.right)) + 1;\n        c.height = Math.max(height(c.left), height(c.right)) + 1;\n\n        return p;\n    }\n\n    private Node rightRotate(Node p) {\n\n        Node c = p.left;\n        Node t = c.left;\n\n        c.right = p;\n        p.left = t;\n\n        p.height = Math.max(height(p.left), height(p.right)) + 1;\n        c.height = Math.max(height(c.left), height(c.right)) + 1;\n\n        return c;\n    }\n\n    public void populate(int[] arr) {\n        for (int i = 0; i \u003c arr.length; i++) {\n            root = insert(root, arr[i]);\n        }\n    }\n\n    public void display() {\n        display(\"Root node is : \", root);\n    }\n\n    private void display(String details, Node node) {\n        if (node == null) {\n            return;\n        }\n        System.out.println(details + node.value);\n        display(\"Left child of \" + node.value + \" is : \", node.left);\n        display(\"Right child of \" + node.value + \" is : \", node.right);\n    }\n}\n```\n\n## Segment Trees : Perform query(sum, average, product, max, min, etc.) in a range(in an array).\n\n- Not a BST.\n- Disadvantage : Extra Space.\n- Time Complexity : O(log(n))\n- It is a full binary tree, every node has 2 children except leaf nodes.\n- Leaf nodes = n-1. Internal Nodes = n. Total Nodes = 2n-1.\n\n#### Update function is also of O(log(n)) time.\n\n#### The traversal methods are for Binary Trees in general.\n\n## Breadth First Search or Level Order Traversal\n\n- Iterative approach is more intuitive in this case.\n- When you've reached at the end of a level, the whole next level is already in the queue.\n- Or it can be said that when you remove a node it's children of the next level are already inside the queue.\n\n```java\npackage binaryTrees;\n\nimport java.util.ArrayList;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Queue;\n\npublic class BFS {\n    private class TreeNode {\n        private int value;\n        private int height;\n        private TreeNode left;\n        private TreeNode right;\n\n        private TreeNode(int value) {\n            this.value = value;\n        }\n    }\n\n    private TreeNode root;\n\n    private List\u003cList\u003cInteger\u003e\u003e BFSTraversal() {\n        List\u003cList\u003cInteger\u003e\u003e result = new ArrayList\u003c\u003e();\n        if (root == null) {\n            return result;\n        }\n\n        Queue\u003cTreeNode\u003e queue = new LinkedList\u003c\u003e(); // to maintain the order of the nodes that needs to be explored and\n        // keep track of current level nodes to be processed.\n        queue.offer(root);\n\n        while (!queue.isEmpty()) {\n            int levelSize = queue.size();\n            List\u003cInteger\u003e currentLevelList = new ArrayList\u003cInteger\u003e(levelSize);\n            for (int i = 0; i \u003c levelSize; i++) {\n                TreeNode currentNode = queue.poll();\n                currentLevelList.add(currentNode.value);\n                if (currentNode.left != null) {\n                    queue.offer(currentNode.left);\n                }\n                if (currentNode.right != null) {\n                    queue.offer(currentNode.right);\n                }\n                // at this point the next level children of the node which was polled\n                // is already in the queue.\n            }\n            result.add(currentLevelList);\n        }\n\n        return result;\n    }\n\n}\n\n```\n\n### Finding if the nodes are siblings\n\n```java\npackage binaryTrees;\n\nimport java.util.LinkedList;\nimport java.util.Queue;\n\n@SuppressWarnings(\"unused\")\n\npublic class IsSibling {\n    // We'll find if the nodes of a binary tree are siblings.\n\n    private class Node {\n        private int value;\n        private Node left;\n        private Node right;\n\n        private Node(int value) {\n            this.value = value;\n        }\n    }\n\n    private Node root;\n\n    private boolean isSibling(Node root, int x, int y) {\n\n        if (root == null) {\n            return false;\n        }\n\n        Queue\u003cNode\u003e queue = new LinkedList\u003c\u003e();\n        queue.offer(root);\n\n        boolean foundX = false;\n        boolean foundY = false;\n\n        while (!queue.isEmpty()) {\n            int levelSize = queue.size();\n            for (int i = 0; i \u003c levelSize; i++) {\n                // in each iteration, we are looking at the node itself\n                foundX = false;\n                foundY = false;\n                Node currentNode = queue.poll();\n\n                // Sibling check\n                if (currentNode.left != null \u0026\u0026 currentNode.right != null) {\n                    if ((currentNode.left.value == x \u0026\u0026 currentNode.right.value == y) ||\n                            (currentNode.left.value == y \u0026\u0026 currentNode.right.value == x)) {\n                        return true;\n                    }\n                }\n\n                if (currentNode.left != null) {\n                    queue.offer(currentNode.left);\n                }\n                if (currentNode.right != null) {\n                    queue.offer(currentNode.right);\n                }\n\n            }\n        }\n        return false;\n    }\n}\n\n```\n\n### Finding a node using BFS\n\n```java\n    private class Node {\n        private int value;\n        private Node left;\n        private Node right;\n\n        private Node(int value) {\n            this.value = value;\n        }\n    }\n\n    private Node root;\n\n    private Node findNodeByValue(Node root, int val) {\n        if (root == null) {\n            return null;\n        }\n\n        if (root.value == val) {\n            return root;\n        }\n\n        Queue\u003cNode\u003e queue = new LinkedList\u003c\u003e();\n        queue.offer(root);\n        while (!queue.isEmpty()) {\n            int levelSize = queue.size();\n            for (int i = 0; i \u003c levelSize; i++) {\n                Node currentNode = queue.poll();\n                if (currentNode.value == val) {\n                    return currentNode;\n                }\n\n                if (currentNode.left != null) {\n                    queue.offer(currentNode.left);\n                }\n\n                if (currentNode.right != null) {\n                    queue.offer(currentNode.right);\n                }\n            }\n        }\n\n        return null;\n    }\n\n    private Node findNode(Node root, Node target) {\n        if (root == null) {\n            return null;\n        }\n\n        if (root == target) {\n            return target;\n        }\n\n        Queue\u003cNode\u003e queue = new LinkedList\u003c\u003e();\n        queue.offer(root);\n        while (!queue.isEmpty()) {\n            int levelSize = queue.size();\n            for (int i = 0; i \u003c levelSize; i++) {\n                Node currentNode = queue.poll();\n                if (currentNode == target) {\n                    return target;\n                }\n\n                if (currentNode.left != null) {\n                    queue.offer(currentNode.left);\n                }\n\n                if (currentNode.right != null) {\n                    queue.offer(currentNode.right);\n                }\n            }\n        }\n\n        return null;\n    }\n```\n\n#### Tips related to BFS questions\n\n- While solving BFS questions, you should `consider deque` if you need to traverse the tree in left to right and then right to left manner, basically, deque shouldn't be out of picture.\n\n```java\npackage leetcode;\n\nimport java.util.ArrayList;\nimport java.util.Deque;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Queue;\n\n@SuppressWarnings(\"unused\")\npublic class $103_BinaryTreeZigZagLevelOrderTraversal {\n    private class TreeNode {\n        int val;\n        TreeNode left;\n        TreeNode right;\n\n        TreeNode(int val) {\n            this.val = val;\n        }\n    }\n\n    public List\u003cList\u003cInteger\u003e\u003e zigzagLevelOrder(TreeNode root) {\n        List\u003cList\u003cInteger\u003e\u003e result = new ArrayList\u003c\u003e();\n\n        if (root == null) {\n            return result;\n        }\n\n        Deque\u003cTreeNode\u003e deque = new LinkedList\u003c\u003e();\n        deque.offerFirst(root); // left to right once done\n        boolean reverse = true;\n\n        while (!deque.isEmpty()) {\n            int levelSize = deque.size();\n            List\u003cInteger\u003e currentLevelList = new ArrayList\u003c\u003e(levelSize);\n            for (int i = 0; i \u003c levelSize; i++) {\n                if (reverse) {\n                    TreeNode currentNode = deque.removeLast();\n                    currentLevelList.add(currentNode.val);\n                    if (currentNode.left != null) {\n                        deque.addFirst(currentNode.left);\n                    }\n\n                    if (currentNode.right != null) {\n                        deque.addFirst(currentNode.right);\n                    }\n                } else {\n                    TreeNode currentNode = deque.removeFirst();\n                    currentLevelList.add(currentNode.val);\n                    if (currentNode.right != null) {\n                        deque.addLast(currentNode.right);\n                    }\n\n                    if (currentNode.left != null) {\n                        deque.addLast(currentNode.left);\n                    }\n                }\n\n            }\n            result.add(currentLevelList);\n            if (reverse == true) {\n                reverse = false;\n            } else {\n                reverse = true;\n            }\n        }\n\n        return result;\n    }\n}\n\n```\n\n- Depending on the question, you might need to change the way how nodes are stored, don't just stick to the original order, improvise if need be, like in the case of symmetric trees.\n\n```java\npackage leetcode;\n\nimport java.util.LinkedList;\nimport java.util.Queue;\n\npublic class $101_SymmetricTree {\n    public class TreeNode {\n        public int val;\n        public TreeNode left;\n        public TreeNode right;\n\n        public TreeNode(int val) {\n            this.val = val;\n        }\n    }\n\n    public boolean isSymmetric(TreeNode root) {\n\n        if (root == null) {\n            return true;\n        }\n\n        Queue\u003cTreeNode\u003e queue = new LinkedList\u003c\u003e();\n        queue.offer(root.left);\n        queue.offer(root.right);\n\n        while (!queue.isEmpty()) {\n            TreeNode left = queue.poll();\n            TreeNode right = queue.poll();\n\n            if (left == null \u0026\u0026 right == null) {\n                continue;\n            }\n\n            if (left == null || right == null) {\n                return false;\n            }\n\n            if (left.val != right.val) {\n                return false;\n            }\n\n            // here we can see the elements are stored differently in the queue\n            // as per requirements\n            queue.offer(left.left);\n            queue.offer(right.right);\n            queue.offer(left.right);\n            queue.offer(right.left);\n\n        }\n\n        return true;\n    }\n}\n\n```\n\n## Depth First Search\n\n- The more intuitive approach is recursion in this algorithm.\n- The methods (Pre-order, In-Order and Post-order) have been described [above](#traversal-methods-in-depth-first-search).\n- It goes into the depth of one child and goes until it can't go further and then revert back.\n\nSome Tid-bits regarding those methods:-\n\n- Do something at that level and then move down : Use Pre-Order Traversal (N \u0026rarr; L \u0026rarr; R)\n\n- To get the leftmost(smallest value in BST) value in a tree, we can use In-Order Traversal (L \u0026rarr; N \u0026rarr; R)\n\n- Perform some operations on the root at the last, e.g. to delete a tree, we'll have to delete all the left nodes first then the right nodes and then the root node, therefore we'll use Post-Order Traversal (L \u0026rarr; R \u0026rarr; N).\n\n- Always use queue or stack when you want to store the node to perform an operation later.\n  (Like flattening a binary tree into a linked list where the left pointers need to be null\n  and right ones need to point to the next node)\n\n#### Diameter of a binary tree\n\n```java\npublic int diameterOfBinaryTree(TreeNode root) {\n        height(root);\n        return diameter - 1; // we have calculated node wise\n    }\n\n    private int height(TreeNode node) {\n        if (node == null) {\n            return 0;\n        }\n\n        int leftHeight = height(node.left);\n        int rightHeight = height(node.right);\n        int dia = leftHeight + rightHeight + 1;\n        diameter = Math.max(diameter, dia); // diameter is the max value of dia of each individual tree\n\n        return Math.max(leftHeight, rightHeight) + 1;\n    }\n```\n\n### Invert a binary tree\n\n```java\npackage leetcode;\n\npublic class $226_InvertBinaryTree {\n\n    public class TreeNode {\n        int val;\n        TreeNode left;\n        TreeNode right;\n\n        TreeNode() {\n        }\n\n        TreeNode(int val) {\n            this.val = val;\n        }\n\n        TreeNode(int val, TreeNode left, TreeNode right) {\n            this.val = val;\n            this.left = left;\n            this.right = right;\n        }\n    }\n\n    public TreeNode invertTree(TreeNode node) {\n        if (node == null) {\n            return node;\n        }\n\n        if (node.left == null \u0026\u0026 node.right == null) {\n            return node;\n        }\n\n        invertTree(node.left);\n        invertTree(node.right);\n        return swap(node);\n    }\n\n    private TreeNode swap(TreeNode x) {\n        TreeNode temp = x.left;\n        x.left = x.right;\n        x.right = temp;\n        return x;\n    }\n}\n\n```\n\n### Traversing from one node to another in a binary tree and printing the path\n\n```java\npackage leetcode;\n\npublic class $2096_StepByStepDirectionsFromABinaryTreeNodeToAnother {\n    public class TreeNode {\n        int val;\n        TreeNode left;\n        TreeNode right;\n\n        TreeNode() {\n        }\n\n        TreeNode(int val) {\n            this.val = val;\n        }\n\n        TreeNode(int val, TreeNode left, TreeNode right) {\n            this.val = val;\n            this.left = left;\n            this.right = right;\n        }\n    }\n\n    StringBuilder s = new StringBuilder(\"\"), d = new StringBuilder(\"\");\n\n    public String getDirections(TreeNode root, int startValue, int destValue) {\n        traverse(root, startValue, s); // s -\u003e start\n        traverse(root, destValue, d); // d -\u003e destination\n        int i = 0;\n        // Find the common path prefix length\n        while (i \u003c s.length() \u0026\u0026 i \u003c d.length() \u0026\u0026 s.charAt(i) == d.charAt(i)) {\n            i++;\n        }\n\n        // Number of steps to move up from the start node to the common ancestor\n        StringBuilder finalPath = new StringBuilder();\n        for (int j = i; j \u003c s.length(); j++) {\n            finalPath.append('U');\n        }\n\n        // Append remaining path to the destination node\n        finalPath.append(d.substring(i));\n\n        return finalPath.toString();\n    }\n\n    // Main thing here is that how you stop the traversal using booleans\n    private boolean traverse(TreeNode root, int value, StringBuilder path) {\n        // Optimize traversal by stopping it the moment value is found!!\n        if (root == null) {\n            return false;\n        }\n\n        if (root.val == value) {\n            return true;\n        }\n\n        path.append(\"L\");\n        if (traverse(root.left, value, path)) {\n            return true;\n        }\n\n        path.setLength(path.length() - 1);\n\n        path.append(\"R\");\n        if (traverse(root.right, value, path)) {\n            return true;\n        }\n        path.setLength(path.length() - 1);\n        return false;\n    }\n}\n\n```\n\n## Heaps\n\nStored as an array internally but is represented as a tree. And that array may not be sorted.\n\nExample: In case of max heap(similarly, min heap will give minimum item in constant time) we want the first item to be maximum, rest of the array may not be sorted that's all.\n\n#### Properties\n\n- Complete Binary Tree Representation(Nodes are inserted from the left side).\n- No pointers like `Node left` or `Node right` is required.\n- `Height is logN so insertion/removal takes O(logN) time.`\n- Upheap method is used to insert an element in heap.\n- Heap sort takes O(NlogN) time, because we simply remove every element and just store it in an array list.\n\n#### Let's discus the case of max heap in detail:\n\n- Highest item at the very first index.\n- Every node value \u003e= All of its children(in case of Max Heap).\n- root = i = 1 (in our case 0th index has been left empty).\n- parent(i) = i/2.\n- left(i) = 2\\*i.\n- right(i) = 2\\*i + 1.\n- In case of min heap, every node value \u003c= all of it's children.\n\n- Only use heaps when you're confident that you're working with a condition.\\\n\n### Code\n\n```java\npackage heaps;\n\nimport java.util.*;\n\n// Min heap\npublic class Heap\u003cT extends Comparable\u003cT\u003e\u003e {\n\n    public static void main(String[] args) throws Exception {\n        Heap\u003cInteger\u003e heap = new Heap\u003c\u003e();\n        heap.insert(10);\n        heap.insert(11);\n        heap.insert(12);\n        heap.insert(13);\n        System.out.println(heap.heapSort());\n    }\n\n    private ArrayList\u003cT\u003e list;\n\n    private void swap(int first, int second) {\n        T temp = list.get(second);\n        list.set(second, list.get(first));\n        list.set(first, temp);\n    }\n\n    // these methods return the indices -\u003e left, right and parent\n    private int parent(int index) {\n        return (index - 1) / 2;\n    }\n\n    private int left(int index) {\n        return 2 * index + 1;\n    }\n\n    private int right(int index) {\n        return index * 2 + 2;\n    }\n\n    public void insert(T value) {\n        list.add(value);\n        // Now we'll apply upheap\n        upheap(list.size() - 1);\n    }\n\n    private void upheap(int i) {\n        if (i == 0) {\n            return;\n        }\n        int p = parent(i);\n        if (list.get(i).compareTo(list.get(p)) \u003c 0) {\n            swap(i, p);\n            upheap(p);\n        }\n\n    }\n\n    private void downheap(int i) {\n        if (i == list.size()) {\n            return;\n        }\n        int min = i;\n        int left = left(i);\n        int right = right(i);\n\n        if (left \u003c list.size() \u0026\u0026 list.get(min).compareTo(list.get(left)) \u003e 0) {\n            min = left;\n        }\n        if (right \u003c list.size() \u0026\u0026 list.get(min).compareTo(list.get(right)) \u003e 0) {\n            min = right;\n        }\n\n        if (min != i) {\n            swap(i, min);\n            downheap(min);\n        }\n    }\n\n    public T remove() throws Exception {\n        if (list.isEmpty()) {\n            throw new Exception(\"List is empty.\");\n        }\n        T root = list.get(0);\n        T last = list.remove(list.size() - 1);\n        if (!list.isEmpty()) {\n            list.set(0, last);\n            downheap(0);\n        }\n        return root;\n    }\n\n    public ArrayList\u003cT\u003e heapSort() throws Exception {\n        if (list.isEmpty()) {\n            throw new Exception(\"The list is empty.\");\n        }\n        ArrayList\u003cT\u003e data = new ArrayList\u003c\u003e();\n        while (!list.isEmpty()) {\n            data.add(this.remove());\n        }\n\n        return data;\n    }\n\n    public Heap() {\n        list = new ArrayList\u003c\u003e();\n    }\n}\n```\n\n## Hashmaps and Hashtables\n\n### Why hashmaps?\n\nWe use hashmaps to retrieve any element in O(1) time.\n\n### What are hashmaps?\n\nIt's a data strutcure which consists of key-value pair(s).\n\n| Key (Name) | Value (Marks) |\n| ---------- | :-----------: |\n| Rajneesh   |      88       |\n| Karan      |      69       |\n| Mukul      |      68       |\n| Lakshya    |      39       |\n\nmap.get(\"Rajneesh\") = 88 : In O(1) time.\n\n### How do they work?\n\nHashcode : It is a numeric representation of a data type/structure. It is derived using some mathematical function.\n\nE.g., hash(\"Rajneesh\") = 12434352 or hash(78) = 78. It is computed via a mathematical function and they are unique.\n\n- HashTable : A hashtable is a data structure that stores key-value pairs and allows for fast retrieval of values using keys. It works by applying a hash function to the key to compute an index, which determines where the key-value pair should be stored in an internal array. This structure ensures efficient lookup, insertion, and deletion operations.\n\n- HashCode : A hashcode is an integer value generated by a hash function from an object's data. It is used to uniquely identify objects and determine their storage location in a hashtable. The hashcode helps distribute objects evenly across the hashtable to minimize collisions and improve access speed.\n\n- Hashcodes could be used to store the data in an array at that particular index.\n  Like if we wanna store \"Rajneesh\" in an array, then we can store it at the index which equals its hashcode, but that poses of problem of the array being very big in size as the hashcode grows for the objects/strings/numbers. This is what a hashtable is(in this case in a form of an array), and thats how we store data in it.\n  Example : Generating a frequency array for elements of an array.\n\n- We can then think of using the modulo operator(like %10) and store it in an array of desired size. Although, the problem arises that what if two hashcodes have same modulo with a given number, say 10, this is called collision.\n\n#### Ways to deal with collisions\n\n1. Chaining\n2. Open Addressing\n\n- Chaining\n\n  So, we can have a linked list at every index of the hashtable(an array in our case basically) and we can simply then insert multiple elements at one index, but what if all the elements fall at the same index, then it will take O(n) time to retrieve and the benefits of hashmaps are gone.\n\n  Then we use a cheat, i.e., Simple Uniform Hashing, which makes use of the following assumption.\n\n  Assumption : Every key is equally likely to be hashed to any slot on the table independent of where all the previous keys were hashed.\n\n  n = total number of keys\n\n  m = size of the table\n\n  \u0026alpha; = load factor\n\n  \u0026alpha; = n/m \u0026rarr; expected number of keys per slot\n\n  So if m = 10(size), n = 20(number of items to be inserted), then \u0026alpha; = 2, i.e., at each index we expect two items, irrespective of the hashcode or any oher factor, because this approach assumes equal probability.\n  Then time of retrieval for the linked list approach will be O(1 + \u0026alpha;).\n  If \u0026alpha; is constant then the time complexity is constant.\n\n  - Hash Functions\n\n  1. Division method : h(k) = k%m (m could be size of th array or any other number), and we assume it to be a prime number but not too close to a power of 2 or 10.\n\n  2. Multiplication method : h(k) = [(a\u0026middot;k)%2] \u003e\u003e (w-r)\n\n  a = random number\n\n  w = number of bits in k\n\n  m = 2\u003csup\u003er\u003c/sup\u003e\n\n  a is odd and 2\u003csup\u003ew-1\u003c/sup\u003e \u003c a \u003c 2\u003csup\u003ew\u003c/sup\u003e, and a is not too close to the bounds.\n\n  Size of the table : m = \u0026theta;(n)\n\n  Small : slow\n\n  Big : Waste of space\n\n  Idea : Start small and slowly scale.\n  When the hashtable gets filled up, double the size. Doubling the table and inserting n items costs us O(n) time.\n\n  So for an average/amortized constant time : number of item(s) = 1, then O(1) time is required.\n\n  If, n = m/4, then we shrink the array by a factor of 2. That again leads to an average of O(1) time.\n\n- Open Addressing\n  - One item per slot : m \u003e= n (size \u003e= number of items)\n  - Probe \u0026rarr; try : if that slot is filled up then look for other indices. Also if an item is deleted we put a flag there to know that it was deleted.\n\nProbing Techniques :\n\n1.  Linear Probing : h(k,i) = (h(k) + i) % m \u0026rarr; Problem isthat a cluster is formed, so we need to jump farther.\n2.  Double Hashing : h(k,i) = (h\u003csub\u003e1\u003c/sub\u003e(k) + i \\* h\u003csub\u003e2\u003c/sub\u003e(k)) % m\n    If h\u003csub\u003e2\u003c/sub\u003e(k) is relatively prime to m for all k, then it will cover all slots.\n\n        (h\u003csub\u003e1\u003c/sub\u003e(k) + i * h\u003csub\u003e2\u003c/sub\u003e(k)) % m = (h\u003csub\u003e1\u003c/sub\u003e(k) + j * h\u003csub\u003e2\u003c/sub\u003e(k)) % m \u0026rarr; m divides (i-j)\n\n- Uniform Hashing Assumption\n\n  Every key is equally likely to have m! permutations.\n  Cost of next operation \u003c= 1/(1-\u0026alpha;)\n\n  \u0026alpha; = 90%, then 10 expected probes.\n\n#### When to use which?\n\n1. OA \u0026rarr; better cache performance(pointers not needed)\n2. Chaining \u0026rarr; less sensitive to hash functions.\n\n### Java has TreeMap, HashMap, HashSet, TreeSet.\n\n    All of them take constant time to perform CRUD operations.\n\n- HashSet : Contains only unique elements.\n- HashMap : Contains key-value pairs.\n- TreeMap : Map in sorted order. Red-black tree based.\n- TreeSet : Sets in sorted order. Red-black tree based.\n\n```java\npackage hashMapsAndHashTables;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\n\npublic class HashMapsAndHashSets {\n    public static void main(String[] args) {\n        HashMap\u003cString, Integer\u003e map = new HashMap\u003c\u003e(); // java hashmap implementation\n        map.put(\"Rajneesh\", 69);\n        map.put(\"Sachin\", 68);\n        System.out.println(map.get(\"Rajneesh\"));\n\n        HashSet\u003cInteger\u003e set = new HashSet\u003c\u003e(); // java hashset implementation\n        set.add(36);\n        set.add(36);\n        System.out.println(set);\n    }\n}\n\n```\n\n### Illustrations\n\n1. Add two numbers of an array to a target. Q1 on leetcode.\n\n```java\npackage leetcode;\n\nimport java.util.HashMap;\n\npublic class $1_TwoSum {\n    public int[] twoSum(int[] nums, int target) {\n       HashMap\u003cInteger, Integer\u003e prev = new HashMap\u003c\u003e();\n       for(int i=0; i \u003c nums.length; i++){\n        int n = nums[i];\n        int diff = target - nums[i];\n        if(prev.containsKey(diff)){\n            return new int[]{prev.get(diff), i};\n        }\n\n        prev.put(n,i);\n       }\n        return new int[]{};\n    }\n}\n```\n\n2. Hashtable usage, Q242 on leetcode, check if two strings are anagrams\n\n```java\npackage leetcode;\n\n\npublic class $242_ValidAnagram {\n    public static void main(String[] args) {\n\n    }\n\n    public boolean isAnagram(String s, String t) {\n        if (s.length() != t.length()) {\n            return false;\n        }\n        int[] f1 = new int[26]; // frequency hash tables\n        int[] f2 = new int[26]; // frequency hash tables\n        for (int i = 0; i \u003c s.length(); i++) {\n            f1[(int) ((s.charAt(i)) - 'a')]++;\n            f2[(int) ((t.charAt(i)) - 'a')]++;\n        }\n        for (int i = 0; i \u003c f2.length; i++) {\n            if (f1[i] != f2[i]) {\n                return false;\n            }\n        }\n        return true;\n    }\n}\n```\n\n3. Storing frequency of elements of an array in hashmap and iterating through a hashmap : Q169 on leetcode\n\n```java\npublic int majorityElement(int[] nums) {\n        int n = nums.length;\n        HashMap\u003cInteger, Integer\u003e map =  new HashMap\u003c\u003e();\n        for(int i=0; i\u003cnums.length; i++){\n            if(!map.containsKey(nums[i])){\n                map.put(nums[i], 1);\n                continue;\n            }\n            map.put(nums[i], map.get(nums[i])+1);\n        }\n\n        for(HashMap.Entry\u003cInteger, Integer\u003e entry : map.entrySet()){\n            if(entry.getValue()\u003en/2){\n                return entry.getKey();\n            }\n        }\n        return 0;\n    }\n```\n\n## Graphs\n\n### What is a graph?\n\n- A structure with nodes/vertices and/or edges.\n- A graph can have multiple connected components and we use the concept of `visitedArray`(with length = number of nodes(if 0-based indexing) or number of nodes+1 (if 1-based indexing)) to keep track of the vertices we visit so that every node is `visited only once`, even if the components don't appear to be connected they could be of the same graph. [(Will become more clear once we dive into algorithms)](#breadth-first-search-or-level-order-traversal-1)\n- Trees are a type of graph with no cycles. If they have N vertices then number of edges equal to N-1.\n\n### Types of Graph:\n\n1. Directed -\u003e The edges have arrows towards the vertices, hence giving it a direction.\n2. Undirected -\u003e The edges don't have specific directions.\n\n- For an undirected graph the degree of the graph is 2\\*(number of edges).\n\n### Other forms are:\n\n1. Cyclic -\u003e When you start with a node and end up back again at that node.\n2. Acyclic -\u003e When there's no way to reach back to the node you started with.\n\n### Degree of a graph\n\n- For undirected graph:\n  Degree of an undirected graph = 2 \\* E, where E is the number of edges.\n  To calculate degree of a vertex, simply calculate the number of edges attached to it and then sum of all of them would be the degree of the graph.\n\n- For directed graph:\n  Degree of a directed graph is defined using the `In-degree` and the `Out-degree` of the nodes. As the name suggests `in-degree` of a node are the number of edges with arrows pointing towards the node and `out-degree` is the number of edges with arrows pointing outwards.\n\n### Ways to store a Graph(complex data structure):\n\n1. Adjacency Matrix(adjMatrix.length = number of nodes), space complexity is O(n\u003csup\u003e2\u003c/sup\u003e), where, n is the number of nodes, that's why avoided. We create a matrix of N X N, where N is the number of Nodes.\n\n2. `Adjacency list(adjList.length = number of nodes), space complexity is ~O(V + 2E), hence this is preferred. V is the number of vertices and E is the number of edges.`\n\n- We create a list of size V.\n\n- Explanation of point 2:\n\n  \u003e adj.get(u).add(v);\n\n  \u003e adj.get(v).add(u);\n\n  The above statments tell us that each edge will be repeated twice in the list(for every u, a v and for every v, a u), hence the 2E plus the number of vertices(V) as the length of the list is V, that's why O(V + 2E).\n\n- `For a directed graph it will be O(V+E)` as no edges are repeated.\n\n---\n\n### if 1-based indexed graph:\n\n#### `Length of visited array = length of adjList = length of adjMatrix = number of vertices + 1.`\n\n### if 0-based indexed graph:\n\n#### `Length of visited array = length of adjList = length of adjMatrix = number of vertices/nodes.`\n\n---\n\n```java\npackage graphs;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\n\n@SuppressWarnings(\"unused\")\npublic class AdjacencyList {\n    public static void main(String[] args) {\n        // 1 -- 2 -- 3 -- 1 -\u003e graph\n        int n = 3;\n        ArrayList\u003cArrayList\u003cInteger\u003e\u003e adj = new ArrayList\u003c\u003e(); // adjacency list\n\n        // we'll insert (n+1) empty lists in the 'adj' list, where 'n' is the number of\n        // nodes.\n        for (int i = 0; i \u003c= n; i++) {\n            adj.add(new ArrayList\u003c\u003e()); // (n+1) array lists inserted\n        }\n\n        // 1 -- 2\n        adj.get(1).add(2);\n        adj.get(2).add(1);\n\n        // 2 -- 3\n        adj.get(2).add(3);\n        adj.get(3).add(2);\n\n        // 3--1\n        adj.get(3).add(1);\n        adj.get(1).add(3);\n\n        /*\n         * u--v : Undirected graph\n         * adj.get(u).add(v);\n         * adj.get(v).add(u);\n         *\n         * u--\u003ev : Directed graph\n         * adj.get(u).add(v);\n         */\n\n        for (int i = 1; i \u003c= n; i++) {\n            System.out.print(\"Node \" + i + \": \");\n            for (int j = 0; j \u003c adj.get(i).size(); j++) {\n                System.out.print(adj.get(i).get(j) + \"\\s\");\n            }\n            System.out.println();\n        }\n    }\n\n}\n```\n\nFor a directed graph one of the `adj.get(u).add(v)` or `adj.get(v).add(u)` is omitted as the direction would be specified.\n\n## Breadth First Search or Level Order Traversal\n\n```java\npackage javaPlayground;\n\nimport java.util.ArrayList;\nimport java.util.LinkedList;\nimport java.util.Queue;\n\n // Time complexity = O(N) + O(2*E)\n // Space complexity = O(3*N)\n\npublic class j10 {\n    public void bfs(ArrayList\u003cArrayList\u003cInteger\u003e\u003e adj) {\n        boolean[] vis = new boolean[adj.size()];\n        Queue\u003cInteger\u003e q = new LinkedList\u003c\u003e();\n        ArrayList\u003cInteger\u003e bfs = new ArrayList\u003c\u003e();\n        q.offer(1); // Starting with node 1 (1-based indexing)\n        vis[1] = true; // whatever goes into the queue is considered to be visited\n        while (!q.isEmpty()) {\n            Integer currentNode = q.poll();\n            bfs.add(currentNode); // add the currentNode from queue into the resultant array\n            for (Integer connectedNode : adj.get(currentNode)) {\n                if (!vis[connectedNode]) {\n                    q.offer(connectedNode);\n                    vis[connectedNode] = true;\n                }\n            }\n        }\n        System.out.println(bfs);\n    }\n\n    public static void main(String[] args) {\n        ArrayList\u003cArrayList\u003cInteger\u003e\u003e adj = new ArrayList\u003c\u003e();\n        for (int i = 0; i \u003c 6; i++) { // Create adjacency list for 6 nodes (0 to 5)\n            adj.add(new ArrayList\u003c\u003e());\n        }\n        adj.get(1).add(2);\n        adj.get(1).add(3);\n        adj.get(2).add(4);\n        adj.get(2).add(5);\n        adj.get(3).add(5);\n\n        j10 obj = new j10();\n        obj.bfs(adj);\n    }\n}\n\n```\n\n### BFS Concept for graphs and n-Ary trees\n\n```java\npackage luv.graphs;\n\nimport java.util.*;\n\npublic class BFS {\n    public static void main(String[] args) {\n        ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph = new ArrayList\u003c\u003e();\n        Scanner input = new Scanner(System.in);\n        int n = input.nextInt();\n        for (int i = 0; i \u003c= n; i++) {\n            graph.add(new ArrayList\u003c\u003e());\n        }\n        for (int i = 0; i \u003c n - 1; i++) {\n            int u = input.nextInt();\n            int v = input.nextInt();\n            graph.get(u).add(v);\n            graph.get(v).add(u);\n        }\n        input.close();\n\n        boolean[] vis = new boolean[n + 1];\n        bfs(1, graph, vis);\n    }\n\n    static void bfs(int source, ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph, boolean[] vis) {\n        Queue\u003cInteger\u003e q = new LinkedList\u003c\u003e();\n        q.add(source);\n        vis[source] = true;\n        while (!q.isEmpty()) {\n            int currentVertex = q.poll();\n            for (int child : graph.get(currentVertex)) {\n                if (!vis[child]) {\n                    q.add(child);\n                    vis[child] = true;\n                }\n            }\n        }\n    }\n}\n\n```\n\n- In an equally weighted graph BFS always gives shortest path between nodes.\n- Queue always stores the next level while the alogrithm traverses the current one.\n\n## Depth First Search or DFS traversal\n\n- It goes into the depth of one child and goes until it can't go further and then revert back.\n- Visited array in this case is a must though it could be avoided in the case of trees.\n\n### DFS Concept\n\n```java\npackage luv.graphs;\n\npublic class DFS {\n    public static void main(String[] args) {\n        ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph = new ArrayList\u003c\u003e();\n        int n = 10, m = 15; // n: no of vertices and m being the number of edges\n        boolean[] vis = new boolean[n];\n        for (int i = 0; i \u003c n; i++) {\n            graph.add(new ArrayList\u003c\u003e());\n        }\n            // if m is given then we are given the configuration of one of the combinations\n            // 1 -- 2, we do the 2 -- 1 by ourselves and run the loop m times instead of n.\n        int count = 0;\n        for (int i = 0; i \u003c vis.length; i++) {\n            if (!vis[i]) {\n                dfs(i, graph, vis);\n            }\n        }\n    }\n    /*\n     * graph = [\n     *            vertex 0 -\u003e [ 1 , 2 , 3 ], -\u003e it's elements are the children\n     *            vertex 1 -\u003e  [ 4 , 5 , 6 ],\n     *         ]\n     vertex 0 -\u003e [ 1 , 2 , 3 ] =\u003e 0 -- 1, 0 -- 2, 0--3; -- : edges\n     * 'child' itself is an array, so for(int child : graph[vertex]) =\u003e you are already inside the vertex array at a child.\n     */\n    static void dfs(int vertex, ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph, boolean[] vis) {\n        /*\n         * Take action on vertex after entering the vertex\n         * Going down\n         */\n        // if(vis[vertex]) {return;}\n        vis[vertex] = true;\n        for (int child : graph.get(vertex)) {\n            /*\n             * Take action on child before entering the child node\n             * Going down\n             */\n            if (vis[child]) {\n                continue;\n            }\n            dfs(child, graph, vis);\n            /*\n             * Take action on child after exiting child node\n             * Coming back up\n             */\n        }\n        /*\n         * Take action on the vertex before exiting the vertex\n         * Coming back up\n         */\n    }\n}\n```\n\n- DFS Implementation\n\n```java\npackage graphs;\n\nimport java.util.ArrayList;\n\npublic class DFS {\n    public void dfsTraversal(ArrayList\u003cArrayList\u003cInteger\u003e\u003e adj) {\n        boolean[] vis = new boolean[adj.size()]; // this calls every component!\n        for (int vertex = 0; vertex \u003c vis.length; vertex++) {\n            dfs(vertex, vis, adj);\n        }\n    }\n\n    private void dfs(int vertex, boolean[] vis, ArrayList\u003cArrayList\u003cInteger\u003e\u003e adj) {\n        // this visits/traverses every node!\n        vis[vertex] = true;\n        for (Integer child : adj.get(vertex)) {\n            System.out.println(\"vertex: \" + vertex + \"child: \"+ child);\n            if (!vis[child])\n                dfs(child, vis, adj);\n        }\n    }\n}\n\n\n```\n\n---\n\nThe following code illustrates the `conversion of adjacency matrix to adjacency list` along with DFS traversal.\n\n```java\npackage javaPlayground;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\n\n@SuppressWarnings(\"unused\")\npublic class j9 {\n    public static void main(String[] args) {\n        int[][] isConnected = {\n                { 1, 1, 0 }, // 0\n                { 1, 1, 0 }, // 1\n                { 0, 0, 1 } // 2\n        };\n        findCircleNum(isConnected);\n    }\n\n    public static void findCircleNum(int[][] isConnected) {\n        // 0-based indexed graph\n        ArrayList\u003cArrayList\u003cInteger\u003e\u003e adjacencyList = new ArrayList\u003cArrayList\u003cInteger\u003e\u003e();\n        for (int i = 0; i \u003c isConnected.length; i++) {\n            adjacencyList.add(new ArrayList\u003cInteger\u003e());\n        }\n        for (int i = 0; i \u003c isConnected.length; i++) {\n            for (int j = 0; j \u003c isConnected.length; j++) {\n                if (isConnected[i][j] == 1 \u0026\u0026 i != j) {\n                    adjacencyList.get(i).add(j);\n                    adjacencyList.get(j).add(i);\n                }\n            }\n        }\n\n        System.out.println(\"adjacencyList: \" + adjacencyList);\n        boolean[] vis = new boolean[isConnected.length];\n        int count = 0;\n        for (int i = 0; i \u003c vis.length; i++) { // it calls every component\n            if (vis[i] == false) {\n                count++;\n                dfs(i, adjacencyList, vis);\n            }\n        }\n        System.out.println(count);\n    }\n\n    private static void dfs(Integer node, ArrayList\u003cArrayList\u003cInteger\u003e\u003e adjacencyList, boolean[] vis) {\n        // this visits every connected node of that component\n        vis[node] = true;\n        for (Integer connectedNode : adjacencyList.get(node)) {\n            if (vis[connectedNode] == false) {\n                dfs(connectedNode, adjacencyList, vis);\n            }\n        }\n    }\n}\n\n```\n\n- The above code also shows the importance of visited array as when the graph has been divided into 'k' connected components then that's how we can reach every node using the visited array.\n\n---\n\n### DFS in Trees(n-Ary)\n\n- No need of a visited array as no loops exist in trees.\n- We just need to make sure that we don't visit the parent node which we came from and for that we can pass on the parent node to the 'dfs' function.\n- Although the exact DFS code for graphs will run for trees because visited array helps us avoiding the same node from visitation twice as that will cause an infinite loop.\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph = new ArrayList\u003c\u003e();\n        Scanner input = new Scanner(System.in);\n        int n = input.nextInt(); // vertices\n        System.out.println(n);\n        for (int i = 0; i \u003c= n; i++) {\n            graph.add(new ArrayList\u003c\u003e());\n        }\n        // int m = input.nextInt(); // edges\n        // in trees, number of edges = n - 1\n        for (int i = 0; i \u003c n - 1; i++) {\n            int u = input.nextInt();\n            int v = input.nextInt();\n            graph.get(u).add(v);\n            graph.get(v).add(u);\n        }\n        input.close();\n        int depth[] = new int[n + 1];\n        int height[] = new int[n + 1];\n        dfs(1, 0, graph, depth, height);\n        System.out.println(\"depth: \" + Arrays.toString(depth));\n        System.out.println(\"height: \" + Arrays.toString(height));\n    }\n\n    static void dfs(int vertex, int parent, ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph, int depth[], int height[]) {\n        // vertex is the current one and the parent one is the one from which it came from\n        // do something when you enter the vertex/enter the recursion\n        for (int child : graph.get(vertex)) {\n            // in context of the vertex\n            if (child == parent) {\n                continue;\n            }\n            // do something when you enter the child/enter the recursion of that child(going\n            // down)\n            // 3 nodes : child, parent and vertex(the current one) and all are different\n            depth[child] = depth[vertex] + 1; // here the parent is the vertex, i.e., child of the current vertex\n            dfs(child, vertex, graph, depth, height);\n            height[vertex] = Math.max(height[child] + 1, height[vertex]);\n            // do something when you leave the child/coming back from the recursion of that\n            // child(coming back up)\n        }\n        // do something when you leave the vertex/exit the recursion\n    }\n\n}\n\n```\n\n### Pre-Computation using DFS in graphs(or trees)\n\n- Pre-computation using DFS, like finding sum of elements of a subtree/subgraph, is done while coming back up from the recursion. (It's obvious just think about it)\n\n#### Way 1: Calling DFS for every query.\n\n```java\nimport java.util.*;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph = new ArrayList\u003c\u003e();\n        Scanner input = new Scanner(System.in);\n        int n = input.nextInt(); // vertices\n        for (int i = 0; i \u003c= n; i++) {\n            graph.add(new ArrayList\u003c\u003e());\n        }\n        for (int i = 0; i \u003c n - 1; i++) {\n            int u = input.nextInt();\n            int v = input.nextInt();\n            graph.get(u).add(v);\n            graph.get(v).add(u);\n        }\n        input.close();\n        System.out.println(subtreeSumUsingDFS(1, 0, graph)); // subtree sum\n        System.out.println(evenCountInASubtreeUsingDFS(13, 1, graph));\n    }\n\n    static int subtreeSumUsingDFS(int vertex, int parent, ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph) {\n        // do something when you enter the vertex/enter the recursion\n        int currentSum = 0;\n        currentSum += vertex;\n        for (int child : graph.get(vertex)) {\n            // for the same vertex all its children, so the parent is the vertex's parent while for all its children the parent is the vertex itself, so the parent is grandparent of the child here.\n            if (child == parent) {\n                // 1 -- 2 : when 2 will run then 1 will be its parent and since we don't want infinite loops we avoid that condition here\n                continue;\n            }\n             // do something when you enter the child/enter the recursion of that child(going\n            // down)\n            int prevSum = subtreeSumUsingDFS(child, vertex, graph);\n             // do something when you leave the child/coming back from the recursion of that\n            // child(coming back up)\n            currentSum += prevSum;\n        }\n        // do something when you leave the vertex/exit the recursion\n        return currentSum;\n    }\n\n    static int evenCountInASubtreeUsingDFS(int vertex, int parent, ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph) {\n        int currentCount = 0;\n        if (vertex % 2 == 0) {\n            currentCount++;\n        }\n        for (int child : graph.get(vertex)) {\n            if (child == parent)\n                continue;\n            int prevCount = evenCountInASubtreeUsingDFS(child, vertex, graph);\n            currentCount += prevCount;\n        }\n        return currentCount;\n    }\n\n}\n\n```\n\n#### Way 2: Calculating subtree sum and even count of the children of each parent\n\n```java\nimport java.util.*;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph = new ArrayList\u003c\u003e();\n        Scanner input = new Scanner(System.in);\n        int n = input.nextInt();\n        for (int i = 0; i \u003c= n; i++) {\n            graph.add(new ArrayList\u003c\u003e());\n        }\n        for (int i = 0; i \u003c n - 1; i++) {\n            int u = input.nextInt();\n            int v = input.nextInt();\n            graph.get(u).add(v);\n            graph.get(v).add(u);\n        }\n        input.close();\n        int subtreeSum[] = new int[n + 1];\n        int evenCount[] = new int[n + 1];\n        dfs(1, 0, graph, subtreeSum, evenCount);\n        System.out.println(\"subtreeSum: \" + Arrays.toString(subtreeSum));\n        System.out.println(\"evenCount: \" + Arrays.toString(evenCount));\n    }\n\n    static void dfs(int vertex, int parent, ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph, int[] subtreeSum, int[] evenCount) {\n        // going into the vertex\n        subtreeSum[vertex] += vertex;\n        if (vertex % 2 == 0) {\n            evenCount[vertex]++;\n        }\n        for (int child : graph.get(vertex)) {\n            // for the same vertex all its children\n            if (child == parent)\n                continue;\n            // entering the recursion into the child\n            dfs(child, vertex, graph, subtreeSum, evenCount);\n            subtreeSum[vertex] += subtreeSum[child];\n            evenCount[vertex] += evenCount[child];\n            // coming back up in the recursion from the child\n        }\n        // exiting the vertex\n    }\n\n}\n\n```\n\n### Diameter of a tree\n\n- Diameter of a tree = max(depth between any two nodes)\n\n##### Brute Force approach\n\n- Brute Force method would be to find the depth between every node and then traversing through that array and finding the maximum depth among them.\n\n##### Optimized approach\n\n- Assume any node to be the root and then go down and find the node at maximum depth. That node will be one of ends of the diameter.\n\n- Then assume that max depth node to be the root and run DFS algorithm to go again to the node which has maximum depth w.r.t this node, this new found node will be the other end of the diameter.\n\n```java\npackage luv.trees;\n\nimport java.util.*;\n\npublic class DiameterOfATree {\n    public static void main(String[] args) {\n        ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph = new ArrayList\u003c\u003e();\n        Scanner input = new Scanner(System.in);\n        int n = input.nextInt();\n        for (int i = 0; i \u003c= n; i++) {\n            graph.add(new ArrayList\u003c\u003e());\n        }\n        for (int i = 0; i \u003c n - 1; i++) {\n            int u = input.nextInt();\n            int v = input.nextInt();\n            graph.get(u).add(v);\n            graph.get(v).add(u);\n        }\n        input.close();\n        int depth[] = new int[n + 1];\n\n        dfs(1, 0, graph, depth);\n        System.out.println(\"depth: \" + Arrays.toString(depth));\n\n        int max_depth = -1;\n        int max_depth_node = -1;\n\n        for (int i = 0; i \u003c depth.length; i++) {\n            if (max_depth \u003c depth[i]) {\n                max_depth = depth[i];\n                max_depth_node = i;\n            }\n            depth[i] = 0;\n        }\n\n        System.out.println(\"max_depth_node: \" + max_depth_node);\n        dfs(max_depth_node, 0, graph, depth);\n        for (int i = 0; i \u003c depth.length; i++) {\n            if (max_depth \u003c depth[i]) {\n                max_depth = depth[i];\n                max_depth_node = i;\n            }\n            depth[i] = 0;\n        }\n        System.out.println(\"max_depth_node: \" + max_depth_node);\n        System.out.println(\"max_depth: \" + max_depth);\n    }\n\n    static void dfs(int vertex, int parent, ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph, int[] depth) {\n        // at this point three different nodes are there : parent(the past one),\n        // vertex(the current one), child(it's future)\n        for (int child : graph.get(vertex)) {\n            // for the same vertex all its children, so the parent is the vertex's parent\n            // while for all its children the parent is the vertex itself, so the parent is\n            // grandparent of the child here.\n            if (child == parent) {\n                // 1 -- 2 : when 2 will run then 1 will be its parent and since we don't want\n                // infinite loops we avoid that condition here\n                continue;\n            }\n            System.out.println(\"Vertex: \" + vertex + \" parent: \" + parent + \" child: \" + child);\n            depth[child] = depth[vertex] + 1;\n            dfs(child, vertex, graph, depth);\n            // coming back up in the recursion from the child\n        }\n    }\n}\n\n```\n\n---\n\n#### Output:\n\n    Vertex: 1 parent: 0 child: 2\n\n    Vertex: 2 parent: 1 child: 5\n\n    Vertex: 5 parent: 2 child: 6\n\n    Vertex: 5 parent: 2 child: 7\n\n    Vertex: 5 parent: 2 child: 8\n\n    Vertex: 8 parent: 5 child: 12\n\n    Vertex: 1 parent: 0 child: 3\n\n    Vertex: 3 parent: 1 child: 4\n\n    Vertex: 4 parent: 3 child: 9\n\n    Vertex: 4 parent: 3 child: 10\n\n    Vertex: 10 parent: 4 child: 11\n\n    Vertex: 1 parent: 0 child: 13\n\n    depth: [0, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 4, 4, 1]\n\n    max_depth_node: 11\n\n    Vertex: 11 parent: 0 child: 10\n\n    Vertex: 10 parent: 11 child: 4\n\n    Vertex: 4 parent: 10 child: 3\n\n    Vertex: 3 parent: 4 child: 1\n\n    Vertex: 1 parent: 3 child: 2\n\n    Vertex: 2 parent: 1 child: 5\n\n    Vertex: 5 parent: 2 child: 6\n\n    Vertex: 5 parent: 2 child: 7\n\n    Vertex: 5 parent: 2 child: 8\n\n    Vertex: 8 parent: 5 child: 12\n\n    Vertex: 1 parent: 3 child: 13\n\n    Vertex: 4 parent: 10 child: 9\n\n    max_depth_node: 12\n\n    max_depth: 8\n\n---\n\n### Lowest Common Ancestor of two nodes in a tree\n\n- While travelling up from the bottom of the tree, the first common node we find for the given nodes, is called the LCA(Lowest Common Ancestor).\n\n- To find LCA we store the path of both the given nodes in an array and then loop through them till the last common index, that element is our LCA.\n\n- And for this, we'll need to store the parents of each node, in an array, so that we can easily trace the path of each node to the root node. For this we'll use DFS.\n\n```java\npublic static void main(String[] args) {\n        ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph = new ArrayList\u003c\u003e();\n        Scanner input = new Scanner(System.in);\n        int n = input.nextInt();\n        for (int i = 0; i \u003c= n; i++) {\n            graph.add(new ArrayList\u003c\u003e());\n        }\n        for (int i = 0; i \u003c n - 1; i++) {\n            int u = input.nextInt();\n            int v = input.nextInt();\n            graph.get(u).add(v);\n            graph.get(v).add(u);\n        }\n        input.close();\n\n        int par[] = new int[n + 1];\n        dfs(1, -1, graph, par); // dfs to store parent of each vertex\n\n        // paths of each from 'node to vertex'\n        List\u003cInteger\u003e path1 = path(10, par);\n        List\u003cInteger\u003e path2 = path(3, par);\n\n        int length = Math.min(path1.size(), path2.size());\n        int LCA = -1;\n\n        // looping through both the path arrays to find the lowest common ancestor\n        for (int i = 0; i \u003c length; i++) {\n            if (path1.get(i) == path2.get(i)) {\n                LCA = path1.get(i);\n            } else {\n                break;\n            }\n        }\n\n        System.out.println(LCA);\n    }\n\n    static void dfs(int vertex, int parent, ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph, int[] par) {\n        par[vertex] = parent;\n        for (int child : graph.get(vertex)) {\n\n            if (child == parent) {\n                continue;\n            }\n            // going down in the recursion of the child\n            dfs(child, vertex, graph, par);\n            // coming back up in the recursion from the child\n        }\n    }\n\n    static List\u003cInteger\u003e path(int vertex, int[] par) {\n        List\u003cInteger\u003e ans = new ArrayList\u003c\u003e();\n        while (vertex != -1) {\n            ans.add(vertex);\n            vertex = par[vertex];\n        }\n        return ans.reversed(); // important step!! As we traverse the tree from bottom to top through the parent array, we actually need the path from 'node to vertex', hence the 'ans' list has been reversed.\n    }\n```\n\n### Precomputation and deleting the edges between nodes\n\nExamples :\n\n1. Maximizing the sum of the subtrees\n\n2. Maximizing the sum of the primes in a subtree\n\nWe pre-compute the sum/number of primes and then delete the edges using a for loop and then apply the given condition.\n\n```java\npackage luv.trees;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Scanner;\n\npublic class EdgeDeletionPrecomputation {\n    public static void main(String[] args) {\n        ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph = new ArrayList\u003c\u003e();\n        Scanner input = new Scanner(System.in);\n        int n = input.nextInt();\n        for (int i = 0; i \u003c= n; i++) {\n            graph.add(new ArrayList\u003c\u003e());\n        }\n        for (int i = 0; i \u003c n - 1; i++) {\n            int u = input.nextInt();\n            int v = input.nextInt();\n            graph.get(u).add(v);\n            graph.get(v).add(u);\n        }\n        input.close();\n\n        boolean[] vis = new boolean[n + 1];\n        int[] subtreeSum = new int[n + 1];\n        dfs(1, graph, vis, subtreeSum);\n\n        System.out.println(\"subtreeSum: \" + Arrays.toString(subtreeSum));\n\n        long ans = 0;\n        for (int i = 2; i \u003c= n; i++) {\n            int sum1 = subtreeSum[i];\n            int diff = subtreeSum[1] - sum1;\n            ans = Math.max(ans, diff * sum1);\n            System.out.println(\"ans at \" + i + \": \" + ans);\n        }\n        System.out.println(\"max product: \" + ans);\n    }\n\n    static void dfs(int vertex, ArrayList\u003cArrayList\u003cInteger\u003e\u003e graph, boolean[] vis, int[] subtreeSum) {\n        vis[vertex] = true;\n        subtreeSum[vertex] += vertex;\n        for (int child : graph.get(vertex)) {\n            // going down in the recursion of the child\n            if (vis[child]) {\n                continue;\n            }\n            dfs(child, graph, vis, subtreeSum);\n            subtreeSum[vertex] += subtreeSum[child];\n            // coming back up in the recursion from the child\n        }\n    }\n}\n\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frajneesh069%2Fdsa-in-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frajneesh069%2Fdsa-in-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frajneesh069%2Fdsa-in-java/lists"}