diff --git a/Crash Course (DS & Algorithms)/Lecture Notes/Comparators in C++.md b/Crash Course (DS & Algorithms)/Lecture Notes/Comparators in C++.md index e9d47016..76b5a2a2 100644 --- a/Crash Course (DS & Algorithms)/Lecture Notes/Comparators in C++.md +++ b/Crash Course (DS & Algorithms)/Lecture Notes/Comparators in C++.md @@ -11,8 +11,8 @@ Comparators are an inherent part of _class_. Suppose you design a new class, and
Structures Vs Class -# Strucutures vs Class -When you need to create your own data types, generally _structures_ suffice. However, there is no harm in using _classes_ to achieve the same task. Since we've only covered _classes_, we will base the entire discussion on it. However, keep in mind that everything can be equally applied to _structures_ as well. The bottomline is, if you want to create a new data type (containing heterogenous fields), you should use _class_ and if you are planning to deal with pointers a lot, use _structures_ as you are already familar with it. +# Structures vs Class +When you need to create your own data types, generally _structures_ suffice. However, there is no harm in using _classes_ to achieve the same task. Since we've only covered _classes_, we will base the entire discussion on it. However, keep in mind that everything can be equally applied to _structures_ as well. The bottom line is, if you want to create a new data type (containing heterogeneous fields), you should use _class_ and if you are planning to deal with pointers a lot, use _structures_ as you are already familiar with it. --- @@ -25,7 +25,7 @@ When you need to create your own data types, generally _structures_ suffice. How # The Default Comparator Numbers are represented as bits in the computer. We've been using numbers a lot (along with their comparisons, such as `>`, `<`, `==`). To define their relative ordering, we have the concept of a comparator. **A comparator is a function which takes 2 objects as an argument and returns True if the first argument is smaller than the second, else it returns False**. (Notice that the order of arguments matter a lot). -So now, we need to tell the computer that `2 < 3`. How do we do this? Lucky for us, there is a default comparator in C++ which does the job. The **default** comparator is `lesser`. Let us talk about what this is. First of all, `lesser` is a function with a boolean return value. So far, we have only talked about the notation `<...>` in the context of containers. What does this symbol mean in terms of function? Well, it means the same. In containers, this notation was used to make the containers universal and accomodate any data type. You just needed to put the name of the data type inside `<...>`. It is the same thing as functions, it is written as a universal function which can accept any data type and perform the same type of operations on that data type. Makes sense, right? Because if you are creating a function that returns the absolute value, you wouldn't create a bunch of functions with different names. Rather you would want to create a function which can take `int`, `long int`, `long long int`, `float` , etc and just return the absolute value of these arguments. Hence, the data type of the input needs to be made universal. This is called **Templates** in C++. +So now, we need to tell the computer that `2 < 3`. How do we do this? Lucky for us, there is a default comparator in C++ which does the job. The **default** comparator is `lesser`. Let us talk about what this is. First of all, `lesser` is a function with a boolean return value. So far, we have only talked about the notation `<...>` in the context of containers. What does this symbol mean in terms of function? Well, it means the same. In containers, this notation was used to make the containers universal and accommodate any data type. You just needed to put the name of the data type inside `<...>`. It is the same thing as functions, it is written as a universal function which can accept any data type and perform the same type of operations on that data type. Makes sense, right? Because if you are creating a function that returns the absolute value, you wouldn't create a bunch of functions with different names. Rather you would want to create a function which can take `int`, `long int`, `long long int`, `float` , etc and just return the absolute value of these arguments. Hence, the data type of the input needs to be made universal. This is called **Templates** in C++. **Caution** : Comparators are not exactly functions, as it is wrapped over a class. But, to keep the discussion less technical, we'll just assume that they are normal functions. @@ -37,7 +37,7 @@ Similarly, there is a function called `greater`. As you might have guessed By default, C++ uses `lesser` to compare 2 numbers. Hence, to know which of the numbers `7,5` is smaller, it would call `lesser(7,5)` and get the answer `false` which means `5` is smaller. Similarly, if it had accidentally called `lesser(5,7)`, it would get the answer `true` and it would still conclude that `5` is smaller. **Tricking the Computer** -C++ would **always** expect the comparator to behave as `lesser`. Hence, no matter what comparator you desgin, if you return `true` from that comparator, C++ would automatically think that the first argument is `smaller`. (As it would expect it to behave as `lesser`). Using this idea, how do we trick the computer to sort the numbers in descending order? Suppose, there was a way to change `lesser` to any other function that you want. Can you do it now? Yes, we can just replace it with `greater`. Now, when C++ calls the comparator with the arguments `(7,5)` , it would get the answer as `true`. Hence it would assume `7 < 5` (as we discussed earlier). Similarly, if it accidentally calls the comparator on `(5,7)`, it would get `false`. It would still conclude that `7 < 5`. I hope you see the underlying trick here. We have fooled the computer into believing that numbers with large magnitude should be seen as smaller numbers. Hence, in the sorted order, we'll have the largest number first (as the computer thinks it to be the smallest number). In this manner, we can sort it in descending order. +C++ would **always** expect the comparator to behave as `lesser`. Hence, no matter what comparator you design, if you return `true` from that comparator, C++ would automatically think that the first argument is `smaller`. (As it would expect it to behave as `lesser`). Using this idea, how do we trick the computer to sort the numbers in descending order? Suppose, there was a way to change `lesser` to any other function that you want. Can you do it now? Yes, we can just replace it with `greater`. Now, when C++ calls the comparator with the arguments `(7,5)` , it would get the answer as `true`. Hence it would assume `7 < 5` (as we discussed earlier). Similarly, if it accidentally calls the comparator on `(5,7)`, it would get `false`. It would still conclude that `7 < 5`. I hope you see the underlying trick here. We have fooled the computer into believing that numbers with large magnitude should be seen as smaller numbers. Hence, in the sorted order, we'll have the largest number first (as the computer thinks it to be the smallest number). In this manner, we can sort it in descending order. Now, recall the **Merge Sort** algorithm. While manually merging the 2 sorted array, there was just one instance where we used `<`. So, if we want to sort custom objects, we need to clarify what is meant by one object being `<` than the second. There are 2 options, either include this as a blueprint in the source code of your object or pass an overloaded optional third parameter to the **sort** function. We'll discuss what the first option means. But for the second option, we just need to create a function that returns `true` when the first arguments is `greater` than the second (to imitate the reverse of `lesser`). If we pass this optional parameter, all usage of `lesser` would be replaced by this function. Here's an example with numbers. [Playground](https://ide.geeksforgeeks.org/lxIMuLVyov) @@ -100,7 +100,7 @@ using namespace std; /* Note that if you aren't dealing with pointers, it is a good idea to do everything with class */ -/* Definiton for struct */ +/* Definition for struct */ struct S_Node { int data; @@ -389,13 +389,13 @@ int main() # Making our lives simpler To create custom containers, there is a lot of work involved. You need to create a new class, put a new function, remember the difference in the syntax between `priority_queue` and `set`, etc. Plus, we still don't know how to implement custom maps. -Let's think about this a bit. When you create a container of integers, do you do all this? No, right! This is beacause all the comparators are already hidden inside the integers. Hence, we don't have to worry about them. Can we do the same for objects? Can we inject something in the blueprint of the object so that compiler would treat it as integers. If so, than our lives would become much simpler. Turns out, there is such a way and I'll let you in on this secret in a few moments. +Let's think about this a bit. When you create a container of integers, do you do all this? No, right! This is because all the comparators are already hidden inside the integers. Hence, we don't have to worry about them. Can we do the same for objects? Can we inject something in the blueprint of the object so that compiler would treat it as integers. If so, than our lives would become much simpler. Turns out, there is such a way and I'll let you in on this secret in a few moments. -In Java, there is one superclass, and every class inherits from it. What's more, you can also over ride the inherited functions. In C++, when defining any class, there is a hidden boolean function called `operator<` which takes a single parameter and determines whether the current object of the class is smaller than the incoming object. This is the default comparator. If you write this function precisely, then you won't have to use comparators with this class, not even in sorting. To sort, you can just do `sort(customVec.begin(), customVec.end())`. To create a set, jsut do, `set`. To create heaps, just do `priority_queue`. To create maps, just do `map>`. As you can see, we can now use it like any other data type because we have embedded the comparator in the blue print. So, all that remains is to modify the blue print. +In Java, there is one superclass, and every class inherits from it. What's more, you can also over ride the inherited functions. In C++, when defining any class, there is a hidden boolean function called `operator<` which takes a single parameter and determines whether the current object of the class is smaller than the incoming object. This is the default comparator. If you write this function precisely, then you won't have to use comparators with this class, not even in sorting. To sort, you can just do `sort(customVec.begin(), customVec.end())`. To create a set, just do, `set`. To create heaps, just do `priority_queue`. To create maps, just do `map>`. As you can see, we can now use it like any other data type because we have embedded the comparator in the blue print. So, all that remains is to modify the blue print. To do so, just create a public function with this template ``` -boool operator < (const &IncomingObject) const +bool operator < (const &IncomingObject) const { // Return true if you see current object is smaller than incoming one // Don't forget to return false explicitly if it is bigger or equal @@ -404,7 +404,7 @@ boool operator < (const &IncomingObject) const **Notice the extra const at the end. Weird syntax, but it is what it is** -Although it looks like it takes 1 argument, it actually takes 2 under the hood. It's just like `lesser`. So now, we want to know what is the first argument and what is the second argument. (Remember, the ordering matters a lot). Well, it turns out, that **The first argument is the object of the class that you are currently standing at and the second is the incoming object**. Hence, the comparator expects that if the object that you are standing at is smaller than the incoming object, then it is your duty to return true. Now, how to access the instance variables of the object that you are standing at? It's simple. Either use `this->VariableName` or just use `instanceVariableName` . This is because there is no name collisons and we don't really require `this`. How to access the variables of incoming object? Use the dot notation. +Although it looks like it takes 1 argument, it actually takes 2 under the hood. It's just like `lesser`. So now, we want to know what is the first argument and what is the second argument. (Remember, the ordering matters a lot). Well, it turns out, that **The first argument is the object of the class that you are currently standing at and the second is the incoming object**. Hence, the comparator expects that if the object that you are standing at is smaller than the incoming object, then it is your duty to return true. Now, how to access the instance variables of the object that you are standing at? It's simple. Either use `this->VariableName` or just use `instanceVariableName` . This is because there is no name collisions and we don't really require `this`. How to access the variables of incoming object? Use the dot notation. After we are done, we don't have to worry about using any function / container which uses ordering. This is the template that I use (and prefer). It's not as difficult as it seems diff --git a/LeetCode Contests/LeetCode Contest #127/#1008 Minimum Domino Rotations For Equal Row/Explanation and Link.md b/LeetCode Contests/LeetCode Contest #127/#1008 Minimum Domino Rotations For Equal Row/Explanation and Link.md index 8b0f428f..1c9bc2b7 100644 --- a/LeetCode Contests/LeetCode Contest #127/#1008 Minimum Domino Rotations For Equal Row/Explanation and Link.md +++ b/LeetCode Contests/LeetCode Contest #127/#1008 Minimum Domino Rotations For Equal Row/Explanation and Link.md @@ -1,7 +1,7 @@ **Intuition** * Create a helper function `minSteps` that takes as input 2 vectors and a `candidate` and returns the minimum steps to convert every element in the `target` array to `candidate`. It returns -1 if the target vector cannot be converted in the desired fashion. This function is used to remove code redundancy. -* Create a frquency array and update the frequency of each element (as every element is in the range `[1,6]`.) -* Traverse the frequency array and capture the `candidates`, i.e, elements which occur atleast half the time [inclusive]. Note that this is not the same as majority element as majority element should occur strictly more than `n/2` times(and hence Moore's Algorithm won't work). However, there can be atmost 2 candidates. +* Create a frequency array and update the frequency of each element (as every element is in the range `[1,6]`.) +* Traverse the frequency array and capture the `candidates`, i.e, elements which occur at least half the time [inclusive]. Note that this is not the same as majority element as majority element should occur strictly more than `n/2` times(and hence Moore's Algorithm won't work). However, there can be at most 2 candidates. * If there is no candidate, return -1 * For each of the candidate, try to adjust it in both the top and bottom half and take the best outcome of the two. diff --git a/LeetCode Contests/LeetCode Contest #127/#1008 Minimum Domino Rotations For Equal Row/Minimum Domino Rotations.cpp b/LeetCode Contests/LeetCode Contest #127/#1008 Minimum Domino Rotations For Equal Row/Minimum Domino Rotations.cpp index 39556718..3458b207 100644 --- a/LeetCode Contests/LeetCode Contest #127/#1008 Minimum Domino Rotations For Equal Row/Minimum Domino Rotations.cpp +++ b/LeetCode Contests/LeetCode Contest #127/#1008 Minimum Domino Rotations For Equal Row/Minimum Domino Rotations.cpp @@ -26,7 +26,7 @@ int Solution :: minSteps(vector& source, vector& target, int candidate /* Returns the min steps to equalize each element in any vector */ int Solution :: minDominoRotations(vector& a, vector& b) { - // Get the size, Create the frequncy and candidate vector + // Get the size, Create the frequency and candidate vector int n = a.size(); vector freq(7,0); vector candidate; @@ -35,7 +35,7 @@ int Solution :: minDominoRotations(vector& a, vector& b) for(int i=0; i=n) candidate.push_back(i); @@ -46,7 +46,7 @@ int Solution :: minDominoRotations(vector& a, vector& b) // Variable to store the min steps int minCount = INT_MAX; - // Try all the candidate elements (atmost 2) + // Try all the candidate elements (at most 2) for(int i=0; i& a) // The reference for modular arithmetic int ref=60; - // Populate the map in modular arithemtic + // Populate the map in modular arithmetic unordered_map count; for(auto ele : a) count[ele%ref]++; diff --git a/LeetCode Contests/LeetCode Contest #128/#1013 Pairs with Sum divisible by 60/ReadMe.md b/LeetCode Contests/LeetCode Contest #128/#1013 Pairs with Sum divisible by 60/ReadMe.md index 2c5128a8..b2c5b396 100644 --- a/LeetCode Contests/LeetCode Contest #128/#1013 Pairs with Sum divisible by 60/ReadMe.md +++ b/LeetCode Contests/LeetCode Contest #128/#1013 Pairs with Sum divisible by 60/ReadMe.md @@ -1,13 +1,13 @@ [Blog](https://leetcode.com/problems/pairs-of-songs-with-total-durations-divisible-by-60/discuss/256782/Detailed-Explanation-using-Modular-Arithmetic-C%2B%2BJavaScript-O(n)) **Intuition** -* The problem can be reduced to modular arithmetic by doing every operation `mod 60`. Since every number divisible by 60 becomes `0` in the modular arithemtic of 60, the equivalent characterization of the problem is, **How many pairs sum upto 0 (in modular arithmetic of 60)**. +* The problem can be reduced to modular arithmetic by doing every operation `mod 60`. Since every number divisible by 60 becomes `0` in the modular arithmetic of 60, the equivalent characterization of the problem is, **How many pairs sum up to 0 (in modular arithmetic of 60)**. * Notice that there are only 60 different numbers in the modular arithmetic. i.e `[0,1,2,...59]`. * We traverse the array and update the count of each of the 60 numbers. (How?). Any number `num` contributes to `num%60` in the modular version. So we increase the count of `num%60` each time we encounter an element. * Now that we only have numbers from `0...59`, let us see which numbers can sum up to zero. * Clearly each `0` can be paired with another zero to sum up to zero. How many such pairs are there? Suppose the count of zeros is `n`. Then selecting any 2 elements out of this would result in an answer. How many ways are there to select? Clearly, `nC2` = `n*(n-1)/2`. * Similarly, `30` can be paired with `30` to give `0` (since `30+30` equals to `0` mod `60`). How many pairs can we form from 30? As argued above, `nC2` = `n*(n-1)/2`, where `n` is the frequency of `30` in the map. -* Now, for the remaining elements, how many ways are there to sum upto `0`? Let's pick a number `a`. The complement of this number is `b` = `60-a`. Suppose the frequency of `a` is `m` and the frequency of `b` is `n`. Now, picking any one `a` and any one `b` would sum upto 0. How many ways are possible to pick one element from each set ? Clearly `m*n`. +* Now, for the remaining elements, how many ways are there to sum up to `0`? Let's pick a number `a`. The complement of this number is `b` = `60-a`. Suppose the frequency of `a` is `m` and the frequency of `b` is `n`. Now, picking any one `a` and any one `b` would sum up to 0. How many ways are possible to pick one element from each set ? Clearly `m*n`. * Care has to be taken to avoid recounting the pairs `(a,b)` and `(b,a)` **Algorithm** @@ -15,5 +15,4 @@ * As discussed above, we deal with `0` and `30` separately as they are their own complements. **Miscellaneous** -* We only loop upto 29 so as to avoid recounting. (Beacause every number greater than 30 has a complement less than 30, which has already been counted in the `for` loop). - +* We only loop up to 29 so as to avoid recounting. (Because every number greater than 30 has a complement less than 30, which has already been counted in the `for` loop). diff --git a/LeetCode Contests/LeetCode Contest #152/#1175 Prime Arrangements/ReadMe.md b/LeetCode Contests/LeetCode Contest #152/#1175 Prime Arrangements/ReadMe.md index e0e035c2..6fe85754 100644 --- a/LeetCode Contests/LeetCode Contest #152/#1175 Prime Arrangements/ReadMe.md +++ b/LeetCode Contests/LeetCode Contest #152/#1175 Prime Arrangements/ReadMe.md @@ -1,9 +1,9 @@ # Intuition * First, count all the primes from 1 to **n** using **Sieve**. Remember to terminate the outer loop at **sqrt(n)**. -* Next , iterate over each positon and get the count of prime positions, call it `k`. +* Next , iterate over each position and get the count of prime positions, call it `k`. * So, for the `k` prime numbers, we have limited choice, we need to arrange them in `k` prime spots. * For the `n-k` non prime numbers, we also have limited choice. We need to arrange them in `n-k` non prime spots. -* Both the events are indepent, so the total ways would be product of them. +* Both the events are independent, so the total ways would be product of them. * Number of ways to arrange `k` objects in `k` boxes is `k!`. * Use the property that `(a*b) %m = ( (a%m) * (b%m) ) % m`. diff --git a/LeetCode Contests/LeetCode Contest #152/#1178 Words and Puzzles/ReadMe.md b/LeetCode Contests/LeetCode Contest #152/#1178 Words and Puzzles/ReadMe.md index f7a71c7c..a57f3405 100644 --- a/LeetCode Contests/LeetCode Contest #152/#1178 Words and Puzzles/ReadMe.md +++ b/LeetCode Contests/LeetCode Contest #152/#1178 Words and Puzzles/ReadMe.md @@ -9,7 +9,7 @@ Anyway, I was thinking of the *trie* based approach during the contest (by looki * Insertion in the trie is trivial, just follow the normal procedure for insertion, and in the end, increase the count of words ending at the last node by 1. -* For any puzzle, we willl traverse the tree and get the answer. Observe that we only need to go 7 levels deep. +* For any puzzle, we will traverse the tree and get the answer. Observe that we only need to go 7 levels deep. * We explore all the 7 possibilities. As soon as we see the first element, we can keep incrementing the count from this node onwards. diff --git a/LeetCode Contests/LeetCode Contest #157/#1220 Count Vowel Permutation/ReadMe.md b/LeetCode Contests/LeetCode Contest #157/#1220 Count Vowel Permutation/ReadMe.md index 605b2faa..e43b32a4 100644 --- a/LeetCode Contests/LeetCode Contest #157/#1220 Count Vowel Permutation/ReadMe.md +++ b/LeetCode Contests/LeetCode Contest #157/#1220 Count Vowel Permutation/ReadMe.md @@ -3,7 +3,7 @@ Let us visualize this as a graph problem. From the above rules, we can create a ![image](https://assets.leetcode.com/users/just__a__visitor/image_1570334589.png) -Now, Let us say that `dp[n][char]` denotes the number of directed paths of length `n` which end at a particular vertex `char`. Then, we know that the last vertex in our path was `char`. However, let's focus on the last second vertex. It could have been any of the vertex which has a direct edge to `char`. Hence, if we can find the number of paths of length `n-1` ending at these vertices, then we can append `char` at the end of every path and we would have exhausted all possibilites. +Now, Let us say that `dp[n][char]` denotes the number of directed paths of length `n` which end at a particular vertex `char`. Then, we know that the last vertex in our path was `char`. However, let's focus on the last second vertex. It could have been any of the vertex which has a direct edge to `char`. Hence, if we can find the number of paths of length `n-1` ending at these vertices, then we can append `char` at the end of every path and we would have exhausted all possibilities. Hence, `dp[n+1][x] = sum of all dp[n][y]` such that there is a directed edge from `y` to `x`. diff --git a/UVa Online Judge/Binary Search/Where is the Marble (10474)/Lower Bound.cpp b/UVa Online Judge/Binary Search/Where is the Marble (10474)/Lower Bound.cpp index cf6949af..238658f9 100644 --- a/UVa Online Judge/Binary Search/Where is the Marble (10474)/Lower Bound.cpp +++ b/UVa Online Judge/Binary Search/Where is the Marble (10474)/Lower Bound.cpp @@ -11,7 +11,7 @@ void solve(vector &vec, vector &queries) int index = itr - vec.begin(); - // ++index to accomodate 1 based indexing + // ++index to accommodate 1 based indexing if(index < vec.size() and vec[index] == query) cout << query << " found at " << ++index << endl; else