# 🐍 🐍 🐍 & C++
## python thingz
cos python is special
### Arithmetic operation on strings
`'a' * 5 -> 'aaaaa'`
### Copying list
```python
a = [1,2,3]
b = a[:] or [x for x in a]
```
### Sorting
sort() -> mutate original list
```python
a = [(4,a), (1,b), (3,z)]
a.sort(key=lambda x:x[1], reverse=True) # sort by descending alphabet
```
sorted() -> does not mutate original list, returns a sorted list
```python
b = sorted(a, key=lambda x:x[0], reverse=True) # sort by descending number
```
### Advance List/Array
```python
A = [1,2,3]
B = [4,5,6]
C = [7,8]
A += B # A = [1,2,3,4,5,6] concatenation can use +=
A.extend(C) # mutates A to become [1,2,3,4,5,6,7,8]
```
Good practice when looping tuples with irrelevant data
```python
A = [(1,a,b), (5,c,d), (10,e,f)]
for x,_,_ in A: # only the number is relevant for this algo
...
```
Enumerate pls, it makes looping cleaner when you need both the index and the value of an element in a list
Without enumerate:
```python
def lcs(a, b):
lengths = [[0 for j in range(len(b) + 1)]
for i in range(len(a) + 1)]
for i in range(len(a)):
for j in range(len(b)):
if a[i] == b[j]:
lengths[i + 1][j + 1] = lengths[i][j] + 1
...
```
With enumerate:
```python
def lcs(a, b):
lengths = [[0 for j in range(len(b) + 1)]
for i in range(len(a) + 1)]
for i, x in enumerate(a):
for j, y in enumerate(b):
if x == y:
lengths[i + 1][j + 1] = lengths[i][j] + 1
...
```
Matrix creation
```
dp = [[0 for j in range(10)] for i in range(20)] # 20x10 matrix
```
### Generator and Yield
https://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do
### char-int conversion
```
ord('A') -> 65
chr(90) -> 'Z'
```
### base-x int conversion
```
int('1111', 2) # 15
```
### Smart debugging
```python
var1 = 100
var2 = [1,2,3]
print(f"{var1=} {var2=}") #outputs var1=100 var2=[1,2,3]
```
### Useful libraries
Good stuff! makes your life and interviewer's life easier
#### collections
- Counter
- defaultdict (very useful for graph problem)
#### queue
- heapq
- PriorityQueue
#### dateutil.parser
- parse -> returns datetime object (can do datetime arithmetically)
#### concurrent
- ThreadPool
#### time
- sleep
#### others
- threading
```
x = threading.Thread(target=fn, args=(a,))
```
args param must contain a tuple, to create a single-element tuple is exactly like (elem,)
#### functools
- lru_cache
#### itertools
- permutation
- combination
#### math
- factorial
- pow
### OOP
#### `@classmethod` vs `@staticmethod`
- `classmethod`: the class of the object is implicitly passed as the first argument instead of `self`. When we define something to be classmethod, it is probably because we want to call the method from the class.
- `staticmethod`: neither `self` (object instance) nor `cls` (class) is implictly passed as the first argument. They behave like plain functions except that you can call them from an instance or the class.
```python3
class A:
_counter = 0
@classmethod
def class_foo(cls, x):
print(f'Executing class_foo({cls}, {x}')
@staticmethod
def static_foo(x):
print(f'Executing class_foo({x}')
a = A()
# classmethod
a.class_foo(1) # executing class_foo(<class '__main__.A'>, 1)
A.class_foo(1) # executing class_foo(<class '__main__.A'>, 1)
# staticmethod
a.static_foo(1) # executing static_foo(1)
A.static_foo('hi') # executing static_foo(hi)
```
#### `@staticmethod` vs plain outside-of-class function
- Static method is an organization/stylistic feature. Sometimes a module have many classes, and some helper functions are logically tied to a given class and not to the others, so it makes sense not to pollute the module with many free functions. It is better to use a static method than relying on the ppor style of mixing classes and function defs together in code just to show they are related.
Reference on static and class method: https://stackoverflow.com/q/136097
### Python OOP (compared to Java)
#### creating class instance
Java needs to declare the class variables outside of the constructor method
Python don't need
Immediately use self.x to create object attribute x
#### class level attributes
Java uses keyword static
Python is like this
```python
class Car:
wheels = 5
def __init__(self):
self.wheels = wheels
car = Car()
car.Car.wheels = 3 #mutate the class-level wheels
car.wheels = 5 #mutate the object's wheels
```
#### public vs private
All attributes in python are public
Make use of `_` and`__` to conceal attributes
`_attribute` technically still accessible - e.g, `object._attribute`, but VSCode with PEP8 plugin would throw warning
`__attribute` would not be accessible through `object.__attribute`. The `__` prefix would rename the attribute and technically could stil be accessed by determined developer - `object._Object__attribute`
setters and getters is the convention for Java, but not for python, everything is public yo
#### Methods & Functions
Python has functions, Java don't. That's it.
Every functions in Java have to be contained in a class. But, it can be static so that it can be called without instance.
#### Inheritance
Java single inheritance, Python multiple inheritance
```python
class Device
class Vehicle
class Car(Device, Vehicle):
def __init__(sef):
# init the subclasses first
Device.__init__()
Vehicle.__ini__()
# only then create Car specific attributes
self.year = ...
```
`Car` would have all the attributes and methods from `Device` and `Vehicle`
#### Types and Polymorphism
Java strict typing gives rise to inheritance to accomodate polymorphism
Python has duck typing. If it walk like duck, quacks like a duck, it's a duck. https://realpython.com/python-type-checking/
Java static typing, Python dynamic typing (it checks as the code execute)
#### Default Methods
All classes in Java inherit the methods from `Object`
In Python, each class also has default methods - `dunder` (double underscore) methods
```
.hashCode() -> __repr__()
.toString() -> __str__()
.equal() -> __eq__()
print(repr(my_car)) -> hashcode
print(str(my_car)) -> "Honda 2000"
...
```
Java needs `@Override`, python does not.
Additional `dunder` methods
```python
def __eq__(self, other)
def __lt__(self, other)
def __add__(self, other):
return Car(self.price + other.price)
```
### Pytest
Allows use of idiomatic python constructs without biolerplate code.
## C++ Data Structures & Algorithms
- `stack<T>`
- `queue<T>`
- `priority_queue<T>` -- there is also another signature that you can define your own order
- `deque<T>`
- `vector<T>`
- `pair<T, R>`
- `tuple<T, R, ...>`
- `map<T, R>` -- RB-Tree, O(log n) access, able to access the (key, value) pair in sorted order (sorted by key)
- `unordered_map<T, R>` -- Hashing, access & insert average O(1), worst O(n), unable to access in sorted order
- `set<T>` -- RB-Tree, O(log n) insert & access
- `unordered_set<T>` -- Hashing (not sure), access & insert average O(1), worst O(n).
- `multiset<T>` -- Able to store multiple elements
- `sort(start, end, [cmp])`
- `unique(start, end)` -- Reorder the elements inside an array / vector such that repeating elements are put at the back. Returns the pointer of first element that is repeated
- `reverse(start, end)`
- `erase(start, end)`
Note: always best to consult with the C++ reference. The list is not exhaustive, so it is also best to be complemented with googling some tips and tricks.
```c++
// Example:
stack<int> st;
st.push(1); st.push(2);
printf("%d\n", st.top()) // returns 2
st.pop();
printf("%d\n", st.top()) // returns 1
// Here, v = {3, 3, 5, 7, 10}
// `auto` will automatically infer the type of variable `k`.
// Also possible to use `int` instead of `auto`.
for (auto &k : v) {
printf("%d\n", k); // Will output the whole element of vector v.
}
// unique(v.begin(), v.end()) will change the content of v
// into {3, 5, 7, 10, 3}
// ^ pointer returned by unique
// This basically means to take all unique elements inside
// vector `v`.
v.erase(unique(v.begin(), v.end()), v.end());
// v = {3, 5, 7, 10}
multiset<int> ms;
ms.insert(1);
ms.insert(1);
ms.insert(-1);
printf("%d\n", (int) ms.count(1)); // Outputs 2
// Erase **ALL** occurences of `1`
ms.erase(1);
printf("%d\n", (int) ms.count(1)); // Outputs 0
/*
* If you only want to delete only an element, you can
* play around with pointers.
*
* Example: ms.erase(ms.find(1));
*
* That will only remove the element pointed out by the
* pointer returned by `ms.find(1)`.
*/
```
### C++ thingz
#### Dijkstra
```c++
// Getting the matrix size
int m = M.size(), n = m ? board[0].size() : 0;
// Defining the 4 directions
static constexpr int DIRS[][2] {{0,1},{1,0},{0,-1},{-1,0}};
for(const auto& d : DIRS) {}
// PriorityQueue parts
priority_queue<tuple<int,int,int>> pq;
pq.emplace(A[0][0], 0, 0);
pq.top()
pq.pop()
pq.empty()
// Lazy to think of the type
auto [a,b,c] = pq.top()
auto i = 0
// Queue
queue<pair<int, int>> q;
q.push({ 0, 0 });
auto c = q.front();
q.pop();
```
### GCD, MIN, MAX
```c++
int min = *min_element(begin(nums), end(nums));
int max = *max_element(begin(nums), end(nums));
// begin() function is used to return an iterator pointing to the first element of the vector container
// end() function is used to return an iterator pointing to next to last element of the vector container
__gcd(a,b) // built-in C++ GCD method
```
### Binary/string/int conversion
```c++
// binary to int
stoi(bin_string, 0, 2) // base 2, default is 10
// int to binary
bitset<n>(num)
// limitations: n is a constant, will be checked during compile time
// it will return binary representation of length n
// alternatively, do manually using mod + bitshift + reverse
// int to string
string x = to_string(num);
int x = stoi(string)
```
### Strings & char
combining string
```c++
string base = "";
for (string word: words) {
base += word
}
```
single quote -> `char`
double quote -> `string`
Iterating string
```c++
for (char c: s){}
// creates copy of s and store it in c, modifying c won't modify s
for (char& c : s) {}
// directly references and stores it in c as an alias. Modifying c does modify s
for (const char& c: s) {}
// if you don't want to accidentally modify s, use const
```
front and back
```c++
string a = "abc";
cout << a.back(); // "c"
cout << a.front(); // "a"
```
char & int, typecast is unnecessary for declaration. But if you want to do arithmetic operation, it has to be typecasted into the same type.
```c++
char a = 97; // 'a'
int b = 'a'; // 97
```
well, sadly there is no `s.split(" ")` or `" ".join(words)` like in python
below is the pre-made split and join, just copy paste it to the coding assessment
```c++
vector<string> split(string s, char delimiter) {
vector<string> strings;
string soFar;
for (char& c : s) {
if (c == delimiter) {
strings.push_back(soFar);
soFar = "";
} else {
soFar += c;
}
}
strings.push_back(soFar);
return strings;
}
string join(vector<string> strings, char delimiter) {
string res = "";
for (int i = 0; i < strings.size()-1; i++) {
res += strings[i];
res += delimiter;
}
res += strings.back();
return res;
}
```
here's a very clean example of problem that involves a lot of string manipulation
useful:
`word.substr()`
`stringstream`
`joining strings routine`
```c++
string sortSentence(string s)
{
stringstream words(s);
string word;
pair<int, string> m;
vector<pair<int, string> > sent;
//SECTION 1
while(words>>word)
{
int len = word.size();
int i = int(word[len-1]) - 48;
sent.push_back(make_pair(i, word.substr(0, len-1)));
}
//SECTION 2
sort(sent.begin(), sent.end());
//SECTION 3
string ans = "";
int len = sent.size();
for(int i=0; i<len; i++)
{
ans += sent[i].second;
if(i!= len-1)
ans += " ";
}
return ans;
}
```
### Trie
https://github.com/stevenhalim/cpbook-code/blob/master/ch6/Trie.cpp
### DP
For fixed matrix sizes, better use fixed array instead of Vector
```c++
int dp[71][70 * 70 + 1] = {[0 ... 70][0 ... 70 * 70] = INT_MAX};
// ... for range initializer to certain value (inclusive range)
// dp[71][70 * 70 + 1] is the array size
```
So what if we do not know the size of the array?
```c++
int* dp = new int[n];
delete[] dp;
dp = NULL // prevent dangling pointer
```
What about dynamic multidimensional array of size mxn?
```c++
int** dp = new int*[m];
for (int i = 0; i < m; i++)
dp[i] = new int[n];
// cleanup
for (int i = 0; i < m; i++)
delete[] dp[i];
delete[] dp;
dp = NULL // prevent dangling pointer
```
infinite values
```
float('inf') -> INT_MAX
```
### Smart Pointers
Why? Because it deallocates itself
```c++
#include <memory>
unique_ptr<int> unPtr = make_unique<int>(25);
unique_ptr<int> unPtr2 = move(unPtr); // unPtr = NULL;
shared_ptr<int> shPtr = make_shared<int>(25);
shared_ptr<int> shPtr2 = shPtr; // shPtr.use_count() = 2
weak_ptr<int> wePtr;
```
### Function Pointers
Why? So that we can pass functions as arguments to other functions e.g., custom comparator
```c++
bool compare(int a, int b) return a < b;
bool(*fnPtr)(int, int) = compare;
fnPtr(5, 7) // invoke normally
```
### Set
```c++
// Initializing from a vector
vector<vector<int>> mat;
vector<set<int>> m;
for (auto &row : mat) {
m.push_back(set<int>(begin(row), end(row)));
}
```
### Iterator
```c++
vector<int> m;
for (auto it = begin(m); it != end(m); it++) {
cout << *it // dereference, iterator is a pointer
}
```
Iterating through vector vs array
```c++
for(const string &text : texts) // vector & array
for(int i = 0; i < n; i++) // vector & array if you know n
for(unsigned int a = 0; a < sizeof(texts)/sizeof(texts[0]); a = a + 1 ) // array
for(unsigned int i = 0; i < texts.size(); i++) // vector
```
### Lambda
```c++
[](){}
// [] -> allows access to variables outside the lambda body
// () -> parameters
// {} -> function body
auto comparator = [](const auto& node1, const auto& node2) {
return node1.val < node2.val;
}
```
### R-Value vs L-Value
```c++
int pow2(int&& x) {
...
}
// && is only used for function parameters
// it means the function can only take r-value
int x = 2 // x is l-value
int z = x + 2 // x + 2 is r-value
pow2(z) // error
pow2(z+2) // valid
```
so the question is, when to use && in a function? when is it useful?
### PriorityQueue
It's max-heap by default, min-heap needs extra parameter
```c++
priority_queue<int> p1; // max-heap
priority_queue <int, vector<int>, greater<int> > p1; // min-heap
```
To make a custom element & comparator
```c++
priority_queue<tuple<int,int,int>> pq; // max-heap
priority_queue<tuple<int,int>, vector<tuple<int,int>>, greater<tuple<int,int>>> pq; // min-heap
pq.emplace(1,2,3);
auto [a,b,c] = pq.top();
```
PriorityQueue can contain any elemnt type, just need to create the custom comparator
```c++
priority_queue<ListNode*, vector<ListNode*>, compare> minheap;
struct compare {
bool operator()(const ListNode* a, const ListNode* b) {
return a->val < b->val;
}
};
```
Tuple is like an unnamed struct, can also be used for typedef
```c++
typedef tuple<int, int, int> Triplet;
priority_queue<Triplet> pq;
priority_queue<Triplet, vector<Triplet>, greater<Triplet>> pq;
```
### map, unordered_map, set, unordered_set
```c++
map<string, int> mp;
mp["qwerty"] = 10;
mp["ponder"] = 11;
for (auto &k : mp) {
// k = pair(key, value);
cout << k.first << " " << k.second << "\n";
// will be output in sorted order of key
}
// initializing multiple things at once
unordered_map<char, int> T = { { 'I' , 1 },
{ 'V' , 5 },
{ 'X' , 10 },
{ 'L' , 50 },
{ 'C' , 100 },
{ 'D' , 500 },
{ 'M' , 1000 } };
set<int> s;
s.insert(1);
s.insert(1);
s.insert(-1);
printf("%d\n", (int) s.count(1)); // Outputs 1
for (auto &k : s) {
printf("%d\n", k); // Will output all elements in the set in order
}
s.erase(1); // Erases 1
```
### Stack
this is work of art lol. Stack in c++ is strictly a stack and doesn't work like a vector, it doesn't have random access using index, only the top element is available.
There is switch case! switch case in c++ is fallthrough and requires a `break`.
```c++
bool isValid(string s) {
stack<char> paren;
for (char& c : s) {
switch (c) {
case '(':
case '{':
case '[': paren.push(c); break;
case ')': if (paren.empty() || paren.top()!='(') return false; else paren.pop(); break;
case '}': if (paren.empty() || paren.top()!='{') return false; else paren.pop(); break;
case ']': if (paren.empty() || paren.top()!='[') return false; else paren.pop(); break;
default: ; // pass
}
}
return paren.empty() ;
}
```
### Iterator & Sorting
Iterator
```c++
vector<int> v = {3, 10, 5, 7, 3};
sort(v.begin(), v.end());
sort(v.begin(), v.end(), greater<int>()); // to sort descendingly
sort(next(v.begin(), 1), prev(v.end(), 1)) // sort subarray -> {3, 5, 7, 10, 3}
```
Sorting vector of vectors
```c++
// sort based on the third element in the vector
sort(logs.begin(), logs.end(),
[](const vector<int>& a, const vector<int>& b) {
return a[2] < b[2];});
// without specification, it will sort the vector lexicographically
```
### LinkedList
for dummy nodes initialization, don't use pointer
```c++
ListNode dummy;
ListNode* node = &dummy;p
...
...
return dummy.next;
```
### Threading
```c++
void print(int n, string name) {cout << n << " " << name << "\n";}
int main() {
vector<thread> threads;
vector<string> names = {"a", "b", "c", "d"};
for (int i = 0; i < names.size(); i++)
threads.push_back(thread(print, i, names[i]));
for (auto& t: threads)
t.join();
```
### Sleep
```cpp
#include <unistd.h>
usleep(n) // n here is in microseconds
```
### Regex
```c++
string str = "the ape was at the apex";
regex reg ("(ape[^ ]?)");
sregex_iterator currentMatch(str.begin(), str.end(), reg);
sregex_iterator lastMatch;
while (currentMatch != lastMatch) {
smatch match = *currentMatch;
cout << match.str() << "\n";
currentMatch++;
}
```
### Unordered_map vs map
`unordered_map` uses hashmap
`map` uses self-balancing BST
which means, `unordered_map` cannot take a `pair<int, int>` as key, whereas map can, because `map` uses < comparison to build the data structure.
`pair<int, int>` does not have a default hash function, we need to define it and pass the function as third parameter
```c++
#include <boost/functional/hash.hpp>
struct hash_pair {
template <class T1, class T2>
size_t operator()(const pair<T1, T2>& p) const
{
size_t seed = 0;
boost::combine(seed, p.first);
boost::combine(seed, p.second);
return seed;
}
}
```
but alternatively, you can just do away with nested `unordered_map<int, unordered_map<int, int>>`
### Long Long
```c++
typedef long long ll;
// working with accumulate need 3rd parameter 0ll
ll top = accumulate(begin(g[0]), end(g[0]), 0ll), bottom = 0;
// INT_MAX for long long
ll res = LLONG_MAX;
```
### Chrono - datetime util
### Random
```c++
int n = rand() % (hi - lo) + lo // [lo, hi)
```
### Writing and Reading files
```c++
#include <fstream>
fstream myFile;
myFile.open("ted.txt", ios::out) // out -> write, app -> append, in -> read
myFile << "hello world";
// for reading
string line;
while (getline(myFile, line)) {}
myFile.close() // dont forget to close!
```
### abs vs labs vs llabs vs fabs
The difference is the input and output types
```c++
int abs(T x); // where T can be int, long long, etc
ll llabs(ll x); //where ll is long long
U fabs(U x); // where U is double / float
```
### Know your <algorithm> !!
```c++
// A is a vector, B is an array
all_of (A.begin(), A.end(), [](int i){return i%2 == 0;})
any_of (...)
find (A.begin(), A.end(), 5)
equal (A.begin(), A.end(), B)
search (A.begin(), A.end(), B, B+2)
count (A.begin(), A.end(), 5)
replace (A.begin(), A.end(), 20, 99) //replace 20 -> 99
shuffle (A.begin(), A.end(), default_random_engine(seed))
sort (A.begin(), A.end(), Comp)
stable_sort (A.begin(), A.end(), Comp)
is_sorted (A.begin(), A.end(), Comp)
```