Modern CPP Tricks often useful in Coding Interviews and Competitive Programming
This is the list of modern CPP tricks often used in Coding Interviews and Competitive Programming.
If you like Rachit's work, you can follow at -
min(x, min(y, ...))
min(x, min(y, ...))
Use initializer list and std::min
and std::max
to make life easy
small = min(x, min(y, min(z, k))); // the old way
small = min({x, y, z, k}); // life is easy
pair<int, int> cur = {1, 2};
auto [x, y] = cur;
// x is now 1, y is now 2
// no need of cur.first and cur.second
array<int, 3> arr = {1, 0, -1};
auto [a, b, c] = arr;
// a is now 1, b is now 0, c is now -1
Straight to the point, I have often used the debug
macro which stringifies the variable names and their values.
#define deb(x) cout << #x << " " << x
int ten = 10;
deb(ten); // prints "ten = 10"
This is often useful in debugging.
However, when you have multiple variables to log, you end up with more deb2
and deb3
macros.
#define deb(x) cout << #x << " " << x
#define deb2(x) cout << #x << " " << x << " " << #y << " " << y
#define deb3(x, y, z) cout << #x << " " << x << " " << #y << " " << y << " " << #z << " " << z
This is not scalable.
Here is the solution using variadic macros and fold expressions,
#define deb(...) logger(#__VA_ARGS__, __VA_ARGS__)
template<typename ...Args>
void logger(string vars, Args&&... values) {
cout << vars << " = ";
string delim = "";
(..., (cout << delim << values, delim = ", "));
}
int xx = 3, yy = 10, xxyy = 103;
deb(xx); // prints "xx = 3"
deb(xx, yy, xxyy); // prints "xx, yy, xxyy = 3, 10, 103"
template <typename... T>
void read(T &...args) {
((cin >> args), ...);
}
template <typename... T>
void write(string delimiter, T &&...args) {
((cout << args << delimiter), ...);
}
template <typename T>
void readContainer(T &t) {
for (auto &e : t) {
read(e);
}
}
template <typename T>
void writeContainer(string delimiter, T &t) {
for (const auto &e : t) {
write(delimiter, e);
}
write("\n");
}
// Question: read three space seprated integers and print them in different lines.
int x, y, z;
read(x, y, z);
write("\n", x, y, z);
// even works with variable data types :)
int n;
string s;
read(n, s);
write(" ", s, "has length", n, "\n");
// Question: read an array of `N` integers and print it to the output console.
int N;
read(N);
vector<int> arr(N);
readContainer(arr);
writeContainer(" ", arr); // output: arr[0] arr[1] arr[2] ... arr[N - 1]
writeContainer("\n", arr);
/**
* output:
* arr[0]
* arr[1]
* arr[2]
* ...
* ...
* ...
* arr[N - 1]
*/
template<typename ...T>
void printer(T&&... args) {
((cout << args << " "), ...);
}
int age = 25;
string name = "Rachit";
printer("I am", name, ',', age, "years old");
// ^ This prints the following
// I am Rachit, 25 years old
template<typename F>
auto debug_func(const F& func) {
return [func](auto &&...args) { // forward reference
cout << "input = ";
printer(args...);
auto res = func(forward<decltype(args)>(args)...);
cout << "res = " << res << endl;
return res;
};
}
debug_func(pow)(2, 3);
// ^ this automatically prints
// input = 2 3 res = 8
Lets define another decorator beautify
as follows.
template<typename F>
auto beautify(const F& func) {
return [func](auto &&...args) { // forward reference
cout << "========" << endl;
func(forward<decltype(args)>(args)...);
cout << "========" << endl;
};
}
beautify(debug_func(pow(2, 3)));
// ^ this now prints
// ========
// input = 2 3 res = 8
// ========
Its amazing how much you can do by writing such generic decorators and nest them.
Think about decorators like log_time
that calculates the time taken for a given function.
s.contains
vs s.find(...) != s.end
set<int> example{1, 2, 3, 4};
example.find(3) != example.end() // true
example.contains(3) // true
Note that this works with map
as well as set
.
multiset.extract
vs multiset.erase(multiset.find(...))
multiset<int> mset{1, 1, 2, 2, 3, 3};
mset.erase(1); // {2, 2, 3, 3} deleted all 1s
mset.erase(mset.find(2)) // {2, 3, 3} need to use erase + find
mset.extract(3) // {2, 3} simple and clean
multiset::extract
helps remove single instance naturally.set
and map
.