Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
coding_cheat_sheet [2020/07/11 23:50] paul [Coding Cheat Sheet] |
coding_cheat_sheet [2021/11/08 00:09] (current) paul [Using Custom Data With Priority Queues] |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Coding Cheat Sheet ====== | ====== Coding Cheat Sheet ====== | ||
+ | |||
+ | For general techniques, see [[Algorithm Techniques]]. | ||
+ | |||
+ | For explanations of problems see [[Algorithm Problems]]. | ||
+ | |||
+ | ===== Strings ===== | ||
Length of a string: | Length of a string: | ||
C++:< | C++:< | ||
- | Python: <code python> len(stringVar) </ | ||
Adding a character to a string: | Adding a character to a string: | ||
Line 16: | Line 21: | ||
</ | </ | ||
- | === Sorting | + | To convert anything into a string use '' |
- | To make a sorting function do as follows: | + | To erase characters, we use '' |
+ | |||
+ | To convert to upper case or lower case you have to iterate over every character | ||
+ | and use '' | ||
+ | character. | ||
+ | |||
+ | To check if a character is alphanumeric (letters and numbers) or just | ||
+ | alphabetic: | ||
<code cpp> | <code cpp> | ||
- | bool sortFunc(const vector<int> &v1, const vector<int> &v2) | + | isalnum(char c) // alpha numeric |
+ | isalpha(char c) // alphabetic | ||
+ | isdigit(char c) // is a number | ||
+ | </ | ||
+ | |||
+ | Returns false (0) if not. | ||
+ | |||
+ | ==== Split ==== | ||
+ | How to split a stream in an array of words. | ||
+ | |||
+ | <code cpp> | ||
+ | // Utility function to split the string using a delim. Refer - | ||
+ | // http:// | ||
+ | vector<string> split(const string | ||
+ | { | ||
+ | | ||
+ | stringstream ss(s); | ||
+ | string item; | ||
+ | while (getline(ss, | ||
+ | elems.push_back(item); | ||
+ | |||
+ | return elems; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== Maps ===== | ||
+ | |||
+ | ==== Going to middle element ==== | ||
+ | |||
+ | Use '' | ||
+ | |||
+ | <code cpp> | ||
+ | #include < | ||
+ | |||
+ | auto it = mySet.begin(); | ||
+ | std:: | ||
+ | </ | ||
+ | |||
+ | ==== Iterating over a map and deleting an element ==== | ||
+ | |||
+ | This is tricky! The following does NOT work!! | ||
+ | |||
+ | [[https:// | ||
+ | |||
+ | <code cpp> | ||
+ | for(auto& entry : dm) | ||
{ | { | ||
- | | + | |
+ | { | ||
+ | dm.erase(entry.first); | ||
+ | changed = true; | ||
+ | } | ||
} | } | ||
</ | </ | ||
- | === Initialize 2D Vector === | + | Use a regular for loop with constant interators. |
+ | <code cpp> | ||
+ | for (auto it = m.cbegin(); it != m.cend() /* not hoisted */; /* no increment */) | ||
+ | { | ||
+ | if (must_delete) | ||
+ | { | ||
+ | m.erase(it++); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | ++it; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
- | <code cpp> | + | ==== Removing Whitespace from a string |
- | ====Time Complexity==== | + | |
- | === Difference Between O(log(n)) and O(nlog(n)) === | + | <code cpp> |
+ | s.erase(std:: | ||
+ | </ | ||
- | https:// | + | ==== String to Number ==== |
+ | you can use | ||
- | Think of it as O(n*log(n)), i.e. "doing log(n) work n times" | + | '' |
+ | where str is your number as '' | ||
- | Remember that O(n) is defined relative to some real quantity n. This might be the size of a list, or the number of different elements in a collection. Therefore, every variable that appears inside O(...) represents something interacting to increase the runtime. O(n*m) could be written O(n_1 + n_2 + ... + n_m) and represent the same thing: "doing n, m times". | + | There are version for all flavours of numbers: long stol(string), float stof(string), double stod(string),... see http:// |
- | Let's take a concrete example of this, mergesort. For n input elements: On the very last iteration of our sort, we have two halves of the input, each half size n/2, and each half is sorted. All we have to do is merge them together, which takes n operations. On the next-to-last iteration, we have twice as many pieces (4) each of size n/4. For each of our two pairs of size n/4, we merge the pair together, which takes n/2 operations for a pair (one for each element in the pair, just like before), i.e. n operations for the two pairs. | + | ===== Ordered Container Order ===== |
- | From here, we can extrapolate | + | In C++ associative containers such as sets and maps store values in ascending order. You can easily change this by passing a comparative function |
+ | <code cpp> | ||
+ | // Here if greater< | ||
+ | // sure that elements are stored in | ||
+ | // descending order of keys. | ||
+ | map<int, string, greater <int> > mymap; | ||
+ | </ | ||
- | * Doubly Linked List | + | ===== Vectors ===== |
- | * Linked list | + | |
- | * Hash table | + | |
- | * Binary Search Tree | + | |
- | * Set | + | |
- | * List | + | |
- | * LRU Cache | + | |
+ | ==== Sorting a 2D Vector ==== | ||
- | ==== Hashtable ==== | + | To make a sorting function do as follows. Remember, it means what has to be true |
+ | for v1 to go before v2. | ||
- | A hashtable allows for the rapid lookup of data based on a key. It works as follows: | + | <code cpp> |
+ | bool compareFunc(const vector< | ||
+ | { | ||
+ | return v1[0] < v2[0]; | ||
+ | } | ||
- | - a hash function | + | // use the sort function |
- | - the value is stored or retrieved from that index. | + | sort(myVect.begin(), myVect.end(), |
+ | </ | ||
- | ===== Scratch Notes ===== | + | Or with a lambda: |
+ | <code cpp> | ||
+ | sort(in.begin(), | ||
+ | </ | ||
- | Learned: | + | ==== Initialize 2D Vector ==== |
- | - unordered_set: It is an ordered set of unique numbers that are stored by a key, which is equal to the number in each element. They are not ordered and allow for the fast retrieval and insertion of each element (constant time O(1)). To make them you use the following syntax: | + | Use the std:: |
+ | size and a default value. | ||
- | < | + | < |
+ | |||
+ | ===== Unordered Set ===== | ||
+ | |||
+ | An ordered set of unique numbers that are stored by a key, which is equal to the | ||
+ | number in each element. They are not ordered and allow for the fast retrieval | ||
+ | and insertion of each element (constant time O(1)). To make them you use the | ||
+ | following syntax: | ||
+ | |||
+ | <code cpp> | ||
#include < | #include < | ||
Line 89: | Line 186: | ||
</ | </ | ||
- | ==== Passing Yearbooks | + | ==== Unordered Sets of Pairs ==== |
- | We are giving an array that represents the parth a yearbook will take to get signed. The index of each element represents the student. We optimize by keeping track of what students are part of a circuit of signatures. Those student' | + | Pairs need a special hashing function for them to work. Regular ordered sets work just fine too. |
- | + | ||
- | ==== First Missing Positive ==== | + | |
- | This a problem that requires us to use constant extra memory, forcing us to use the input array itself to encode more data on it without losing the element information. Information about key assumptions must be had. | + | <code cpp> |
+ | struct pair_hash | ||
+ | { | ||
+ | template <class T1, class T2> | ||
+ | std:: | ||
+ | { | ||
+ | std:: | ||
+ | std:: | ||
- | The minimum positive element is going to be anywhere between 1 and n+1. Here is why. | + | return h1 ^ h2; |
- | If we have the perfectly ordered array with n = 5: | + | } |
- | [1 2 3 4 5] | + | }; |
- | The next positive element is 6 (n+1). | + | |
- | The smaller possible positive element is going to be 1. This means our range spans the same number of elements as we have in the input. Which means if there was a way to overlay this boolean state of whether or not we have seen this number in the array, we can solve this problem with no further memory required. | + | |
- | We do this in three steps: | + | unordered_set< |
+ | </ | ||
- | First pass: | ||
- | Search for a 1, and if we find any numbers out of possible solutions (negative or greater than n), we reset them to 1. | ||
- | Second pass: | + | ===== Queue ==== |
- | Map the value of each element to its index and then set that value to negative if present in the array. Hard problems would not be hard if they were easy to explain. | + | |
- | Thirst pass: | + | A queue is just a line man. First in fist out. You can only remove the element |
- | Look for the first non present negative number. If not found, handle | + | in the front of the line of a queue. Remember that! |
- | YOU GO THIS! | + | - '' |
+ | - '' | ||
+ | - '' | ||
+ | - '' | ||
+ | - '' | ||
+ | - '' | ||
- | ==== Permutations and Combinations | + | ===== Priority Queue ===== |
- | Theres like... all these different kinds of permutations and combinations with repetitions, with unique values, etc. | + | A C++ '' |
+ | the standard less comparator. Easy to get confused here, because the '' | ||
+ | function isn't getting the begin element of the container. Just remember, by | ||
+ | default a prioirty queue is a max heap. | ||
- | === Unique permutations with unique result === | + | <code cpp> |
- | https:// | + | priority_queue< |
- | - Sort input candidates. | + | max_heap.push(10); |
- | - Make a boolean flag array to track used elements. | + | max_heap.push(1); |
- | - Recurse over the canditations, | + | |
- | - If the next option is the same, skip it. | + | |
+ | cout << "Top of max_heap: " << max_heap.top() << endl; | ||
+ | // prints 10 | ||
- | ==== Power Function ==== | + | priority_queue< |
+ | min_heap.push(10); | ||
+ | min_heap.push(1); | ||
- | Implement your own power function. The following is the naive algorithm and takes too much time: | + | cout << "Top of min_heap: " << min_heap.top() << endl; |
+ | // prints 1 | ||
+ | </ | ||
+ | ==== Max Heap with Pairs ==== | ||
- | < | + | By default, max heaps using type pair are ordered by the first element. You do not need to create a custom Compare class. See [[https:// |
- | class Solution { | + | <code cpp> |
- | public: | + | typedef pair<int,int> num_t; |
- | double myPow(double x, int n) { | + | |
- | + | ||
- | double ans = 1; | + | |
- | + | ||
- | if(n == 0) | + | |
- | return 1; | + | |
- | + | ||
- | for(int i = 1; i <= abs(n); i++) | + | |
- | { | + | |
- | ans = x * ans; | + | |
- | } | + | |
- | + | ||
- | if(n < 0) | + | |
- | ans = 1/ans; | + | |
- | + | ||
- | return ans; | + | |
- | + | ||
- | } | + | |
- | };</ | + | |
- | {{:: | + | priority_queue< |
- | < | + | maxHeap.push(make_pair(1, |
- | class Solution | + | maxHeap.push(make_pair(2, |
+ | |||
+ | // This will be true | ||
+ | assert_true(maxHeap.top().first == 2); | ||
+ | </code> | ||
+ | |||
+ | ==== Using Custom Data With Priority Queues ==== | ||
+ | |||
+ | There are numerous was of doing this but here is the most elegant way: | ||
+ | |||
+ | <code cpp> | ||
+ | struct node{ | ||
+ | node(int id, int value) : id(id), value(value){} | ||
+ | int id; | ||
+ | int value; | ||
+ | }; | ||
+ | |||
+ | auto cmp = [](const node &a, const node &b){ | ||
+ | //Max Heap: | ||
+ | // | ||
+ | //larger b will appear later in the container and therefore have a higher priority | ||
+ | return a.value < b.value; | ||
+ | |||
+ | //MIN Heap: | ||
+ | //if a is larger than b, it will appear before b, so smaller b will have higher priority | ||
+ | return a.value > b.value; | ||
+ | }; | ||
+ | |||
+ | priority_queue< | ||
+ | </ | ||
+ | |||
+ | A less elegant way of overloading the default less than operator is as follows: | ||
+ | |||
+ | <code cpp> | ||
+ | struct node{ | ||
+ | node(int _id, int _value) : id(_id), value(_value){} | ||
+ | int id; | ||
+ | int value; | ||
+ | }; | ||
+ | |||
+ | bool operator< | ||
+ | // Priority look at the " | ||
+ | // the highest priority | ||
+ | |||
+ | /*--- FOR A MAX HEAP ---*/ | ||
+ | |||
+ | // B will go after A and have a higher priority than A | ||
+ | return A.value < B.value; | ||
+ | |||
+ | /*--- FOR A MIN HEAP ---*/ | ||
+ | |||
+ | // a GREATER THAN b means b will go before a. The smaller element a will have | ||
+ | // a higher priority than b. | ||
+ | return A.value > B.value; | ||
+ | } | ||
+ | |||
+ | // Now you initalize your priority queue normally, as it will call the | ||
+ | // overloaded LESS THAN comparator | ||
+ | |||
+ | priority_queue< | ||
+ | |||
+ | </ | ||
+ | |||
+ | See [[https:// | ||
+ | |||
+ | Another option: | ||
+ | |||
+ | <code cpp> | ||
+ | typedef pair< | ||
+ | |||
+ | class Compare{ | ||
public: | public: | ||
- | | + | |
- | | + | if(a.second |
- | if ( n == 0) | + | return |
- | return 1.0; | + | }else { |
- | double half = fastPow(x, n / 2); | + | return |
- | if( n % 2 == 0) | + | |
- | | + | |
- | return | + | |
- | } | + | |
- | | + | |
- | | + | |
- | return | + | |
} | } | ||
} | } | ||
- | | + | }; |
- | | + | |
- | long long N = n; | + | // This is a max heap based on number of the int in the pair, and if numbers are the same, word thats lower on the alphabetical compare wins. |
- | if(N < 0) | + | priority_queue< |
- | | + | </ |
- | x = 1/x; | + | |
- | | + | [[https:// |
- | } | + | ===== Range Based Loops ===== |
- | + | ||
- | | + | Range based loops return copies unless a reference is requested. They return the |
- | } | + | pair, so no pointer member access required. |
- | };</ | + | |
+ | <code cpp> | ||
+ | unordered_map< | ||
+ | multimap< | ||
+ | for(auto& | ||
+ | { | ||
+ | | ||
+ | } | ||
+ | vector<int> out; | ||
+ | for(auto& | ||
+ | { | ||
+ | | ||
+ | if(--k == 0) | ||
+ | | ||
+ | } | ||
+ | </code> | ||
+ | ===== Lists ===== | ||
+ | Lists are C++ implementations of doubly linked lists. They allow for | ||
+ | manipulation of data from both ends of the list. The following functions allow | ||
+ | you to control them: | ||
+ | |||
+ | * pop_back() | ||
+ | * push_back() | ||
+ | * pop_front() | ||
+ | * push_front() | ||
+ | * front() | ||
+ | * back() | ||
+ | |||
+ | List iteartors are bidrectional! '' | ||
+ | points the last element of the list (assuming the list has size greater than | ||
+ | zero). | ||
+ | |||
+ | We can also splice in elemnts into a position. For example, say we had a list | ||
+ | like the following: | ||
+ | |||
+ | <code cpp> | ||
+ | myList.push_back(1); | ||
+ | myList.push_back(2); | ||
+ | myList.push_back(3); | ||
+ | myList.push_back(4); | ||
+ | </ | ||
+ | |||
+ | '' | ||
+ | |||
+ | |||
+ | And we want to place 4 in the front. We can do the following: | ||
+ | |||
+ | '' | ||