diff --git a/.gitbook/assets/49b8844f-cb50-46e0-baec-b338be6722b7 (1).jpeg b/.gitbook/assets/49b8844f-cb50-46e0-baec-b338be6722b7 (1).jpeg new file mode 100644 index 0000000..3449d17 Binary files /dev/null and b/.gitbook/assets/49b8844f-cb50-46e0-baec-b338be6722b7 (1).jpeg differ diff --git a/.gitbook/assets/49b8844f-cb50-46e0-baec-b338be6722b7.jpeg b/.gitbook/assets/49b8844f-cb50-46e0-baec-b338be6722b7.jpeg new file mode 100644 index 0000000..c99a617 Binary files /dev/null and b/.gitbook/assets/49b8844f-cb50-46e0-baec-b338be6722b7.jpeg differ diff --git a/.gitbook/assets/cpp.json b/.gitbook/assets/cpp.json new file mode 100644 index 0000000..e5015ed --- /dev/null +++ b/.gitbook/assets/cpp.json @@ -0,0 +1,2485 @@ +{ + "Header Information": { + "prefix": "header", + "body": [ + "#include ", + "#include ", + "#include ", + "#include ", + "using namespace std;", + "using namespace __gnu_pbds;", + "typedef tree, rb_tree_tag, tree_order_statistics_node_update> pbds;", + "typedef trie, pat_trie_tag, trie_prefix_search_node_update> pref_trie;", + "typedef unsigned long long BITMASK; typedef long long ll; typedef long double ld; typedef pair pii; typedef pair pdd; typedef pair pll;", + "#define has_bit(bit_mask, x) ((bit_mask) & (1ULL << (x)))", + "#define turn_on_bit(bit_mask, x) (bit_mask |= (1ULL << (x)))", + "#define turn_off_bit(bit_mask, x) (bit_mask &= (~(1ULL << (x))))", + "#define smallest_on_bit(bit_mask) (__builtin_ctzint((bit_mask) & (-(bit_mask))))", + "#define CLOCK_START clock_t chrono_clk_beg = clock()", + "#define CLOCK_END clock_t chrono_clk_end = clock(); cerr << (double(chrono_clk_end - chrono_clk_beg) / CLOCKS_PER_SEC) << \" sec\"", + "#define bug(args ...) cerr << __LINE__ << \">> \", err(new istringstream(string(#args)), args), cerr << '\\n'", + "#define decToBin(name, num) string name = bitset<8>(num).to_string();", + "#define binToDec(name, binary) unsigned long name = bitset<8>(binary).to_ulong();", + "#define radToDeg(name, radians) double name = radians * 180 / M_PI;", + "#define all(x) x.begin(), x.end()", + "#define removeDuplicates(vec) sort(vec.begin(), vec.end()); vec.erase(unique(vec.begin(), vec.end()), vec.end())", + "#define printMat(mat) for (auto &x : mat) { for (auto &y : x) { if (y < INF) cout << setw(7) << y; else cout << setw(7) << \"-\"; } cout << '\\n'; }", + "#define fillMat(mat, n, m, x) for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) mat[i][j] = x;", + "#define printArr(arr) for (auto &x : arr) cout << x << \" \"; cout << '\\n';", + "#define arrReplace(arr, from, to) for (auto &x : arr) if (x == from) x = to;", + "#define INF (1LL<<30)", + "#define INF32 (1LL<<62)", + "#define F first", + "#define S second", + "#define M_PI 3.14159265358979323846", + "#define MOD 1000000007", + "#define int ll", + "ll powMod(ll a, ll b) { ll x = 1; while (b > 0) { if (b&1) x = (x*a) % MOD; a = (a*a) % MOD; b >>= 1; } return x; }", + "ll multiply(ll x, ll y) { return ((x % MOD) * (y % MOD)) % MOD; }", + "ll divide(ll x, ll y) { return ((x % MOD) * powMod(y % MOD, MOD-2)) % MOD; }", + "inline int ceil(int a, int b) { return (a+b-1)/b; }", + "void err(istringstream *iss) {} template void err(istringstream *iss, const T &_val, const Args & ... args) { string _name; *iss >> _name; if (_name.back()==',') _name.pop_back(); cerr << _name << \" = \" << _val << \"; \", err(iss, args ...); }", + "int str_replace(string& str, const string& from, const string& to, int limit = -1) { if(from.empty()) return 0; size_t start_pos = 0; int cnt = 0; while((start_pos = str.find(from, start_pos)) != std::string::npos) { str.replace(start_pos, from.length(), to); start_pos += to.length(); cnt++; if (cnt == limit) break; } return cnt; }", + "", + "signed main()", + "{", + " ios_base::sync_with_stdio(false); cin.tie(NULL);", + " int t;", + " cin >> t;", + " while (t--)", + " {", + " }", + " return 0;", + "}" + ], + "description": "Header Information" + }, + "longestPalindromicManacher": { + "prefix": "longestPalindromicManacher", + "body": [ + "string longestPaindromicManacher(string str, int &start, int &end)", + "{", + " int n = str.size();", + " if (n == 0) return \"\";", + " if (n == 1) return str;", + " n = 2*n + 1;", + " int L[n];", + " L[0] = 0, L[1] = 1;", + " int C = 1, R = 2, i = 0, iMirror, maxLPSLength = 0, maxLPSCenterPosition = 0, diff = -1;", + " start = -1, end = -1;", + " for (i = 2; i < n; i++)", + " {", + " iMirror = 2*C-i, L[i] = 0, diff = R - i;", + " if(diff > 0) L[i] = min(L[iMirror], diff);", + " while (((i + L[i]) < n && (i - L[i]) > 0) && (((i + L[i] + 1) % 2 == 0) || ", + " (str[(i + L[i] + 1)/2] == str[(i - L[i] - 1)/2] )))", + " {", + " L[i]++;", + " }", + " if(L[i] > maxLPSLength) maxLPSLength = L[i], maxLPSCenterPosition = i;", + " if (i + L[i] > R) C = i, R = i + L[i];", + " }", + " start = (maxLPSCenterPosition - maxLPSLength)/2;", + " end = start + maxLPSLength - 1;", + " stringstream ss;", + " for (i = start; i <= end; ++i) ss << str[i];", + " return ss.str();", + "}" + ], + "description": "longestPalindromicManacher" + }, + "binarySearchRange": { + "prefix": "binarySearchRange", + "body": [ + "while (l < r)", + "{", + " int mid = (l+r+1)/2;", + " cout << mid << endl;", + " if (res == TARG) break;", + " else if (res < TARG) l = mid;", + " else r = mid-1;", + "}" + ], + "description": "binarySearchRange" + }, + "prefixSum": { + "prefix": "prefixSum", + "body": [ + "vector prefSmArr;", + "int prefSmInit(vector &arr)", + "{", + " prefSmArr.resize(arr.size());", + " prefSmArr[0] = arr[0];", + " for (int i = 1; i < arr.size(); ++i) prefSmArr[i] = arr[i] + prefSmArr[i-1];", + "}", + "ll prefSmQuery(int l, int r) { return (l == 0) ? prefSmArr[r] : prefSmArr[r]-prefSmArr[l-1]; }" + ], + "description": "prefixSum" + }, + "Header3": { + "prefix": "header3", + "body": [ + "#include ", + "#include ", + "#include ", + "#include ", + "using namespace std;", + "using namespace __gnu_pbds;", + "typedef tree, rb_tree_tag, tree_order_statistics_node_update> pbds;", + "typedef trie, pat_trie_tag, trie_prefix_search_node_update> pref_trie;", + "typedef unsigned long long BITMASK; typedef long long ll; typedef long double ld; typedef pair pii; typedef pair pdd; typedef pair pll;", + "#define has_bit(bit_mask, x) ((bit_mask) & (1ULL << (x)))", + "#define turn_on_bit(bit_mask, x) (bit_mask |= (1ULL << (x)))", + "#define turn_off_bit(bit_mask, x) (bit_mask &= (~(1ULL << (x))))", + "#define smallest_on_bit(bit_mask) (__builtin_ctzint((bit_mask) & (-(bit_mask))))", + "#define CLOCK_START clock_t chrono_clk_beg = clock()", + "#define CLOCK_END clock_t chrono_clk_end = clock(); cerr << (double(chrono_clk_end - chrono_clk_beg) / CLOCKS_PER_SEC) << \" sec\"", + "#define bug(args ...) cerr << __LINE__ << \">> \", err(new istringstream(string(#args)), args), cerr << '\\n'", + "#define decToBin(name, num) string name = bitset<8>(num).to_string();", + "#define binToDec(name, binary) unsigned long name = bitset<8>(binary).to_ulong();", + "#define radToDeg(name, radians) double name = radians * 180 / M_PI;", + "#define all(x) x.begin(), x.end()", + "#define removeDuplicates(vec) sort(vec.begin(), vec.end()); vec.erase(unique(vec.begin(), vec.end()), vec.end())", + "#define printMat(mat) for (auto &x : mat) { for (auto &y : x) { if (y < INF) cout << setw(7) << y; else cout << setw(7) << \"-\"; } cout << '\\n'; }", + "#define fillMat(mat, n, m, x) for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) mat[i][j] = x;", + "#define printArr(arr) for (auto &x : arr) cout << x << \" \"; cout << '\\n';", + "#define arrReplace(arr, from, to) for (auto &x : arr) if (x == from) x = to;", + "#define INF (1LL<<30)", + "#define INF32 (1LL<<62)", + "#define F first", + "#define S second", + "#define M_PI 3.14159265358979323846", + "#define MOD 1000000007", + "#define int ll", + "ll powMod(ll a, ll b) { ll x = 1; while (b > 0) { if (b&1) x = (x*a) % MOD; a = (a*a) % MOD; b >>= 1; } return x; }", + "ll multiply(ll x, ll y) { return ((x % MOD) * (y % MOD)) % MOD; }", + "ll divide(ll x, ll y) { return ((x % MOD) * powMod(y % MOD, MOD-2)) % MOD; }", + "inline int ceil(int a, int b) { return (a+b-1)/b; }", + "void err(istringstream *iss) {} template void err(istringstream *iss, const T &_val, const Args & ... args) { string _name; *iss >> _name; if (_name.back()==',') _name.pop_back(); cerr << _name << \" = \" << _val << \"; \", err(iss, args ...); }", + "int str_replace(string& str, const string& from, const string& to, int limit = -1) { if(from.empty()) return 0; size_t start_pos = 0; int cnt = 0; while((start_pos = str.find(from, start_pos)) != std::string::npos) { str.replace(start_pos, from.length(), to); start_pos += to.length(); cnt++; if (cnt == limit) break; } return cnt; }", + "", + "signed main()", + "{", + " ios_base::sync_with_stdio(false); cin.tie(NULL);", + " int t;", + " cin >> t;", + " int tc = 1;", + " while (t--)", + " {", + " // cout << \"Case #\" << (tc++) << \": \" << ", + " }", + " return 0;", + "}" + ], + "description": "Header Information" + }, + "BIT": { + "prefix": "BIT", + "body": [ + "const int N = 1000;", + "int BIT[N+5];", + "void update(int i, int val)", + "{", + " while (i <= N)", + " {", + " BIT[i] += val;", + " i += (i & -i);", + " }", + "}", + "int query(int i)", + "{", + " int sm = 0;", + " while (i)", + " {", + " sm += BIT[i];", + " i -= (i & -i);", + " }", + " return sm;", + "}", + "int query(int l, int r) { return query(r) - query(l-1); }", + "int findWithGivenCumFreq(int curFreq)", + "{", + " int i = 0;", + " int bitMask = (int)(pow(2, (int)(log2(N))));", + " while (bitMask)", + " {", + " int temp = i + bitMask;", + " bitMask >>= 1;", + " if (temp > N) continue;", + " if (curFreq == BIT[temp]) return temp;", + " else if (curFreq > BIT[temp]) i = temp, curFreq -= BIT[temp];", + " }", + " if (curFreq != 0) return -1;", + " else return i;", + "}" + ], + "description": "BIT" + }, + "2DBIT": { + "prefix": "2DBIT", + "body": [ + "const int X = 1000, Y = 1000;", + "int BIT[X+5][Y+5];", + "void update(int x, int y, int val)", + "{", + " while (x <= X)", + " {", + " int _y = y;", + " while (_y <= Y) BIT[x][_y] += val, _y += (_y & -_y);", + " x += (x & -x);", + " }", + "}", + "int query(int x, int y)", + "{", + " int sm = 0;", + " while (x)", + " {", + " int _y = y;", + " while (_y) sm += BIT[x][_y], _y -= (_y & -_y);", + " x -= (x & -x);", + " }", + " return sm;", + "}" + ], + "description": "2DBIT" + }, + "BigInt": { + "prefix": "bigInt", + "body": [ + "const int base = 1000000000, base_digits = 9;", + "struct BigInt", + "{", + " vector a;", + " int sign;", + "", + " BigInt() : sign(1) { }", + " BigInt(ll v) { *this = v; }", + " BigInt(const string &s) { read(s); }", + " void operator=(const BigInt &v) { sign = v.sign; a = v.a; }", + " BigInt operator*(int v) const { BigInt res = *this; res *= v; return res; }", + " BigInt operator/(const BigInt &v) const { return divmod(*this, v).first; }", + " BigInt operator%(const BigInt &v) const { return divmod(*this, v).second; }", + " BigInt operator/(int v) const { BigInt res = *this; res /= v; return res; }", + " void operator+=(const BigInt &v) { *this = *this + v; }", + " void operator-=(const BigInt &v) { *this = *this - v; }", + " void operator*=(const BigInt &v) { *this = *this * v; }", + " void operator/=(const BigInt &v) { *this = *this / v; }", + " bool operator>(const BigInt &v) const { return v < *this; }", + " bool operator<=(const BigInt &v) const { return !(v < *this); }", + " bool operator>=(const BigInt &v) const { return !(*this < v); }", + " bool operator==(const BigInt &v) const { return !(*this < v) && !(v < *this); }", + " bool operator!=(const BigInt &v) const { return *this < v || v < *this; }", + " bool isZero() const { return a.empty() || (a.size() == 1 && !a[0]); }", + " void trim()", + " {", + " while (!a.empty() && !a.back()) a.pop_back();", + " if (a.empty()) sign = 1;", + " }", + " BigInt operator-() const", + " {", + " BigInt res = *this;", + " res.sign = -sign;", + " return res;", + " }", + " BigInt abs() const", + " {", + " BigInt res = *this;", + " res.sign *= res.sign;", + " return res;", + " }", + " void operator=(ll v)", + " {", + " sign = 1;", + " if (v < 0) sign = -1, v = -v;", + " for (; v > 0; v = v / base) a.push_back(v % base);", + " }", + " int operator%(int v) const", + " {", + " if (v < 0) v = -v;", + " int m = 0;", + " for (int i = a.size() - 1; i >= 0; --i) m = (a[i] + m * (ll)base) % v;", + " return m * sign;", + " }", + " BigInt operator+(const BigInt &v) const", + " {", + " if (sign == v.sign)", + " {", + " BigInt res = v;", + " for (int i = 0, carry = 0; i < (int)max(a.size(), v.a.size()) || carry; ++i)", + " {", + " if (i == (int)res.a.size()) res.a.push_back(0);", + " res.a[i] += carry + (i < (int)a.size() ? a[i] : 0);", + " carry = res.a[i] >= base;", + " if (carry) res.a[i] -= base;", + " }", + " return res;", + " }", + " return *this - (-v);", + " }", + "", + " BigInt operator-(const BigInt &v) const", + " {", + " if (sign == v.sign)", + " {", + " if (abs() >= v.abs())", + " {", + " BigInt res = *this;", + " for (int i = 0, carry = 0; i < (int)v.a.size() || carry; ++i)", + " {", + " res.a[i] -= carry + (i < (int)v.a.size() ? v.a[i] : 0);", + " carry = res.a[i] < 0;", + " if (carry) res.a[i] += base;", + " }", + " res.trim();", + " return res;", + " }", + " return -(v - *this);", + " }", + " return *this + (-v);", + " }", + "", + " void operator*=(int v)", + " {", + " if (v < 0) sign = -sign, v = -v;", + " for (int i = 0, carry = 0; i < (int)a.size() || carry; ++i)", + " {", + " if (i == (int)a.size()) a.push_back(0);", + " ll cur = a[i] * (ll)v + carry;", + " carry = (int)(cur / base);", + " a[i] = (int)(cur % base);", + " //asm(\"divl %%ecx\" : \"=a\"(carry), \"=d\"(a[i]) : \"A\"(cur), \"c\"(base));", + " }", + " trim();", + " }", + "", + " friend pair divmod(const BigInt &a1, const BigInt &b1)", + " {", + " int norm = base / (b1.a.back() + 1);", + " BigInt a = a1.abs() * norm, b = b1.abs() * norm, q, r;", + " q.a.resize(a.a.size());", + " for (int i = a.a.size() - 1; i >= 0; i--)", + " {", + " r *= base, r += a.a[i];", + " int s1 = r.a.size() <= b.a.size() ? 0 : r.a[b.a.size()];", + " int s2 = r.a.size() <= b.a.size() - 1 ? 0 : r.a[b.a.size() - 1];", + " int d = ((ll)base * s1 + s2) / b.a.back();", + " r -= b * d;", + " while (r < 0) r += b, --d;", + " q.a[i] = d;", + " }", + " q.sign = a1.sign * b1.sign, r.sign = a1.sign;", + " q.trim(); r.trim();", + " return make_pair(q, r / norm);", + " }", + " void operator/=(int v)", + " {", + " if (v < 0) sign = -sign, v = -v;", + " for (int i = (int)a.size() - 1, rem = 0; i >= 0; --i)", + " {", + " ll cur = a[i] + rem * (ll)base;", + " a[i] = (int)(cur / v);", + " rem = (int)(cur % v);", + " }", + " trim();", + " }", + " bool operator<(const BigInt &v) const", + " {", + " if (sign != v.sign) return sign < v.sign;", + " if (a.size() != v.a.size()) return a.size() * sign < v.a.size() * v.sign;", + " for (int i = a.size() - 1; i >= 0; i--)", + " if (a[i] != v.a[i]) return a[i] * sign < v.a[i] * sign;", + " return false;", + " }", + " void read(const string &s)", + " {", + " sign = 1;", + " a.clear();", + " int pos = 0;", + " while (pos < (int)s.size() && (s[pos] == '-' || s[pos] == '+'))", + " {", + " if (s[pos++] == '-') sign = -sign;", + " }", + " for (int i = s.size() - 1; i >= pos; i -= base_digits)", + " {", + " int x = 0;", + " for (int j = max(pos, i - base_digits + 1); j <= i; j++) x = x * 10 + s[j] - '0';", + " a.push_back(x);", + " }", + " trim();", + " }", + " friend istream &operator>>(istream &stream, BigInt &v)", + " {", + " string s;", + " stream >> s;", + " v.read(s);", + " return stream;", + " }", + " string toString()", + " {", + " stringstream stream;", + " if (sign == -1) stream << '-';", + " stream << (a.empty() ? 0 : a.back());", + " for (int i = (int)a.size() - 2; i >= 0; --i) stream << setw(base_digits) << setfill('0') << a[i];", + " return stream.str();", + " }", + " friend ostream &operator<<(ostream &stream, const BigInt &v)", + " {", + " if (v.sign == -1) stream << '-';", + " stream << (v.a.empty() ? 0 : v.a.back());", + " for (int i = (int)v.a.size() - 2; i >= 0; --i) stream << setw(base_digits) << setfill('0') << v.a[i];", + " return stream;", + " }", + " static vector convert_base(const vector &a, int old_digits, int new_digits)", + " {", + " vector p(max(old_digits, new_digits) + 1);", + " p[0] = 1;", + " for (int i = 1; i < (int)p.size(); i++) p[i] = p[i - 1] * 10;", + " vector res;", + " ll cur = 0;", + " int cur_digits = 0;", + " for (int i = 0; i < (int)a.size(); i++)", + " {", + " cur += a[i] * p[cur_digits];", + " cur_digits += old_digits;", + " while (cur_digits >= new_digits)", + " {", + " res.push_back(int(cur % p[new_digits]));", + " cur /= p[new_digits];", + " cur_digits -= new_digits;", + " }", + " }", + " res.push_back((int)cur);", + " while (!res.empty() && !res.back()) res.pop_back();", + " return res;", + " }", + " static vector karatsubaMultiply(const vector &a, const vector &b)", + " {", + " int n = a.size();", + " vector res(n + n);", + " if (n <= 32)", + " {", + " for (int i = 0; i < n; i++)", + " for (int j = 0; j < n; j++) res[i + j] += a[i] * b[j];", + " return res;", + " }", + " int k = n >> 1;", + " vector a1(a.begin(), a.begin() + k);", + " vector a2(a.begin() + k, a.end());", + " vector b1(b.begin(), b.begin() + k);", + " vector b2(b.begin() + k, b.end());", + " vector a1b1 = karatsubaMultiply(a1, b1);", + " vector a2b2 = karatsubaMultiply(a2, b2);", + " for (int i = 0; i < k; i++) a2[i] += a1[i];", + " for (int i = 0; i < k; i++) b2[i] += b1[i];", + " vector r = karatsubaMultiply(a2, b2);", + " for (int i = 0; i < (int)a1b1.size(); i++) r[i] -= a1b1[i];", + " for (int i = 0; i < (int)a2b2.size(); i++) r[i] -= a2b2[i];", + " for (int i = 0; i < (int)r.size(); i++) res[i + k] += r[i];", + " for (int i = 0; i < (int)a1b1.size(); i++) res[i] += a1b1[i];", + " for (int i = 0; i < (int)a2b2.size(); i++) res[i + n] += a2b2[i];", + " return res;", + " }", + " BigInt operator*(const BigInt &v) const", + " {", + " vector a6 = convert_base(this->a, base_digits, 6);", + " vector b6 = convert_base(v.a, base_digits, 6);", + " vector a(a6.begin(), a6.end());", + " vector b(b6.begin(), b6.end());", + " while (a.size() < b.size()) a.push_back(0);", + " while (b.size() < a.size()) b.push_back(0);", + " while (a.size() & (a.size() - 1)) a.push_back(0), b.push_back(0);", + " vector c = karatsubaMultiply(a, b);", + " BigInt res;", + " res.sign = sign * v.sign;", + " for (int i = 0, carry = 0; i < (int)c.size(); i++)", + " {", + " ll cur = c[i] + carry;", + " res.a.push_back((int)(cur % 1000000));", + " carry = (int)(cur / 1000000);", + " }", + " res.a = convert_base(res.a, 6, base_digits);", + " res.trim();", + " return res;", + " }", + "};", + "BigInt __gcd(BigInt a, BigInt b) { return b == 0 ? a : __gcd(b, a - (a / b) * b); }" + ], + "description": "BigInt" + }, + "segmentTree": { + "prefix": "segmentTree", + "body": [ + "const int N = 1e6;", + "int n, segmentTree[2*N];", + "void build()", + "{", + " for (int i = n-1; i > 0; --i)", + " segmentTree[i] = segmentTree[i<<1] + segmentTree[i<<1|1];", + "}", + "void modify(int p, int value)", + "{", + " for (segmentTree[p += n] = value; p > 1; p >>= 1)", + " segmentTree[p>>1] = segmentTree[p] + segmentTree[p^1];", + "}", + "int query(int l, int r)", + "{", + " int res = 0;", + " for (l += n, r += n; l < r; l >>= 1, r >>= 1)", + " {", + " if (l&1) res += segmentTree[l++];", + " if (r&1) res += segmentTree[--r];", + " }", + " return res;", + "}" + ], + "description": "segmentTree" + }, + "header2": { + "prefix": "header2", + "body": [ + "#include ", + "#include ", + "#include ", + "#include ", + "using namespace std;", + "using namespace __gnu_pbds;", + "typedef tree, rb_tree_tag, tree_order_statistics_node_update> pbds;", + "typedef trie, pat_trie_tag, trie_prefix_search_node_update> pref_trie;", + "typedef unsigned long long BITMASK; typedef long long ll; typedef long double ld; typedef pair pii; typedef pair pdd; typedef pair pll;", + "#define has_bit(bit_mask, x) ((bit_mask) & (1ULL << (x)))", + "#define turn_on_bit(bit_mask, x) (bit_mask |= (1ULL << (x)))", + "#define turn_off_bit(bit_mask, x) (bit_mask &= (~(1ULL << (x))))", + "#define smallest_on_bit(bit_mask) (__builtin_ctzint((bit_mask) & (-(bit_mask))))", + "#define CLOCK_START clock_t chrono_clk_beg = clock()", + "#define CLOCK_END clock_t chrono_clk_end = clock(); cerr << (double(chrono_clk_end - chrono_clk_beg) / CLOCKS_PER_SEC) << \" sec\"", + "#define bug(args ...) cerr << __LINE__ << \">> \", err(new istringstream(string(#args)), args), cerr << '\\n'", + "#define decToBin(name, num) string name = bitset<8>(num).to_string();", + "#define binToDec(name, binary) unsigned long name = bitset<8>(binary).to_ulong();", + "#define radToDeg(name, radians) double name = radians * 180 / M_PI;", + "#define all(x) x.begin(), x.end()", + "#define removeDuplicates(vec) sort(vec.begin(), vec.end()); vec.erase(unique(vec.begin(), vec.end()), vec.end())", + "#define printMat(mat) for (auto &x : mat) { for (auto &y : x) { if (y < INF) cout << setw(7) << y; else cout << setw(7) << \"-\"; } cout << '\\n'; }", + "#define fillMat(mat, n, m, x) for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) mat[i][j] = x;", + "#define printArr(arr) for (auto &x : arr) cout << x << \" \"; cout << '\\n';", + "#define arrReplace(arr, from, to) for (auto &x : arr) if (x == from) x = to;", + "#define INF (1LL<<30)", + "#define INF32 (1LL<<62)", + "#define F first", + "#define S second", + "#define M_PI 3.14159265358979323846", + "#define MOD 1000000007", + "#define int ll", + "ll powMod(ll a, ll b) { ll x = 1; while (b > 0) { if (b&1) x = (x*a) % MOD; a = (a*a) % MOD; b >>= 1; } return x; }", + "ll multiply(ll x, ll y) { return ((x % MOD) * (y % MOD)) % MOD; }", + "ll divide(ll x, ll y) { return ((x % MOD) * powMod(y % MOD, MOD-2)) % MOD; }", + "inline int ceil(int a, int b) { return (a+b-1)/b; }", + "void err(istringstream *iss) {} template void err(istringstream *iss, const T &_val, const Args & ... args) { string _name; *iss >> _name; if (_name.back()==',') _name.pop_back(); cerr << _name << \" = \" << _val << \"; \", err(iss, args ...); }", + "int str_replace(string& str, const string& from, const string& to, int limit = -1) { if(from.empty()) return 0; size_t start_pos = 0; int cnt = 0; while((start_pos = str.find(from, start_pos)) != std::string::npos) { str.replace(start_pos, from.length(), to); start_pos += to.length(); cnt++; if (cnt == limit) break; } return cnt; }", + "", + "signed main()", + "{", + " ios_base::sync_with_stdio(false); cin.tie(NULL);", + " return 0;", + "}" + ], + "description": "header2" + }, + "countInInterval": { + "prefix": "countInInterval", + "body": [ + "int countInInterval(int x1, int y1, int x2, int y2)", + "{", + " int sz = max({x1, x2, y1, y2}) - min({x1, x2, y1, y2}) + 1;", + " int sz_a = y1-x1+1, sz_b = y2-x2+1;", + " if (sz_a + sz_b - 1 == sz) return 1;", + " else if (sz_a + sz_b -1 < sz) return 0;", + " else return (sz_a + sz_b - sz);", + "}" + ], + "description": "countInInterval" + }, + "topologicalSort": { + "prefix": "topologicalSort", + "body": [ + "vector topologicalSort(int n, vector adj[])", + "{", + " vector inDeg(n, 0);", + " for (int i = 0; i < n; ++i)", + " for (auto &x : adj[i]) ++inDeg[x];", + " queue q;", + " for (int i = 0; i < n; ++i)", + " if (inDeg[i] == 0) q.push(i);", + " vector topOrder;", + " while (!q.empty())", + " {", + " auto cur = q.front();", + " q.pop();", + " topOrder.push_back(cur);", + " for (auto &x : adj[cur])", + " {", + " --inDeg[x];", + " if (inDeg[x] == 0) q.push(x);", + " }", + " }", + " return topOrder;", + "}" + ], + "description": "topologicalSort" + }, + "eulertotient": { + "prefix": "eulertotient", + "body": [ + "int totient(int x)", + "{", + " int ret = x;", + " for (int i = 2; i*i <= x; ++i)", + " {", + " if (x%i == 0)", + " {", + " ret = ret / i*(i-1);", + " while (x % i == 0) x /= i;", + " }", + " }", + " if (x > 1) ret = ret / x*(x-1);", + " return ret;", + "}" + ], + "description": "eulertotient" + }, + "Array Input": { + "prefix": "arrayInp", + "body": [ + "int n;", + "cin >> n;", + "vector arr(n);", + "for (int i = 0; i < n; ++i) cin >> arr[i];" + ], + "description": "Array Input" + }, + "Difference Array": { + "prefix": "differenceArray", + "body": [ + "class DifferenceArray", + "{", + "public:", + " vector arr;", + " DifferenceArray(int n) { arr.resize(n); }", + " void update(int l, int r, int val)", + " {", + " if (l >= arr.size() || l < 0 || r < l) return;", + " arr[l] += val;", + " if (r+1 < arr.size()) arr[r+1] -= val;", + " }", + " vector query()", + " {", + " vector res(arr.size());", + " for (int i = 0; i < arr.size(); ++i)", + " res[i] = (i == 0) ? arr[i] : arr[i] + res[i-1];", + " return res;", + " }", + "};" + ], + "description": "Difference Array" + }, + "Array Input Max Min": { + "prefix": "arrayInpMAXMIN", + "body": [ + "int n;", + "cin >> n;", + "vector arr(n);", + "int mn = LONG_MAX, mx = LONG_MIN;", + "for (int i = 0; i < n; ++i) { cin >> arr[i]; mn = min(mn, arr[i]); mx = max(mx, arr[i]); }" + ], + "description": "Array Input Max Min" + }, + "Divisor": { + "prefix": "divisor", + "body": [ + "vector findDivisors(ll n)", + "{", + " vector res;", + " for (ll i = 1; i <= sqrt(n); ++i)", + " {", + " if (n%i == 0)", + " {", + " res.push_back(i);", + " if (n/i != i) res.push_back(n/i);", + " }", + " }", + " return res;", + "}" + ], + "description": "Divisor" + }, + "prime factors": { + "prefix": "primefactors", + "body": [ + "vector primeFactors(ll n)", + "{", + " vector res;", + " while (n%2 == 0) { res.push_back(2); n /= 2; }", + " for (int i = 3; i <= sqrt(n); i += 2)", + " while (n % i == 0) { res.push_back(i); n /= i; }", + " if (n > 2) res.push_back(n);", + " return res;", + "}" + ], + "description": "prime factors" + }, + "sieve": { + "prefix": "sieve", + "body": [ + "ll sieve[2000005];", + "set primes;", + "void makeSieve()", + "{", + " fill(sieve, sieve + 2000005, 1);", + " sieve[0] = 0;", + " sieve[1] = 0;", + " for (int i = 2; i < 2000005; ++i)", + " {", + " if (sieve[i] == 1)", + " {", + " for (int j = i*2; j < 2000005; j+=i)", + " sieve[j] = 0;", + " }", + " }", + " for (int i = 0; i < 2000005; ++i)", + " if (sieve[i]) primes.insert(i);", + "}" + ], + "description": "sieve" + }, + "LIS": { + "prefix": "lis", + "body": [ + "int LIS(vector& nums)", + "{", + " set st;", + " for (int i = 0; i < nums.size(); ++i)", + " {", + " if (st.lower_bound(nums[i]) != st.end())", + " st.erase(st.lower_bound(nums[i]));", + " st.insert(nums[i]);", + " }", + " return st.size();", + "}" + ], + "description": "LIS" + }, + "modularArithematic": { + "prefix": "modularArithematic", + "body": [ + "class ModularArithematic", + "{", + "private:", + " static pair chineaseRemainderTheorem(ll x, ll a, ll y, ll b)", + " {", + " ll s, t, d = extendedEuclid(x, y, s, t);", + " if (a%d != b%d) return make_pair(0, -1);", + " return make_pair(((s*b*x + t*a*y + x*y)%(x*y))/d, x*y/d);", + " }", + " ", + "public:", + " static ll __lcm (ll a, ll b) { return (a/__gcd(a,b)*b); }", + " static ll powerMod(ll a, ll b)", + " {", + " ll x = 1;", + " while (b > 0)", + " {", + " #ifdef MOD", + " if (b&1) x = (x*a) % MOD;", + " a = (a*a) % MOD;", + " #else", + " if (b&1) x *= a;", + " a *= a;", + " #endif", + " b >>= 1;", + " }", + " return x;", + " }", + " static ll multiplyMod(ll a, ll b)", + " {", + " #ifdef MOD", + " ll res = 0;", + " while(b)", + " {", + " if (b&1)", + " {", + " res += a;", + " if (res >= MOD) res -= MOD;", + " }", + " b >>= 1;", + " a = (a << 1);", + " if (a >= MOD) a-= MOD;", + " }", + " return res;", + " #else", + " return a*b;", + " #endif", + " }", + " static ll inverseMod(ll a, ll m)", + " {", + " a = a % m;", + " for (ll x = 1; x < m; x++)", + " {", + " if ((a * x) % m == 1)", + " return x;", + " }", + " return -1;", + " }", + " static ll nCr(ll n, ll r)", + " {", + " if (n < r) return 0;", + " ll res = 1, rem = 1;", + " for (ll i = n - r + 1; i <= n; i++) res = multiplyMod(res, i);", + " for (ll i = 2; i <= r; i++) rem = multiplyMod(rem, i);", + " return multiplyMod(res, powerMod(rem, MOD - 2));", + " }", + " // returns d = gcd(a,b); finds x,y such that d = ax + by", + " static ll extendedEuclid(ll a, ll b, ll &x, ll &y)", + " {", + " ll xx = y = 0;", + " ll yy = x = 1;", + " while (b)", + " {", + " ll q = a/b;", + " ll t = b; b = a%b; a = t;", + " t = xx; xx = x-q*xx; x = t;", + " t = yy; yy = y-q*yy; y = t;", + " }", + " return a;", + " }", + " // finds all solutions to ax = b (mod n)", + " static vector modularLinearEquationSolver(ll a, ll b, ll n)", + " {", + " ll x, y;", + " vector solutions;", + " ll d = extendedEuclid(a, n, x, y);", + " if (b%d == 0)", + " {", + " x = ((x * (b/d) + n) % n);", + " for (ll i = 0; i < d; ++i)", + " solutions.push_back((x + i*(n/d) + n) % n);", + " }", + " return solutions;", + " }", + " // computes x and y such that ax + by = c; on failure, x = y =-1", + " static void linearDiophantine(ll a, ll b, ll c, ll &x, ll &y)", + " {", + " ll d = __gcd(a, b);", + " if (c%d) x = y = -1;", + " else", + " {", + " x = c/d * inverseMod(a/d, b/d);", + " y = (c-a*x)/b;", + " }", + " }", + " // finds z such that z % x[i] = a[i] for all i. returns (z, M) on failure M = -1", + " // Note: we require a[i]'s to be relatively prime", + " static pair chineaseRemainderTheorem(const vector &x, const vector &a)", + " {", + " pair ret = make_pair(x[0], a[0]);", + " for (int i = 1; i < x.size(); ++i)", + " {", + " ret = chineaseRemainderTheorem(ret.first, ret.second, x[i], a[i]);", + " if (ret.second == -1) break;", + " }", + " return ret;", + " }", + " ", + " static void nCrPreprocess(int size, vector &fact, vector &inv)", + " {", + " fact.resize(size + 5);", + " inv.resize(size + 5);", + " fact[0] = inv[0] = 1;", + " for(int i = 1; i < size; ++i)", + " {", + " fact[i] = multiplyMod(fact[i-1], i);", + " inv[i] = powerMod(fact[i], MOD-2);", + " }", + " }", + " ", + " static int nCrQuery(int n, int r, vector &fact, vector &inv)", + " {", + " if (n < r) return 0;", + " int res = 1; res = multiplyMod(res, fact[n]);", + " res = multiplyMod(res, inv[r]);", + " res = multiplyMod(res, inv[n-r]);", + " return res;", + " }", + "};" + ], + "description": "dayOfWeek" + }, + "Matrix Helper": { + "prefix": "matrix", + "body": [ + "template ", + "class Matrix", + "{", + "public:", + " vector< vector > mat;", + " int rows, columns;", + " Matrix() : rows(0), columns(0) {}", + " Matrix(int _r, int _c) : rows(_r), columns(_c) { mat.assign(rows, vector(columns)); }", + " Matrix(int _r, int _c, const T &val) : rows(_r), columns(_c) { mat.assign(rows, vector(columns, val)); }", + " Matrix(int _n) : rows(_n), columns(_n)", + " {", + " mat.assign(_n, vector(_n));", + " for (int i = 0; i < _n; ++i) mat[i][i] = (T)1;", + " }", + " void display(int space = 5)", + " {", + " for (auto &x : mat)", + " {", + " for (auto &y : x) cout << setw(space) << y;", + " cout << '\\n';", + " }", + " }", + " Matrix operator *(const Matrix &B)", + " {", + " assert(columns == B.rows);", + " Matrix C(rows, B.columns, 0);", + " for (int i = 0; i < rows; ++i)", + " {", + " for (int j = 0; j < B.columns; ++j)", + " {", + " for (int k = 0; k < columns; ++k)", + " {", + " #ifdef MOD", + " C.mat[i][j] = (C.mat[i][j] + ((mat[i][k] * B.mat[k][j]) % MOD)) % MOD;", + " #else", + " C.mat[i][j] += mat[i][k] * B.mat[k][j];", + " #endif", + " }", + " }", + " }", + " return C;", + " }", + " Matrix operator *(ll x)", + " {", + " Matrix C(rows, columns);", + " for (int i = 0; i < rows; ++i)", + " {", + " for (int j = 0; j < rows; ++j)", + " {", + " #ifdef MOD", + " C.mat[i][j] = (mat[i][j] * x) % MOD;", + " #else", + " C.mat[i][j] = mat[i][j] * x;", + " #endif", + " }", + " }", + " return C;", + " }", + " Matrix operator +(const Matrix &B)", + " {", + " assert(rows == B.rows); assert(columns == B.columns);", + " Matrix C(rows, columns, 0);", + " for (int i = 0; i < rows; ++i)", + " {", + " for (int j = 0; j < columns; ++j)", + " {", + " #ifdef MOD", + " C.mat[i][j] = (mat[i][j] + B.mat[i][j]) % MOD;", + " #else", + " C.mat[i][j] = mat[i][j] + B.mat[i][j];", + " #endif", + " }", + " }", + " return C;", + " }", + " Matrix operator -(const Matrix &B)", + " {", + " assert(rows == B.rows); assert(columns == B.columns);", + " Matrix C(rows, columns, 0);", + " for (int i = 0; i < rows; ++i)", + " {", + " for (int j = 0; j < columns; ++j)", + " {", + " #ifdef MOD", + " C.mat[i][j] = (mat[i][j] - B.mat[i][j] + MOD) % MOD;", + " #else", + " C.mat[i][j] = mat[i][j] - B.mat[i][j];", + " #endif", + " }", + " }", + " return C;", + " }", + " Matrix operator^(ll n)", + " {", + " assert(rows == columns);", + " Matrix C(rows), X(rows, columns, 0);", + " for (int i = 0; i < rows; ++i)", + " for (int j = 0; j < columns; ++j)", + " X.mat[i][j] = mat[i][j];", + " while (n)", + " {", + " if (n&1) C *= X;", + " X *= X;", + " n /= 2;", + " }", + " return C;", + " }", + " Matrix transpose()", + " {", + " Matrix res(columns, rows);", + " for (int i = 0; i < columns; ++i)", + " for (int j = 0; j < rows; ++j)", + " res[i][j] = mat[j][i];", + " return res;", + " }", + " void operator *=(const Matrix &B) { auto res = operator*(B); rows = res.rows, columns = res.columns, mat = res.mat; }", + " void operator *=(ll x) { auto res = operator*(x); rows = res.rows, columns = res.columns, mat = res.mat; }", + " void operator +=(const Matrix &B) { auto res = operator+(B); rows = res.rows, columns = res.columns, mat = res.mat; }", + " void operator -=(const Matrix &B) { auto res = operator-(B); rows = res.rows, columns = res.columns, mat = res.mat; }", + " void operator ^=(ll x) { auto res = operator^(x); rows = res.rows, columns = res.columns, mat = res.mat; }", + " void transposeInplace() { auto res = transpose(); rows = res.rows, columns = res.columns, mat = res.mat; }", + "};" + ], + "description": "Matrix Helper" + }, + "Kaden": { + "prefix": "kaden", + "body": [ + "struct kaden_ans { int l, r, val; };", + "kaden_ans kaden(vector &arr, int l, int r, bool canBeEmpty = true, bool product = false)", + "{", + " vector kaden(r-l+1);", + " kaden[0] = arr[l];", + " int res = kaden[0], maxV = kaden[0], minV = kaden[0], _r = 0, _l = 0;", + " for (int i = 1; i < kaden.size(); ++i)", + " {", + " if (product)", + " {", + " int prev = maxV;", + " maxV = max({minV * arr[l+i], prev * arr[l+i], arr[l+i]});", + " minV = min({minV * arr[l+i], prev * arr[l+i], arr[l+i]});", + " if (maxV > res) res = maxV, _r = l+i;", + " }", + " else", + " {", + " kaden[i] = max(arr[l+i], arr[l+i] + kaden[i-1]);", + " if (kaden[i] > res) res = kaden[i], _r = l+i;", + " }", + " }", + " if (canBeEmpty && res < 0) return {-1, -1, 0};", + " int cur = 0;", + " for (int i = _r; i >= 0; --i)", + " {", + " if (product) cur *= arr[i];", + " else cur += arr[i];", + " if (cur == res) _l = i;", + " }", + " return {_l, _r, res};", + "}" + ], + "description": "Kaden" + }, + "NTT": { + "prefix": "ntt", + "body": [ + "#pragma region NTT", + "template ", + "class Modular", + "{", + "public:", + " using Type = typename decay::type;", + "", + " constexpr Modular() : value() {}", + " template ", + " Modular(const U &x)", + " {", + " value = normalize(x);", + " }", + "", + " template ", + " static Type normalize(const U &x)", + " {", + " Type v;", + " if (-mod() <= x && x < mod())", + " v = static_cast(x);", + " else", + " v = static_cast(x % mod());", + " if (v < 0)", + " v += mod();", + " return v;", + " }", + "", + " const Type &operator()() const { return value; }", + " template ", + " explicit operator U() const { return static_cast(value); }", + " constexpr static Type mod() { return T::value; }", + "", + " Modular &operator+=(const Modular &other)", + " {", + " if ((value += other.value) >= mod())", + " value -= mod();", + " return *this;", + " }", + " Modular &operator-=(const Modular &other)", + " {", + " if ((value -= other.value) < 0)", + " value += mod();", + " return *this;", + " }", + " template ", + " Modular &operator+=(const U &other) { return *this += Modular(other); }", + " template ", + " Modular &operator-=(const U &other) { return *this -= Modular(other); }", + " Modular &operator++() { return *this += 1; }", + " Modular &operator--() { return *this -= 1; }", + " Modular operator++(int)", + " {", + " Modular result(*this);", + " *this += 1;", + " return result;", + " }", + " Modular operator--(int)", + " {", + " Modular result(*this);", + " *this -= 1;", + " return result;", + " }", + " Modular operator-() const { return Modular(-value); }", + "", + " template ", + " typename enable_if::Type, int>::value, Modular>::type &operator*=(const Modular &rhs)", + " {", + "#ifdef _WIN32", + " uint64_t x = static_cast(value) * static_cast(rhs.value);", + " uint32_t xh = static_cast(x >> 32), xl = static_cast(x), d, m;", + " asm(", + " \"divl %4; \\n\\t\"", + " : \"=a\"(d), \"=d\"(m)", + " : \"d\"(xh), \"a\"(xl), \"r\"(mod()));", + " value = m;", + "#else", + " value = normalize(static_cast(value) * static_cast(rhs.value));", + "#endif", + " return *this;", + " }", + " template ", + " typename enable_if::Type, int64_t>::value, Modular>::type &operator*=(const Modular &rhs)", + " {", + " int64_t q = static_cast(static_cast(value) * rhs.value / mod());", + " value = normalize(value * rhs.value - q * mod());", + " return *this;", + " }", + " template ", + " typename enable_if::Type>::value, Modular>::type &operator*=(const Modular &rhs)", + " {", + " value = normalize(value * rhs.value);", + " return *this;", + " }", + "", + " Modular inverse() const", + " {", + " Type a = value, b = mod(), u = 0, v = 1;", + " while (a != 0)", + " {", + " Type t = b / a;", + " b -= t * a;", + " swap(a, b);", + " u -= t * v;", + " swap(u, v);", + " }", + " assert(b == 1);", + " return Modular(u);", + " }", + " Modular &operator/=(const Modular &other) { return *this *= other.inverse(); }", + "", + " template ", + " friend bool operator==(const Modular &lhs, const Modular &rhs);", + "", + " template ", + " friend std::istream &operator>>(std::istream &stream, Modular &number);", + "", + "private:", + " Type value;", + "};", + "", + "template ", + "bool operator==(const Modular &lhs, const Modular &rhs) { return lhs.value == rhs.value; }", + "template ", + "bool operator==(const Modular &lhs, U rhs) { return lhs == Modular(rhs); }", + "template ", + "bool operator==(U lhs, const Modular &rhs) { return Modular(lhs) == rhs; }", + "", + "template ", + "bool operator!=(const Modular &lhs, const Modular &rhs) { return !(lhs == rhs); }", + "template ", + "bool operator!=(const Modular &lhs, U rhs) { return !(lhs == rhs); }", + "template ", + "bool operator!=(U lhs, const Modular &rhs) { return !(lhs == rhs); }", + "", + "template ", + "Modular operator+(const Modular &lhs, const Modular &rhs) { return Modular(lhs) += rhs; }", + "template ", + "Modular operator+(const Modular &lhs, U rhs) { return Modular(lhs) += rhs; }", + "template ", + "Modular operator+(U lhs, const Modular &rhs) { return Modular(lhs) += rhs; }", + "", + "template ", + "Modular operator-(const Modular &lhs, const Modular &rhs) { return Modular(lhs) -= rhs; }", + "template ", + "Modular operator-(const Modular &lhs, U rhs) { return Modular(lhs) -= rhs; }", + "template ", + "Modular operator-(U lhs, const Modular &rhs) { return Modular(lhs) -= rhs; }", + "", + "template ", + "Modular operator*(const Modular &lhs, const Modular &rhs) { return Modular(lhs) *= rhs; }", + "template ", + "Modular operator*(const Modular &lhs, U rhs) { return Modular(lhs) *= rhs; }", + "template ", + "Modular operator*(U lhs, const Modular &rhs) { return Modular(lhs) *= rhs; }", + "", + "template ", + "Modular operator/(const Modular &lhs, const Modular &rhs) { return Modular(lhs) /= rhs; }", + "template ", + "Modular operator/(const Modular &lhs, U rhs) { return Modular(lhs) /= rhs; }", + "template ", + "Modular operator/(U lhs, const Modular &rhs) { return Modular(lhs) /= rhs; }", + "", + "template ", + "Modular power(const Modular &a, const U &b)", + "{", + " assert(b >= 0);", + " Modular x = a, res = 1;", + " U p = b;", + " while (p > 0)", + " {", + " if (p & 1)", + " res *= x;", + " x *= x;", + " p >>= 1;", + " }", + " return res;", + "}", + "", + "template ", + "string to_string(const Modular &number)", + "{", + " return to_string(number());", + "}", + "", + "template ", + "std::ostream &operator<<(std::ostream &stream, const Modular &number)", + "{", + " return stream << number();", + "}", + "", + "template ", + "std::istream &operator>>(std::istream &stream, Modular &number)", + "{", + " typename common_type::Type, int64_t>::type x;", + " stream >> x;", + " number.value = Modular::normalize(x);", + " // stream >> number.value;", + " // number.value = Modular::normalize(number.value);", + " return stream;", + "}", + "", + "/*", + "using ModType = int;", + "", + "struct VarMod { static ModType value; };", + "ModType VarMod::value;", + "ModType& md = VarMod::value;", + "using Mint = Modular;", + "*/", + "", + "constexpr int md = MOD;", + "using Mint = Modular::type, md>>;", + "", + "template ", + "class NTT", + "{", + "public:", + " using Type = typename decay::type;", + "", + " static Type md;", + " static Modular root;", + " static int base;", + " static int max_base;", + " static vector> roots;", + " static vector rev;", + "", + " static void clear()", + " {", + " root = 0;", + " base = 0;", + " max_base = 0;", + " roots.clear();", + " rev.clear();", + " }", + "", + " static void init()", + " {", + " md = T::value;", + " assert(md >= 3 && md % 2 == 1);", + " auto tmp = md - 1;", + " max_base = 0;", + " while (tmp % 2 == 0)", + " {", + " tmp /= 2;", + " max_base++;", + " }", + " root = 2;", + " while (power(root, (md - 1) >> 1) == 1)", + " {", + " root++;", + " }", + " assert(power(root, md - 1) == 1);", + " root = power(root, (md - 1) >> max_base);", + " base = 1;", + " rev = {0, 1};", + " roots = {0, 1};", + " }", + "", + " static void ensure_base(int nbase)", + " {", + " if (md != T::value)", + " {", + " clear();", + " }", + " if (roots.empty())", + " {", + " init();", + " }", + " if (nbase <= base)", + " {", + " return;", + " }", + " assert(nbase <= max_base);", + " rev.resize(1 << nbase);", + " for (int i = 0; i < (1 << nbase); i++)", + " {", + " rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (nbase - 1));", + " }", + " roots.resize(1 << nbase);", + " while (base < nbase)", + " {", + " Modular z = power(root, 1 << (max_base - 1 - base));", + " for (int i = 1 << (base - 1); i < (1 << base); i++)", + " {", + " roots[i << 1] = roots[i];", + " roots[(i << 1) + 1] = roots[i] * z;", + " }", + " base++;", + " }", + " }", + "", + " static void fft(vector> &a)", + " {", + " int n = (int)a.size();", + " assert((n & (n - 1)) == 0);", + " int zeros = __builtin_ctz(n);", + " ensure_base(zeros);", + " int shift = base - zeros;", + " for (int i = 0; i < n; i++)", + " {", + " if (i < (rev[i] >> shift))", + " {", + " swap(a[i], a[rev[i] >> shift]);", + " }", + " }", + " for (int k = 1; k < n; k <<= 1)", + " {", + " for (int i = 0; i < n; i += 2 * k)", + " {", + " for (int j = 0; j < k; j++)", + " {", + " Modular x = a[i + j];", + " Modular y = a[i + j + k] * roots[j + k];", + " a[i + j] = x + y;", + " a[i + j + k] = x - y;", + " }", + " }", + " }", + " }", + "", + " static vector> multiply(vector> a, vector> b)", + " {", + " if (a.empty() || b.empty())", + " {", + " return {};", + " }", + " int eq = (a.size() == b.size() && a == b);", + " int need = (int)a.size() + (int)b.size() - 1;", + " int nbase = 0;", + " while ((1 << nbase) < need)", + " nbase++;", + " ensure_base(nbase);", + " int sz = 1 << nbase;", + " a.resize(sz);", + " b.resize(sz);", + " fft(a);", + " if (eq)", + " b = a;", + " else", + " fft(b);", + " Modular inv_sz = 1 / static_cast>(sz);", + " for (int i = 0; i < sz; i++)", + " {", + " a[i] *= b[i] * inv_sz;", + " }", + " reverse(a.begin() + 1, a.end());", + " fft(a);", + " a.resize(need);", + " return a;", + " }", + "};", + "", + "template ", + "typename NTT::Type NTT::md;", + "template ", + "Modular NTT::root;", + "template ", + "int NTT::base;", + "template ", + "int NTT::max_base;", + "template ", + "vector> NTT::roots;", + "template ", + "vector NTT::rev;", + "", + "template ", + "vector> inverse(const vector> &a)", + "{", + " assert(!a.empty());", + " int n = (int)a.size();", + " vector> b = {1 / a[0]};", + " while ((int)b.size() < n)", + " {", + " vector> x(a.begin(), a.begin() + min(a.size(), b.size() << 1));", + " x.resize(b.size() << 1);", + " b.resize(b.size() << 1);", + " vector> c = b;", + " NTT::fft(c);", + " NTT::fft(x);", + " Modular inv = 1 / static_cast>((int)x.size());", + " for (int i = 0; i < (int)x.size(); i++)", + " {", + " x[i] *= c[i] * inv;", + " }", + " reverse(x.begin() + 1, x.end());", + " NTT::fft(x);", + " rotate(x.begin(), x.begin() + (x.size() >> 1), x.end());", + " fill(x.begin() + (x.size() >> 1), x.end(), 0);", + " NTT::fft(x);", + " for (int i = 0; i < (int)x.size(); i++)", + " {", + " x[i] *= c[i] * inv;", + " }", + " reverse(x.begin() + 1, x.end());", + " NTT::fft(x);", + " for (int i = 0; i < ((int)x.size() >> 1); i++)", + " {", + " b[i + ((int)x.size() >> 1)] = -x[i];", + " }", + " }", + " b.resize(n);", + " return b;", + "}", + "", + "template ", + "vector> inverse_old(vector> a)", + "{", + " assert(!a.empty());", + " int n = (int)a.size();", + " if (n == 1)", + " {", + " return {1 / a[0]};", + " }", + " int m = (n + 1) >> 1;", + " vector> b = inverse_old(vector>(a.begin(), a.begin() + m));", + " int need = n << 1;", + " int nbase = 0;", + " while ((1 << nbase) < need)", + " {", + " ++nbase;", + " }", + " NTT::ensure_base(nbase);", + " int size = 1 << nbase;", + " a.resize(size);", + " b.resize(size);", + " NTT::fft(a);", + " NTT::fft(b);", + " Modular inv = 1 / static_cast>(size);", + " for (int i = 0; i < size; ++i)", + " {", + " a[i] = (2 - a[i] * b[i]) * b[i] * inv;", + " }", + " reverse(a.begin() + 1, a.end());", + " NTT::fft(a);", + " a.resize(n);", + " return a;", + "}", + "", + "template ", + "vector> operator*(const vector> &a, const vector> &b)", + "{", + " if (a.empty() || b.empty())", + " {", + " return {};", + " }", + " if (min(a.size(), b.size()) < 100)", + " {", + " vector> c(a.size() + b.size() - 1, 0);", + " for (int i = 0; i < (int)a.size(); i++)", + " {", + " for (int j = 0; j < (int)b.size(); j++)", + " {", + " c[i + j] += a[i] * b[j];", + " }", + " }", + " return c;", + " }", + " return NTT::multiply(a, b);", + "}", + "", + "template ", + "vector> &operator*=(vector> &a, const vector> &b)", + "{", + " return a = a * b;", + "}", + "", + "template ", + "vector &operator+=(vector &a, const vector &b)", + "{", + " if (a.size() < b.size())", + " {", + " a.resize(b.size());", + " }", + " for (int i = 0; i < (int)b.size(); i++)", + " {", + " a[i] += b[i];", + " }", + " return a;", + "}", + "", + "template ", + "vector operator+(const vector &a, const vector &b)", + "{", + " vector c = a;", + " return c += b;", + "}", + "", + "template ", + "vector &operator-=(vector &a, const vector &b)", + "{", + " if (a.size() < b.size())", + " {", + " a.resize(b.size());", + " }", + " for (int i = 0; i < (int)b.size(); i++)", + " {", + " a[i] -= b[i];", + " }", + " return a;", + "}", + "", + "template ", + "vector operator-(const vector &a, const vector &b)", + "{", + " vector c = a;", + " return c -= b;", + "}", + "", + "template ", + "vector operator-(const vector &a)", + "{", + " vector c = a;", + " for (int i = 0; i < (int)c.size(); i++)", + " {", + " c[i] = -c[i];", + " }", + " return c;", + "}", + "", + "// (x + 1) * (x + 2) * ... * (x + n)", + "template ", + "vector sequence(int n)", + "{", + " if (n == 0)", + " {", + " return {1};", + " }", + " if (n % 2 == 1)", + " {", + " return sequence(n - 1) * vector{n, 1};", + " }", + " vector c = sequence(n / 2);", + " vector a = c;", + " reverse(a.begin(), a.end());", + " T f = 1;", + " for (int i = n / 2 - 1; i >= 0; i--)", + " {", + " f *= n / 2 - i;", + " a[i] *= f;", + " }", + " vector b(n / 2 + 1);", + " b[0] = 1;", + " for (int i = 1; i <= n / 2; i++)", + " {", + " b[i] = b[i - 1] * (n / 2) / i;", + " }", + " vector h = a * b;", + " h.resize(n / 2 + 1);", + " reverse(h.begin(), h.end());", + " f = 1;", + " for (int i = 1; i <= n / 2; i++)", + " {", + " f /= i;", + " h[i] *= f;", + " }", + " vector res = c * h;", + " return res;", + "}", + "#pragma endregion", + "vector calculatePolynomial(int n)", + "{", + " vector coeff = sequence(n);", + " vector res(n+2, 0);", + " for (int i = 0; i < coeff.size(); ++i)", + " {", + " #ifdef MOD", + " res[i+1] = ((ll)(coeff[i])) % MOD;", + " #else", + " res[i+1] = ((ll)(coeff[i]));", + " #endif", + " }", + " return res;", + "}" + ], + "description": "NTT" + }, + "fft": { + "prefix": "fft", + "body": [ + "double PI = acos(0) * 2;", + "class Complex", + "{", + "public:", + " double a, b;", + " Complex() {a = 0.0; b = 0.0;}", + " Complex(double na, double nb) {a = na; b = nb;}", + " const Complex operator+(const Complex &c) const", + " {return Complex(a + c.a, b + c.b);}", + " const Complex operator-(const Complex &c) const", + " {return Complex(a - c.a, b - c.b);}", + " const Complex operator*(const Complex &c) const", + " {return Complex(a*c.a - b*c.b, a*c.b + b*c.a);}", + " double magnitude() {return sqrt(a*a+b*b);}", + " void print() {printf(\"(%.3f %.3f)\\n\", a, b);}", + "};", + "", + "class FFT", + "{", + "public:", + " vector data;", + " vector roots;", + " vector rev;", + " int s, n;", + " void setSize(int ns)", + " {", + " s = ns;", + " n = (1 << s);", + " int i, j;", + " rev = vector(n);", + " data = vector (n);", + " roots = vector (n+1);", + " for (i = 0; i < n; i++)", + " for (j = 0; j < s; j++)", + " if ((i & (1 << j)) != 0)", + " rev[i] += (1 << (s-j-1));", + " roots[0] = Complex(1, 0);", + " Complex mult = Complex(cos(2*PI/n), sin(2*PI/n));", + " for (i = 1; i <= n; i++)", + " roots[i] = roots[i-1] * mult;", + " }", + " void bitReverse(vector &array)", + " {", + " vector temp(n);", + " int i;", + " for (i = 0; i < n; i++)", + " temp[i] = array[rev[i]];", + " for (i = 0; i < n; i++)", + " array[i] = temp[i];", + " }", + " void transform(bool inverse = false)", + " {", + " bitReverse(data);", + " int i, j, k;", + " for (i = 1; i <= s; i++) {", + " int m = (1 << i), md2 = m / 2;", + " int start = 0, increment = (1 << (s-i));", + " if (inverse) {", + " start = n;", + " increment *= -1;", + " }", + " Complex t, u;", + " for (k = 0; k < n; k += m) {", + " int index = start;", + " for (j = k; j < md2+k; j++) {", + " t = roots[index] * data[j+md2];", + " index += increment;", + " data[j+md2] = data[j] - t;", + " data[j] = data[j] + t;", + " }", + " }", + " }", + " if (inverse)", + " for (i = 0; i < n; i++) {", + " data[i].a /= n;", + " data[i].b /= n;", + " }", + " }", + " static vector convolution(vector &a, vector &b)", + " {", + " int alen = a.size(), blen = b.size();", + " int resn = alen + blen - 1; // size of the resulting array", + " int s = 0, i;", + " while ((1 << s) < resn) s++; // n = 2^s", + " int n = 1 << s; // round up the the nearest power of two", + "", + " FFT pga, pgb;", + " pga.setSize(s); // fill and transform first array", + " for (i = 0; i < alen; i++) pga.data[i] = Complex(a[i], 0);", + " for (i = alen; i < n; i++) pga.data[i] = Complex(0, 0);", + " pga.transform();", + "", + " pgb.setSize(s); // fill and transform second array", + " for (i = 0; i < blen; i++) pgb.data[i] = Complex(b[i], 0);", + " for (i = blen; i < n; i++) pgb.data[i] = Complex(0, 0);", + " pgb.transform();", + "", + " for (i = 0; i < n; i++) pga.data[i] = pga.data[i] * pgb.data[i];", + " pga.transform(true); // inverse transform", + " vector result = vector (resn); // round to nearest integer", + " for (i = 0; i < resn; i++) result[i] = (int) (pga.data[i].a + 0.5);", + "", + " int actualSize = resn - 1; // find proper size of array", + " while (result[actualSize] == 0)", + " actualSize--;", + " if (actualSize < 0) actualSize = 0;", + " result.resize(actualSize+1);", + " return result;", + " }", + "}; // ... " + ], + "description": "fft" + }, + "zfunction": { + "prefix": "zfunction", + "body": [ + "vector z_func(string s)", + "{", + " int n = s.size();", + " vector z(n, 0);", + " for (int i = 1, l = 0, r = 0; i < n; ++i)", + " {", + " if (i <= r) z[i] = min(r-i+1, z[i-l]);", + " while (i + z[i] < n && s[z[i]] == s[i + z[i]]) ++z[i];", + " if (i + z[i] - 1 > r) l = i, r = i + z[i] - 1;", + " }", + " return z;", + "}", + "", + "int patternCount(string s, string p, bool allowOverlap)", + "{", + " auto z = z_func(p + '$' + s);", + " int count = 0;", + " for (int i = 0; i < z.size(); ++i)", + " {", + " if (z[i] == p.size())", + " {", + " count++;", + " if (!allowOverlap) i += p.size()-1;", + " }", + " }", + " return count;", + "}", + "" + ], + "description": "zfunction" + }, + "Graph Matching": { + "prefix": "graphMatching", + "body": [ + "class GraphMatching", + "{", + "private:", + " static bool findMatch(int i, const vector> &inp_w, vector &out_row, vector &out_column, vector &seen)", + " {", + " // 0 is NO_EDGE here", + " if (seen[i]) return false;", + " seen[i] = true;", + " for (int j = 0; j < inp_w[i].size(); ++j)", + " {", + " if (inp_w[i][j] != 0 && out_column[j] < 0)", + " {", + " out_row[i] = j, out_column[j] = i;", + " return true;", + " }", + " }", + " for (int j = 0; j < inp_w[i].size(); ++j)", + " {", + " if (inp_w[i][j] != 0 && out_row[i] != j)", + " {", + " if (out_column[j] < 0 || findMatch(out_column[j], inp_w, out_row, out_column, seen))", + " {", + " out_row[i] = j, out_column[j] = i;", + " return true;", + " }", + " }", + " }", + " return false;", + " }", + " static bool dfs(int n, int N, vector> &inp_con, vector &blossom, vector &vis, vector &out_match)", + " {", + " vis[n] = 0;", + " for (int i = 0; i < N; ++i)", + " {", + " if (!inp_con[n][i]) continue;", + " if (vis[i] == -1)", + " {", + " vis[i] = 1;", + " if (out_match[i] == -1 || dfs(out_match[i], N, inp_con, blossom, vis, out_match))", + " {", + " out_match[n] = i, out_match[i] = n;", + " return true;", + " }", + " }", + " if (vis[i] == 0 || blossom.size())", + " {", + " blossom.push_back(i), blossom.push_back(n);", + " if (n == blossom[0])", + " {", + " out_match[n] = -1;", + " return true;", + " }", + " return false;", + " }", + " }", + " return false;", + " }", + " static bool augment(int N, vector> &inp_con, vector &out_match)", + " {", + " for (int i = 0; i < N; ++i)", + " {", + " if (out_match[i] != -1) continue;", + " vector blossom;", + " vector vis(N, -1);", + " if (!dfs(i, N, inp_con, blossom, vis, out_match)) continue;", + " if (blossom.size() == 0) return true;", + " int base = blossom[0], S = blossom.size();", + " vector> newCon = inp_con;", + " for (int i = 1; i != S-1; ++i)", + " for (int j = 0; j < N; ++j)", + " newCon[base][j] = newCon[j][base] |= inp_con[blossom[i]][j];", + " for (int i = 1; i != S-1; ++i)", + " for (int j = 0; j < N; ++j)", + " newCon[blossom[i]][j] = newCon[j][blossom[i]] = 0;", + " newCon[base][base] = 0;", + " if (!augment(N, newCon, out_match)) return false;", + " int n = out_match[base];", + " if (n != -1)", + " {", + " for (int i = 0; i < S; ++i)", + " {", + " if (!inp_con[blossom[i]][n]) continue;", + " out_match[blossom[i]] = n, out_match[n] = blossom[i];", + " if (i&1)", + " {", + " for (int j = i+1; j < S; j += 2)", + " out_match[blossom[j]] = blossom[j+1], out_match[blossom[j+1]] = blossom[j];", + " }", + " else", + " {", + " for (int j = 0; j < i; j += 2)", + " out_match[blossom[j]] = blossom[j+1], out_match[blossom[j+1]] = blossom[j];", + " }", + " break;", + " }", + " }", + " return true;", + " }", + " return false;", + " }", + "public:", + " /* weighted bipartite matching, inp_w[i][j] is cost from row node i to column node j", + " out vector out_row & out_column is assignment for that node or -1 if unassigned", + " It has a heuristic that will give excellent performance on complete graphs where rows <= columns. */", + " static int bipartiteMatching(const vector> &inp_w, vector &out_row, vector &out_column)", + " {", + " out_row = vector (inp_w.size(), -1);", + " out_column = vector (inp_w[0].size(), -1);", + " vector seen(inp_w.size());", + " int count = 0;", + " for (int i = 0; i < inp_w.size(); ++i)", + " {", + " fill(seen.begin(), seen.end(), 0);", + " if (findMatch(i, inp_w, out_row, out_column, seen)) count++;", + " }", + " return count;", + " }", + " // unweighted inp_conn[i][j] = 1 for edge 0 otherwise, returns no. of edges in max matching", + " static int nonBipartiteMatching(vector> &inp_con, vector &out_match)", + " {", + " int res = 0;", + " int N = inp_con.size();", + " out_match = vector(N, -1);", + " while (augment(N, inp_con, out_match)) res++;", + " return res;", + " }", + "};" + ], + "description": "Graph Matching" + }, + "dateGeorgianJullian": { + "prefix": "dateGeorgianJullian", + "body": [ + "int georgianDateToJullian(int m, int d, int y)", + "{", + " return 1461 * (y + 4800 + (m - 14) / 12) / 4 +", + " 367 * (m - 2 - (m - 14) / 12 * 12) / 12 - ", + " 3 * ((y + 4900 + (m - 14) / 12) / 100) / 4 + ", + " d - 32075;", + "}", + "void jullianDateToGeorgian(int jd, int &m, int &d, int &y)", + "{", + " int x, n, i, j;", + " x = jd + 68569;", + " n = 4 * x / 146097;", + " x -= (146097 * n + 3) / 4;", + " i = (4000 * (x + 1)) / 1461001;", + " x -= 1461 * i / 4 - 31;", + " j = 80 * x / 2447;", + " d = x - 2447 * j / 80;", + " x = j / 11;", + " m = j + 2 - 12 * x;", + " y = 100 * (n - 49) + i + x;", + "}" + ], + "description": "dateGeorgianJullian" + }, + "geometry": { + "prefix": "geometry", + "body": [ + "const double EPS = 1e-7;", + "struct Point", + "{", + " double x, y, z;", + " Point() : x(0), y(0), z(0) { }", + " Point(double _x, double _y) : x(_x), y(_y), z(0) { }", + " Point(double _x, double _y, double _z) : x(_x), y(_y), z(_z) { }", + " Point operator+(const Point &p) { return Point(x+p.x, y+p.y, z+p.z); }", + " Point operator-(const Point &p) { return Point(x-p.x, y-p.y, z-p.z); }", + " Point operator*(double c) { return Point(x*c, y*c, z*c); }", + " Point operator/(double c) { return Point(x/c, y/c, z/c); }", + "};", + "typedef Point Vector;", + "typedef pair Line;", + "typedef vector Polygon;", + "struct Plane { double a, b, c, d; }; // ax + by + cz = d form", + "double crossProduct(const Vector &a, const Vector &b) { return a.x * b.y - a.y * b.x; }", + "double dotProduct(const Vector &a, const Vector &b) { return a.x * b.x + a.y * b.y; }", + "double sqrDist(Point p, Point q) { return dotProduct(p-q, p-q); }", + "", + "// internal used functions", + "vector< pair > vec;", + "double length(const Vector &a) { return sqrt(dotProduct(a, a)); }", + "inline int dcmp(double x) { return (x > 1e-10) - (x < -(1e-10)); }", + "inline void add(double x, double flag) { vec.push_back(make_pair(x, -flag)); }", + "double get(Point &p, Vector &v, Point &q, Vector &w) { return crossProduct(w, p-q) / crossProduct(v, w); }", + "void getSegmentIntersection(Point p, Vector v, Point q, Vector w)", + "{", + " if (!dcmp(crossProduct(v, w)))", + " {", + " if (!dcmp(crossProduct(v, q-p)))", + " {", + " double l = dotProduct(v, q-p) / dotProduct(v, v);", + " double r = dotProduct(v, q+w-p) / dotProduct(v, v);", + " if (l > r) swap(l, r);", + " add(l, +1); add(r, -1);", + " }", + " }", + " else", + " {", + " static int num = 0;", + " double temp = get(q, w, p, v);", + " if (dcmp(temp) >= 0 && dcmp(temp-1) <= 0)", + " {", + " double rate = 1;", + " if (dcmp(temp) == 0 || dcmp(temp-1) == 0) rate = .5;", + " temp = get(p, v, q, w);", + " add(temp, dcmp(crossProduct(w, v)) > 0 ? +rate : -rate);", + " }", + " }", + "}", + "", + "// Helper functions", + "Point rotateCounterClockwise(Point pt, double radians) { return Point(pt.x*cos(radians) - pt.y*sin(radians), pt.x*sin(radians) + pt.y*cos(radians)); }", + "Point rotateCounterClockwise(Point pt, double radians, Point ref) { return rotateCounterClockwise(pt-ref, radians)+ref; }", + "Point rotateClockwise(Point pt, double radians) { return rotateCounterClockwise(pt, -radians); }", + "Point rotateClockwise(Point pt, double radians, Point ref) { return rotateCounterClockwise(pt, -radians, ref); }", + "double pointPlaneDistance(Point a, Plane b) { return fabs(b.a*a.x + b.b*a.y + b.c*a.z - b.d) / sqrt(b.a*b.a + b.b*b.b + b.c*b.c); }", + "Point projectPointOnLine(Line a, Point b) { return a.F + (a.S-a.F) * dotProduct(b-a.F, a.S-a.F)/dotProduct(a.S-a.F, a.S-a.F); }", + "Point projectPointOnLineSegment(Line a, Point b)", + "{", + " double r = dotProduct(a.S-a.F, a.S-a.F);", + " if (fabs(r) < EPS) return a.F;", + " r = dotProduct(b-a.F, a.S-a.F)/r;", + " if (r < 0) return a.F;", + " if (r > 1) return a.S;", + " return a.F + (a.S-a.F)*r;", + "}", + "bool linesParalle(Line a, Line b) { return (fabs(crossProduct(a.S-a.F, b.F-b.S)) < EPS); }", + "bool linesCollinear(Line a, Line b) { return (linesParalle(a, b) && (fabs(crossProduct(a.F-b.F, b.S-a.S)) < EPS)); }", + "bool linesIntersect(Line a, Line b)", + "{", + " if ((crossProduct(b.S-a.F, a.S-a.F) * crossProduct(b.F-a.F, a.S-a.F)) > 0) return false;", + " if ((crossProduct(a.F-b.F, b.S-b.F) * crossProduct(a.S-b.F, b.S-b.F)) > 0) return false;", + " return true;", + "}", + "Point computeLineIntersection(Line a, Line b)", + "{", + " a.S = a.S-a.F; b.S = b.F-b.S; b.F = b.F-a.F;", + " if (dotProduct(a.S, a.S) < EPS) return a.F;", + " if (dotProduct(b.S, b.S) < EPS) return b.F;", + " return a.F + a.S*crossProduct(b.F, b.S)/crossProduct(a.S, b.S);", + "}", + "// Point in possibly non-convex polygon, returns 1 for strictly interior points,", + "// 0 for strictly exterior points, and 0 or 1 for the remaining points", + "bool pointInPolygon(const Polygon &poly, Point pt)", + "{", + " bool res = false;", + " for (int i = 0; i < poly.size(); ++i)", + " {", + " int j = (i+1) % poly.size();", + " if ((poly[i].y <= pt.y && pt.y < poly[j].y || poly[j].y <= pt.x && pt.y < poly[i].y) &&", + " pt.x < poly[i].x + (poly[j].x - poly[i].x)*(pt.y - poly[i].y)/(poly[j].y - poly[i].y))", + " res = !res;", + " }", + " return res;", + "}", + "bool pointOnPolygon(const Polygon &poly, Point pt)", + "{", + " for (int i = 0; i < poly.size(); ++i)", + " {", + " Line ln(poly[i], poly[(i+1)%poly.size()]);", + " if (sqrDist(projectPointOnLineSegment(ln, pt), pt) < EPS)", + " return true;", + " }", + " return false;", + "}", + "vector circleLineIntersection(Line line, Point center, double radius)", + "{", + " vector res;", + " Point d = line.S-line.F;", + " double D = crossProduct(line.F-center, line.S-center);", + " double e = sqrt(radius*radius*dotProduct(d, d) - D*D);", + " res.push_back (center + Point(D*d.y+(d.y >= 0 ? 1 : -1)*d.x*e, -D*d.x+fabs(d.y)*e) / dotProduct(d,d));", + " if (e > 0) res.push_back (center + Point(D*d.y-(d.y >= 0 ? 1 : -1)*d.x*e,-D*d.x-fabs(d.y)*e) / dotProduct(d,d));", + " return res;", + "}", + "vector intersectionPointBetweenTwoCircles(Point a, Point b, double r, double R)", + "{", + " vector ret;", + " double d = sqrt(sqrDist(a,b));", + " if (d > r+R || d+min(r,R) < max(r,R)) return ret;", + " double x = (d*d-R*R+r*r)/(2*d);", + " double y = sqrt(r*r-x*x);", + " Point v = (b-a)/d;", + " ret.push_back (a+v*x + rotateCounterClockwise(v, M_PI/2)*y);", + " if (y > 0) ret.push_back (a+v*x - rotateCounterClockwise(v, M_PI/2)*y);", + " return ret;", + "}", + "double areaBetweenTwoCircles(Point a, Point b, double r, double R)", + "{", + " double n = sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));", + " if (n >= r+R) return 0;", + " else if (n+r <= R || n+R <= r) return (M_PI * min(r, R) * min(r, R));", + " else", + " {", + " double a = acos((R*R + n*n - r*r) / (2*R*n)) * 2;", + " double b = acos((r*r + n*n - R*R) / (2*r*n)) * 2;", + " return ((R*R*a + r*r*b - R*R*sin(a) - r*r*sin(b)) * 0.5);", + " }", + "}", + "// assuming that the coordinates are listed in a clockwise or counterclockwise order", + "double polygonSignedArea(Polygon poly)", + "{", + " double area = 0;", + " for (int i = 0; i < poly.size(); ++i)", + " {", + " int j = (i+1) % poly.size();", + " area += poly[i].x*poly[j].y - poly[j].x*poly[i].y;", + " }", + " return area / 2.0;", + "}", + "double polygonArea(Polygon poly) { return fabs(polygonSignedArea(poly)); }", + "pair polygonCentroid(Polygon poly)", + "{", + " double cx = 0, cy = 0;", + " double scale = 6.0 * polygonSignedArea(poly);", + " for (int i = 0; i < poly.size(); ++i)", + " {", + " int j = (i+1) % poly.size();", + " cx += (poly[i].x+poly[j].x) * (poly[i].x*poly[j].y - poly[j].x*poly[i].y);", + " cy += (poly[i].y+poly[j].y) * (poly[i].x*poly[j].y - poly[j].x*poly[i].y);", + " }", + " return {cx/scale, cy/scale};", + "}", + "/* Given a n side polygon (Not necessarily convex) and m lines, it finds section length", + " in nmlogn time. If the line fully lies inside the polygon it's that lines length, its", + " length that lies inside polygon. */", + "vector polygonLineIntersection(Polygon poly, vector lines)", + "{", + " int n = poly.size(), m = lines.size(), x = 0;", + " poly.push_back(poly[0]);", + " vector ans(m, 0);", + " for (auto &line : lines)", + " {", + " Point a = line.first, b = line.second;", + " vec.clear();", + " for (int i = 0; i < n; ++i)", + " getSegmentIntersection(a, b-a, poly[i], poly[i+1] - poly[i]);", + " sort(all(vec));", + " double k = 0;", + " for (size_t i = 0; i < vec.size(); ++i)", + " {", + " k += vec[i].second;", + " if (dcmp(k)) ans[x] += vec[i+1].first - vec[i].first;", + " }", + " ans[x++] *= length(b-a);", + " }", + " return ans;", + "}" + ], + "description": "geometry" + }, + "convexHull": { + "prefix": "convexHull", + "body": [ + "const int MAXN = 5e4 + 10;", + "class ConvexHullDynamic", + "{", + " typedef long long coef_t, coord_t, val_t;", + " //Line 'y=a*x+b' represented by 2 coefficients 'a' and 'b'", + "private:", + " struct Line", + " {", + " coef_t a, b;", + " double xLeft;", + " enum Type { line, maxQuery, minQuery } type;", + " coord_t val;", + " explicit Line(coef_t aa = 0, coef_t bb = 0) : a(aa), b(bb), xLeft(-INFINITY), type(Type::line), val(0) {}", + " val_t valueAt(coord_t x) const { return a * x + b; }", + " friend bool areParallel(const Line &l1, const Line &l2) { return l1.a == l2.a; }", + " friend double intersectX(const Line &l1, const Line &l2) { return areParallel(l1, l2) ? INFINITY : 1.0 * (l2.b - l1.b) / (l1.a - l2.a); }", + " bool operator<(const Line &l2) const", + " {", + " if (l2.type == line) return this->a > l2.a;", + " if (l2.type == maxQuery) return this->xLeft < l2.val;", + " if (l2.type == minQuery) return this->xLeft > l2.val;", + " assert(0);", + " return false;", + " }", + " };", + " bool hasPrev(std::set::iterator it) { return it != hull.begin(); }", + " bool hasNext(std::set::iterator it) { return it != hull.end() && std::next(it) != hull.end(); }", + " bool irrelevant(const Line &l1, const Line &l2, const Line &l3) { return intersectX(l1, l3) <= intersectX(l1, l2); }", + " bool irrelevant(std::set::iterator it) { return hasPrev(it) && hasNext(it) && ((isMax && irrelevant(*std::prev(it), *it, *std::next(it))) || (!isMax && irrelevant(*std::next(it), *it, *std::prev(it)))); }", + " std::set::iterator updateLeftBorder(std::set::iterator it)", + " {", + " if ((isMax && !hasPrev(it)) || (!isMax && !hasNext(it))) return it;", + " double val = intersectX(*it, isMax ? *std::prev(it) : *std::next(it));", + " Line buf(*it);", + " it = hull.erase(it), buf.xLeft = val, it = hull.insert(it, buf);", + " return it;", + " }", + "", + "public:", + " bool isMax; //whether or not saved envelope is top(search of max value)", + " std::set hull; //envelope itself", + " explicit ConvexHullDynamic() : isMax(1) {} // true is for max and false is for min", + " void addLine(coef_t a, coef_t b)", + " {", + " Line l3 = Line(a, b);", + " auto it = hull.lower_bound(l3);", + " if (it != hull.end() && areParallel(*it, l3))", + " {", + " if ((isMax && it->b < b) || (!isMax && it->b > b)) it = hull.erase(it);", + " else return;", + " }", + " it = hull.insert(it, l3);", + " if (irrelevant(it)) { hull.erase(it); return; }", + " while (hasPrev(it) && irrelevant(std::prev(it))) hull.erase(std::prev(it));", + " while (hasNext(it) && irrelevant(std::next(it))) hull.erase(std::next(it));", + " it = updateLeftBorder(it);", + " if (hasPrev(it)) updateLeftBorder(std::prev(it));", + " if (hasNext(it)) updateLeftBorder(std::next(it));", + " }", + " val_t getBest(coord_t x) const", + " {", + " Line q;", + " q.val = x, q.type = isMax ? Line::Type::maxQuery : Line::Type::minQuery;", + " auto bestLine = hull.lower_bound(q);", + " if (isMax) --bestLine;", + " return bestLine->valueAt(x);", + " }", + "};" + ], + "description": "convexHull" + }, + "slidingWindowMinMax": { + "prefix": "slidingWindowMinMax", + "body": [ + "vector slidingWindowMinMax(vector &arr, int k, bool max = true)", + "{", + " deque q;", + " vector res;", + " int n = arr.size();", + " for(int i = 0; i < n; ++i)", + " {", + " while (!q.empty() && q.front() < i-k+1) q.pop_front();", + " if (max)", + " {", + " while (!q.empty() && arr[i] > arr[q.back()])", + " q.pop_back();", + " }", + " else", + " {", + " while (!q.empty() && arr[i] < arr[q.back()])", + " q.pop_back();", + " }", + " q.push_back(i);", + " if(i >= k-1) res.push_back(arr[q.front()]);", + " }", + " return res;", + "}" + ], + "description": "slidingWindowMinMax" + }, + "nextMonotonicElement": { + "prefix": "nextMonotonicElement", + "body": [ + "vector nextMonotonicElement(vector &arr, bool greater = true, bool circularArray = false)", + "{", + " vector res(arr.size());", + " stack st;", + " for (int i = (circularArray) ? (2*arr.size()-1) : (arr.size()-1); i >= 0; --i)", + " {", + " if (greater)", + " {", + " while (!st.empty() && arr[st.top()] <= arr[i % arr.size()])", + " st.pop();", + " }", + " else", + " {", + " while (!st.empty() && arr[st.top()] >= arr[i % arr.size()])", + " st.pop();", + " }", + " res[i % arr.size()] = st.empty() ? -1 : arr[st.top()];", + " st.push(i % arr.size());", + " }", + " return res;", + "}" + ], + "description": "nextMonotonicElement" + }, + "largestHistogramArea": { + "prefix": "largestHistogramArea", + "body": [ + "int largestHistogramArea(vector& arr)", + "{", + " stack st;", + " int ans = 0;", + " arr.push_back(-1);", + " for (int i = 0; i < arr.size(); ++i)", + " {", + " while (!st.empty() && arr[i] <= arr[st.top()])", + " {", + " int height = arr[st.top()]; st.pop();", + " int width = i - (st.empty() ? -1 : st.top()) - 1;", + " ans = max(ans, height * width);", + " }", + " st.push(i);", + " }", + " return ans;", + "}" + ], + "description": "largestHistogramArea" + }, + "shortestSubarrayWithSumAtleastK": { + "prefix": "shortestSubarrayWithSumAtleastK", + "body": [ + "int shortestSubarray(vector& arr, int k, int &r, int &l)", + "{", + " deque> dq;", + " dq.emplace_back(0, -1);", + " int presum = 0, res = INF;", + " for (int i = 0; i < arr.size(); ++ i)", + " {", + " presum += arr[i];", + " while(!dq.empty() && presum - dq.front().first >= k)", + " {", + " int cur = i-dq.front().second;", + " if (cur < res) res = cur, r = i, l = i-(cur-1);", + " dq.pop_front();", + " }", + " while(!dq.empty() && dq.back().first >= presum) dq.pop_back();", + " dq.emplace_back(presum, i);", + " }", + " return res == INF ? -1 : res;", + "}" + ], + "description": "shortestSubarrayWithSumAtleastK" + }, + "LCA_query": { + "prefix": "LCA_query", + "body": [ + "#define MAXN 200005", + "#define MAXLVL 25", + "int lcaDepth[MAXN], lcaParent[MAXN][MAXLVL];", + "void computeDepthAndParent(vector adj[], int cur = 1, int par = 0)", + "{", + " lcaDepth[cur] = lcaDepth[par]+1;", + " lcaParent[cur][0] = par;", + " for (auto &x : adj[cur])", + " {", + " if (x == par) continue;", + " computeDepthAndParent(adj, x, cur);", + " }", + "}", + "void preprocess(int n, vector adj[])", + "{", + " computeDepthAndParent(adj);", + " for (int i = 1; i < MAXLVL; ++i)", + " for (int j = 1; j <= n; ++j)", + " if (lcaParent[j][i-1] != -1) lcaParent[j][i] = lcaParent[lcaParent[j][i-1]][i-1];", + "}", + "int LCA(int u, int v)", + "{", + " if (lcaDepth[v] < lcaDepth[u]) swap(u, v);", + " int diff = lcaDepth[v] - lcaDepth[u];", + " for (int i = 0; i < MAXLVL; ++i)", + " if ((diff>>i)&1) v = lcaParent[v][i];", + " if (u == v) return u;", + " for (int i = MAXLVL-1; i >= 0; --i)", + " if (lcaParent[u][i] != lcaParent[v][i]) u = lcaParent[u][i], lcaParent[v][i];", + " return lcaParent[u][0];", + "}", + "// Use 1 based indexing in adjancey list" + ], + "description": "LCA_query" + }, + "newtonMethod": { + "prefix": "newtonMethod", + "body": [ + "#define EPS 1e-7", + "double f(double x) { return exp(-x); }", + "double fd(double x) { return -1 * exp(-x); } // derrivative of f", + "double bisection()", + "{", + " double l = 0, r = 1;", + " while (l + EPS < r)", + " {", + " double mid = (l + r)/2;", + " if (f(l) * f(mid) <= 0) r = mid;", + " else l = mid;", + " }", + " return (l + r)/2;", + "}", + "double newton()", + "{", + " if (f(0) == 0) return 0;", + " for (double x = 0.5; ;)", + " {", + " double x1 = x - f(x)/fd(x);", + " if (fabs(x1-x) < EPS) return x;", + " x = x1;", + " }", + "}" + ], + "description": "newtonMethod" + }, + "maxXorPair": { + "prefix": "maxXorPair", + "body": [ + "int maxXorPair(vector &arr)", + "{", + " int mx = 0, mask = 0;", + " set st;", + " for (int i = 60; i >= 0; --i)", + " {", + " mask |= (1<= l; --i) sparseTable[lvl][i] = func(sparseTable[lvl][i+1], arr[i])%p;", + " if (m+1 < r)", + " {", + " sparseTable[lvl][m+1] = arr[m+1]%p;", + " for (int i = m+2; i < r; ++i) sparseTable[lvl][i] = func(sparseTable[lvl][i-1], arr[i])%p;", + " }", + " if (l+1 != r) { build(lvl+1, l, m); build(lvl+1, m, r); }", + "}", + "int query(int L, int R)", + "{", + " if (L == R) return arr[L]%p;", + " int k = __builtin_clz(L^R) ^ 31;", + " int lvl = maxLvl - 1 - k;", + " int res = sparseTable[lvl][L];", + " if (R & ((1< o +``` + +With sanitizers + +```bash +time g++ -std=c++17 cprog.cpp -Wshadow -Wall -g -fsanitize=address -fsanitize=undefined -D_GLIBCXX_DEBUG && timeout 5 ./a.out < i > o +``` + +## Stress Test + +```cpp +#include +using namespace std; + +int LIMIT = 1000; +void generateTestCase() +{ + ofstream fout("i"); + int n = 20; + fout << n << '\n'; + while (n--) + { + int x = 1 + rand()%1000; + fout << x << " "; + } + fout << '\n'; + fout.close(); +} +string inp, wa, ac; +int main() +{ + system("g++ -std=c++17 cprog.cpp -o ac.out"); + system("g++ -std=c++17 ctest.cpp -o wa.out"); + srand(time(0)); + while (LIMIT--) + { + generateTestCase(); + ifstream inpf("i"); + getline(inpf, inp, char(EOF)); + inpf.close(); + + system("./wa.out < i > o"); + ifstream waf("o"); + getline(waf, wa, char(EOF)); + waf.close(); + + system("./ac.out < i > o"); + ifstream acf("o"); + getline(acf, ac, char(EOF)); + acf.close(); + + if (wa != ac) + { + cout << "Failed at:\n"; + cout << inp << '\n'; + cout << "Expected:\n"; + cout << ac << '\n'; + cout << "Found:\n"; + cout << wa << '\n'; + cout << "-----------\n\n"; + } + } + return 0; +} +``` + +### **Regex** + +```cpp +string str = "Hello\tWorld\n"; +string raw_str = R"(Hello\tWorld +this is ankit\n)"; +/* Output: +Hello World +Hello\tWorld +this is ankit\n + +raw strings escape \t \n and considers real +new line instrings doing new line gives error +unless done with escape character \ like in +macro */ + +// Regex match +// https://youtu.be/sa-TUpSx1JA +/* + . - Any Character Except New Line + \d - Digit (0-9) + \D - Not a Digit (0-9) + \w - Word Character (a-z, A-Z, 0-9, _) + \W - Not a Word Character + \s - Whitespace (space, tab, newline) + \S - Not Whitespace (space, tab, newline) + + \b - Word Boundary + \B - Not a Word Boundary + ^ - Beginning of a String + $ - End of a String + + [] - Matches Characters in brackets + [^ ] - Matches Characters NOT in brackets + | - Either Or + ( ) - Group + + Quantifiers: + * - 0 or More + + - 1 or More + ? - 0 or One + {3} - Exact Number + {3,4} - Range of Numbers (Minimum, Maximum) +*/ +regex email_pattern(R"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)"); +if (regex_match("ankitpriyarup@gmail.com", email_pattern)) + cout << "Yes" << endl; +else + cout << "No" << endl; +``` + +### All, Any, None + +```cpp +if (all_of(all(arr), [](const int x){ return x >= 1 && x <= 5; })) + cout << "All values in range"; + +// simmlarly there are none_of any_of +``` + +### Policy Based Data Structures + +Gives access to the indices that the elements would have in a sorted array. + +```cpp +pbds A; // works in logN +A.insert(1); A.insert(3); A.insert(5); A.insert(7); A.insert(9); A.insert(11); + +// Iterator of element at specified pos k +A.find_by_order(k) +// Position of x in sorted array +A.order_of_key(x) + +// If the element is not present we get the pos that the element +// would have in set if present +``` + +### Matrix Exponentiation + +```cpp +// Fibonacci +Matrix T(2, 2), F(2, 1); +T.mat = {{0, 1}, {1, 1}}; +F.mat = {{0}, {1}}; +T ^= n; +T *= F; +cout << T.mat[0][0] << '\n'; +``` + diff --git a/SUMMARY.md b/SUMMARY.md new file mode 100644 index 0000000..ddae4cb --- /dev/null +++ b/SUMMARY.md @@ -0,0 +1,40 @@ +# Table of contents + +* [Tips & Tricks](README.md) +* [System Design](system-design.md) +* [Puzzles](puzzles.md) +* [ADHOC](adhoc.md) +* [Sorting](sorting.md) +* [Searching](searching.md) +* [Linked List](linked-list.md) +* [Monotonic Structures](monotonic-structures.md) +* [Greedy](greedy.md) +* [Bit Manipulation](bit-manipulation.md) +* [Dynamic Programming](dynamic-programming.md) +* [Range Queries](range-queries.md) +* [Graph Theory](graph-theory.md) +* [Implementation Based](implementation-based.md) +* [Number Theory](number-theory.md) +* [Game Theory](game-theory.md) +* [String Algorithms](string-algorithms.md) +* [Square Root Algorithms](square-root-algorithms.md) +* [Geometry Theory](geometry.md) +* [Semester](semester/README.md) + * [DBMS](semester/dbms.md) + * [Web Technologies](semester/web-technologies.md) + * [OOPS](semester/oops.md) + * [C++](semester/c++.md) + * [OS](semester/os.md) +* [Problem Set](problem-set/README.md) + * [CSES Problem Set - I](problem-set/cses-problem-set.md) + * [CSES Problem Set - II](problem-set/cses-problem-set-ii.md) + * [Training Set I](problem-set/codeforces-training-set-i.md) +* [Interview Resource](interview-resource/README.md) + * [Google Interview](interview-resource/google-interview.md) + * [Amazon OA](interview-resource/amazon-oa.md) + * [HackerRank Problems - Easy](interview-resource/hacker-rank-easy.md) + * [HackerRank Problems - Medium](interview-resource/hackerrank-problems-medium.md) + * [HackerRank Problems - Hard](interview-resource/hackerrank-problems-hard.md) + * [HackerRank Problems - Extra](interview-resource/hackerrank-problems-extra.md) + * [HackerRank Problems - SQL](interview-resource/hackerrank-problems-sql.md) + diff --git a/adhoc.md b/adhoc.md new file mode 100644 index 0000000..587f2fa --- /dev/null +++ b/adhoc.md @@ -0,0 +1,2110 @@ +# ADHOC + +### Super-Duper Easy + +```cpp +// UVA00272 +signed main() +{ + string str; + bool first = true; + while (getline(cin, str)) + { + for (auto ch : str) + { + if (ch == '\"') + { + if (first) cout << "``"; + else cout << "''"; + first = !first; + } + else cout << ch; + } + cout << '\n'; + } + return 0; +} + +// UVA10550 +signed main() +{ + int s, a, b, c; + while (cin >> s >> a >> b >> c && (s || a || b || c)) + cout << (1080) + ((s-a+40)%40 + (b-a+40)%40 + (b-c+40)%40) * 9 << '\n'; + return 0; +} + +// UVA11044 +signed main() +{ + int t; + cin >> t; + while (t--) + { + int x, y; + cin >> x >> y; + cout << (x/3) * (y/3) << '\n'; + } + return 0; +} + +// UVA11364 +signed main() +{ + int t; + cin >> t; + while (t--) + { + int n; + cin >> n; + vector arr(n); + for (int i = 0; i < n; ++i) cin >> arr[i]; + cout << (*max_element(arr.begin(), arr.end()) - *min_element(arr.begin(), arr.end())) * 2 << '\n'; + } + return 0; +} + +// UVA11498 +signed main() +{ + int n, px, py, x, y; + cin >> n; + while (n) + { + cin >> px >> py; + while (n--) + { + cin >> x >> y; + if (x == px || y == py) cout << "divisa\n"; + else if (x < px && y > py) cout << "NO\n"; + else if (x > px && y > py) cout << "NE\n"; + else if (x > px && y < py) cout << "SE\n"; + else if (x < px && y < py) cout << "SO\n"; + } + cin >> n; + } + return 0; +} + +// UVA11547 +signed main() +{ + int t; + cin >> t; + while (t--) + { + int n; + cin >> n; + int x = 315*n + 36962; + string y = to_string(x); + cout << y[y.size()-2] << '\n'; + } + return 0; +} + +// UVA11727 +signed main() +{ + int t; + cin >> t; + for (int i = 1; i <= t; ++i) + { + vector a(3); + for (int i = 0; i < 3; ++i) cin >> a[i]; + sort(a.begin(), a.end()); + cout << "Case " << i << ": " << a[1] << '\n'; + } + return 0; +} + +// UVA12250 +signed main() +{ + string helloArray [] = {"HELLO", "HOLA", "HALLO", "BONJOUR", "CIAO", "ZDRAVSTVUJTE"}; + string languageArray [] = {"ENGLISH", "SPANISH", "GERMAN", "FRENCH", "ITALIAN","RUSSIAN"}; + string inp; + int cases = 0; + while (cin >> inp && inp != "#") + { + int len = 6; + bool found = false; + for (int i = 0; i < len; ++i) + { + if (helloArray [i] == inp) + { + printf ("Case %d: %s\n", ++cases, languageArray [i].c_str()); + found = true; + break; + } + } + if (!found) printf ("Case %d: UNKNOWN\n", ++cases); + } + return 0; +} + +// UVA12279 +signed main() +{ + int n; + int cases = 1; + while (cin >> n && n) + { + int ans = 0; + for (int i = 0; i < n; ++i) + { + int x; + cin >> x; + if (x == 0) ans--; + else ans++; + } + cout << "Case " << cases << ": " << ans << '\n'; + cases++; + } + return 0; +} + +//UVA12289 +signed main() +{ + int t; + cin >> t; + while (t--) + { + string str; + cin >> str; + if (str.size() == 5) cout << "3\n"; + else + { + int count = 0; + if (str[0] == 'o') count++; + if (str[1] == 'n') count++; + if (str[2] == 'e') count++; + if (count >= 2) cout << "1\n"; + else cout << "2\n"; + } + } + return 0; +} + +// UVA12372 +signed main() +{ + int t; + cin >> t; + int cases = 1; + while (t--) + { + int x, y, z; + cin >> x >> y >> z; + if (x <= 20 && y <= 20 && z <= 20) cout << "Case " << cases << ": good\n"; + else cout << "Case " << cases << ": bad\n"; + ++cases; + } + return 0; +} + +// UVA12403 +signed main() +{ + int t; + cin >> t; + int cur = 0; + while (t--) + { + string x; + int v; + cin >> x; + if (x == "donate") + { + cin >> v; + cur += v; + } + else cout << cur << '\n'; + } + return 0; +} +``` + +### Super-Easy + +```cpp +// UVA00621 +signed main() +{ + int t; + cin >> t; + while (t--) + { + string str; + cin >> str; + if (str == "1" || str == "4" || str == "78") cout << "+\n"; + else if (str.size() >= 3 && str[str.size()-2] == '3' && str[str.size()-1] == '5') cout << "-\n"; + else if (str.size() >= 3 && str[0] == '9' && str[str.size()-1] == '4') cout << "*\n"; + else cout << "?\n"; + } + return 0; +} + +// UVA10114 +signed main() +{ + int d, dep; + double dp, a; + while (cin >> d && d >= 0) + { + cin >> dp >> a; + cin >> dep; + unordered_map deprec; + while (dep--) + { + int nx; + double ny; + cin >> nx >> ny; + deprec[nx] = ny; + } + double prev = deprec[0]; + for (int i = 1; i <= d; ++i) + { + if (deprec[i] == 0) deprec[i] = prev; + else prev = deprec[i]; + } + double curVal = (a + dp) * (1 - deprec[0]); + double curLoan = a; + int month = 0; + while (curVal < curLoan) + { + month++; + curLoan -= (a/d); + curVal = curVal * (1 - deprec[month]); + } + cout << month; + if (month != 1) cout << " months\n"; + else cout << " month\n"; + } + return 0; +} + +// UVA10300 +signed main() +{ + int t; + cin >> t; + while (t--) + { + int n; + cin >> n; + int ans = 0; + for (int i = 0; i < n; ++i) + { + int x, y, z; + cin >> x >> y >> z; + ans += x*z; + } + cout << ans << '\n'; + } + return 0; +} + +// UVA10963 +signed main() +{ + int t; + cin >> t; + while (t--) + { + int n; + cin >> n; + int x, y; + cin >> x >> y; + int gap = (x-y); + bool ans = true; + for (int i = 0; i < n-1; ++i) + { + cin >> x >> y; + if ((x-y) != gap) ans = false; + } + if (ans) cout << "yes\n"; + else cout << "no\n"; + if (t) cout << '\n'; + } + return 0; +} + +// UVA11332 +signed main() +{ + int n; + while (cin >> n && n) + { + while (n/10) + { + int x = 0; + while (n) + { + x += n % 10; + n /= 10; + } + n = x; + } + cout << n << '\n'; + } + return 0; +} + +// UVA1559 +int n, s, m[30], dp[30][1<<14]; +int solve(int d, int s) +{ + if (s <= 0) return 1; + if (d >= 2*n) d -= 2*n; + if (dp[d][s] != -1) return dp[d][s]; + dp[d][s] = 0; + for (int i = 1; i <= m[d]; ++i) + if (!solve(d+1, s-i)) dp[d][s] = 1; + return dp[d][s]; +} +signed main() +{ + while (cin >> n && n) + { + cin >> s; + for (int i = 0; i < 2*n; ++i) cin >> m[i]; + memset(dp, -1, sizeof(dp)); + cout << solve(0, s) << '\n'; + } + return 0; +} + +// UVA11679 +signed main() +{ + int b, n; + while (cin >> b >> n && (b != 0 || n != 0)) + { + vector banks(b); + for (int i = 0; i < b; ++i) cin >> banks[i]; + for (int i = 0; i < n; ++i) + { + int deb, cred, val; + cin >> deb >> cred >> val; + banks[deb-1] -= val; + banks[cred-1] += val; + } + if (*min_element(banks.begin(), banks.end()) < 0) cout << "N\n"; + else cout << "S\n"; + } +} + +// UVA11764 +signed main() +{ + int t; + cin >> t; + int tc = 0; + while (t--) + { + tc++; + int n; + cin >> n; + int x = 0, y = 0; + int prev; + cin >> prev; + for (int i = 0; i < n-1; ++i) + { + int cur; + cin >> cur; + if (cur > prev) x++; + else if (cur < prev) y++; + prev = cur; + } + cout << "Case " << tc << ": " << x << " " << y << '\n'; + } + return 0; +} + +// UVA11942 +signed main() +{ + int t; + cin >> t; + cout << "Lumberjacks:\n"; + while (t--) + { + vector arr(10); + for (int i = 0; i < 10; ++i) cin >> arr[i]; + vector s1 = arr, s2 = arr; + sort(s1.begin(), s1.end()); + sort(s2.begin(), s2.end(), greater()); + bool flag = true; + for (int i = 0; i < 10; ++i) + { + if (s1[i] != arr[i]) + { + flag = false; + break; + } + } + if (flag) cout << "Ordered\n"; + else + { + flag = true; + for (int i = 0; i < 10; ++i) + { + if (s2[i] != arr[i]) + { + flag = false; + break; + } + } + if (flag) cout << "Ordered\n"; + else cout << "Unordered\n"; + } + } + return 0; +} + +// UVA12015 +signed main() +{ + int t; + cin >> t; + int tc = 0; + while (t--) + { + ++tc; + map> rec; + for (int i = 0; i < 10; ++i) + { + string x; + int y; + cin >> x >> y; + rec[-y].push_back(x); + } + cout << "Case #" << tc <<":\n"; + for (auto x : rec.begin()->second) + cout << x << '\n'; + } + return 0; +} + +// UVA12157 +signed main() +{ + int t; + cin >> t; + int tc = 1; + while (t--) + { + int n; + cin >> n; + int x = 0, y = 0; + while (n--) + { + int cur; + cin >> cur; + x += ceil(cur/(double)29.9) * 10; + y += ceil(cur/(double)59.9) * 15; + } + cout << "Case " << tc << ": "; + if (x > y) cout << "Juice " << y << '\n'; + else if (x == y) cout << "Mile Juice " << x << '\n'; + else cout << "Mile " << x << '\n'; + ++tc; + } + return 0; +} + +// UVA12468 +signed main() +{ + int a, b; + while (cin >> a >> b && (a != -1 || b != -1)) + cout << min((b - a + 100) % 100, (a - b + 100) % 100) << '\n'; + return 0; +} + +// UVA12503 +signed main() +{ + int t; + cin >> t; + while (t--) + { + int n; + cin >> n; + vector instr(n); // true = left, false = right + int pos = 0; + for (int i = 0; i < n; ++i) + { + string x; + cin >> x; + if (x == "LEFT") instr[i] = true, pos--; + else if (x == "RIGHT") instr[i] = false, pos++; + else + { + int num; + cin >> x; + cin >> num; + instr[i] = instr[num-1]; + if (instr[i]) pos--; + else pos++; + } + } + cout << pos << '\n'; + } + return 0; +} +``` + +### Easy + +```cpp +// UVA00119 +signed main() +{ + int n; + cin >> n; + while (true) + { + unordered_map rec; + vector rec2(n); + for (int i = 0; i < n; ++i) + { + string name; + cin >> name; + rec[name] = i; + rec2[i] = name; + } + vector> adj[n]; + for (int i = 0; i < n; ++i) + { + string name; + int amount, num; + cin >> name >> amount >> num; + if (num == 0) continue; + int div = amount/num; + int from = rec[name]; + while (num--) + { + cin >> name; + adj[from].push_back({rec[name], div}); + } + } + int score[n] {}; + for (int x = 0; x < n; ++x) + { + for (auto y : adj[x]) + { + score[x] -= y.second; + score[y.first] += y.second; + } + } + for (int i = 0; i < n; ++i) + cout << rec2[i] << " " << score[i] << '\n'; + if (cin >> n) cout << '\n'; + else break; + } + return 0; +} + +// UVA00573 +signed main() +{ + double h, d, n, f; + while (cin >> h >> d >> n >> f && (h != 0 || d != 0 || n != 0 || f != 0)) + { + int day = 1; + double init_d = d, cur = 0; + while (true) + { + cur += (d - n); + if (d > 0) d -= (f * init_d) / (double)100; + if (cur+n > h) + { + cout << "success on day " << day << '\n'; + break; + } + else if (cur < 0) + { + cout << "failure on day " << day << '\n'; + break; + } + day++; + } + } + return 0; +} + +// UVA00661 +signed main() +{ + int n, m, c; + int tc = 1; + while (cin >> n >> m >> c && (n != 0 || m != 0 || c != 0)) + { + int arr[n]; + for (int i = 0; i < n; ++i) cin >> arr[i]; + int v = 0, ans = 0; + cout << "Sequence " << tc << '\n'; + bool res = true; + while (m--) + { + int x; + cin >> x; + x--; + arr[x] *= -1; + v -= arr[x]; + ans = max(ans, v); + if (ans > c) res = false; + } + if (res) + { + cout << "Fuse was not blown.\n"; + cout << "Maximal power consumption was " << ans << " amperes.\n"; + } + else cout << "Fuse was blown.\n"; + cout << '\n'; + ++tc; + } + return 0; +} + +// UVA10141 +signed main() +{ + int r, n, tc = 0; + string x; + while (cin >> r >> n && (r != 0 || n != 0)) + { + tc++; + double price = 2000000000, p; + int reqMet = -1, rm; + string name, nam; + for (int i = 0; i < r; i++) cin.ignore(), getline(cin, x); + while (n--) + { + getline(cin, nam); + scanf("%lf %d\n", &p, &rm); + if ((rm > reqMet) || (rm == reqMet && p < price)) + reqMet = rm, name = nam, price = p; + for (int i = 0; i < rm; i++) getline(cin, x); + } + + if (tc > 1) cout << '\n'; + cout << "RFP #" << tc << '\n'; + cout << name << '\n'; + } + + return 0; +} + +// UVA10324 +signed main() +{ + string str; + int tc = 1; + while (cin >> str && str != "0") + { + int arr[str.size()+1]; + arr[0] = 0; + for (int i = 1; i <= str.size(); ++i) + arr[i] = arr[i-1] + (str[i-1] - '0'); + int q; + cin >> q; + cout << "Case " << tc << ":\n"; + while (q--) + { + int x, y; + cin >> x >> y; + int p = min(x, y), q = max(x, y); + if (arr[q+1] - arr[p] == 0 || arr[q+1] - arr[p] == q-p+1) cout << "Yes" << '\n'; + else cout << "No" << '\n'; + } + ++tc; + } + return 0; +} + +// UVA10424 +signed main() +{ + string a, b; + // getline takes empty character cin >> a WOULD NOT + while (getline(cin, a)) + { + getline(cin, b); + int s1 = 0, s2 = 0; + for (int i = 0; i < a.size(); ++i) + { + if (a[i] >= 'a' && a[i] <= 'z') s1 += a[i] - 'a' + 1; + if (a[i] >= 'A' && a[i] <= 'Z') s1 += a[i] - 'A' + 1; + } + for (int i = 0; i < b.size(); ++i) + { + if (b[i] >= 'a' && b[i] <= 'z') s2 += b[i] - 'a' + 1; + if (b[i] >= 'A' && b[i] <= 'Z') s2 += b[i] - 'A' + 1; + } + while (s1/10) + { + int cur = 0; + while (s1) + { + cur += s1%10; + s1 /= 10; + } + s1 = cur; + } + while (s2/10) + { + int cur = 0; + while (s2) + { + cur += s2%10; + s2 /= 10; + } + s2 = cur; + } + double ans = min(((double)s1/s2), ((double)s2/s1)); + cout << fixed << setprecision(2) << ans * 100 << " %\n"; + } + return 0; +} + +// UVA10919 +signed main() +{ + int k, m; + while (cin >> k && k != 0) + { + cin >> m; + map courses; + for (int i = 0; i < k; ++i) + { + string x; + cin >> x; + ++courses[x]; + } + bool ans = true; + for (int i = 0; i < m; ++i) + { + int c, r; + cin >> c >> r; + for (int j = 0; j < c; ++j) + { + string x; + cin >> x; + if (courses.find(x) != courses.end()) --r; + } + if (r > 0) ans = false; + } + cout << (ans ? "yes\n" : "no\n"); + } + return 0; +} + +// UVA11507 +signed main() +{ + bends["+z"]["+z"] = "-x", + bends["+z"]["-z"] = "+x"; + bends["-z"]["+z"] = "+x"; + bends["-z"]["-z"] = "-x"; + + bends["+y"]["+y"] = "-x", + bends["+y"]["-y"] = "+x"; + bends["-y"]["+y"] = "+x"; + bends["-y"]["-y"] = "-x"; + + bends["+z"]["+y"] = "+z", + bends["+z"]["-y"] = "+z"; + bends["-z"]["+y"] = "-z"; + bends["-z"]["-y"] = "-z"; + + bends["+y"]["+z"] = "+y", + bends["+y"]["-z"] = "+y"; + bends["-y"]["+z"] = "-y"; + bends["-y"]["-z"] = "-y"; + + bends["+x"]["+y"] = "+y", + bends["+x"]["-y"] = "-y"; + bends["+x"]["+z"] = "+z", + bends["+x"]["-z"] = "-z"; + bends["-x"]["+y"] = "-y", + bends["-x"]["-y"] = "+y"; + bends["-x"]["+z"] = "-z", + bends["-x"]["-z"] = "+z"; + + int n; + while (cin >> n && n) + { + n--; + string ans = "+x", cur; + while (n--) + { + cin >> cur; + if (cur != "No") ans = bends[ans][cur]; + } + cout << ans << '\n'; + } + return 0; +} + +// UVA11586 +signed main() +{ + int t; + cin >> t; + cin.ignore(); + while (t--) + { + string str; + getline(cin, str); + stringstream ss(str); + string temp; + int maleBegining = 0, femaleBeginning = 0; + int maleEnd = 0, femaleEnd = 0; + int n = 0; + while (getline(ss, temp, ' ')) + { + if (temp[0] == 'M') maleBegining++; + else femaleBeginning++; + if (temp[1] == 'M') maleEnd++; + else femaleEnd++; + n++; + } + if ((maleBegining == femaleEnd || maleEnd == femaleBeginning) && n%2 == 0) cout << "LOOP\n"; + else cout << "NO LOOP\n"; + } + return 0; +} + +// UVA11661 +signed main() +{ + int n; + while (cin >> n && n) + { + string str; + cin >> str; + int ans = INT_MAX; + int prev = -1; + char prevTyp = 'X'; + bool flag = false; + for (int i = 0; i < n; ++i) + { + if (str[i] == '.') continue; + if (str[i] == 'Z') + { + cout << "0\n"; + flag = true; + break; + } + if (str[i] == 'R') + { + if (prevTyp == 'D') ans = min(ans, i-prev); + prev = i, prevTyp = str[i]; + } + if (str[i] == 'D') + { + if (prevTyp == 'R') ans = min(ans, i-prev); + prev = i, prevTyp = str[i]; + } + } + if (!flag) cout << ans << '\n'; + } + return 0; +} + +// UVA11683 +signed main() +{ + int a, c; + while (cin >> a && a) + { + cin >> c; + vector arr(c); + for (int i = 0; i < c; ++i) cin >> arr[i]; + int tot, cur; + for (int i = 0; i < c; ++i) + { + if (i == 0) tot = a-arr[i], cur = arr[i]; + else + { + if (arr[i] < cur) + tot += (cur-arr[i]); + } + cur = arr[i]; + } + cout << tot << '\n'; + } + return 0; +} + +// UVA11687 +signed main() +{ + string str; + while (cin >> str && str != "END") + { + int n = str.size(); + if (n == 1 && str[0] == '1') cout << "1\n"; + else + { + int x = 1, prev = n; + while (true) + { + x++; + int nw = to_string(prev).size(); + if (nw == prev) break; + prev = nw; + } + cout << x << '\n'; + } + } + return 0; +} + +// UVA11956 +signed main() +{ + int t, tc = 0; + cin >> t; + while (t--) + { + ++tc; + string ins; + cin >> ins; + int index = 0, out[105] {}; + for (char ch : ins) + { + if (ch == '>') index = (index+1) % 100; + else if (ch == '<') index = (index-1+100) % 100; + else if (ch == '+') out[index] = (out[index]+1) % 256; + else if (ch == '-') out[index] = (out[index]-1+256) % 256; + } + cout << "Case " << tc << ": "; + for (int i = 0; i < 100; ++i) + { + // prints value in hex making upper case and appending leading zeroes making size 2 + cout << hex << uppercase << setw(2) << setfill('0') << out[i]; + if (i < 99) cout << ' '; + else cout << '\n'; + } + } + return 0; +} +``` + +### Game \(Cards\) + +```cpp +// UVA00162 +deque p1, p2, middle; +bool isPlayer = false; +string pickCard() +{ + string card = (isPlayer) ? p2.front() : p1.front(); + if (isPlayer) p2.pop_front(); + else p1.pop_front(); + middle.push_back(card); + return card; +} +int getRank(string card) +{ + if (card[1] == 'A') return 4; + else if (card[1] == 'K') return 3; + else if (card[1] == 'Q') return 2; + else if (card[1] == 'J') return 1; + else return 0; +} +signed main() +{ + string str; + while (cin >> str && str != "#") + { + isPlayer = false; + p1.clear(), p2.clear(), middle.clear(); + p1.push_front(str); + for (int i = 1; i < 52; ++i) + { + cin >> str; + if (i&1) p2.push_front(str); + else p1.push_front(str); + } + string prevCard = pickCard(); + isPlayer = !isPlayer; + int counter = 100; + while (true) + { + int rank = getRank(prevCard); + if (rank) + { + bool countered = false; + while (rank--) + { + if ((isPlayer && p2.empty()) || (!isPlayer && p1.empty())) goto x; + prevCard = pickCard(); + if (getRank(prevCard)) + { + countered = true; + break; + } + } + if (!countered) + { + if (!isPlayer) p2.insert(p2.end(), middle.begin(), middle.end()); + else p1.insert(p1.end(), middle.begin(), middle.end()); + middle.clear(); + } + } + else prevCard = pickCard(); + isPlayer = !isPlayer; + if ((isPlayer && p2.empty()) || (!isPlayer && p1.empty())) break; + } + x:; + if (p1.size() > p2.size()) printf("%d%3d\n", 2, p1.size()); + else printf("%d%3d\n", 1, p2.size()); + } + return 0; +} + +// UVA00462 +signed main() +{ + map suitConversion; + suitConversion['S'] = 0, suitConversion['H'] = 1, suitConversion['D'] = 2, suitConversion['C'] = 3; + char back[4] = {'S', 'H', 'D', 'C'}; + vector ace(4), king(4), queen(4), jack(4), trump(4); + vector count(4); + int points, extraPoints, pos; + string temp; + while (cin >> temp) + { + for (int i = 0; i < 4; ++i) + { + ace[i] = king[i] = queen[i] = jack[i] = trump[i] = false; + count[i] = 0; + } + points = extraPoints = 0; + for (int i = 0; i < 13; ++i) + { + if (i != 0) cin >> temp; + pos = suitConversion[temp[1]]; + if (temp[0] == 'A') ace[pos] = true, points += 4; + else if (temp[0] == 'K') king[pos] = true, points += 3; + else if (temp[0] == 'Q') queen[pos] = true, points += 2; + else if (temp[0] == 'J') jack[pos] = true, points += 1; + ++count[pos]; + } + for (int i = 0; i < 4; ++i) + { + if (ace[i]) trump[i] = true; + if (king[i] && count[i] < 2) --points; + else if (king[i]) trump[i] = true; + if (queen[i] && count[i] < 3) --points; + else if (queen[i]) trump[i] = true; + if (jack[i] && count[i] < 4) --points; + if (count[i] == 2) ++extraPoints; + else if (count[i] < 2) extraPoints += 2; + } + if (trump[0] && trump[1] && trump[2] && trump[3] && points >= 16) cout << "BID NO-TRUMP\n"; + else if (points + extraPoints >= 14) + { + char output = 'S'; + int maxV = 0; + for (int i = 1; i < 4; ++i) + if (count[i] > count[maxV]) maxV = i, output = back[i]; + cout << "BID " << output << '\n'; + } + else cout << "PASS\n"; + } + return 0; +} + +// UVA00555 +struct person { vector cards[4]; }; +int cardRank(char card) +{ + if (card == 'T') return 10; + else if (card == 'J') return 11; + else if (card == 'Q') return 12; + else if (card == 'K') return 13; + else if (card == 'A') return 14; + else return (card - '0'); +} +signed main() +{ + map dir; dir['N'] = 0, dir['E'] = 1, dir['S'] = 2, dir['W'] = 3; + map per; per[0] = 'N', per[1] = 'E', per[2] = 'S', per[3] = 'W'; + map typ; typ['C'] = 0, typ['D'] = 1, typ['S'] = 2, typ['H'] = 3; + map inf; inf[0] = 'C', inf[1] = 'D', inf[2] = 'S', inf[3] = 'H'; + string str; + while (cin >> str && str != "#") + { + int curPer = dir[str[0]]; + person persons[4]; + cin >> str; + for (int i = 0; i < str.size(); i += 2) + { + curPer = (curPer+1) % 4; + persons[curPer].cards[typ[str[i]]].push_back(str[i+1]); + } + cin >> str; + for (int i = 0; i < str.size(); i += 2) + { + curPer = (curPer+1) % 4; + persons[curPer].cards[typ[str[i]]].push_back(str[i+1]); + } + curPer = dir['S']; + for (int counter = 0; counter < 4; curPer = (curPer + 1) % 4, counter++) + { + cout << per[curPer] << ": "; + int sz = 0; + for (int i = 0; i < 4; ++i) + if (!persons[curPer].cards[i].empty()) sz = max(sz, i); + for (int i = 0; i < 4; ++i) + { + sort(persons[curPer].cards[i].begin(), persons[curPer].cards[i].end(), [](char a, char b){ + return (cardRank(a) < cardRank(b)); + }); + for (int x = 0; x < persons[curPer].cards[i].size(); ++x) + { + cout << inf[i] << persons[curPer].cards[i][x]; + if (x != persons[curPer].cards[i].size()-1 || i != sz) cout << " "; + } + } + cout << '\n'; + } + } + + return 0; +} + +// UVA10205 +string values[] = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King", "Ace"}; +string suits[] = {"Clubs", "Diamonds", "Hearts", "Spades"}; +string deck[53]; +void initDeck() +{ + for (int i = 1; i < 53; i++) deck[i] = values[(i - 1) % 13] + " of " + suits[(i - 1) / 13]; + return; +} +void Map(string SourceDeck[], string TargetDeck[], vector> &ShuffleMaps, int ShuffleNumber) +{ + for (int i = 1; i < 53; i++) TargetDeck[i] = SourceDeck[ShuffleMaps[ShuffleNumber][i]]; +} +int main() +{ + int t; + scanf("%d\n", &t); + for (int i = 0; i < t; ++i) + { + scanf("\n"); + int nShuffles; + scanf("%d\n", &nShuffles); + vector> ShuffleMaps; + ShuffleMaps.push_back(*(new vector)); + for (int j = 1; j <= nShuffles; j++) + { + ShuffleMaps.push_back(*(new vector)); + ShuffleMaps[j].push_back(0); + for (int k = 1; k < 53; k++) + { + int T; + scanf("%d", &T); + ShuffleMaps[j].push_back(T); + } + } + + vector Shuffles; + char Input[1000]; + scanf("\n"); + while (fgets(Input, 5, stdin) != NULL) + { + int T; + if (Input[0] == '\n') break; + stringstream s(Input); + s >> T; + Shuffles.push_back(T); + } + + initDeck(); + for (int j = 0; j < Shuffles.size(); j++) + { + string TempDeck[53]; + Map(deck, TempDeck, ShuffleMaps, Shuffles[j]); + for (int k = 1; k < 53; k++) deck[k] = TempDeck[k]; + } + for (int k = 1; k < 53; k++) cout << deck[k] << '\n'; + if (i != t - 1) cout << '\n'; + } + return 0; +} + +// UVA10646 +int main() +{ + int t; + cin >> t; + string pile[27], hand[25]; + for (int tc = 1; tc <= t; ++tc) + { + for (int i = 0; i < 27; ++i) cin >> pile[i]; + for (int i = 0; i < 25; ++i) cin >> hand[i]; + int x, y = 0, temp = 27; + for (int i = 0; i < 3; ++i) + { + x = isdigit(pile[temp-1][0]) ? pile[temp-1][0] - '0' : 10; + y += x; + temp -= 11-x; + } + string p = (y > temp) ? hand[y-1-temp] : pile[y-1]; + cout << "Case "<< tc << ": " << p << '\n'; + } + return 0; +} + +// UVA11678 +int main() +{ + int a, b; + while (cin >> a >> b && (a != 0 || b != 0)) + { + vector alice(a), bob(b); + unordered_set rec1, rec2; + for (int i = 0; i < a; ++i) + { + cin >> alice[i]; + rec1.insert(alice[i]); + } + for (int i = 0; i < b; ++i) + { + cin >> bob[i]; + rec2.insert(bob[i]); + } + int p = 0, q = 0; + for (auto i : rec1) + if (rec2.find(i) == rec2.end()) q++; + for (auto i : rec2) + if (rec1.find(i) == rec1.end()) p++; + cout << min(p, q) << '\n'; + } + return 0; +} + +// UVA12247 +int main() +{ + int a, b, c, d, e, f; + while (cin >> a >> b >> c >> d >> e && (a != 0 || b != 0 || c != 0 || d != 0 | e != 0)) + { + if (d > max({a, b, c}) && e > max({a, b, c})) + { + int f = 1; + while (f == d || f == e || f == a || f == b || f == c) f++; + if (f > 52) cout << "-1\n"; + else cout << f << '\n'; + } + else if ((d > a && d > b && d > c) || (e > a && e > b && e > c) || + (d > b && e > b && d > c && e > c) || + (d > a && e > a && d > c && e > c) || + (d > a && e > a && d > b && e > b)) + { + int count = 0; + if (d > a && d > b && d > c) count = (e < a) + (e < b) + (e < c); + else if (e > a && e > b && e > c) count = (d < a) + (d < b) + (d < c); + else count = ((d < a) || (e < a)) + ((d < b) || (e < b)) + ((d < c) || (e < c)); + int f = max({a, b, c}); + if (count == 1) + { + int pos = 0; + if (d > a && d > b && d > c) + { + if (e < a) pos = 0; + else if (e < b) pos = 1; + else if (e < c) pos = 2; + } + else + { + if (d < a) pos = 0; + else if (d < b) pos = 1; + else if (d < c) pos = 2; + } + if (pos == 0) f = max({b, c}); + else if (pos == 1) f = max({a, c}); + else if (pos == 2) f = max({a, b}); + } + while (f == d || f == e || f == a || f == b || f == c) f++; + if (f > 52) cout << "-1\n"; + else cout << f << '\n'; + } + else cout << "-1\n"; + } + return 0; +} +``` + +### Game \(Chess\) + +```cpp +// UVA00255 +char board[8][8]; +const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, -1, 0, 1}; +void putPieces(int king, int queen) { board[king/8][king%8] = 'K', board[queen/8][queen%8] = 'Q'; } +bool isValid(int x, int y) { return (x >= 0 && y >= 0 && x < 8 && y < 8); } +void calculateMoves(int king, int queen) +{ + int kx = king/8, ky = king%8, qx = queen/8, qy = queen%8; + for (int i = 0; i < 4; ++i) + { + int nkx = kx + dx[i], nky = ky + dy[i]; + if (isValid(nkx, nky) && board[nkx][nky] != 'Q') board[nkx][nky] = 'k'; + } + for (int i = 0; i < 4; ++i) + { + for (int nqx = qx + dx[i], nqy = qy + dy[i]; ; nqx += dx[i], nqy += dy[i]) + { + if (isValid(nqx, nqy) && board[nqx][nqy] != 'K') + { + if (board[nqx][nqy] == 'k') board[nqx][nqy] = '_'; + else board[nqx][nqy] = 'q'; + } else break; + } + } +} +int main() +{ + int k, q, qm; + while (cin >> k >> q >> qm) + { + if (k == q) cout << "Illegal state\n"; + else + { + memset(board, 0, 64); + putPieces(k, q); + calculateMoves(k, q); + if (board[qm / 8][qm % 8] == '_') cout << "Move not allowed\n"; + else if (board[qm / 8][qm % 8] != 'q') cout << "Illegal move\n"; + else + { + memset(board, 0, 64); + putPieces(k, qm); + calculateMoves(k, qm); + int kingMoves = 0; + for (int i = 0; i < 8; ++i) + for (int j = 0; j < 8; ++j) + kingMoves += (board[i][j] == 'k'); + if (kingMoves > 0) cout << "Continue\n"; + else cout << "Stop\n"; + } + } + } + return 0; +} + +// UVA00278 +int main() +{ + int t; + cin >> t; + while (t--) + { + char ch; + int n, m; + cin >> ch >> n >> m; + if (ch == 'r') cout << min(n, m) << '\n'; + else if (ch == 'Q') cout << min(n, m) << '\n'; + else if (ch == 'K') cout << ((m+1)/2 * (n+1)/2) << '\n'; + else if (ch == 'k') + { + int ans = 0; + if (min(m, n) > 0) + { + if (min(m, n) == 1) ans = max(m, n); + else if (min(m, n) == 2) + { + int x = max(m, n); + ans = 4*(x/4) + 2*min((x%4), 2); + } + else ans = (((m+1)/2) * ((n+1)/2)) + ((m/2) * (n/2)); + } + cout << ans << '\n'; + } + } + return 0; +} + +// UVA10849 +int main() +{ + int t; + cin >> t; + while (t--) + { + int a, b, c, d, n; + cin >> n >> c; + while (n--) + { + cin >> a >> b >> c >> d; + if (a == c && b == d) cout << "0\n"; + else if ((a+b)%2 != (c+d)%2) cout << "no move\n"; + else if (a+b == c+d || a-b == c-d) cout << "1\n"; + else cout << "2\n"; + } + } + return 0; +} + +// UVA11494 +int main() +{ + int a, b, c, d; + while (cin >> a >> b >> c >> d && (a || b || c || d)) + { + if (a == c && b == d) cout << "0\n"; + // a-b (no abs) is primary diagonal + // a+b is other diagonal + else if ((a+b == c+d) || ((a-b) == (c-d)) || a == c || b == d) cout << "1\n"; + else cout << "2\n"; + } + return 0; +} +``` + +### Game \(Others\) + +```cpp +// UVA00489 +int main() +{ + int n; + while (cin >> n && n != -1) + { + string a, b; + cin >> a >> b; + set chars; + for (char ch : a) chars.insert(ch); + int count = 0; + bool ended = false; + cout << "Round " << n << '\n'; + set rec; + for (int i = 0; i <= b.size(); ++i) + { + if (chars.empty()) + { + cout << "You win.\n"; + ended = true; + break; + } + if (count >= 7) + { + cout << "You lose.\n"; + ended = true; + break; + } + if (i < b.size()) + { + if (rec.find(b[i]) != rec.end()) continue; + if (chars.find(b[i]) == chars.end()) count++; + else chars.erase(b[i]); + rec.insert(b[i]); + } + } + if (!ended) cout << "You chickened out.\n"; + } + return 0; +} + +// UVA00947 +void solve(vector &arr, vector &cur, int &count, int x, int y, int pos = 0) +{ + if (pos == cur.size()) + { + int count_x = 0, count_y = 0; + map elems; + for (int i = 0; i < cur.size(); ++i) + { + if (arr[i] == cur[i]) count_x++; + else elems[cur[i]]++; + } + for (int i = 0; i < cur.size(); ++i) + { + if (arr[i] != cur[i]) + { + if (elems.find(arr[i]) != elems.end()) + { + count_y++; + elems[arr[i]]--; + if (elems[arr[i]] == 0) elems.erase(arr[i]); + } + } + } + if (count_x == x && count_y == y) count++; + return; + } + for (int i = 1; i <= 9; ++i) + { + cur[pos] = i; + solve(arr, cur, count, x, y, pos+1); + } +} +int main() +{ + int t; + cin >> t; + while (t--) + { + int x, y, count = 0; + string str; + cin >> str >> x >> y; + vector arr(str.size()); + for (int i = 0; i < str.size(); ++i) arr[i] = (str[i] - '0'); + vector cur(arr.size()); + solve(arr, cur, count, x, y); + cout << count << '\n'; + } + return 0; +} + +// UVA10530 +int main() +{ + int n; + string str; + int l = 1, r = 10; + while (cin >> n && n) + { + cin.ignore(); + getline(cin, str); // this min max part caused me 1 WA + if (str == "too high") r = min(r, n-1); + else if (str == "too low") l = max(l, n+1); + else if (str == "right on") + { + if (n >= l && n <= r) cout << "Stan may be honest\n"; + else cout << "Stan is dishonest\n"; + l = 1, r = 10; + } + } + return 0; +} + +// UVA12239 +int main() +{ + int n, b, x[100]; + while (cin >> n >> b && (n || b)) + { + set checker; + for (int i = 0; i < b; ++i) cin >> x[i]; + for (int i = 0; i < b; ++i) + for (int j = i; j < b; ++j) + if (abs(x[i]-x[j]) <= n) checker.insert(abs(x[i]-x[j])); + if (checker.size() == n+1) cout << "Y\n"; + else cout << "N\n"; + } + return 0; +} +``` + +### Game \(Others\) - Hard + +```cpp +// UVA00141 +#define MOD 923673411 +int board[50][50]; +char b[500][50][50]; +int h[500]; +int n; +void copy_p(int p) +{ + int v = 0; + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) + b[p][i][j] = board[i][j], v += (v*2 + board[i][j]) % MOD; + h[p] = v; +} +bool compare(int p, int q) +{ + if (h[p] != h[q]) return false; + return true; + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) + if (b[p][i][j] != b[q][i][j]) return false; + return false; +} +void rotate(int p, int q) +{ + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) + b[q][n-j-1][i] = b[p][i][j]; + int v = 0; + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) + v = (v*2 + b[q][i][j]) % MOD; + h[q] = v; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + while (true) + { + if (cin >> n && n == 0) break; + for (int x = 0; x < n; ++x) + for (int y = 0; y < n; ++y) + board[x][y] = 0; + int p = 0; + copy_p(p++); + int x, y, i; string s; + for (i = 0; i < 2*n; ++i) + { + cin >> x >> y >> s; + x--, y--; + if (s[0] == '+') board[x][y] = 1; + else if (s[0] == '-') board[x][y] = 0; + copy_p(p); + for (int j = 0; j < p; ++j) if (compare(j, p)) goto x; + rotate(p, p+1); rotate(p+1, p+2); rotate(p+2, p+3); + p += 4; + } + cout << "Draw\n"; + goto y; + x:; + cout << "Player " << (((i+1)&1)+1) << " wins on move " << i+1 << '\n'; + for (i++; i < 2*n; ++i) cin >> x >> y >> s; + y:; + } + return 0; +} + +// UVA00339 + +// UVA00379 + +// UVA00584 + +// UVA00647 + +// UVA10363 +bool hasNotWon(vector &grid, char ch) +{ + if (grid[0][0] == ch && grid[0][1] == ch && grid[0][2] == ch) return false; + if (grid[1][0] == ch && grid[1][1] == ch && grid[1][2] == ch) return false; + if (grid[2][0] == ch && grid[2][1] == ch && grid[2][2] == ch) return false; + if (grid[0][0] == ch && grid[1][0] == ch && grid[2][0] == ch) return false; + if (grid[0][1] == ch && grid[1][1] == ch && grid[2][1] == ch) return false; + if (grid[0][2] == ch && grid[1][2] == ch && grid[2][2] == ch) return false; + if (grid[0][0] == ch && grid[1][1] == ch && grid[2][2] == ch) return false; + if (grid[0][2] == ch && grid[1][1] == ch && grid[2][0] == ch) return false; + return true; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t; + cin >> t; + vector grid(3); + while (t--) + { + int xcount = 0, ocount = 0; + for (int i = 0; i < 3; ++i) + { + cin >> grid[i]; + for (char ch : grid[i]) + { + if (ch == 'X') ++xcount; + else if (ch == 'O') ++ocount; + } + } + bool valid = false; + if (xcount == ocount) valid = hasNotWon(grid, 'X'); + else if (xcount == ocount+1) valid = hasNotWon(grid, 'O'); + else valid = false; + + if (valid) cout << "yes\n"; + else cout << "no\n"; + } + return 0; +} + +// UVA10443 + + +// UVA10813 +bool bingo[5][5]; +int call[75], card[5][5]; +bool check() +{ + bool flag; + for (int i = 0; i < 5; ++i) + { + flag = true; + for (int j = 0; j < 5; ++j) + if (!bingo[i][j]) { flag = false; break; } + if (flag) return true; + } + + for (int i = 0; i < 5; ++i) + { + flag = true; + for (int j = 0; j < 5; ++j) + if (!bingo[j][i]) { flag = false; break; } + if (flag) return true; + } + + flag = true; + for (int i = 0; i < 5; ++i) + if (!bingo[i][i]) { flag = false; break; } + if (flag) return true; + + flag = true; + for (int i = 0; i < 5; ++i) + if (!bingo[4-i][i]) { flag = false; break; } + if (flag) return true; + + return false; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; + cin >> n; + while (n--) + { + int hit = -1; + for (int i = 0; i < 5; ++i) + { + for (int j = 0; j < 5; ++j) + { + if (i != 2 || j != 2) cin >> card[i][j]; + bingo[i][j] = false; + } + } + card[2][2] = -1; bingo[2][2] = true; + for (int i = 0; i < 75; ++i) + { + cin >> call[i]; + if (hit < 0) + { + for (int j = 0; j < 5; ++j) + for (int k = 0; k < 5; ++k) + if (call[i] == card[j][k]) bingo[j][k] = true; + if (check()) hit = i; + } + } + cout << "BINGO after " << hit+1 << " numbers announced" << '\n'; + } + return 0; +} + +// UVA10903 +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, k; + map mp; + mp["rock"] = "paper"; mp["paper"] = "scissors"; mp["scissors"] = "rock"; + bool first = true; + while (cin >> n && n) + { + cin >> k; + if (!first) cout << '\n'; + k = k * n * (n-1) / 2; + first = false; + string p, q; int x, y; + map wins; + map loses; + set players; + while (k--) + { + cin >> x >> p >> y >> q; + players.insert(x); players.insert(y); + if (mp[p] == q) wins[y]++, loses[x]++; + else if (mp[q] == p) wins[x]++, loses[y]++; + } + for (auto x : players) + { + double deno = wins[x] + loses[x]; + if (deno == 0) cout << "-\n"; + else cout << fixed << setprecision(3) << (wins[x] / deno) << '\n'; + } + } + return 0; +} +``` + +### Palindromes + +```cpp +// UVA00353 +bool checkPalindrome(string str) +{ + for (int i = 0, j = str.size()-1; i <= j; ++i, --j) + if (str[i] != str[j]) return false; + return true; +} +int main() +{ + string str; + while (cin >> str) + { + set counter; + for (int i = 1; i <= str.size(); ++i) + { + for (int j = 0; j <= str.size()-i; ++j) + { + string substr = str.substr(j, i); + if (checkPalindrome(substr)) counter.insert(substr); + } + } + cout << "The string '" << str << "' contains " << counter.size() << " palindromes." << '\n'; + } + return 0; +} + +// UVA00401 +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + map mp; + mp['A'] = 'A'; mp['E'] = '3'; mp['H'] = 'H'; mp['I'] = 'I'; mp['J'] = 'L'; + mp['L'] = 'J'; mp['M'] = 'M'; mp['O'] = 'O'; mp['S'] = '2'; mp['T'] = 'T'; + mp['U'] = 'U'; mp['V'] = 'V'; mp['W'] = 'W'; mp['X'] = 'X'; mp['Y'] = 'Y'; + mp['Z'] = '5'; mp['1'] = '1'; mp['2'] = '5'; mp['3'] = 'E'; mp['5'] = 'Z'; + mp['8'] = '8'; + string str; + while (cin >> str) + { + string mirror = str; + bool mirrored = true; + for (char &ch : mirror) + { + if (mp.find(ch) == mp.end()) { mirrored = false; break; } + else ch = mp[ch]; + } + if (mirrored) + { + reverse(all(mirror)); + for (int i = 0; i < str.size(); ++i) + { + if (mirror[i] == str[i]) continue; + else if ((mirror[i] == 'S' || mirror[i] == '5') && (str[i] == 'S' || str[i] == '5')) continue; + else if ((mirror[i] == '0' || mirror[i] == 'O') && (str[i] == '0' || str[i] == 'O')) continue; + else { mirrored = false; break; } + } + } + + string rev = str; + reverse(all(rev)); + bool palindrome = (rev == str); + if (mirrored && palindrome) cout << str << " -- is a mirrored palindrome.\n"; + else if (mirrored && !palindrome) cout << str << " -- is a mirrored string.\n"; + else if (!mirrored && palindrome) cout << str << " -- is a regular palindrome.\n"; + else if (!mirrored && !palindrome) cout << str << " -- is not a palindrome.\n"; + cout << '\n'; + } + return 0; +} + +// UVA10018 +pair solve(int n, int i = 1) +{ + int a = n, b = 0; + while (n) b = ((b * 10) + (n % 10)), n /= 10; + a += b; + string res = to_string(a); + string rev = res; + reverse(all(rev)); + if (rev == res) return {a, i}; + else return solve(a, i+1); +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t, x; + cin >> t; + while (t--) + { + cin >> x; + auto ans = solve(x); + cout << ans.second << " " << ans.first << '\n'; + } + return 0; +} + +// UVA11221 +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t; + cin >> t; + cin.ignore(); + for (int tc = 1; tc <= t; ++tc) + { + string str; + getline(cin, str); + stringstream ss; + for (char &ch : str) + { + if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) + ss << ch; + } + str = ss.str(); + int n = str.size(); + int k = sqrt(n); + cout << "Case #" << tc << ":\n"; + if (k * k != n) cout << "No magic :(\n"; + else + { + bool flag = true; + for (int i = 0, j = n-1; i <= j; ++i, --j) + if (str[i] != str[j]) { flag = false; break; } + if (!flag) cout << "No magic :(\n"; + else + { + for (int i = 0, j = n-1; i <= j; i += k, j -= k) + if (str[i] != str[j]) { flag = false; break; } + if (!flag) cout << "No magic :(\n"; + else cout << k << '\n'; + } + } + } + return 0; +} + +// UVA11309 +``` + +### Anagrams + +```cpp +// UVA00148 + +// UVA00156 + +// UVA00195 + +// UVA00454 + +// UVA00630 + +// UVA00642 + +// UVA10098 +``` + +### Real Life Problems - Easy + +```cpp +// UVA00161 + +// UVA00187 + +// UVA00362 + +// UVA00637 + +// UVA00857 + +// UVA10082 + +// UVA10191 + +// UVA10528 + +// UVA10554 + +// UVA10812 + +// UVA11530 + +// UVA11945 + +// UVA11984 + +// UVA12195 + +// UVA12555 +``` + +### Real Life Problems - Hard + +```cpp +// UVA00139 + +// UVA00145 + +// UVA00333 + +// UVA00346 + +// UVA00403 + +// UVA00447 + +// UVA00448 + +// UVA00449 + +// UVA00457 + +// UVA00538 + +// UVA00608 + +// UVA00706 + +// UVA01061 + +// UVA10415 + +// UVA10659 + +// UVA11223 + +// UVA11743 + +// UVA12342 +``` + +### Time + +```cpp +// UVA00170 + +// UVA00300 + +// UVA00579 + +// UVA00893 + +// UVA10070 + +// UVA10339 + +// UVA10371 + +// UVA10683 + +// UVA11219 + +// UVA11356 + +// UVA11650 + +// UVA11677 + +// UVA11947 + +// UVA11958 + +// UVA12019 + +// UVA12136 + +// UVA12148 + +// UVA12439 + +// UVA12531 +``` + diff --git a/bit-manipulation.md b/bit-manipulation.md new file mode 100644 index 0000000..90cf67c --- /dev/null +++ b/bit-manipulation.md @@ -0,0 +1,453 @@ +# Bit Manipulation + +* C++ type int is a 32-bit type, which means that every int number consists of 32 bits +* Representation is indexed from right to left +* The bit representation of a number is either signed or unsigned +* **Least Significant Bit \(LSB\) & Most Significant Bit \(MSB\):** 99 in binary \(MSB part\)01100011\(LSB part\) so in MSB 01100011 in LSB 11000110 Endiness \(Storing data in memory\) : Little Endian \(LSB\), Big Endian \(MSB\) +* 1's Complement: Toggling every bit ~ +* 2's Complement: -X = ~X + 1 X = ~\(-X-1\) +* \_\_builtin\_clz\(x\): the number of zeros at the beginning of the number \(count leading zeroes\) +* \_\_builtin\_ctz\(x\): the number of zeros at the end of the number \(count trailing zeroes\) +* \_\_builtin\_popcount\(x\): the number of ones in the number +* \(A+B\) = \(A^B\) + 2\(A&B\) + +```cpp +// Multiplication +int mul(int a, int b) +{ + int ans = 0; + for (int i = 0 ; i < 32; ++i) + { + if (b & 1) ans += a; + b = b>>1; + a = a<<1; + } + return ans; +} + +// Swap two numbers without extra space +int x = 10, y = 5; +x = x ^ y; +y = x ^ y; //y = (x ^ y) ^ y = (y ^ y) ^ x = 0 ^ x = x +x = x ^ y; //x = (x ^ y) ^ x = y +``` + +> **Multiplication:** +> i \* 8; +> i << 3; \[8 = 2^3, so use 3\] +> +> **Division:** +> i / 16; +> i >> 4; \[16 = 2^4, so use 4\] +> +> **Modulo:** +> i % 4; +> i & 3; \[4 = 1 << 2, apply \(\(1 << 2\) - 1\), so use 3\] +> +> There are two shifts - logical shift & arithmetic shift. In right both are different for left both are same. Logical shift is normal. In arithmetic most significant signed bit is copied instead of zero. So a negative number remains negative. + +### Repeating elements of array problem + +Given array \[1, 2, 4, 2, 1\] finding xor 1^2^4^2^1 = xor\(1^1\)^\(2^2\)^\(4\) = 0^0^4 = 4 + +Given Array \[1, 1, 2, 2, 4, 5\] we need to find both 4 & 5 + If we simply xor all numbers we will get 4^5 which will definitely be non zero. \(100\)^\(101\)=\(001\) Now if we divide the array elements into two one having 1 at unit place other having 0. \[1, 1, 5\], \[2, 2, 4\] take xor of both to get the ans + If 100\(4\) & 110\(6\) are non repeating numbers we need to divide the array based on tense \(check rightmost set bit pos\) place set or unset + +```cpp +int arr[] = {1, 1, 2, 2, 3, 9}; +int n = sizeof(arr) / sizeof(int); +int xors = 0; +for (int i = 0; i < n; ++i) xors ^= arr[i]; + +int temp = 0; +while(xors > 0) +{ + if (xors&1) break; + ++temp; + xors >>= 1; +} +int mask = 1<>temp)&1) num1 ^= arr[i]; + else num2 ^= arr[i]; +} +cout << num1 << " " << num2 << endl; +``` + +Given array \[7, 7, 3, 4, 2, 4, 3, 3, 4, 7\] all numbers except one is occurring thrice we need to find that number. + add binary position values \(111 + 111 + 011 + 100 + 010 + 100 + 011 + 011 + 100 + 111\) = 676 %3 all digit = 010 = 0.20 + 1.21 + 0.22 = 2 + +```cpp +int arr[] = {7, 11, 3, 4, 9, 4, 3, 3, 4, 7, 9, 9, 7}; + int n = sizeof(arr) / sizeof(int); + + int count[32] {}; + for (int i = 0; i < n; ++i) + { + int cur = arr[i], pos = 0; + while (cur > 0) + { + if (cur&1) ++count[pos]; + ++pos; + cur >>= 1; + } + } + int ans = 0; + for (int i = 0; i < 32; ++i) ans += pow(2, i) * (count[i] % 3); + cout << ans << endl; +``` + +### Calculating number of set bits + +```cpp +int countBits(int n) +{ + //Time: O(number of bits) + int count = 0; + while (n > 0) + { + count += (n&1); + n = n>>1; + } + return count; + + //Time: O(number of set bits) + int count = 0; + while(n) + { + ++count; + n = n&(n-1); + } + + // __builtin_popcount(n); or __builtin_popcountl or __builtin_popcountll +} +``` + +### Get Set Clear ith bit + +```cpp +int getIthBit(int n, int i) +{ + return (n&(1<> (end - start + 1)) its 00111111 +and both of them we will get mask 00111000 + +But you know what this is bullshit XD a way easier solution is create an +array of this struct +*/ +struct myStruct +{ + int x : (3 * 8); + // This will automatically reserve continuous 24 bits or 3 bytes +}; +``` + +### Insertion + +You are given two 32-bit numbers N, M and two bit positions i and j. Write a method to insert M into N such that M starts at bit j and ends at bit i. You can assume that the bits j through i have enough space to fit all of M. That is if M = 10011, you can assume that there are at least 5 bits between j and i. You would not , for example, have j = 3 and i = 2, because M could not fully fit between bit 3 and bit 2. + +Example: N = 10000000000, M = 10011, i = 2, j = 6 +Output: 10001001100 + +```text +Create a mask like this 1111100000111111 then and it with n +then shift m i bits << +Then n | m will be ans +``` + +### Binary to String + +Given a real number between 0 and 1 \(e.g. 0.72\) that is passed in as a double, print the binary representation. If the number cannot be represented accurately in binary with at most 32 characters, print 'ERROR' + +```cpp +/* Say given 0.875 = 1*(2^-1) + 0*(2^-2) + 1*(2^-3) +So in binary it becomes 0.101*/ +void printBinaryFloat(double num) +{ + assert(num >= 0 && num <= 1); + string res = "0."; + while (num) + { + if (res.size() > 32) { cout << "ERROR!\n"; return; } + double x = num*2; + if (x >= 1) { res += '1'; num = r - 1; } + else { res += '0'; num = r; } + } + cout << res << '\n'; +} +``` + +### Flip Bit to Win + +You have an integer and you can flip exactly one bit from a 0 to 1. Write code to find the length of longest sequence of 1s you could create. + +Input: 1775 \(11011101111\) +Output: 8 + +```cpp +/* Easy solution is we create a prefSum from both side. Then iterate +bitstring if 0 comes we will basically try to flip it and max +there will be prefL[i-1] + 1 + prefR[i+1] */ + +/* Better approach is create (ex testacse): +[0, 4, 1, 3, 1, 2, 21] this array it starts for 0 (right to left +in binary) we have 0 zeroes then 4 ones then 1 zero then 3 ones +then 1 zero then 2 ones. */ + +int longestSeq(int n) +{ + vector seq; + bool onesTurn = false; + int cnt = 0; + while (n) + { + if (onesTurn ^ (n&1)) + { + seq.push_back(cnt); + onesTurn = !onesTurn; + cnt = 1; + } + else cnt++; + n >>= 1; + } + if (cnt) seq.push_back(cnt); + seq.push_back(32 - accumulate(seq.begin(), seq.end(), 0)); + + int res = 0; + for (int i = 0; i < seq.size(); i += 2) + { + if (seq[i] == 1) + { + int cur = 1; + if (i-1 >= 0) cur += seq[i-1]; + if (i+1 < seq.size()) cur += seq[i+1]; + res = max(res, cur); + } + } + return res; +} + +/* We can reduce O(N) space to O(1) idea is we only need 3 states +so do both task in one iteration while mainting only 3 states. */ +``` + +### Closest smaller and greater numbers with same number of set bits + +Given a positive integer, print the next smallest and the next largest number that have the same number of 1 bits in their binary representation. + +```cpp +/* Next number: Find rightmost unset bit, and set it +Prev number: Find rightmost set bit, unset it and set all before + +but we have to also maintain set bits count, so if we flip a set to +unset to compensate we must do vice versa to some other bit. + +(Next Greater) +> Flip right most non-trailing zero +eg: 11011001111100 + 11011011111100 +> Clear bits to the right + 11011010000000 +> Maintain set bit cnt from right size + 11011010001111 + +(Prev Smaller) +> Flip right most non-trailing one +eg: 10011110000011 + 10011100000011 +> Clear bits to the right + 10011100000000 +> maintain count from left of chosen point (in step 1) + 10011101110000 */ + +// More optimized approach (TODO explanation) +void getNext(int x) +{ + int cntZeroes = 0, cntOnes = 0, cur = x; + while (cur && !(cur&1)) // cnts no of trailing zeroes + cntZeroes++, cur >>= 1; + while (cur&1) // cnts immediate one set block + cntOnes++, cur >>= 1; + + if (cntZeroes+cntOnes == (8*sizeof(x)-1) || cntZeroes+cntOnes == 0) + return -1; + + return (x + (1<>= 1; + if (cur == 0) return -1; + while (cur && !(cur&1)) cntZeroes++, cur >>= 1; + + return (x - (1< 1010 1010 1010 1010 1010 1010 1010 1010 + // 0x55555555 in bin -> 0101 0101 0101 0101 0101 0101 0101 0101 +} +``` + +### Draw Line + +A monochrome screen is stored as a single array of bytes, allowing eight consecutive pixels to be stored in one byte. The screen has width w, where w is divisible by 8 \(that is, no byte will be split across rows\). The height of the screen, of course, can be derived from the length of the array and the width. Implement a function that draws a horizontal line from \(x1, y\) \(x2, y\). +The method signature should look something like: +`drawLine(byte[] screen, int width, int x1, int x2, int y)` + +```cpp +/* Naive way is iterate (x1, x2) in yth row and set the pixel +we can optimize it by setting entire 8 bytes 0xFF if the gap is +large. */ + +void drawLine(byte[] screen, int width, int x1, int x2, int y) +{ + int startOffset = x1%8, firstFullByte = x1/8; + if (startOffset != 0) firstFullByte++; + int endOffset = x2%8, lastFullByte = x2/8; + if (endOffset != 0) endFullByte++; + + for (int i = firstFullByte; i <= lastFullByte; ++i) + screen[(width/8)*y + i] = (byte)0xFF; + + byte startMask = (byte)(0xFF >> startOffset); + byte endMask = (byte)~(0xFF >> endOffset); + + if (x1/8 == x2/8) // x1 and x2 are same byte + screen[(width/8)*y + (x1/8)] |= (byte)(startMask & endMask); + else + { + if (startOffset != 0) + screen[(width/8)*y + firstFullByte - 1] |= startMask; + if (endOffset != 7) + screen[(width/8)*y + lastFullByte + 1] |= endMask; + } +} +``` + +### [Bitwise AND of numbers in range](https://leetcode.com/problems/bitwise-and-of-numbers-range/) + +```cpp +int rangeBitwiseAnd(int m, int n) +{ + int res = 0; + for (int i = 31; i >= 0; --i) + { + bool p = (m>>i)&1, q = (n>>i)&1; + if (!p && !q) continue; + if (p && q) res += (1<& nums) +{ + int lastPos = nums.size()-1; + for (int i = nums.size()-2; i >= 0; --i) + if (i+nums[i] >= lastPos) lastPos = i; + return lastPos == 0; +} +// TLE +int jump(vector& A) +{ + int n = A.size(); + vector dp(n, INT_MAX); + dp[n-1] = 0; + for (int i = n-2; i >= 0; --i) + { + for (int j = i+1; j <= min(n-1, i+A[i]); ++j) + dp[i] = min(dp[i], 1 + dp[j]); + } + return dp[0]; +} + +/* Simpler solution is with BFS. Start from index 0 and keep +moving, Why BFS? because we want to find shortest jump so BFS will +go in layer wise manner hence will find solution quickest. */ +int jump(vector& nums) +{ + int n = nums.size(); + queue q; + vector visited(n, false); + q.push(0); + visited[0] = true; + int res = 0; + while (!q.empty()) + { + int sz = q.size(); + while (sz--) + { + int cur = q.front(); + q.pop(); + if (cur == n-1) return res; + for (int i = cur+1; i <= min(n-1, cur+nums[cur]); ++i) + { + if (visited[i]) continue; + visited[i] = true; + q.push(i); + } + } + res++; + } + return -1; +} +/* This above solution however gives TLE, even though we are +visiting every node ones but there we are checking through for loop +to avoid this we can extend above idea in a range wise BFS + +[2, 3, 1, 1, 4] +Initially our queue holds 0 element so l = 0, r = 0 +then we get 1st and 2nd element in our queue making l = 1, r = 2 +then we get l = 3, r = 4 +Basically just extending the idea in range manner */ +int jump(vector& nums) +{ + int n = nums.size(), l = 0, r = 0, res = 0; + while (r < n-1) + { + int nxt = r; + for (int i = l; i <= r; ++i) nxt = max(nxt, nums[i]+i); + l = r+1, r = nxt; + ++res; + } + return res; +} +``` + +### [Paint Fence](https://www.lintcode.com/problem/paint-fence/description) + +```cpp +/* Basically 0011 1100 is allowed 0001 1110 is not allowed. +dp[i] = (k-1) * (dp[i-1] + dp[i-2]) +Basically we are taking dp[i-1] combinations and placing a different (non +matching) color to ith one And taking dp[i-2] combinations and painting i-1 +th and ith as same color. */ +int numWays(int n, int k) +{ + int dp[n+1]; + dp[1] = k, dp[2] = k*k; + for (int i = 3; i <= n; ++i) dp[i] = (k-1) * (dp[i-1] + dp[i-2]); + return dp[n]; +} +``` + +### Ugly Number + +```cpp +/* An ugly number is the one whose prime factors only include 2, 3, 5. +Find nth ugly number. +Input: n = 10 +Output: 12 +Explanation: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of +the first 10 ugly numbers. */ +int nthUglyNumber(int n) +{ + int dp[n]; + dp[0] = 1; + int x = 0, y = 0, z = 0; + for (int i = 1; i < n; ++i) + { + dp[i] = min({2*dp[x], 3*dp[y], 5*dp[z]}); + if (dp[i] == 2*dp[x]) x++; + if (dp[i] == 3*dp[y]) y++; + if (dp[i] == 5*dp[z]) z++; + } + return dp[n-1]; +} +/* Genric variation with primes set instead of 2, 3, 5 */ +int nthSuperUglyNumber(int n, vector& primes) +{ + vector mark(primes.size(), 0); + int dp[n]; + dp[0] = 1; + for (int i = 1; i < n; ++i) + { + dp[i] = INT_MAX; + for (int j = 0; j < primes.size(); ++j) + dp[i] = min(dp[i], primes[j] * dp[mark[j]]); + for (int j = 0; j < primes.size(); ++j) + if (primes[j] * dp[mark[j]] == dp[i]) mark[j]++; + } + return dp[n-1]; +} + +/* Now a number is ugly if it's divisible by a, b, c find nth ugly number. +Binary search over values and then count. */ +#define ll long long +ll nthUglyNumber(ll n, ll a, ll b, ll c) +{ + ll l = a, r = 1e18; + ll x1 = lcm(a, b), x2 = lcm(b, c), x3 = lcm(c, a), x4 = lcm(a, lcm(b, c)); + while (l < r) + { + ll mid = l + (r-l)/2; + ll val = mid/a + mid/b + mid/c - mid/x1 - mid/x2 - mid/x3 + mid/x4 + 1; + if (val > n) r = mid; + else l = mid+1; + } + return l; +} +``` + +### Decode Ways + +* [https://leetcode.com/problems/decode-ways/](https://leetcode.com/problems/decode-ways/) +* [https://leetcode.com/problems/decode-ways-ii/](https://leetcode.com/problems/decode-ways-ii/) + +```cpp +int numDecodings(string s) +{ + int n = s.size(); + if (n == 0 || s[0] == '0') return 0; + int dp[n+1]; + dp[0] = 1, dp[1] = 1; + for (int i = 2; i <= n; ++i) + { + int num = stoi(s.substr(i-2, 2)); + dp[i] = ((num <= 26 && num > 9) ? dp[i-2] : 0) + ((s[i-1] == '0') ? 0 : dp[i-1]); + } + return dp[n]; +} + +const int M = 1e9 + 7; +int numDecodings(string s) +{ + int n = s.length(); + vector dp(n+1); + dp[0] = 1; + if (s[0] == '0') return 0; + dp[1] = (s[0] == '*') ? 9 : 1; + for (int i = 2; i <= n; ++i) + { + if (s[i-1] == '0') + { + if (s[i-2] == '1' || s[i-2] == '2') dp[i] = dp[i-2]; + else if (s[i-2] == '*') dp[i] = 2*dp[i-2]; + else return 0; + } + else if (s[i-1] >= '1' && s[i-1] <= '9') + { + dp[i] = dp[i-1]; + if (s[i-2] == '1' || (s[i-2] == '2' && s[i-1] <= '6')) + dp[i] = (dp[i] + dp[i-2]) % M; + else if (s[i-2] == '*') + dp[i] = (s[i-1] <= '6') ? (dp[i] + dp[i-2]*2) % M : (dp[i] + dp[i-2]) % M; + } + else + { + dp[i] = (dp[i-1]*9) % M; + if (s[i-2] == '1') dp[i] = (dp[i] + 9*dp[i-2]) % M; + else if (s[i-2] == '2') dp[i] = (dp[i] + 6*dp[i-2]) % M; + else if (s[i-2] == '*') dp[i] = (dp[i] + 15*dp[i-2]) % M; + } + } + return dp[n]; +} +``` + +### Minimum Cost Path + +![](.gitbook/assets/image%20%28130%29.png) + +Right side given matrix we need to go from top left to bottom right we can only go bottom and right otherwise this question would have infinite possibilities. Left side is the dp each cell having minimum cost till that block. min\(dp\[i-1\]\[j\], dp\[i\]\[j-1\]\) + mat\[i\]\[j\] + +#### **Another Varient** + +![](.gitbook/assets/image%20%2817%29.png) + +If we were given condition to move in any 4 direction then there would have been infinite possibilities. + +This problem can be solved using combinatorics, consider 7x3 grid we have to travel total 8 steps in which 6 are left and 2 are bottom. So ans is 8C2 or 8C2. Ans is m+n-2 C m-1 + +### Increasing Path In a Matrix + +* [https://leetcode.com/problems/longest-increasing-path-in-a-matrix/](https://leetcode.com/problems/longest-increasing-path-in-a-matrix/) + +```cpp +class Solution { +public: + vector dx = {+1, 0, -1, 0}, dy = {0, +1, 0, -1}; + int n, m; + vector> dp; + int solve(vector> &arr, int x, int y) + { + if (dp[x][y] != -1) return dp[x][y]; + int res = 1; + for (int i = 0; i < 4; ++i) + { + int _x = x+dx[i], _y = y+dy[i]; + if (_x >= 0 && _x < n && _y >= 0 && _y < m && arr[_x][_y] > arr[x][y]) + res = max(res, 1 + solve(arr, _x, _y)); + } + return dp[x][y] = res; + } + int longestIncreasingPath(vector>& arr) + { + n = arr.size(); + if (n == 0) return 0; + m = arr[0].size(); + if (m == 0) return 0; + + dp.assign(n, vector (m, -1)); + + int res = 1; + for (int i = 0; i < n; ++i) + for (int j = 0; j < m; ++j) + res = max(res, solve(arr, i, j)); + return res; + } +}; +``` + +### Robot in Maze + +Given M X N board with robot at bottom left side and he has to reach bottom right. He can go - right, top right, bottom right. Find no. of ways to reach in O\(NM\) time and O\(m\) space + +```cpp +/* DP Approach: +0 0 0 1 +0 0 1 3 +0 1 2 5 +1 1 2 4 */ + +/* Combinatorics Approach: +we have 3 operations: A = x+1, y B = x+1, y-1 C = x+1, y+1 +Ap + Bq + Cr = dx, dy +p(x+1) + q(x+1) + r(x+1) = dx +(p + q + r)(1 + x) = dx +p + q + r = dx + +p(y) + q(y-1) + r(y+1) = dy +y(p + q + r) + (r - q) = dy +dy - dx = r - q +simply use extended eucledian find all possible solution */ +``` + +### Probability to reach a point in a grid + +Given W x H grid where L, U, D, R denotes \(left, up, down, right\) part which has been cut out and if player goes there he will fall off. Find the probability of player not falling. + +From above discussions we can say P \(Probability of going x, y\) is + +$$ +P(x, y) = {x+y-2 \choose x-1} / {2^{x+y-2}} +$$ + +We can precompute nCk/2^n using by taking log both sides + +$$ +\left(\frac{n \choose k}{2^n}\right) = 2^{log{{n \choose k}} - log{2^n}} = 2^{log{n!} - log{(n-k)!} - log{k!} - n} +$$ + +![We need to find probToGo to bottomleft of hole and top right of hole then continue DP](.gitbook/assets/image%20%2870%29.png) + +```cpp +const int MAXN = 1e5+5; +double logFact[MAXN]; +inline double func(int n, int k) { return pow(2, logFact[n] - logFact[n-k] - logFact[k] - n); } +inline double probToReach(int x, int y) { return func(x+y-2, x-1); } +logFact[0] = 0; +for (int i = 1; i < MAXN; ++i) logFact[i] = logFact[i-1] + log2(i); +``` + +### Dungeon Game + +```cpp +/* each block reduces (say -2) health or increases (say +30) health, + find health reqd to move from top left to bottom right. + -2 -3 3 7 5 2 + -5 -10 1 6 11 5 + 10 30 -5 1 1 6 +DP(Each state represents health reqd from that pos) DP[0][0] is ans */ +class Solution { +public: + int calculateMinimumHP(vector>& dungeon) + { + int n = dungeon.size(), m = dungeon[0].size(); + vector< vector > DP(n+1, vector(m+1, INT_MAX)); + DP[n][m-1] = DP[n-1][m] = 1; + for (int i = n-1; i >= 0; --i) + { + for (int j = m-1; j >= 0; --j) + { + int reqd = min(DP[i+1][j], DP[i][j+1]) - dungeon[i][j]; + DP[i][j] = reqd <= 0 ? 1 : reqd; + } + } + return DP[0][0]; + } +}; +``` + +### Probability Knight Remain in Chessboard + +Given a knight in a chessboard he can move in 8 directions for exactly k steps what is the probability that the knight remains in the chessboard. + +```cpp +const int K = 8, N = 8; +double DP[K][N][N]; +pair moves[] = { {1, 2}, {2, 1}, {2, -1}, {1, -2}, {-1, -2}, {-2, -1}, {-2, 1}, {-1, 2} }; +double findProb(int startX, int startY, int steps) +{ + memset(DP, 0, sizeof(DP)); + DP[0][startX][startY] = 1.0; + for (int k = 1; k <= steps; ++k) + { + for (int x = 0; x < N; ++x) + { + for (int y = 0; y < N; ++y) + { + for (auto &cur : moves) + { + int newX = x + cur.F, newY = y + cur.S; + if (newX >= 0 && newY >= 0 && newX < N && newY < N) + DP[k][newX][newY] += DP[k-1][x][y] / 8.0; + } + } + } + } + double res = 0.0; + for (int x = 0; x < N; ++x) for (int y = 0; y < N; ++y) res += DP[steps][x][y]; + return res; +} +``` + +[Markov Chain](https://youtu.be/uvYTGEZQTEs) Solution: + +```cpp +/* There'll be 11 degenerate states, Let 10 represent out of board state */ +int states[8][8] = { + { 0, 1, 3, 4, 4, 3, 1, 0 }, + { 1, 2, 5, 6, 6, 5, 2, 1 }, + { 3, 5, 7, 8, 8, 7, 5, 3 }, + { 4, 6, 8, 9, 9, 8, 6, 4 }, + { 4, 6, 8, 9, 9, 8, 6, 4 }, + { 3, 5, 7, 8, 8, 7, 5, 3 }, + { 1, 2, 5, 6, 6, 5, 2, 1 }, + { 0, 1, 3, 4, 4, 3, 1, 0 } +}; +/* T[i][]]: Transposition matrix represents probability of going from ith +state to jth */ +double findProb(int x, int y, int k) +{ + Matrix T(11, 11); + T.mat = { + //0 1 2 3 4 5 6 7 8 9 10 + { 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 6 }, + { 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 5 }, + { 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 4 }, + { 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 4 }, + { 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 4 }, + { 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 2 }, + { 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 2 }, + { 0, 2, 0, 0, 2, 0, 2, 0, 0, 2, 0 }, + { 0, 0, 1, 1, 1, 1, 1, 0, 2, 1, 0 }, + { 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8 } + }; + T *= (1 / (double)8); + return (1.0 - (T^k).mat[states[x][y]][10]); +} +``` + +### Domino Problems + +```cpp +/* You have a 2x1 domino and L shaped tromino. Find ways to fill it in 2xN mat +dp[0][N] represents ways to fill till N col. complete +dp[1][N] represents ways to fill till N col. with last col. having a vacancy */ +const int MOD = 1e9 + 7; +int numTilings(int N) +{ + long long dp[2][max(3, N+1)]; + dp[0][1] = 1, dp[0][2] = 2, dp[1][1] = 0, dp[1][2] = 2; + for (int i = 3; i <= N; ++i) + { + dp[0][i] = ((dp[0][i-1] + dp[0][i-2])%MOD + dp[1][i-1])%MOD; + dp[1][i] = ((2*dp[0][i-2])%MOD + dp[1][i-1]) % MOD; + } + return dp[0][N]; +} +``` + +For problems: Given N x M grid find number of ways to place 1 x 2 and 2 x 1, tiles in it there's a formula which works in O\(NM\) Otherwise it's a complex DP problem with O\(n \* 2^m\) having 2^m instead of 2 \(same idea as above solution\). + +![](.gitbook/assets/image%20%2825%29.png) + +```cpp +#define M_PI 3.14159265358979323846 +inline int ceil(int a, int b) { return (a+b-1)/b; } +int solve(int n, int m) +{ + if (n < 2 && m < 2) return 0; + int ans = 1; + for (int a = 1; a <= ceil(n, 2); ++a) + for (int b = 1; b <= ceil(m, 2); ++b) + ans = ans * (4 * ((cos((M_PI*a)/(n+1)) * cos((M_PI*a)/(n+1))) + (cos((M_PI*b)/(m+1)) * cos((M_PI*b)/(m+1))))); + return ans; +} +``` + +### Wine Selling Problem + +```cpp +//We will use 2D DP storing l & r +int dp[1000][1000]; +int solve(int arr[], int l, int r, int year) +{ + if (l > r) return 0; + if (dp[l][r] != -1) return dp[l][r]; + int q1 = arr[l]*year + solve(arr, l+1, r, year+1); + int q2 = arr[r]*year + solve(arr, l, r-1, year+1); + int ans = max(q1, q2); + dp[l][r] = ans; + return ans; +} +//Without memoization it's complexity was O(2^n) with memoization it is O(N^2) + +//Bottom up approach +int solve(int arr[], int n) +{ + int dp[1000][1000] {}; + int year = n; + for (int i = 0; i < n; ++i) dp[i][i] = year*arr[i]; + --year; + for (int len = 2; len <= n; ++len) + { + int l = 0, r = n-len; + while (l <= r) + { + int temp = l+len-1; + dp[l][temp] = max(arr[l]*year + dp[l+1][temp], + arr[temp]*year + dp[l][temp-1]); + ++l; + } + -year; + } + return dp[0][n-1]; +} + +/* For [2, 3, 5, 1, 4] + 2 3 5 1 4 +2 10 23 43 +3 0 15 37 40 +5 0 0 25 29 +1 0 0 0 5 24 +4 0 0 0 0 20 +*/ + +// Quick way to do diagonal filling (excludes diagonal) +for (int i = 1; i < n; ++i) + for (int j = 0, k = i; k < n; ++k, ++j) +``` + +* Similar: [https://www.geeksforgeeks.org/optimal-strategy-for-a-game-dp-31/](https://www.geeksforgeeks.org/optimal-strategy-for-a-game-dp-31/) + +### Matrix Chain Multiplication + +```text +Given A (10x30) B (30x5) C (5x60) then we need to find +order of multiplication such that operations are +minimized + +(AB)C = (10×30×5) + (10×5×60) = 4500 operations +A(BC) = (30×5×60) + (10×30×60) = 27000 operations. + + 0 1 2 +0 [0, 10x30] [1500, 10x5] [4500, 10x60] +1 [0, 30x5] [9000, 30x60] +2 [0, 5x60] +``` + +### Burst Balloon Problem + +```text +Given values of balloons: 3 1 5 8 +Each bursting means that value * left * right value +We need to burst them such that max val: like in +order-5 1 3 8 (1*5*8 + 3*1*8 + 3*8 + 8 = 96) + +Diagonals represents first balloon which we burst. 0 1 means +balloons within 0 to 1 + 0 1 2 3 +0 3 30 159 167 +1 15 135 159 +2 40 48 +3 40 + +For [0, 2] value left [0, 1] denotes what if we choose [0, 1] to +burst first then we will burst 2 so for ever cell it's +dp[i][j] = max(dp[i][j-1] + arr[j]*arr[j+1], dp[i+1][j] + +arr[0]*arr[j+1]) +``` + +### Rod Cutting Problem + +```text +We have rod of length 5 with pieces value: 2, 5, 7, 8 for +1, 2, 3 & 4 respectively. + 1 2 3 4 5 +2 2 4 6 8 10 +5 2 5 7 10 +5 +7 +``` + +### Longest Increasing Subsequence + +```cpp +/* [3, 10, 2, 1, 20] = [3, 10, 20] = 3 +[3, 2] = [3] or [2] = 1 +[50, 3, 10, 7, 40, 50] = [3, 7, 40, 50] or [3, 10, 40, 50] = 4 */ +// N squared solution is very easy to have + +/* NlogN approach: Length of st denotes LIS formed by including +currently encountered element and maintaining an analogous LIS +behavior. */ +int lengthOfLIS(vector& nums) +{ + set st; + for (int x : nums) + { + auto lb = st.lower_bound(x); + if (lb != st.end()) st.erase(lb); + st.insert(x); + } + for (auto &x : st) cout << x << " "; + return st.size(); +} + +/* If the problem was Find Long Increasing Bitonic subsequence, +bitonic means a subsequence which first increases and then +decreases. Idea is find LIS from Left 2 Right and Right 2 Left +and then add both array then -1. + +2 -1 4 3 5 -1 3 2 [Array] +1 1 2 2 3 1 2 2 [L2R LIS] +2 1 3 2 3 1 2 1 [R2L LIS] +2 1 4 3 5 1 3 2 [Longest Increasing bitonic sequence] */ + +/* Counting minimum number of Increasing subsequences, +[1 3 2 4] it's - 2 i.e 1,3 and 2,4 +[4 3 2 1] it's - 4 i.e. 4,3,2,1 */ +multiset st; +for (auto &x : arr) +{ + auto cur = st.lower_bound(x); + if (cur != st.begin()) st.erase(--cur); + st.insert(x); +} +cout << st.size() << '\n'; +``` + +* [https://leetcode.com/problems/russian-doll-envelopes/](https://leetcode.com/problems/russian-doll-envelopes/) + +```cpp +/* Follow up question do we have to take care of orientation? In that case +rotate envelopes initially such first w is small h is large always. */ + +/* Idea is to apply LIS on one of two i.e. fix the other. So sorting it and +applying same LIS Binary search logic. */ +int binarySearch(vector& dp, int target) +{ + if (dp.size() == 0) return 0; + int l = 0, r = dp.size()-1; + while (l < r) + { + int mid = l + (r-l)/2; + if (dp[mid] < target) l = mid+1; + else r = mid; + } + if (dp[l] >= target) return l; + return dp.size(); +} +/* Why sort second val in desc order? Consider the case +[1,1] [4,5] [4,6] +Sorting second in asc order will give: 1 5 6 +While in desc order it gives: 1 5 which is correct since we can't take 2 values +in LIS having same first value. */ +int maxEnvelopes(vector>& envelopes) +{ + sort(envelopes.begin(), envelopes.end(), [](auto a, auto b) { + return (a[0] == b[0]) ? (a[1] > b[1]) : (a[0] < b[0]); + }); + vector dp; + for (auto e:envelopes) + { + int idx = binarySearch(dp, e[1]); + if (idx == dp.size()) dp.push_back(e[1]); + else dp[idx] = e[1]; + } + return dp.size(); +} +``` + +### [Candy](https://leetcode.com/problems/candy) + +```cpp +// Naive N^2 approach +int candy(vector& ratings) +{ + int n = ratings.size(); + vector candies(n, 1); + bool changes = true; + while (changes) + { + changes = false; + for (int i = 0; i < n; ++i) + { + if (i != n-1 && ratings[i] > ratings[i+1]&& candies[i] <= candies[i+1]) + candies[i] = candies[i+1]+1, changes = true; + if (i > 0 && ratings[i] > ratings[i-1]&& candies[i] <= candies[i-1]) + candies[i] = candies[i-1]+1, changes = true; + } + } + return accumulate(candies.begin(), candies.end(), 0); +} + +// O(N) time with O(N) space approach +int candy(vector& ratings) +{ + int n = ratings.size(); + vector lft(n, 1), rgt(n, 1); + for (int i = 1; i < n; ++i) + if (ratings[i] > ratings[i-1]) lft[i] = lft[i-1]+1; + for (int i= n-2; i >= 0; --i) + if (ratings[i] > ratings[i+1]) rgt[i] = rgt[i+1]+1; + int sm = 0; + for (int i = 0; i < n; ++i) sm += max(lft[i], rgt[i]); + return sm; +} + +/* One pass, constant space appraoch +Observation: Candies are always given increment of 1. Local minimum number of +candies given to a student is 1 so subdistribution is of form 1, 2, 3, ..., n or +n,..., 2, 1 which is (n*(n+1))/2 + +Ratings [1 3 2 3 2 1] + * * + / \ / \ +* * * + \ + * +Give [1 2 1 3 2 1] = 10 +End of ith iteration: (from 1) +C U D O N +0 1 0 0 1 +0 1 1 1 -1 +3 1 0 -1 1 +3 1 1 1 -1 +3 1 2 -1 -1 */ +inline int count(int n) { return (n*(n+1))/2; } +int candy(vector& ratings) +{ + int n = ratings.size(); + if (n <= 1) return n; + int candies = 0, up = 0, down = 0, oldSlope = 0; + for (int i = 1; i < n; ++i) + { + int newSlope = (ratings[i] < ratings[i-1]) ? -1 : ((ratings[i] == ratings[i-1]) ? 0 : 1); + if ((oldSlope == 1 && newSlope == 0) || (oldSlope == -1 && newSlope >= 0)) + candies += count(up) + count(down) + max(up, down), up = 0, down = 0; + if (newSlope == 1) up++; + else if (newSlope == -1) down++; + else candies++; + oldSlope = newSlope; + } + candies += count(up) + count(down) + max(up, down) + 1; + return candies; +} +``` + +### [Length of Longest Fibonacci Subsequence](https://leetcode.com/problems/length-of-longest-fibonacci-subsequence/) + +Find longest subsequences from given array that follows fibonacci property \(x+y = z\) + +```cpp +// Method 1 : N^2 log(MAXN_OF_ARR) +class Solution { +public: + int lenLongestFibSubseq(vector& arr) + { + int n = arr.size(); + unordered_set st(arr.begin(), arr.end()); + + int ans = 0; + for (int i = 0; i < n; ++i) + { + for (int j = i+1; j < n; ++j) + { + int x = arr[j], y = arr[i]+arr[j]; + int len = 2; + while (st.find(y) != st.end()) + { + int z = x+y; + x = y; y = z; + ans = max(ans, ++len); + } + } + } + return ans >= 3 ? ans : 0; + } +}; + +// DP +class Solution { +public: + int lenLongestFibSubseq(vector& arr) + { + int n = arr.size(); + unordered_map ind; + for (int i = 0; i < n; ++i) + ind[arr[i]] = i; + + /* x + y = z i.e. x = z - y (of indices i, j and k respectively) + dp[j][k] stores values we can form after picking j and k, why such + bizare dp? (considering we +2 for ans) because of overlaping problem + 1 2 3 5 we mant some dp already overlapping to be able to fresh start + aswell and also indulge in some other overlapping */ + vector> dp(n, vector(n, 0)); + int ans = 0; + for (int k = 0; k < n; ++k) + { + for (int j = 0; j < k; ++j) + { + int z = arr[k], y = arr[j]; + int x = z-y; + if (x < y && ind.find(x) != ind.end()) + { + int i = ind[x]; + dp[j][k] = dp[i][j]+1; + ans = max(ans, dp[j][k]+2); + } + } + } + return ans >= 3 ? ans : 0; + } +}; +``` + +### Longest Common Subsequence / Substring + +```cpp +/* X = nematode Y = empty +ans is 3 i.e. emt + + i--> + "" A G G T A B +"" 0 0 0 0 0 0 0 +G 0 0 1 1 1 1 1 +X 0 0 1 1 1 1 1 +T 0 0 1 1 2 2 2 +X 0 +T 0 +A 0 +B 0 +dp[i][j] = 1+dp[i-1][j-1] or max(dp[i-1][j], dp[i][j-1]) +depending upon (x[i] == y[j]) + +Longest Common Subsequence (in triplet i.e. 3 strings) - O(N^3)*/ +for (int i = 0; i < s1.size(); ++i) +{ + for (int j = 0; j < s2.size(); ++j) + { + for (int k = 0; k < s3.size(); ++k) + { + if (i == 0 || j == 0 || k == 0) dp[i][j][k] = 0; + else dp[i][j][k] = (s1[i-1] == s2[j-1] && s1[i-1] == s3[k-1]) + ? dp[i-1][j-1][k-1] + 1 + : max({dp[i-1][j][k], dp[i][j-1][k], dp[i][j][k-1]}); + } + } +} +return dp[s1.size()][s2.size()][s3.size()]; + +/* Longest Common Substring is different say in abcdaf & zbcdf. +bcd is longest common substring whearas bcdf is longest common subsequence. +Now dp[i][j] = 1 + dp[i-1][j-1] if same otherwise 0 */ +``` + +### [Count Distinct Subsequence](https://www.spoj.com/problems/DSUBSEQ/) + +```cpp +int n = s.size(); +vector dp(n+1, 0); // subsequence cnt of first i characters +dp[0] = 1; // null char has 1 cnt +unordered_map last; +for (int i = 1; i <= n; ++i) +{ + // why *2 consider it like a bitmap either we taken element or not + dp[i] = 2*dp[i-1]; + if (last.find(s[i-1]) != last.end()) + dp[i] = dp[i] - dp[last[s[i-1]]]; + last[s[i-1]] = i-1; +} +/* '' a b c + 1 2 4 8 + + '' a a a + 1 2 3 4 */ +``` + +Nice variant to this problem: + +[https://codingnotes-ap.gitbook.io/mycodingnotes/-M6x0YvWiA9Kptd-4E8g/practice-archives/hackerrank-problems-hard\#paths-to-a-goal-distinctmoves](https://codingnotes-ap.gitbook.io/mycodingnotes/-M6x0YvWiA9Kptd-4E8g/practice-archives/hackerrank-problems-hard#paths-to-a-goal-distinctmoves) + +### Edit Distance + +```text + i--> + "" S A T U R D A Y +"" 0 1 2 3 4 5 6 7 8 +S 1 0 1 2 3 4 5 6 7 +U 2 +N 3 +D 4 +A 5 +Y 6 + +We want to make saturday -> sunday +each cell represents min operations reqd. to convert inp. to out. + +At any point this DP represents say for i=3, j=1 +We want to make S from SAT this means 2 deletion. so 2 min operations. +replacement: 1 + dp[i-1][j-1] +deletion: 1 + dp[i+1][j] +insertion: 1 + dp[i][j-1] +min of all three is ans of that cell +if charactre matches look for i-1, j-1 element since checking that +element is redundant +``` + +#### [One Edit Distance](https://www.lintcode.com/en/old/problem/one-edit-distance/) + +```cpp +bool isOneEditDistance(string &s, string &t) +{ + int n = s.size(), m = t.size(); + if (abs(n-m) > 1) return false; + + int count = 0, i, j; + for (i = 0, j = 0; i < n, j < m;) + { + if (s[i] == t[j]) i++, j++; + else + { + if (n > m) i++; + else if (n < m) j++; + else i++, j++; + count++; + } + if (count > 1) return false; + } + if (i < n || j < m) count++; + return count == 1; +} +``` + +### Distinct Subsequence + +```text +Input: S = "rabbbit", T = "rabbit" +Output: 3 +Explanation: + +As shown below, there are 3 ways you can generate "rabbit" from S. +(The caret symbol ^ means the chosen letters) + +rabbbit +^^^^ ^^ +rabbbit +^^ ^^^^ +rabbbit +^^^ ^^^ + + "" r a b b b i t + "" 1 1 1 1 1 1 1 1 + r 0 1 1 1 1 1 1 1 + a 0 0 1 1 1 1 1 1 + b 0 0 0 1 2 3 3 3 + b 0 + i 0 + t 0 + + if characters match: DP[i-1][j-1] + DP[i][j-1] + else: DP[i][j-1] +``` + +### Palindrome Problems + +* Longest Palindromic Substring +* Count Palindromic Substring +* Longest Palindromic Subsequence +* Minimum Insertion to form a palindrome +* Palindromic Partition: Minimum cuts to form palindromes +* Count Palindromic Subsequence +* Count Different Palindromic Subsequence + +```cpp +// Longest Palindromic Substring +string longestPalindrome(string s) +{ + if (s.size() <= 1) return s; + int L = 0, R = 0; + for (int i = 0; i < s.size(); ++i) + { + int len = max(expandAroundCenter(s, i, i), expandAroundCenter(s, i, i+1)); + if (len > R-L) L = i - (len-1)/2, R = i + len/2; + } + return s.substr(L, R-L+1); +} +int expandAroundCenter(string s, int L, int R) +{ + while (L >= 0 && R < s.size() && s[L] == s[R]) L--, R++; + return R - L - 1; +} + +// Count Palindromic Substring +int countSubstrings(string s) +{ + if (s.size() <= 1) return 1; + int ans = 0; + for (int i = 0; i < s.size(); ++i) + ans += expandAroundCenter(s, i, i) + expandAroundCenter(s, i, i+1); + return ans; +} + +int expandAroundCenter(string &s, int L, int R) +{ + int cnt = 0; + while (L >= 0 && R < s.size() && s[L] == s[R]) L--, R++, cnt++; + return cnt; +} + +/* Longest Palindromic Subsequence of: agbda + 0 1 2 3 4 5 +0 1 1 1 1 3 4 +1 1 1 1 3 3 +2 1 1 3 3 +3 1 1 1 +4 1 1 +5 1 + +if s[i] == s[j] then dp[i][j] = dp[i+1][j-1] + 2 +else max(dp[i+1][j], dp[i][j-1]) + + +Minimum Insertion to form a palindrome: +dp[l, r] = dp[l+1, r-1] if first and last char are same + min(dp[l, r-1], dp[l+1, r]) otherwise + +Other solution is: str.length - LCS(str, rev_str).length +LCS here is the maximum possible palindrome.*/ + +/* Palindromic Partition: Minimum cuts to form palindromes + abacccbc = 2 + a b a c c c b c +a 0 1 0 1 2 +b 0 1 2 2 2 +a 0 1 1 1 2 +c 0 0 0 1 2 +c 0 0 1 1 +c 0 1 0 +b 0 1 +c 0 + if string(i..j) is palindrome DP[i][j] = 0 + else DP[i][j] = 1 + min(DP[i][k] + DP[k+1][j]), k = i to j-1 +*/ +int minCut(string s) +{ + int n = s.size(); + if (n <= 1) return 0; + vector< vector > isPalind(n, vector(n, false)); + int minCuts[n]; + for (int i = 0; i < n; ++i) minCuts[i] = i; + for (int j = 0; j < n; ++j) + { + for (int i = j; i >= 0; --i) + { + if (s[i] == s[j] && ((j-i <= 2) || isPalind[i+1][j-1])) + { + isPalind[i][j] = true; + minCuts[j] = (i == 0) ? 0 : min(minCuts[j], 1 + minCuts[i-1]); + } + } + } + return minCuts[n-1]; +} + + +/* Count Palindromic Subsequence need not to be distinct: +countPS(str, 0, str.size()-1); +For "bccb" -> b, c, c, cc, b, bb, bcb, bcb, bccb +Complexity: O(N^2)*/ +int countPS(string &str, int i, int j) +{ + if (i > j) return 0; + if (memo[i][j] != -1) return memo[i][j]; + if (i == j) return memo[i][j] = 1; + if (j-i == 1) return memo[i][j] = (str[i] == str[j]) ? 3 : 2; + return memo[i][j] = (str[i] == str[j]) + ? (countPS(str, i+1, j) + countPS(str, i, j-1) + 1) + : (countPS(str, i+1, j) + countPS(str, i, j-1) - countPS(str, i+1, j-1)); +} + +/* Count Different Palindromic Subsequence, here there could be only 4 chars +For "bccb" -> b, c, bb, cc, bcb, bccb +Complexity: O(N^2 * 4)*/ +int memo[1001][1001][4]; +const int MOD = 1e9 + 7; +int solve(string &str, int i, int j, int x) +{ + if (i > j) return 0; + if (i == j) return (str[i] == ('a'+x)); + if (memo[i][j][x] != -1) return memo[i][j][x]; + long long res = 0; + if (str[i] == str[j] && str[i] == (x+'a')) + { + res = (res + 2) % MOD; + for (int ch = 0; ch < 4; ++ch) + res = (res + solve(str, i+1, j-1, ch)) % MOD; + } + else + { + res = (res + solve(str, i+1, j, x)) % MOD; + res = (res + solve(str, i, j-1, x)) % MOD; + res = (res - solve(str, i+1, j-1, x) + MOD) % MOD; + } + return memo[i][j][x] = res; +} +int countPalindromicSubsequences(string str) +{ + memset(memo, -1, sizeof(memo)); + int ans = 0; + for (int i = 0; i < 4; ++i) ans = (ans + solve(str, 0, str.size()-1, i)) % MOD; + return ans; +} + +// Longest Palindromic Substring in O(N) using Manacher's Algorithm +string longestPaindromicManacher(string str, int &start, int &end) +{ + int n = str.size(); + if (n == 0) return ""; + if (n == 1) return str; + n = 2*n + 1; + int L[n]; + L[0] = 0, L[1] = 1; + int C = 1, R = 2, i = 0, iMirror, maxLPSLength = 0, maxLPSCenterPosition = 0, diff = -1; + start = -1, end = -1; + for (i = 2; i < n; i++) + { + iMirror = 2*C-i, L[i] = 0, diff = R - i; + if(diff > 0) L[i] = min(L[iMirror], diff); + while (((i + L[i]) < n && (i - L[i]) > 0) && (((i + L[i] + 1) % 2 == 0) || + (str[(i + L[i] + 1)/2] == str[(i - L[i] - 1)/2] ))) + { + L[i]++; + } + if(L[i] > maxLPSLength) maxLPSLength = L[i], maxLPSCenterPosition = i; + if (i + L[i] > R) C = i, R = i + L[i]; + } + start = (maxLPSCenterPosition - maxLPSLength)/2; + end = start + maxLPSLength - 1; + stringstream ss; + for (i = start; i <= end; ++i) ss << str[i]; + return ss.str(); +} +``` + +### Subset Sum Problem + +```text +Given array = [1 2 4 5 9] + 0 1 2 3 4 5 6 7 8 9 10 11 +1 T T F F F F +2 T T T T F +4 +5 +9 +``` + +### Knapsack + +```text +Total Weight: 7 +Items (weight-val): 1-1, 3-4, 4-5, 5-7 + + (total weight capacity of knapsack) +Val (Weight) 0 1 2 3 4 5 6 7 + 1 (1) 0 1 1 1 1 1 1 1 [we only have 1 quantity of + 4 (3) 0 1 1 4 5 5 5 5 each item, other varient could + 5 (4) 0 1 1 4 5 *6* 6 9 could be having as many item] + 7 (5) 0 1 1 4 5 7 8 9 +``` + +### [Pizza with 3n Slices](https://leetcode.com/problems/pizza-with-3n-slices/) + +```cpp +/* This problem can be broken down into selecting n/3 (given n is divisible by 3) +slices such that they are not adjacent and their sum is maximum possible. Also +since this is a circular array we can select from 1...n-1 elements then 2...n +elements that way the circular property won't violate result. + +Input: slices = [1,2,3,4,5,6] +Output: 10 + +Row represent slices, column is array. dp[i][j] is what max val we can get if we +can have i slices and 1..j elements such that no two chosen slice is adjacent. + 1 2 3 4 5 +1 1 2 3 4 5 +2 1 2 4 6 8 + +Simmilarly for other part + 2 3 4 5 6 +1 2 3 4 5 6 +2 2 3 6 8 10 + +ans = max(8, 10) */ + +int maxSizeSlices(vector& slices) +{ + int n = slices.size(); + int k = n/3; + int dp[k+1][n+1]; // 1 based indexing, j shifted twice cause of dp[i-1][j-2] + memset(dp, 0, sizeof(dp)); + + for (int j = 2; j <= n; ++j) + for (int i = 1; i <= k; ++i) + dp[i][j] = max(dp[i][j-1], dp[i-1][j-2] + slices[j-2]); + int ans = dp[k][n]; + for (int j = 2; j <= n; ++j) + for (int i = 1; i <= k; ++i) + dp[i][j] = max(dp[i][j-1], dp[i-1][j-2] + slices[j-1]); + ans = max(ans, dp[k][n]); + return ans; +} +``` + +### Maximum Submatrix with sides x + +```cpp +/* mat[6][6] = X O X X X X + X O X X O X + X X X O O X + O X X X X X + X X X O X O + O O X O O O +DP[6][6] = [1,1] [0,0] [1,1] [2,1] [3,1] [4,1] + [1,2] [0,0] [1,2] [2,2] [0,0] [1,2] + [1,3] [2,1] [3,3] [0,0] [0,0] [1,3] + [0,0] [1,2] [2,4] [3,1] [4,1] [5,4] + [1,1] [2,3] [3,5] [0,0] [1,2] [0,0] + [0,0] [0,0] [1,6] [0,0] [0,0] [0,0] + +After that: (zero-indexed) */ +int res = 0; +for (int i = n-1; i >= 1; --i) +{ + for (int j = n-1; j >= 1; --j) + { + int cur = getMin(DP[i][j].F, DP[i][j].S); + while (cur > res) + { + if (DP[i][j-cur+1].S >= cur && DP[i-cur+1][j].F >= cur) res = cur; + cur--; + } + } +} +return res; +``` + +### Kaden's Algorithm on Product + +```cpp +int maxProduct(vector& nums) +{ + int ans = nums[0], maxToHere = nums[0], minToHere = nums[0]; + for (int i = 1; i < nums.size(); ++i) + { + int prevMaxToHere = maxToHere; + int x = nums[i]; + maxToHere = max({minToHere * x, prevMaxToHere * x, x}); + minToHere = min({minToHere * x, prevMaxToHere * x, x}); + ans = max(ans, maxToHere); + } + return ans; +} +``` + +### Kaden to find Maximum Sum Sub-matrix + +```cpp +/* + 2 1 -3 -4 5 2 3 0 -4 1 + 0 6 3 4 1 0 6 9 13 14 + 2 -2 -1 4 -5 2 0 -1 3 -2 +-3 3 1 0 3 -3 0 1 1 4 + [Horizontal prefix sum matrix] +Idea is to reduce N^4 brute force to N^3 using kaden (so we are converting +problem to Kaden) Iterate over all possible L, R and then using prefixsm mat +find a single column mat on which apply kaden to find maximum. +``` + +### Egg Dropping Puzzle + +There are n floors and k eggs if we drop an egg from a floor and it breaks we cannot reuse it otherwise we can, What is the minimum number of moves required to find at which floor egg breaks. + +![](.gitbook/assets/image%20%2843%29.png) + +```cpp +/* Naive DP: 1 + min_for_x_1_to_N(max(DP[e-1, x-1], DP[e, n-x])) +It's straightforward, if we throw egg it breaks means we have e-1 eggs +and n-1 floors otherwise n-1 floors and e eggs. This leads us to O(KN^2) solution. + +Now DP[k, n] function is monotonic increasing on N because of that +T1: DP[k-1, x-1] is also increasing but T2: DP[k, n-x] is decreasing on x. +[Refer image] +T1 < T2 (x is too small) T1 > T2 (x is too large) +So apply binary search accordingly. */ +unordered_map memo; +int superEggDrop(int k, int n) +{ + if (n == 0) return 0; + if (k == 1) return n; + if (memo.find(n*1000 + k) != memo.end()) return memo[n*1000 + k]; + int l = 1, r = n; + while (l < r) + { + int mid = l + (r-l)/2; + if (superEggDrop(k-1, mid-1) < superEggDrop(k, n-mid)) l = mid+1; + else r = mid; + } + return memo[n*1000 + k] = 1 + max(superEggDrop(k-1, l-1), superEggDrop(k, n-l)); +} +``` + +### **Text Justification** + +```cpp +//Greedy +vector fullJustify(vector& words, int maxWidth) +{ + vector res, cur; + int len = 0; + string str; + for (int i = 0; i < words.size(); ++i) + { + if (len+cur.size()+words[i].size() <= maxWidth) + { + cur.push_back(words[i]); + len += words[i].size(); + } + else + { + if (cur.size() == 1) + { + str = cur[0]; + str.append(maxWidth - str.size(), ' '); + } + else + { + int div = (maxWidth - len) / (cur.size() - 1); + int mod = (maxWidth - len) % (cur.size() - 1); + str = cur[0]; + for (int j = 1; j < cur.size(); ++j) + { + if (j <= mod) str.append(div+1, ' '); + else str.append(div, ' '); + str += cur[j]; + } + } + res.push_back(str); + cur.clear(); + cur.push_back(words[i]); + len = words[i].size(); + } + } + + // Last line, add space in the right side + str = cur[0]; + for (int j = 1; j < cur.size(); ++j) str += ' ' + cur[j]; + str.append(maxWidth - str.size(), ' '); + res.push_back(str); + return res; +} + +/* Given: Tushar Roy likes to code Width: 10 + spaces +Tushar Roy -> 0 +likes to -> 2 +code -> 6 + + spaces +Tushar -> 4 +Roy likes -> 1 +to code -> 3 + +we check badness of arrangement by space left squared sum +(we could have even taken cube it's just to make it sensitive to minor errors) +so 40 & 26. Greedy approach of fitting as many words will fail. + +This dp represents badness of picking i-j elements to display on one line +of given width + 0 1 2 3 4 +0 16 0 INF INF INF +1 49 1 INF INF +2 25 4 INF +3 64 9 +4 36 + +Now we will create another dp table that will keep track of minimum badness for +each new word we put +[16, 0, 17, 4, 26] +last index has the answer of total badness */ +``` + +### Interleaving Strings + +```cpp +/* Given three strings A, B and C. Write a function that +checks whether C is an interleaving of A and B. C is +said to be interleaving A and B, if it contains all +characters of A and B and order of all characters in +individual strings is preserved. */ + +// Simple Solution +bool isInterleave(string a, string b, string c) +{ + int i = 0, j = 0, k = 0; + while (k < c.size()) + { + if (a[i] == c[k]) ++i; + else if (b[j] == c[k]) ++j; + else return false; + ++k; + } + if (i < a.size()-1 || j < b.size()-1) return false; + return true; +} +/* Simple solution doesn’t work if strings A and B have some common characters. +This recursive solution works but works in 2^n complexity. Memoizing requres i, j, +cur all three there are no overlapping subproblems directly if we convert it */ +class Solution { +public: + vector> dp; + bool check(string &s1, string &s2, string &s3, int i = 0, int j = 0) + { + int cur = i + j; + if (i == s1.size() && j == s2.size()) return true; + if (dp[i][j] != -1) return dp[i][j]; + + bool res = false; + if (s3[cur] == s1[i]) res |= check(s1, s2, s3, i+1, j); + if (s3[cur] == s2[j]) res |= check(s1, s2, s3, i, j+1); + return dp[i][j] = res; + } + bool isInterleave(string s1, string s2, string s3) + { + dp = vector>(s1.size()+1, vector(s2.size()+1, -1)); + if (s1.size() + s2.size() != s3.size()) return false; + return check(s1, s2, s3); + } +}; +​ +// DP Approach +class Solution { +public: + bool isInterleave(string s1, string s2, string s3) + { + int len1 = s1.size(), len2 = s2.size(), len3 = s3.size(); + if (len1 + len2 != len3) return false; +​ + // dp[i][j] means s3[0 to i+j-1] is interleaving for s1[0 to i-1] and s2[0 to j-1] + vector< vector > dp(len1 + 1, vector(len2 + 1, false)); + dp[0][0] = true; + for (int i = 1; i <= len1; ++i) + dp[i][0] = (s1[i-1] == s3[i-1]) ? dp[i-1][0] : false; + for (int i = 1; i <= len2; ++i) + dp[0][i] = (s2[i-1] == s3[i-1]) ? dp[0][i-1] : false; + for (int i = 1; i <= len1; ++i) + { + for (int j = 1; j <= len2; ++j) + { + // Current character of s3 matches with current character of + // s1 but not with s2 + if (s1[i-1] == s3[i+j-1] && s2[j-1] != s3[i+j-1]) + dp[i][j] = dp[i-1][j]; + else if (s1[i-1] != s3[i+j-1] && s2[j-1] == s3[i+j-1]) + dp[i][j] = dp[i][j-1]; + else if (s1[i-1] == s3[i+j-1] && s2[j-1] == s3[i+j-1]) + dp[i][j] = (dp[i][j-1] || dp[i-1][j]); + } + } + return dp[len1][len2]; + } +}; +``` + +### [Longest Valid Parentheses](https://leetcode.com/problems/longest-valid-parentheses/) + +```cpp +int longestValidParentheses(string s) +{ + int n = s.size(); + vector dp(n, 0); + int ans = 0; + for (int i = 1; i < n; ++i) + { + if (s[i] == ')') + { + // () + if (s[i-1] == '(') + dp[i] = (i >= 2) ? dp[i-2] + 2 : 2; + // ()(()) = 020026 + else if (i-dp[i-1]-1 >= 0 && s[i-dp[i-1]-1] == '(') + dp[i] = (i-dp[i-1] >= 2) ? + dp[i-1] + dp[i-dp[i-1]-2] + 2 : dp[i-1] + 2; + } + ans = max(ans, dp[i]); + } + return ans; +} + +``` + +### Word Break + +* [https://leetcode.com/problems/word-break/](https://leetcode.com/problems/word-break/) +* [https://leetcode.com/problems/word-break-ii/](https://leetcode.com/problems/word-break-ii/) + +```cpp +bool wordBreak(string s, vector& wordDict) +{ + unordered_set rec; + for (string s : wordDict) rec.insert(s); + string cur = ""; + for (int i = 0; i < s.size(); ++i) + { + cur += s[i]; + if (i == s.size()-1) + return (rec.find(cur) != rec.end()); + if (rec.find(cur) != rec.end()) + cur = ""; + } + return false; +} +/* Above greedy solution won't work for this testcase +"aaaaaaa" ["aaaa","aaa"], DP solution is needed */ +bool wordBreak(string s, vector& wordDict) +{ + unordered_set rec; + for (string s : wordDict) rec.insert(s); + vector DP(s.size(), false); + for (int i = 0; i < s.size(); ++i) + { + for (int j = i; j >= 0; --j) + { + string cur = s.substr(j, i-j+1); + if (rec.count(cur) && (j-1 < 0 || DP[j-1])) { DP[i] = true; break; } + } + } + return DP[s.size()-1]; +} + +// The HARD variation also wants you to show every possible finding +class Solution { +public: + vector dp; + vector> vals; + bool solve(string &s, unordered_map &rec, int cur = 0) + { + if (cur == s.size()) return true; + if (dp[cur] != -1) return dp[cur]; + + bool res = false; + for (int i = cur; i < s.size(); ++i) + { + string x = s.substr(cur, i-cur+1); + auto ind = rec.find(x); + if (ind != rec.end() && solve(s, rec, i+1)) + { + res = true; + vals[cur].push_back(ind->second); + } + } + return dp[cur] = res; + } + vector curAns; + void dfs(vector &wordDict, vector &ans, int cur = 0) + { + if (cur == vals.size()) + { + string finalAns = ""; + for (auto &x : curAns) finalAns += x + ' '; + ans.push_back(finalAns.substr(0, finalAns.size()-1)); + return; + } + for (auto &x : vals[cur]) + { + curAns.push_back(wordDict[x]); + dfs(wordDict, ans, cur + wordDict[x].size()); + curAns.pop_back(); + } + } + vector wordBreak(string s, vector& wordDict) + { + unordered_map rec; + for (int i = 0; i < wordDict.size(); ++i) rec[wordDict[i]] = i; + dp.assign(s.size(), -1); + vals.resize(s.size()); + solve(s, rec); + + vector ans; + curAns.clear(); + dfs(wordDict, ans); + return ans; + } +}; +``` + +### Number of Subsequences of form a^i b^j c^k + +If given string is sorted in a b c order then ans would have been simply: \(2^cnta - 1\) \* \(2^cntb - 1\) \* \(2^cntc - 1\) +2^cnt - 1 because we are doing nCr for all r except r = 1 \(n = cnt here\) this is equal to 2^cnt - 1 + +```cpp +/* If current char is 'a' it can mean - ch begins a new seq., it's part of an +ongoing a's, not any of the two. */ +string str; cin >> str; +int aCnt = 0, bCnt = 0, cCnt = 0; +for (auto &ch : str) +{ + if (ch == 'a') aCnt = (1 + 2*aCnt); + else if (ch == 'b') bCnt = (aCnt + 2*bCnt); + else if (ch == 'c') cCnt = (bCnt + 2*cCnt); +} +cout << cCnt << '\n'; +``` + +### Best time to buy and sell stock + +```cpp +/* I: Consider it as a line graph, we want to buy at valley and sell +at peak */ +int maxProfit(vector& prices) +{ + int mn = INT_MAX; + int ans = 0; + for (auto &x : prices) + { + mn = min(mn, x); + ans = max(ans, x-mn); + } + return ans; +} + +/* II: As many transaction as possible, Continuing upon previous idea we will +sell for every consecutive valley and peak */ +int maxProfit(vector& prices) +{ + if (prices.size() <= 1) return 0; + int n = prices.size(); + int ans = 0; + for (int i = 0; i < n-1; ++i) + { + while (i < n-1 && prices[i] > prices[i+1]) i++; + int valley = prices[i]; + while (i < n-1 && prices[i] < prices[i+1]) i++; + int peak = prices[i]; + ans += peak-valley; + } + return ans; +} + +/* III: At most 2 transactions, it's extension of variation 1 though here +constraint optimizing is done keeping 4 parameters. */ +int maxProfit(vector& prices) +{ + int buy1 = INT_MIN, buy2 = INT_MIN, sell1 = 0, sell2 = 0; + for (auto &x : prices) + { + buy1 = max(buy1, -x); // Keeping profit in mind that's why -x + sell1 = max(sell1, buy1 + x); + buy2 = max(buy2, sell1 - x); + sell2 = max(sell2, buy2 + x); + } + return sell2; +} + +/* IV: At most k transactions, extending idea of IIIrd */ +int maxProfit(int k, vector& prices) +{ + if (k >= prices.size()/2) + { + int ans = 0; + for (int i = 1; i < prices.size(); ++i) + if (prices[i] > prices[i-1]) ans += prices[i] - prices[i-1]; + return ans; + } + vector buy(k+1, INT_MIN), sell(k+1, 0); + for (int &x : prices) + { + for (int i = 1; i <= k; ++i) + { + buy[i] = max(buy[i], sell[i-1] - x); + sell[i] = max(sell[i], buy[i] + x); + } + } + return sell[k]; +} + +/* V: With cooldown, top down version */ +int solve(vector &prices, vector &memo, int cur = 0) +{ + if (cur >= prices.size()) return 0; + if (memo[cur] != -1) return memo[cur]; + int mn = INT_MAX; + int res = 0; + for (int i = cur; i < prices.size(); ++i) + { + mn = min(mn, prices[i]); + res = max(res, (prices[i] - mn) + solve(prices, memo, i+2)); + } + return memo[cur] = res; +} +int maxProfit(vector& prices) +{ + if (prices.size() <= 1) return 0; + vector memo(prices.size(), -1); + return solve(prices, memo); +} + +/* Bottom up version, Consider a 2D DP with n columns and 3 rows: +0 (No transaction on hold) 1 (Currently bought 1) 2 (Sold off) */ +int maxProfit(vector& prices) +{ + int n = prices.size(); + if (n <= 1) return 0; + int dp[3] = {0, -prices[0], INT_MIN}; + for (int i = 1; i < n; ++i) + { + int x = max(dp[0], dp[2]); + int y = max(dp[1], dp[0] - prices[i]); + int z = max(dp[2], dp[1] + prices[i]); + dp[0] = x, dp[1] = y, dp[2] = z; + } + return max(dp[0], dp[2]); +} + +/* VI: With transaction fees */ +int maxProfit(vector& prices, int fee) +{ + int n = prices.size(); + if (n <= 1) return 0; + int dp[3] = {0, -prices[0], -(1<<30)}; + for (int i = 0; i < n; ++i) + { + dp[0] = max(dp[0], dp[2] - fee); + dp[1] = max(dp[1], dp[0] - prices[i]); + dp[2] = max(dp[2], dp[1] + prices[i]); + } + return max(dp[0], dp[2]-fee); +} +``` + +### Weighted Job Scheduling Problem + +Given jobs along with their weights we need to choose such that we get max weight out of it. + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, tuple> arr(n); + for (auto &x : arr) { int s, e, w; cin >> s >> e >> w; x = {e, s, w}; } + sort(all(arr)); + + vec<1, int> dp(n); + dp[0] = get<2>(arr[0]); + for (int i = 1; i < n; ++i) + { + int e = get<0>(arr[i]), s = get<1>(arr[i]), w = get<2>(arr[i]); + int optimal = lower_bound(all(arr), make_tuple(s, 0, 0)) - arr.begin() - 1; + if (optimal >= 0) dp[i] = max({dp[i-1], dp[optimal] + w, w}); + else dp[i] = max(dp[i-1], w); + } + cout << dp[n-1] << '\n'; + return 0; +} +``` + +### Wildcard & Regex Matching + +* [https://leetcode.com/problems/wildcard-matching](https://leetcode.com/problems/wildcard-matching) +* [https://leetcode.com/problems/regular-expression-matching](https://leetcode.com/problems/regular-expression-matching) + +```cpp +/* Wildcard Matching +'?' Matches any single character. +'*' Matches any sequence of characters (including the empty sequence). */ +bool isMatch(string s, string p) +{ + bool dp[s.size()+1][p.size()+1] {}; + dp[0][0] = true; + for (int i = 1; i <= s.size(); ++i) dp[i][0] = false; + for (int i = 1; i <= p.size(); ++i) dp[0][i] = (p[i-1] == '*') ? dp[0][i-1] : false; + for (int i = 1; i <= s.size(); ++i) + { + for (int j = 1; j <= p.size(); ++j) + { + if (p[j-1] == '?') dp[i][j] = dp[i-1][j-1]; + else if (p[j-1] == '*') dp[i][j] = dp[i-1][j] || dp[i][j-1] || dp[i-1][j-1]; + else dp[i][j] = (s[i-1] == p[j-1]) ? dp[i-1][j-1] : false; + } + } + return dp[s.size()][p.size()]; +} + +/* Regex Matching +'.' Matches any single character. +'*' Matches zero or more of the preceding element. +aab -> c*a*b -> true c can be repeated 0 times, a 1 then b + + '' c * a * b +'' T F T F T F +a F F F T T F +a F F F F T F +b F F F F F T */ +bool isMatch(string s, string p) +{ + int m = s.size(), n = p.size(); + vector< vector > dp(m+1, vector(m+1, false)); + dp[0][0] = true; + for (int i = 1; i <= m; ++i) dp[i][0] = false; + for (int j = 1; j <= n; ++j) dp[0][j] = (j > 1 && p[j-1] == '*' && dp[0][j-2]); + for (int i = 1; i <= m; ++i) + { + for (int j = 1; j <= n; ++j) + { + if (p[j-1] != '*') + dp[i][j] = (dp[i-1][j-1] && (s[i-1] == p[j-1] || p[j-1] == '.')); + else + dp[i][j] = (dp[i][j-2] || ((s[i-1] == p[j-2] || p[j-2] == '.') && dp[i-1][j])); + } + } + return dp[m][n]; +} + +``` + +### Travelling Salesman Problem + +Salesman travels over a set of cities, he has to return to source. Minimize total distance travelled by him. Such cycle is also called hamiltonian cycle. We want minimum weight hamiltonian cycle. we will use bitmask to make it efficient. 000001 means out of all 6 cities 1st is visited. + +![](.gitbook/assets/image%20%28155%29.png) + +```cpp +#include +using namespace std; + +int n = 4; +int dist[4][4] = +{ + { 0, 20, 42, 25}, + { 20, 0, 30, 34}, + { 42, 30, 0, 10}, + { 25, 34, 10, 0} +}; +int VISITED_ALL = (1<val is used to memoize + int minCameraCover(TreeNode* root, + bool hasCam = false, bool isMonitored = false) + { + if (!root) return 0; + if (hasCam) + return 1 + minCameraCover(root->left, false, true) + + minCameraCover(root->right, false, true); + + if (isMonitored) + { + int noCam = minCameraCover(root->left, false, false) + + minCameraCover(root->right, false, false); + int rootCam = 1 + minCameraCover(root->left, false, true) + + minCameraCover(root->right, false, true); + return min(noCam, rootCam); + } + + if (root->val != 0) return root->val; + + int rootCam = 1 + minCameraCover(root->left, false, true) + + minCameraCover(root->right, false, true); + int leftCam = (root->left) + ? minCameraCover(root->left, true, false) + + minCameraCover(root->right, false, false): INT_MAX; + int rightCam = (root->right) + ? minCameraCover(root->left, false, false) + + minCameraCover(root->right, true, false) : INT_MAX; + return root->val = min({rootCam, leftCam, rightCam}); + } +}; +``` + +### [Cherry Pickup](https://leetcode.com/problems/cherry-pickup) + +```cpp +/* Greedy method of doing first traverse from top left +to bottom right then bottom right to top left fails! */ + +/* Top down DP approach +We basically have to deal with both case together, we can +reverse the second path because direction won't matter so +we want to find two paths from top left to bottom right +giving maximum count. + +classical one path problem stores states like: dp[r][c] is +maximum cherries that can be picked at r row and c cloumn. +Now we have r1, c1, r2, c2. At any point of traversal +r1 + c1 = r2 + c2 using this we can avoid one term +so, r2 = r1 + c1 - c2 +now we can form simmilar dp[r1][c1][c2] */ +int n, dp[55][55][55]; +int compute(vector> &grid, int r1, int c1, int c2) +{ + int r2 = r1+c1-c2; + if (r1 == n || r2 == n || c1 == n || c2 == n || grid[r1][c1] == -1 || grid[r2][c2] == -1) return INT_MIN; + if (r1 == n-1 && c1 == n-1) return grid[r1][c1]; + if (dp[r1][c1][c2] != INT_MIN) return dp[r1][c1][c2]; + + int ans = grid[r1][c1]; + if (c1 != c2) ans += grid[r2][c2]; + ans += max({compute(grid, r1, c1+1, c2+1), compute(grid, r1+1, c1, c2+1), + compute(grid, r1, c1+1, c2), compute(grid, r1+1, c1, c2)}); + dp[r1][c1][c2] = ans; + return ans; +} +int cherryPickup(vector>& grid) +{ + n = grid.size(); + for (int i = 0; i < 55; ++i) for (int j = 0; j < 55; ++j) for (int k = 0; k < 55; ++k) dp[i][j][k] = INT_MIN; + return max(0, compute(grid, 0, 0, 0)); +} +``` + +### [Number of Music Playlist](https://leetcode.com/problems/number-of-music-playlists/) + +First, what is important in deciding a state? Naive way is to store for every number \(N\) then previous appearance value but this means N+1 states which is insane. To reduce states we have to apply some mathematical relation. After observation, if we have x length of playlist in which y are unique and rest are repeating. So if we have total z ways to have such state then in transitioning: + +* Either we pick a song which is not unique. Multiply by unique-K because we can pick any such song since the gap of K is satisfied. +* We are picking a unique song, Multiply it by N-unique because we can pick any such non picked unique song. + +```cpp +class Solution { +public: + #define ll long long + const int MOD = 1e9+7; + vector> dp; + ll solve(int &N, int &L, int &K, int cur = 0, int unique = 0) + { + if (cur == L) return unique == N; + if (dp[cur][unique] != -1) return dp[cur][unique]; + + ll res = (solve(N, L, K, cur+1, unique) * max(0, unique-K)) % MOD; + (res += (solve(N, L, K, cur+1, unique+1) * (N-unique)) % MOD) %= MOD; + return dp[cur][unique] = res; + } + int numMusicPlaylists(int N, int L, int K) + { + dp.assign(L, vector(L, -1)); + return solve(N, L, K); + } +}; +``` + +### [The Maze](https://www.lintcode.com/problem/the-maze/description) + +```cpp +class Solution { +public: + vector> inRow, inCol; + vector>> inRowG, inColG; + int n, m; + pair getPos(int r, int c, int dir) + { + if (dir == 0) // north + { + auto it = inColG[c].lower_bound(r); + return (it == inColG[c].end()) ? make_pair(0, c) : make_pair(*it+1, c); + } + else if (dir == 1) // east + { + auto it = inRow[r].lower_bound(c); + return (it == inRow[r].end()) ? make_pair(r, m-1) : make_pair(r, *it-1); + } + else if (dir == 2) // south + { + auto it = inCol[c].lower_bound(r); + return (it == inCol[c].end()) ? make_pair(n-1, c) : make_pair(*it-1, c); + } + else // west + { + auto it = inRowG[r].lower_bound(c); + return (it == inRowG[r].end()) ? make_pair(r, 0) : make_pair(r, *it+1); + } + } + vector> dp; + bool canReach(vector &end, pair cur) + { + if (cur.first == end[0] && cur.second == end[1]) return true; + if (dp[cur.first][cur.second] != -1) return dp[cur.first][cur.second]; + + dp[cur.first][cur.second] = false; + for (int dir : {0, 1, 2, 3}) + { + if (canReach(end, getPos(cur.first, cur.second, dir))) return dp[cur.first][cur.second] = true; + } + return false; + } + bool hasPath(vector> &maze, vector &start, vector &destination) + { + n = maze.size(), m = maze[0].size(); + dp.resize(n, vector(m, -1)); inRow.resize(n); inCol.resize(m); inRowG.resize(n); inColG.resize(m); + for (int i = 0; i < n; ++i) + for (int j = 0; j < m; ++j) + if (maze[i][j] == 1) inRow[i].insert(j), inCol[j].insert(i), inRowG[i].insert(j), inColG[j].insert(i); + return canReach(destination, {start[0], start[1]}); + } +}; +``` + +### [Minimum Cost From Leaf Values](https://leetcode.com/problems/minimum-cost-tree-from-leaf-values/) + +```cpp +/* Input: arr = [6,2,4] +Output: 32 +Explanation: +There are two possible trees. The first has +non-leaf node sum 36, and the second has non-leaf +node sum 32. + + 24 24 + / \ / \ + 12 4 6 8 + / \ / \ +6 2 2 4 + +Greedy approach using priority queue won't work. + +This is kinda simillar to a classical DP optimization problem +but not exactly, since we can have any pair combined and not +just consecutive ones. + +We can basically start with root and split optimally */ +#define INF (1<<30) +vector> dp; +int solve(vector> &maxBetween, int l, int r) +{ + if (l == r) return 0; // leaf node + if (dp[l][r] != -1) return dp[l][r]; + int res = INF; + for (int i = l; i < r; ++i) + res = min(res, solve(maxBetween, l, i) + solve(maxBetween, i+1, r) + + maxBetween[l][i]*maxBetween[i+1][r]); + return dp[l][r] = res; +} +int mctFromLeafValues(vector& arr) +{ + vector> maxBetween(arr.size(), vector(arr.size())); + for (int i = 0; i < arr.size(); ++i) + { + maxBetween[i][i] = arr[i]; + for (int j = i+1; j < arr.size(); ++j) + maxBetween[i][j] = max(maxBetween[i][j-1], arr[j]); + } + dp.assign(arr.size(), vector(arr.size(), -1)); + return solve(maxBetween, 0, arr.size()-1); +} +``` + +### Strobogrammatic Number + +* [https://www.lintcode.com/problem/strobogrammatic-number/description](https://www.lintcode.com/problem/strobogrammatic-number/description) +* [https://www.lintcode.com/problem/strobogrammatic-number-ii/description](https://www.lintcode.com/problem/strobogrammatic-number-ii/description) +* [https://leetcode.com/problems/confusing-number/](https://leetcode.com/problems/confusing-number/) +* [https://leetcode.com/problems/confusing-number-ii/](https://leetcode.com/problems/confusing-number-ii/) + +```cpp +/* I - tell if given number is strobogrammatic i.e. looks the same when +rotated 180 degrees (looked at upside down): eg - 69, 88 */ +bool isStrobogrammatic(string &num) +{ + unordered_map mirrorChars; + mirrorChars['0'] = '0', mirrorChars['1'] = '1', mirrorChars['6'] = '9'; + mirrorChars['8'] = '8', mirrorChars['9'] = '6'; + + for (int l = 0, r = num.size()-1; l <= r; ++l, --r) + { + if (mirrorChars.find(num[l]) == mirrorChars.end() || + mirrorChars.find(num[r]) == mirrorChars.end() || + mirrorChars[num[l]] != num[r] || + mirrorChars[num[r]] != num[l]) // this line is redundant + return false; + } + return true; +} +``` + +```cpp +// Find all strobogrammatic numbers that are of length = n. +vector processString(const vector &arr, int n, int total) +{ + vector res; + for (string s : arr) + { + /* no leading zero that's why n != total, if n = 4 then 1001 will + also be there, for inner n = 2 total = 4 */ + if (n != total) res.push_back("0" + s + "0"); + res.push_back("1" + s + "1"); + res.push_back("8" + s + "8"); + res.push_back("6" + s + "9"); + res.push_back("9" + s + "6"); + } + return res; +} +/* total is basically initial value of n (doesn't change) n changes +as per recurssion */ +vector findStrobogrammatic(int n, int total = -1) +{ + if (total == -1) total = n; + if (n == 0) return {""}; + if (n == 1) return {"1", "8", "0"}; + return processString(findStrobogrammatic(n-2, total), n, total); +} + +// Iterative +vector findStrobogrammatic(int n) +{ + vector res; + if (n&1) res = {"0", "1", "8"}; + else res = {""}; + while (n > 1) + { + n -= 2; + vector tempRes; + for (const string s : res) + { + if (n >= 2) tempRes.push_back('0' + s + '0'); + tempRes.push_back('1' + s + '1'); + tempRes.push_back('8' + s + '8'); + tempRes.push_back('6' + s + '9'); + tempRes.push_back('9' + s + '6'); + } + swap(res, tempRes); + } + return res; +} +``` + +```cpp +/* count strobogrammatic between string low and string high. +One solution is iterate over [low.size(), high.size()] for each generate +all strobogrammatic number using above code then do comparison */ +bool compare(string a, string b) { return a.size() == b.size() ? a >= b : a.size() > b.size(); } +int strobogrammaticInRange(string low, string high) +{ + int res = 0; + for (int i = l.size(); i <= r.size(); ++i) + { + for (const string s : findStrobogrammatic(i)) + res += (compare(s, low) && compare(high, s)); + } + return res; +} + +// Other way is to use DFS +int rotate(int x) +{ + int res = 0; + while (x) + { + int cur = x%10; + if (cur == 6) cur = 9; + else if (cur == 9) cur = 6; + res = res*10 + cur; + x /= 10; + } + return res; +} +void dfs(const int n, int &ans, int num = 0) +{ + if (num > n) return; + if (rotate(num) == num) ++ans; // Make != for confusing number II + + if (num) dfs(n, ans, num*10); + dfs(n, ans, num*10 + 1); + dfs(n, ans, num*10 + 6); + dfs(n, ans, num*10 + 8); + dfs(n, ans, num*10 + 9); +} +int countStrobogrammaticFrom1ToN(int n) +{ + int ans = 0; + dfs(n, ans); + return ans; +} +``` + +### Top Down to Bottom Up Conversion : [Student Attendance Record II](https://leetcode.com/problems/student-attendance-record-ii/) + +```cpp +// Top down - TLE +const int MOD = 1e9+7; +vector>> dp; +int solve(const int n, int curDate = 0, bool wasAbsent = false, int wasLate = 0) +{ + if (curDate == n) return 1; + if (dp[curDate][wasAbsent][wasLate] != -1) return dp[curDate][wasAbsent][wasLate]; + + int res = 0; + res = (res + solve(n, curDate+1, wasAbsent, 0)) % MOD; // present + if (!wasAbsent) res = (res + solve(n, curDate+1, true, 0)) % MOD; // absent + if (wasLate < 2) res = (res + solve(n, curDate+1, wasAbsent, wasLate+1)) % MOD; // late + return dp[curDate][wasAbsent][wasLate] = res; +} +int checkRecord(int n) +{ + dp = vector>>(n, vector>(2, vector(3, -1))); + return solve(n); +} + +// Bottom up +int checkRecord(int n) +{ + int dp[n+1][2][3]; + memset(dp, 0, sizeof(dp)); + dp[0][0][0] = 1; + for (int day = 0; day < n; ++day) + { + for (bool wasAbsent : {false, true}) + { + for (int lateDays : {0, 1, 2}) + { + if (dp[day][wasAbsent][lateDays] == 0) continue; + + (dp[day+1][wasAbsent][0] += dp[day][wasAbsent][lateDays]) %= MOD; // present + if (!wasAbsent) + (dp[day+1][true][0] += dp[day][wasAbsent][lateDays]) %= MOD; // absent + if (lateDays < 2) + (dp[day+1][wasAbsent][lateDays+1] += dp[day][wasAbsent][lateDays]) %= MOD; // late + } + } + } + + int res = 0; + for (bool wasAbsent : {false, true}) + { + for (int lateDays : {0, 1, 2}) + (res += dp[n][wasAbsent][lateDays]) %= MOD; + } + return res; +} +``` + +## AtCoder DP Contest + +* [A - Frog 1](https://atcoder.jp/contests/dp/tasks/dp_a): O\(1\) Space solution - [https://atcoder.jp/contests/dp/submissions/12201992](https://atcoder.jp/contests/dp/submissions/12201992) +* [B - Frog 2](https://atcoder.jp/contests/dp/tasks/dp_b): [https://atcoder.jp/contests/dp/submissions/12205560](https://atcoder.jp/contests/dp/submissions/12205560) \(Can be done in O\(K\) space\) +* [C - Vacation](https://atcoder.jp/contests/dp/tasks/dp_c): [https://atcoder.jp/contests/dp/submissions/12205672](https://atcoder.jp/contests/dp/submissions/12205672) +* [D - Knapsack 1](https://atcoder.jp/contests/dp/tasks/dp_d): [https://atcoder.jp/contests/dp/submissions/12205835](https://atcoder.jp/contests/dp/submissions/12205835) \(Can be done in O\(N\) space\) +* [H - Grid 1](https://atcoder.jp/contests/dp/tasks/dp_h): [https://atcoder.jp/contests/dp/submissions/12207877](https://atcoder.jp/contests/dp/submissions/12207877) +* [F - LCS](https://atcoder.jp/contests/dp/tasks/dp_f): [https://atcoder.jp/contests/dp/submissions/12208540](https://atcoder.jp/contests/dp/submissions/12208540) +* [E - Knapsack 2](https://atcoder.jp/contests/dp/tasks/dp_e): [https://atcoder.jp/contests/dp/submissions/12207798](https://atcoder.jp/contests/dp/submissions/12207798) +* [L - Deque](https://atcoder.jp/contests/dp/tasks/dp_l): [https://atcoder.jp/contests/dp/submissions/12218686](https://atcoder.jp/contests/dp/submissions/12218686) +* [I - Coins](https://atcoder.jp/contests/dp/tasks/dp_i): [https://atcoder.jp/contests/dp/submissions/12212430](https://atcoder.jp/contests/dp/submissions/12212430) +* [G - Longest Path](https://atcoder.jp/contests/dp/tasks/dp_g): [https://atcoder.jp/contests/dp/submissions/12213578](https://atcoder.jp/contests/dp/submissions/12213578) \(Apply topological sort then see ending at cur node what's the val DP\[v\] = max\(DP\[v\], DP\[u\] + 1\) +* [R - Walk](https://atcoder.jp/contests/dp/tasks/dp_r): Naive O\(N\*K\) solution which finds K walk using all neighbouring K-1 walks. However it won't work because K is huge here. Adj graph property of exponentiation works here. [https://atcoder.jp/contests/dp/submissions/12269213](https://atcoder.jp/contests/dp/submissions/12269213) +* [Y - Grid 2](https://atcoder.jp/contests/dp/tasks/dp_y): f is n+m-2 C m-1 \(Submission: [https://atcoder.jp/contests/dp/submissions/12289185](https://atcoder.jp/contests/dp/submissions/12289185)\) + +```cpp +arr.push_back({h, w}); +/* Defines our DP order those before i are definitely <= (first & second) */ +sort(all(arr), [](auto x, auto y) { + return x.F + x.S < y.F + y.S; +}); + +vec<1, int> DP(arr.size()); +for (int i = 0; i < arr.size(); ++i) +{ + // All the ways to reach cur point without considering obstacles + int res = f(arr[i].F, arr[i].S); + for (int j = 0; j < i; ++j) + { + /* Check is imp because x+y will also hold true for y+x sorting was + for defining order as all those <= will definitely be before leaving + some exceptions. */ + if (arr[j].F <= arr[i].F && arr[j].S <= arr[i].S) + res = (res - multiply(DP[j], f(arr[i].F-arr[j].F+1, arr[i].S-arr[j].S+1)) + MOD) % MOD; + } + /* Ways to reach that point times ways to reach cur from that point + subtract this since this counts as obstacle */ + DP[i] = res; +} +cout << DP.back() << '\n'; +``` + +* [K - Stones](https://atcoder.jp/contests/dp/tasks/dp_k) - This problem resembles subset sum problem in a way, applying that logic we can have 0...k stone piles for each we can choose n elements. + +```text +n = 3, k = 2 [2 7 3] +DP: 0 1 2 3 + 4 F F F F F means first player can't win + 2 F F T T + 1 F T T F + +DP[i][j] = DP[i-1][j] | DP[i][j-arr[i]] +This relation has a problem that j-arr[i] term must be looked from final (last +row) so we need to perform operation column major form + 0 1 2 3 + F T T F +Here DP[i] |= DP[i-arr[x]] where arr[x] is every item of arr +``` + +[https://atcoder.jp/contests/dp/submissions/12217943](https://atcoder.jp/contests/dp/submissions/12217943) + +* [P - Independent Set](https://atcoder.jp/contests/dp/tasks/dp_p): Consider 1D DP of pairs first denoting combinations ending at that node \(ends at white\) and second \(ends at black\). [https://atcoder.jp/contests/dp/submissions/12231618](https://atcoder.jp/contests/dp/submissions/12231618) +* [M - Candies](https://atcoder.jp/contests/dp/tasks/dp_m): Create a 2D DP with 0..k columns and rows denoting array, now in DP\[i\]\[j\] we want to find min candies if we pick first i childrens and j candies what will be total possibilities, it will simply be DP\[i\]\[j\] += DP\[i-1\]\[j-x\] Where x is 0...arr\[i\] We can optimize this by prefix summing \(i-1\)th DP row, overall making it O\(N\*K\) [https://atcoder.jp/contests/dp/submissions/12221309](https://atcoder.jp/contests/dp/submissions/12221309) +* [Q - Flowers](https://atcoder.jp/contests/dp/tasks/dp_q): It's basically LIS with having maximal sum instead of count. Naive N^2 solution: [https://atcoder.jp/contests/dp/submissions/12255142](https://atcoder.jp/contests/dp/submissions/12255142) To optimize it to run in NlogN time use segment tree, Find max DP from height 0 to height\[i\]-1 [https://atcoder.jp/contests/dp/submissions/12268856](https://atcoder.jp/contests/dp/submissions/12268856) +* [N - Slimes](https://atcoder.jp/contests/dp/tasks/dp_n): First solution that came to mind was wine problem style DP however it will fail for testcase 2 and that's because in wine problem merging happens at ends \(connected\) here any two can pair up. + +```text +Consider like a binary tree +10 10 10 10 10 + \ / / + \ / / + 20,20 / + \ / + \ / + +We basically have to compute such binary tree arrangement giving minimal result +let DP[l][r] denote minimal result from range l to r. +If l = r then it's simply 0 +otherwise we have to merge and let a point x (x is l...r-1) then +DP[l][r] = min for all x: DP[l][x] + DP[x+1][r] + sum(l...r) +``` + +[https://atcoder.jp/contests/dp/submissions/12226101](https://atcoder.jp/contests/dp/submissions/12226101) + +* [S - Digit Sum](https://atcoder.jp/contests/dp/tasks/dp_s): Since our K is super large we cannot use it we have to store it in string and iterate over its digit. At a particular point if we cannot choose a digit bigger that the same moment digit of K \(unless we have encountered a smaller already before\). If we create a DP\[sum\]\[smallerAlready\] we can find count of numbers discovered so far \(while iterating digits\). In the end our answer will be at DP\[d\]\[false\] + DP\[d\]\[true\] but this denotes from 0 to K \(since we still iterate dig from 0 to 9 for 1st num\) so we have to add extra -1 in answer. [https://atcoder.jp/contests/dp/submissions/12245183](https://atcoder.jp/contests/dp/submissions/12245183) +* [O - Matching](https://atcoder.jp/contests/dp/tasks/dp_o): N is very low here so we are going to use bitmasking DP here. let's incremently pair every man with a woman and represent already paired woman in bitmask. Initially none are paired so DP\[0\] = 1 then we will find next state basically pair popcount th man and for woman try with all N woman first check if that one is currently single then add prevCount to newMask. [https://atcoder.jp/contests/dp/submissions/12251462](https://atcoder.jp/contests/dp/submissions/12251462) +* [J - Sushi](https://atcoder.jp/contests/dp/tasks/dp_j): At a particular scenerio sequence doesn't matter only number of plates having 1 sushi 2 sushi... matters so that's what will be represented in our state. Initial state is initial count from there we will move to other states. Keep a, b, c for loop order in mind. We find expected value assuming we reach that stage and then adding expValueWaste is without that assumption. [https://atcoder.jp/contests/dp/submissions/8751646](https://atcoder.jp/contests/dp/submissions/8751646) +* [U - Grouping](https://atcoder.jp/contests/dp/tasks/dp_u): Again a DP with bitmask problem, 2^n states which will represent if we picked those bit position best possible score. Starting from 0 state we first find notTaken positions and then iterate over that set picking element or not picking them. This last part although looks complex is still 3^n because there are only 3 possibilities for every item either taken, already taken, not taken. [https://atcoder.jp/contests/dp/submissions/12278381](https://atcoder.jp/contests/dp/submissions/12278381) Precomputation takes: O\(2^n \* n^2\) Rest takes: O\(2^n \* n + 3^n\) Overall: O\(2^n \* n^2 + 3^n\) +* [Z - Frog 3](https://atcoder.jp/contests/dp/tasks/dp_z): O\(N^2\) solution simmilar to Frog 2 wont work due to constraint. \[Explanation below in convex hull part\] [https://atcoder.jp/contests/dp/submissions/12284255](https://atcoder.jp/contests/dp/submissions/12284255) \[Convex hull trick\] [https://atcoder.jp/contests/dp/submissions/12286413](https://atcoder.jp/contests/dp/submissions/12286413) \[Using Li Chao Tree\] +* X +* T +* V +* W + +## Optimizations + +### Convex Hull Trick + +$$ +DP[i] = min_{j < i}(DP[j] + b[j] * a[i]) +$$ + +* Complexity O\(n^2\) -> O\(n\) +* Condition: b\[i + 1\] <= b\[i\] + +Problem: [https://atcoder.jp/contests/dp/tasks/dp\_z](https://atcoder.jp/contests/dp/tasks/dp_z) + +```cpp +/* DP[i] = min{ DP[j] + (h[j] - h[i])^2 } + C +DP[i] = min{ DP[j] + h[j]^2 - 2h[i]h[j] } + h[i]^2 + C + +min terms are of above form DP[j] + h[j]^2 is const term while +-2h[i]h[j] depends on h[i]. Also given h is increasing + +Idea is to put a line Ax + B where A = -2h[i] and B = dp[i] + h[i]^2 making val +Ax + B at some point h[j] equal to our required minimized expression. +Start denotes initial line which hasn't been removed yet. If first line is >= +second line then we will increment start. + +Final while loop is most important part of code. +If a inters b <= b inters line then popback where a is second last line and b +is last line */ +struct Line +{ + int a, b; + int value(int x) { return (a*x + b); } + pii intersection(Line& other) + { + int p = other.b - b, q = a - other.a; + if (q < 0) p *= -1, q *= -1; + return {p, q}; + } +}; +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, c; cin >> n >> c; + vec<1, int> h(n); + for (auto &x : h) cin >> x; + + vec<1, Line> lines; + int start = 0; + for (int i = 0; i < n; ++i) + { + while (start <= (int)lines.size() - 2) + { + Line a = lines[start], b = lines[start+1]; + if (a.value(h[i]) >= b.value(h[i])) ++start; + else break; + } + + int dp = (i == 0) ? 0 : lines[start].value(h[i]) + h[i]*h[i] + c; + + Line line{ -2*h[i], dp + h[i]*h[i] }; + while (start <= (int)lines.size() - 2) + { + Line a = lines.end()[-2], b = lines.end()[-1]; + pii x = a.intersection(b), y = b.intersection(line); + if (x.F*y.S >= x.S*y.F) lines.pop_back(); + else break; + } + lines.push_back(line); + + if (i == n-1) cout << dp << '\n'; + } + return 0; +} +``` + +### Li Chao tree + +```cpp +const int MAXN = 2e7; +typedef pii point; +point line[4*MAXN]; +int dot(point a, point b) { return (a.F*b.F + a.S*b.S); } +int f(point a, int x) { return dot(a, {x, 1}); } +void addLine(point pt, int v = 1, int l = 0, int r = MAXN) +{ + int m = (l+r) / 2; + bool lef = (f(pt, l) < f(line[v], l)), mid = (f(pt, m) < f(line[v], m)); + if (mid) swap(line[v], pt); + if (r-l == 1) return; + else if (lef != mid) addLine(pt, 2*v, l, m); + else addLine(pt, 2*v + 1, m, r); +} +int get(int x, int v = 1, int l = 0, int r = MAXN) +{ + int m = (l+r) / 2; + if (r-l == 1) return f(line[v], x); + else if (x < m) return min(f(line[v], x), get(x, 2*v, l, m)); + else return min(f(line[v], x), get(x, 2*v + 1, m, r)); +} +``` + +Li Chao Implementation of above problem + +```cpp +for (int i = 0; i < n; ++i) +{ + int dp = (i == 0) ? 0 : get(h[i]) + h[i]*h[i] + c; + addLine({-2*h[i], dp + h[i]*h[i]}); + if (i == n-1) cout << dp << '\n'; +} +``` + +### Divide & Conquer Optimization + +### Knuth Optimization + +## Non Trivial Problems + +* [Boredom](https://codeforces.com/problemset/problem/455/A) - Given an array of n elements. You can pick a number ak and remove it \(only one of it's value instance\) along with all of elements of value ak+1 and ak-1. Doing so you will get ak points, find maximum number of points you can get. **Solution:** Consider frequencies and then traverse across all values. dp\[i\] = max \(dp\[i-1\], count of i \* i + dp\[i-2\]\) If we try finding optimal answer till ith element we can eit +* her remove that element or pick i-1th. [https://codeforces.com/contest/455/submission/72575905](https://codeforces.com/contest/455/submission/72575905) +* [K-Tree](https://codeforces.com/problemset/problem/431/C) - Given a k-nary tree having paths to child of weight 1, 2, 3...k. We want to find number of paths such that it's sum is n and contains atleast one edge of weight atleast d. **Solution:** Write a recursive solution and then memoize it. [https://codeforces.com/contest/431/submission/72577677](https://codeforces.com/contest/431/submission/72577677) +* [Hard Problem](https://codeforces.com/problemset/problem/706/C) - Given n strings and also an array of n integers. ith element in array denotes cost to reverse ith string. We want to arrange strings in lexiographical order in least cost possible. **Solution:** Create a pair of elements dp, first denotes minimal till that point if did not took reverse of ith string while second denotes if we took reverse. There will be four cases for every ith element those are - str\[i\] >= str\[i-1\], >= rev\_str\[i-1\], rev\_str\[i\] >= str\[i-1\], >= rev\_str\[i-1\] [https://codeforces.com/contest/706/submission/72579029](https://codeforces.com/contest/706/submission/72579029) +* [Another Problem On Strings](https://codeforces.com/problemset/problem/165/C) - Given a binary string an a value k, we have to find how many substrings from the given binary string have exactly k 1s in it. **Solution:** We just want to find subarray of sum k, use hashing very simple. [https://codeforces.com/contest/165/submission/72581785](https://codeforces.com/contest/165/submission/72581785) +* [Obtain The String](https://codeforces.com/problemset/problem/1295/C) - Given several testcases each having two strings s & t. We want to make t starting from an empty string by appending only subsequences of s. How many minimum subsequences we have to append. **Solution:** Store positions of each char in s as vector<int> idea is to iterate t and for each char in t we will find upper bound location of same char from previous chosen index. If we can't find such we will increment ans. Using set instead of array gives TLE. [https://codeforces.com/contest/1295/submission/72583393](https://codeforces.com/contest/1295/submission/72583393) +* [Chain Reaction](https://codeforces.com/problemset/problem/607/A) - Given an array of pairs. First denotes coordinate in 1D space, second denotes capacity of that bomb. When ith position bomb is activated it destroys all to its left which are capacity distance away \(inclusive\). We can place a new bomb strictly to the right of any existing one, find minimum no. of bombs that can be destroyed. **Solution:** We can create a dp considering values so dp\[i\] will mean we are considering bombs till ith position what is the maximum no. of bombs that can be destroyed. If we find max then minimum can be found easily by n-mx. Our dp relation will be dp\[i\] = dp\[i - x -1\] + 1. In case i has a valid bomb, x is it's capacity. Otherwise dp\[i\] = dp\[i-1\] [https://codeforces.com/contest/607/submission/72680942](https://codeforces.com/contest/607/submission/72680942) +* [Two Arrays](https://codeforces.com/problemset/problem/1288/C) - Given two numbers n \(<= 1000\) & m \(<= 10\). We have two tell how many combinations of 2 arrays are possible such that a is sorted in non decreasing while b is in non increasing and a\[i\] <= b\[i\]. Size of array should be m and can only contains element b/w 1 to n \(repetition allowed\) **Solution:** Started with a recursive solution which picks current index element for both array basically itterating over all possibilities. To avoid TLE ise memoization. Now naive memoization is \[last0\]\[last1\]\[cur\] but it can be seen that overlapping subproblem holds for \[last1-last0\]\[cur\] so take that. Now observing answers it resolves down to a single formula after looking over OEIS. [https://codeforces.com/contest/1288/submission/72880919](https://codeforces.com/contest/1288/submission/72880919) +* [Dima and a Bad XOR](https://codeforces.com/problemset/problem/1151/B) - Given a matrix of n rows and m columns. We can pick one element from each row and keep xoring them in the end we want > 0 value is it possible? if yes then print sequence of valid picking. **Solution:** My first approach was to create a 2D DP in which dp\[i\]\[j\] represents xor after picking mat\[i\]\[j\] as last value but it gave WA on a trivial case in which xor becomes zero and then can become greater again so doing max is wrong approach. [https://codeforces.com/contest/1151/submission/72972141](https://codeforces.com/contest/1151/submission/72972141) Correct approach is to consider a 2d dp of width 1024 \(as in consider all possible xors we can get\) [https://codeforces.com/contest/1151/submission/72979659](https://codeforces.com/contest/1151/submission/72979659) +* [RGB Substring](https://codeforces.com/problemset/problem/1196/D2) - Given a string of n length containing only RGB characters we want to convert it into a string by changing minimum number of characters such that a substring of modified string having length k is also a substring of RGBRGBRGBRGB... **Solution:** Naive approach which will work in easier version is do 3\*N\*K [https://codeforces.com/contest/1196/submission/73019555](https://codeforces.com/contest/1196/submission/73019555) Better solution is trying matching with pattern in sliding window fashion [https://codeforces.com/contest/1196/submission/73020056](https://codeforces.com/contest/1196/submission/73020056) +* [Star Sky](https://codeforces.com/problemset/problem/835/C) - Prepare a count dp such that we can find in O\(1\) count of particular color value star. Look at constraints carefully this problem is easy after looking that. [https://codeforces.com/problemset/problem/835/C](https://codeforces.com/problemset/problem/835/C) +* [Alyona and Spreadsheet](https://codeforces.com/problemset/problem/777/C) - Given a matrix with 10^5 rows and columns and 10^5 queries giving l & r. In each query we have to tell if we take l-r rows and ignore rest is there atleast 1 column which is sorted non decreasingly. **Solution:** Create a 2D dp marking the longest contiguous sorted column wise. To make it query in logN sort them and use lower bound. [https://codeforces.com/contest/777/submission/73358260](https://codeforces.com/contest/777/submission/73358260) +* [Dasha and Passwords](https://codeforces.com/problemset/problem/761/C) - Preety straight forward recursive + memoization type problem [https://codeforces.com/contest/761/submission/73365985](https://codeforces.com/contest/761/submission/73365985) +* [Colorful Bricks](https://codeforces.com/problemset/problem/1081/C) - Given n, m, k. There's an array of n tiles which we want to paint from given m colors such that exactly k tiles are painted differently from \(i-1\)th tile find number of such tiles possible. **Solution:** Create a 2D DP where dp\[n\]\[k\] is count if we have n tiles and k are different. dp\[n\]\[k\] = dp\[n\]\[k-1\] + dp\[n-1\]\[k-1\]\*\(m-1\) [https://codeforces.com/contest/1081/submission/73431055](https://codeforces.com/contest/1081/submission/73431055) +* [An impassioned circulation of affection](https://codeforces.com/problemset/problem/814/C) - Given a string containing lowercase letters say "kayomi" \(n <= 1500\) next we will be given q queries in each we will be given m & ch. we have to tell max length subsegment of ch if we can repaint m cells. **Solution:** Let's consider we have to find max subsegment of o in "kayomi" we can create a 2D DP\[m+1\]\[n\] where dp\[i\]\[j\] represents maximum subsegment ending at j and we have done i repaints. dp\[i\]\[j\] = dp\[i-1\]\[j-1\] +1 \(if cur j is not o\) dp\[i\]\[j-1\] + 1 \(otherwise\). Now we can't query n^2 inside q queries so instead make a 3D DP storing for every 26 chars. [https://codeforces.com/contest/814/submission/73473937](https://codeforces.com/contest/814/submission/73473937) +* [Caeser's Legion](https://codeforces.com/contest/118/problem/D) - Given n1 n2 k1 k2 we have to place n1 soldiers and n2 horsemen such that atmost k1 soldiers and k2 horsemen are adjacent. Find number of such possible arrangements. **Solution:** Consider a 2D DP suggesting we are placing n1 \(columns\) and n2 \(rows\) dp\[i\]\[j\] is number of ways to place i horsemen and j soldiers while keeping the property now we will observe for dp property to hold we will have to split our 2D dp to 3D dp where z axis will have 2 units. 0 means placement ending with horsement and 1 means placement ending with soldier. Now dp relation can be easily established. [https://codeforces.com/contest/118/submission/74261384](https://codeforces.com/contest/118/submission/74261384) +* [Knapsack for All Segments](https://atcoder.jp/contests/abc159/tasks/abc159_f) - We basically want to find for every L, R pair possible count of subsequences having sum s. **Solution:** Considering 1 based indexing, if there's a subsequence giving sum s then overall it will add upto l\*\(n-r+1\) more to the final result. Fixing r we get \(l1 + l2 + ...\) \* \(n-r+1\) so if we find out for a particular end point r what all start point exists which give subsequence s then we may find the answer. Preparing such DP where DP\[i\]\[j\] means count of left points which have a subsequence of sum s \(l-r subsequence\) so for j == arr\[i\] it's i \(since all left point can be included\) For \(j > arr\[i\]\) it's DP\[k\]\[j\] summation where k is for every < i point so maintaining a prefSum \(vertically across columns\) [https://atcoder.jp/contests/abc159/submissions/12423455](https://atcoder.jp/contests/abc159/submissions/12423455) + diff --git a/game-theory.md b/game-theory.md new file mode 100644 index 0000000..749256f --- /dev/null +++ b/game-theory.md @@ -0,0 +1,2 @@ +# Game Theory + diff --git a/geometry.md b/geometry.md new file mode 100644 index 0000000..7d700a4 --- /dev/null +++ b/geometry.md @@ -0,0 +1,2 @@ +# Geometry Theory + diff --git a/graph-theory.md b/graph-theory.md new file mode 100644 index 0000000..bd658b9 --- /dev/null +++ b/graph-theory.md @@ -0,0 +1,3168 @@ +# Graph Theory + +## Key Points + +* A graph is called dense if it is close to maximum edges otherwise it is sparse. We use adjancy matrix for dense graph and adjancy list for sparse graph. Most of situations are for sparse. +* If not more than 2 children \(then binary tree\) if exactly 0 or 2 children \(then strict binary tree\) +* Indegree of a node is the number of edges that end at the node, and the outdegree of a node is the number of edges that start at the node. +* Full Binary tree: every node has 0 or 2 children +* Complete Binary Tree is a binary tree in which it is completely filled except fot the last level and last level has to be as left as possible so h = log2\(n+1\) - 1 +* Perfect Binary Tree: all internal nodes have 2 children and leaves are at the same level. +* A Perfect Binary Tree of height h \(where height is the number of nodes on the path from the root to leaf\) has 2^h – 1 node. +* A graph is bipartite if it is possible to color it's node it using two colors such that no adjacent have same color. +* A graph is simple if no edge starts and ends at the same node. \(self loop, parallel edges\) +* A tree is a connected graph that consists of n nodes and n−1 edges. + +![Properties of tree](.gitbook/assets/image%20%28174%29.png) + +* To differentiate between tree and graph also we can do Total Nodes = 2Leaves - 1 for tree - Handshaking lemma +* In a k-ary tree where every node has either 0 or k children. L = I\*\(k-1\) + 1 + + L = Number of leaf node, I = Number of internal nodes i.e. nodes having k childs + +* Inorder traversal of a BST is sorted +* AVL Tree: [https://youtu.be/jDM6\_TnYIqE](https://youtu.be/jDM6_TnYIqE) +* Representations: Adjancy matrix, Adjancy list, Edge list +* **Chromatic Number:** Minimum number of colors required to color Graph G such that no two adjacent vertex gets same color +* **Independent Vertex Set:** Set of vertices in a graph G ,no two of which are adjacent that means no two vertices in this set is connected by an edge +* **Vertex Cover:** Set of Vertices in a Graph G, such that each Edge in G incident on atleast one Vertex in the Set. +* **Edge Cover:** Set of Edges in a Graph G, such that every vertex of G is incident on atleast one of the edges in the set. +* **A clique:** of a graph G is a complete subgraph of G, and the clique of largest possible size is referred to as a _maximum clique_. +* Total number of BSTs possible are catalan\(n\) and Binary Trees possible are catalan\(n\) \* n! **Proof for BST:** cat\(n\) **=** \(2n\)! / \(\(n + 1\)! \* n!\) Consider all possible BST with each element at the root. If there are n nodes, then for each choice of root node, there are n – 1 non-root nodes and these non-root nodes must be partitioned into those that are less than a chosen root and those that are greater than the chosen root. + +![](.gitbook/assets/image%20%28203%29.png) + +## Traversals + +* [https://leetcode.com/problems/binary-tree-inorder-traversal/](https://leetcode.com/problems/binary-tree-inorder-traversal/) +* [https://leetcode.com/problems/binary-tree-preorder-traversal/](https://leetcode.com/problems/binary-tree-preorder-traversal/) +* [https://leetcode.com/problems/binary-tree-postorder-traversal/](https://leetcode.com/problems/binary-tree-postorder-traversal/) + +```cpp +vector inorderTraversal(TreeNode* root) +{ + vector res; + stack st; + auto cur = root; + while (!st.empty() || cur) + { + while (cur) st.push(cur), cur = cur->left; + cur = st.top(); st.pop(); + res.push_back(cur->val); + cur = cur->right; + } + return res; +} + +vector preorderTraversal(TreeNode* root) +{ + vector res; + if (!root) return res; + stack st; + st.push(root); + while (!st.empty()) + { + auto cur = st.top(); st.pop(); + res.push_back(cur->val); + if (cur->right) st.push(cur->right); + if (cur->left) st.push(cur->left); + } + return res; +} + +vector postorderTraversal(TreeNode* root) +{ + vector res; + if (!root) return res; + stack st; + st.push(root); + while (!st.empty()) + { + auto cur = st.top(); st.pop(); + res.push_back(cur->val); + if (cur->left) st.push(cur->left); + if (cur->right) st.push(cur->right); + } + reverse(res.begin(), res.end()); + return res; +} +``` + +* Moris Traversal - O\(1\) Space Idea is to keep corresponding successor + +[https://www.youtube.com/watch?v=wGXB9OWhPTg](https://www.youtube.com/watch?v=wGXB9OWhPTg) + +```cpp +/* 10 + / \ + 5 30 + / \ \ + -2 6 40 + \ \ + 2 8 + / + 1 +Stack basically tells the inorder successor after we are +exhausted with our current subtree. To get rid of stack here + +inorder predecessor of 8 is 10 so we will create a link between +8->10 + +Time complexity is O(N) since we traverse each node atmost 3 +times only O(3N) = O(N )*/ +vector inorderTraversal(TreeNode* root) +{ + vector res; + auto cur = root; + while (cur) + { + if (!cur->left) + { + res.push_back(cur->val); + cur = cur->right; // successor link is established + } + else + { + // tmp is predecessor of cur + auto tmp = cur->left; + while (tmp->right && tmp->right != cur) + tmp = tmp->right; + + // >>> 1 <<< for inorder + if (!tmp->right) + tmp->right = cur, cur = cur->left; + else + { + // already traversed in the path so remove link + tmp->right = NULL; + res.push_back(cur->val); + cur = cur->right; + } + + // >>> 2 <<< for preorder + if (!tmp->right) + { + res.push_back(cur->val); + tmp->right = cur, cur = cur->left; + } + else + { + tmp->right = NULL; + cur = cur->right; + } + } + } + return res; +} + +/* >>> 3 <<< for postorder +Same as preorder code except flip left with right */ +vector postorderTraversal(TreeNode* root) +{ + vector res; + auto cur = root; + while (cur) + { + if (!cur->right) + { + res.push_back(cur->val); + cur = cur->left; + } + else + { + auto tmp = cur->right; + while (tmp->left && tmp->left != cur) + tmp = tmp->left; + + if (!tmp->left) + { + res.push_back(cur->val); + tmp->left = cur, cur = cur->right; + } + else + { + tmp->left = NULL; + cur = cur->left; + } + } + } + reverse(res.begin(), res.end()); + return res; +} +``` + +## Binary Tree + +### BST Implementation + +```cpp +struct Node{ int data; Node *left, *right; } *root = NULL; +Node* searchNode(Node* cur, int x) +{ + if (cur == NULL || cur->data == x) return cur; + if (cur->data < x) return searchNode(cur->right, x); + return searchNode(cur->left, x); +} +Node* insertNode(Node* cur, int value) +{ + if (cur == NULL) + { + cur->data = value; + cur->left = NULL; + cur->right = NULL; + return cur; + } + else if (cur->data > value) + { + cur->left = insertNode(cur->left, value); + return cur; + } + else + { + cur->right = insertNode(cur->right, value); + return cur; + } +} +Node* deleteNode(Node* cur, int value) +{ + if (cur == NULL) return cur; //If no node with specified value + else if (cur->data > value) + { + cur->left = deleteNode(cur->left, value); + return cur; + } + else if (cur->data < value) + { + cur->right = deleteNode(cur->right, value); + return cur; + } + else + { + //Case 1 : leaf node + if (cur->left == NULL && cur->right == NULL) + { + delete cur; + cur = NULL; + return cur; + } + //case 2 : One child + else if (cur->left == NULL) + { + Node *temp = cur; + cur = cur->right; + delete temp; + return cur; + } + else if (cur->right == NULL) + { + Node *temp = cur; + cur = cur->left; + delete temp; + return cur; + } + //Case 3 : Two childrens + else + { + //either find min of right subtree or max of left subtree + Node* temp = cur->right; + while(temp->left != NULL) temp = temp->left; + cur->data = temp->data + cur->right = deleteNode(cur->right, temp); + return cur; + } + } +} +//O(logN) or in worst case if it's skewed tree then O(N) +``` + +### Binary Heap Implementation + +```cpp +#define MAXSIZE 50 +#define parent(x) (x-1) >> 1 +#define child1(x) (x << 1) + 1 +#define child2(x) (x << 1) + 2 + +int heapArr[MAXSIZE]; +int size = 0; +void push(int x) +{ + if (size == MAXSIZE-1) + { + cout << "DIE!!!" << endl; + return; + } + heapArr[size] = x; + int cur = size; + while(heapArr[parent(cur)] > heapArr[cur]) + { + int temp = heapArr[cur]; + heapArr[cur] = heapArr[parent(cur)]; + heapArr[parent(cur)] = temp; + cur = parent(cur); + } + ++size; +} +void pop() +{ + heapArr[0] = heapArr[size-1]; + --size; + int cur = 0; + while(min(child1(cur), child2(cur)) < size) + { + int temp = heapArr[cur]; + heapArr[cur] = min(heapArr[child1(cur)], heapArr[child2(cur)]); + heapArr[min(child1(cur), child2(cur))] = temp; + cur = min(child1(cur), child2(cur)); + } +} +``` + +### [Diameter of a Binary Tree](https://leetcode.com/problems/diameter-of-binary-tree/) + +```cpp +pair DFS(TreeNode* cur) +{ + if (!cur) return {0, 0}; + auto l = DFS(cur->left); + auto r = DFS(cur->right); + int diam = max({l.first, r.first, l.second + r.second}); + return {diam, max(l.second, r.second) + 1}; +} +int diameterOfBinaryTree(TreeNode* root) { return DFS(root).first; } +``` + +### Two Sum BST + +```cpp +bool Solution::t2Sum(TreeNode* A, int B) +{ + if (!A) return 0; + stack st1, st2; + TreeNode *cur1 = A, *cur2 = A; + while(cur1) st1.push(cur1), cur1 = cur1->left; + while(cur2) st2.push(cur2), cur2 = cur2->right; + cur1 = st1.top(), cur2 = st2.top(); // cur1 is lowest cur2 is highest + while (cur1 && cur2 && cur1->val < cur2->val) + { + if (cur1->val + cur2->val == B) return true; + if (cur1->val + cur2->val < B) + { + st1.pop(); + cur1 = cur1->right; + while (cur1) st1.push(cur1), cur1 = cur1->left; + cur1 = st1.top(); + } + else + { + st2.pop(); + cur2 = cur2->left; + while (cur2) st2.push(cur2), cur2 = cur2->right; + cur2 = st2.top(); + } + } + return false; +} +``` + +### Invert Binary Tree + +```cpp +void invert(TreeNode* root) +{ + if (root == NULL) return; + invert(root->left); + invert(root->right); + + TreeNode* temp = root->left; + root->left = root->right; + root->right = temp; +} + +TreeNode* Solution::invertTree(TreeNode* root) +{ + invert(root); + return root; +} +``` + +### Symmetric Tree + +```cpp +bool check(TreeNode *l, TreeNode *r) +{ + if (!l && !r) return true; + if (!l || !r) return false; + if (l->val != r->val) return false; + return check(l->left, r->right) && check(l->right, r->left); +} +bool isSymmetric(TreeNode* root) +{ + if (!root) return true; + return check(root->left, root->right); +} +``` + +### Least Common Ancestor + +```cpp +// Naive binary tree implementaiton +TreeNode *LCAinBinaryTree(TreeNode *root, TreeNode *p, TreeNode *q) +{ + int delta = depth(p) - depth(q); + TreeNode *shallower = (delta > 0) ? q : p; + TreeNode *deeper = (delta > 0) ? p : q; + deeper = goUpBy(deeper, abs(delta)); + while (shallower != deeper && !shallower && !deeper) + { + shallower = shallower->parent; + deeper = deeper->parent; + } + return (!deeper || !shallower) ? NULL : shallower; +} + +// O(N) +TreeNode* LCAinBinaryTree(TreeNode *root, TreeNode *p, TreeNode *q) +{ + if (!root || root->val == p->val || root->val == q->val) return root; + auto L = LCA(root->left, p, q); + auto R = LCA(root->right, p, q); + if (L && R) return root; + else return L ? L : R; +} +// O(logN) worst case still O(N) in linkedlist type BST +TreeNode* LCAinBST(TreeNode *root, TreeNode *p, TreeNode *q) +{ + // If both p and q are greater than parent then look at right side + if (root->val < p->val && root->val < q->val) + return LCA(root->right, p, q); + // If both p and q are lower than parent then look at left side + else if (root->val > p->val && root->val > q->val) + return LCA(root->left, p, q); + else + return root; +} +``` + +### [Verify Preorder Sequence in BST](https://www.lintcode.com/problem/verify-preorder-sequence-in-binary-search-tree/description) + +```cpp +/* Consider this testcase: [4,3,5,1,2,3] it should give false + 4 + / \ + 3 5 + / + 1 + \ + 2 + \ + 3 + Subtree 5 should contain all nodes greater than 4 to be valid */ +bool verifyPreorder(vector &preorder) +{ + stack st; + int otherHalfMax = INT_MIN; + for (auto &x : preorder) + { + if (x < otherHalfMax) return false; + while (!st.empty() && x > st.top()) + { + otherHalfMax = st.top(); + st.pop(); + } + st.push(x); + } + return true; +} +/* When we are at a node, all of it's subtree (coming vals in array) must be +smaller then parent. stack store exactly the left half so for above example +[4 3 otherHalfMax finds max among these groups +[5 1 +[2 +[3 */ +``` + +### Construct Binary Tree + +To construct a binary tree we need either + +**Preorder + Inorder:** +ABCDEFCGHJLK, DBFEAGCLJHK + +In preorder left most is the root node. \(A\) +Then see it in Inorder \(DBFE\) left - \(GCLJHK\) right + +![](.gitbook/assets/image%20%28133%29.png) + +Again recursively check left most of DBFE then see it in Inorder. to solve the entire tree. + +**Postorder + Inorder:** +Here everything will be simillar as 1\) except the rightmost is the root node. + +**Preorder + Postorder:** +ABDGHKCEF, GKHDBEFCA A is root node, B is left to A +B in post order has B-EFC-A so B is left EFC is right to A + +![](.gitbook/assets/image%20%28134%29.png) + +```cpp +/* Minimal Tree +Given a sorted (increasing order) array with unique integer +elements, write an algorithm to create a binary search tree with +minimal height. */ +TreeNode* makeTree(vector &A, int start, int end) +{ + if (start > end) return NULL; + int mid = (start + end) / 2; + TreeNode* root = new TreeNode(A[mid]); + root->left = makeTree(arr, start, mid-1); + root->right = makeTree(arr, mid+1, end); + return root; +} +TreeNode* Solution::buildTree(vector &A) +{ + return makeTree(A, 0, A.size()-1); +} + +// Construct maximum tree +TreeNode* makeTree(vector &A, int start, int end) +{ + if (start > end) return NULL; + int maxIndex = max_element(A.begin()+start, A.begin()+end+1) - A.begin(); + TreeNode* root = new TreeNode(A[maxIndex]); + root->left = makeTree(A, start, maxIndex-1); + root->right = makeTree(A, maxIndex+1, end); + return root; +} +TreeNode* Solution::buildTree(vector &A) +{ + return makeTree(A, 0, A.size()-1); +} +​ +// Construct using Inorder and Preorder +// for postorder and inorder follow comments +class Solution { +public: + /* + preorder [3 8 20 15 7] inorder [9 3 15 20 7] + 3 + / \ + 9 20 + / \ + 15 7 + */ + unordered_map indexes; + TreeNode* makeTree(vector preorder, vector inorder, int start, int end) + { + if (start > end) return NULL; + int parentIndex = INT_MAX, otherIndex; // change INT_MAX to INT_MIN + for (int i = start; i <= end; ++i) + { + if (indexes[inorder[i]] < parentIndex) // change sign + parentIndex = indexes[inorder[i]], otherIndex = i; + } + + TreeNode *parent = new TreeNode(preorder[parentIndex]); + parent->left = makeTree(preorder, inorder, start, otherIndex-1); + parent->right = makeTree(preorder, inorder, otherIndex+1, end); + return parent; + } + TreeNode* buildTree(vector& preorder, vector& inorder) + { + indexes.clear(); + for (int i = 0; i < preorder.size(); ++i) indexes[preorder[i]] = i; + return makeTree(preorder, inorder, 0, preorder.size()-1); + } +}; +​ +/* Construct from preorder and postorder + 1 + / \ + 2 3 + / \ + 4 5 preorder: 1 2 4 5 3 postorder: 4 5 2 3 1 + +We can pick the top most from preorder, that's root node +it may or may not have left-right subtree. We can maintain +a stack of levels so here 1->2->4 but now we have to realize +when to stop. So it's clear that here it is post[0] since its +left most. if we keep iterating over post we can maintain it */ +class Solution { +public: + TreeNode* constructFromPrePost(vector& pre, vector& post) + { + if (pre.empty()) return NULL; + stack st; + st.push(new TreeNode(pre[0])); + // i is in pre, j is in post + for (int i = 1, j = 0; i < pre.size(); ++i) + { + TreeNode *cur = new TreeNode(pre[i]); + while (st.top()->val == post[j]) st.pop(), j++; + if (!st.top()->left) st.top()->left = cur; + else st.top()->right = cur; + st.push(cur); + } + while (st.size() > 1) st.pop(); + return st.top(); + } +}; +​ +// Construct BST from preorder +TreeNode* construct(vector &preorder, int l, int r) +{ + if (l > r) return NULL; +​ + int leftStart = l+1, rightStart = l; + while (rightStart < preorder.size() && preorder[rightStart] <= preorder[l]) + rightStart++; + TreeNode* root = new TreeNode(preorder[l]); + root->left = construct(preorder, leftStart, rightStart-1); + root->right = construct(preorder, rightStart, r); + return root; +} +TreeNode* bstFromPreorder(vector& preorder) +{ + if (preorder.empty()) return NULL; + return construct(preorder, 0, preorder.size()-1); +} +​ +// Recover tree from preorder +// "1-401--349---90--88" = [1,401,null,349,88,90] +TreeNode* recoverFromPreorder(string S) +{ + stack st; + for (int p = 0, len = 0, level = 0; p < S.size(); p += len) + { + level = 0, len = 0; + while (S[p] == '-') ++level, ++p; + while (p + len < S.size() && S[p + len] != '-') ++len; + TreeNode *n = new TreeNode(stoi(S.substr(p, len))); + while (st.size() > level) st.pop(); + if (!st.empty()) + { + if (!st.top()->left) st.top()->left = n; + else st.top()->right = n; + } + st.push(n); + } + while (st.size() > 1) st.pop(); + return st.top(); +} +``` + +### [Flatten BST to Linked List](https://leetcode.com/problems/flatten-binary-tree-to-linked-list/) + +```cpp +/* + 1 1 + / \ 2 + 2 5 -> 3 + / \ 4 +3 4 5 + +To do it in-place we cannot begin with setting 1 then 2 then 3 +we have to go from bottom. */ +void flatten(TreeNode* root) +{ + TreeNode *cur = root; + while (cur) + { + if (cur->left) + { + TreeNode *tmp = cur->left; + while (tmp->right) tmp = tmp->right; + tmp->right = cur->right; + cur->right = cur->left; + cur->left = NULL; + } + cur = cur->right; + } +} +``` + +### [Maximum Path Sum](https://leetcode.com/problems/binary-tree-maximum-path-sum/) + +```cpp +int maxPathSum(TreeNode* root) +{ + int ans = INT_MIN; + DFS(root, ans); + return ans; +} +int DFS(TreeNode* root, int &ans) +{ + if (!root) return 0; + int left = max(0, DFS(root->left, ans)); + int right = max(0, DFS(root->right, ans)); + ans = max(ans, left + right + root->val); + return max(left, right) + root->val; +} +``` + +### [Generate All Unique BST](https://leetcode.com/problems/unique-binary-search-trees-ii/) + +```cpp +/* Generate all unique BSTs +Input: 3 +Output: +[ + [1,null,3,2], + [3,2,null,1], + [3,1,null,null,2], + [2,1,3], + [1,null,2,null,3] +] + + 1 3 3 2 1 + \ / / / \ \ + 3 2 1 1 3 2 + / / \ \ + 2 1 2 3 */ +// Generate total cat(n) BSTs +class Solution { +public: + vector genTree(int start, int end) + { + vector res; + if (start >= end) + { + if (start == end) res.push_back(new TreeNode(start)); + else res.push_back(NULL); + return res; + } + vector left, right; + for (int i = start; i <= end; ++i) + { + left = genTree(start, i-1); + right = genTree(i+1, end); + for (auto x : left) + { + for (auto y : right) + { + TreeNode *cur = new TreeNode(i); + cur->left = x, cur->right = y; + res.push_back(cur); + } + } + } + return res; + } + vector generateTrees(int n) + { + if (n == 0) return {}; + return genTree(1, n); + } +}; +``` + +### [Validate BST](https://leetcode.com/problems/validate-binary-search-tree/) + +```cpp +/* Validate BST +The left subtree of a node contains only nodes with keys less than the node's key. +The right subtree of a node contains only nodes with keys greater than the node's key. +Both the left and right subtrees must also be binary search trees. */ +class Solution { +public: + bool check(TreeNode *root, TreeNode *lower, TreeNode *higher) + { + if (!root) return true; + if (lower && root->val <= lower->val) return false; + if (higher && root->val >= higher->val) return false; + return check(root->left, lower, root) && check(root->right, root, higher); + } + bool isValidBST(TreeNode* root) + { + return check(root, NULL, NULL); + } +}; +``` + +### [Count Complete Tree Node](https://leetcode.com/problems/count-complete-tree-nodes/) + +```cpp +/* Count Complete Tree Nodes + 1 + / \ + 2 3 + / \ / + 4 5 6 + output = 6 +*/ +int countNodes(TreeNode* root) +{ + if (!root) return 0; + TreeNode *l = root, *r = root; + int heightL = 0, heightR = 0; + while (l) heightL++, l = l->left; + while (r) heightR++, r = r->right; + if (heightL == heightR) return (1<left) + countNodes(root->right); +} +``` + +### [Complete Binary Tree Inserter](https://leetcode.com/problems/complete-binary-tree-inserter/description/) + +```cpp +class CBTInserter { +public: + vector tree; // store tree nodes to a list in bfs order + CBTInserter(TreeNode* root) + { + tree.push_back(root); + for (int i = 0; i < tree.size();++i) + { + if (tree[i]->left) tree.push_back(tree[i]->left); + if (tree[i]->right) tree.push_back(tree[i]->right); + } + } + int insert(int v) // insert node to very last level (create one) find it's parent + { + int N = tree.size(); + TreeNode* node = new TreeNode(v); + tree.push_back(node); + if (N&1) tree[(N - 1) / 2]->left = node; + else tree[(N - 1) / 2]->right = node; + return tree[(N - 1) / 2]->val; + } + TreeNode* get_root() { return tree[0]; } +}; +``` + +### [BST Iterator](https://leetcode.com/problems/binary-search-tree-iterator/) + +```cpp +stack st; +void pushAll(TreeNode *root) +{ + while (root) + { + st.push(root); + root = root->left; + } +} +BSTIterator(TreeNode* root) { pushAll(root); } +bool hasNext() { return !st.empty(); } +int next() +{ + auto cur = st.top(); st.pop(); + pushAll(cur->right); + return cur->val; +} +``` + +### [Recover BST](https://www.interviewbit.com/problems/recover-binary-search-tree/#) + +Two elements of BST are swapped by mistake, find those 2 points. + +```cpp +/* In inorder traversal previous value must not be greater + then cur */ +vector Solution::recoverTree(TreeNode* A) +{ + stack st; + TreeNode *cur = A, *prev = NULL, *first = NULL, *last = NULL; + while(!st.empty() || cur) + { + while (cur) st.push(cur), cur = cur->left; + cur = st.top(); st.pop(); + if (prev) + { + if (prev->val > cur->val) + { + /* This part is tricky we could have just + written first = prev, last = cur and then + break BUT agar non immediate child se swap + hua he tab uss case me ek toh humesha fixed + rahega dusra badalta rahega */ + if (!first) last = prev; + first = cur; + } + } + prev = cur; + cur = cur->right; + } + vector sol; + if (first && last) + { + sol.push_back(first->val); + sol.push_back(last->val); + } + sort(sol.begin(), sol.end()); + return sol; +} +``` + +### [Serialize and Deserialize Binary Tree](https://leetcode.com/problems/serialize-and-deserialize-binary-tree/) + +```cpp +// Serialize & Deserialize Binary Tree +// If BST then very simple, store preorder value +class Codec { +private: + /* + 1 + / \ + 2 3 + / \ + 4 5 + 1[2,3[4,5]] preorder traverse put [ when a new layer + comes in */ + void encode(TreeNode *root, string &res) + { + if (!root) return; + res += to_string(root->val); + if (root->left || root->right) + { + res += '['; + encode(root->left, res); + res += ','; + encode(root->right, res); + res += ']'; + } + } + TreeNode *decode(string &data, int &pos) + { + int i; bool foundL = false; + for (i = pos; i < data.size(); ++i) + { + if (data[i] == ',' || data[i] == ']') break; + if (data[i] == '[') { foundL = true; break; } + } + + if (i == pos) return NULL; + int val = stoi(data.substr(pos, i-pos)); + auto node = new TreeNode(val); + if (i == data.size()) return node; + + pos = i; + if (foundL) + { + pos++; // skip '[' + node->left = decode(data, pos); + pos++; // skip ',' + node->right = decode(data, pos); + pos++; // skip ']' + } + return node; + } + +public: + string serialize(TreeNode* root) + { + string res = ""; + encode(root, res); + return res; + } + + TreeNode* deserialize(string data) + { + if (data == "") return NULL; + int pos = 0; + return decode(data, pos); + } +}; +``` + +* [https://www.lintcode.com/problem/path-sum-iv/](https://www.lintcode.com/problem/path-sum-iv/) + +```cpp +/* In this problem, binary tree with depth < 5 is serialized +as a list of 3 digit integers. +eg: [113, 215, 221] -> means first node (hunread 1 means 1 +depth, tense 1 means horizontal pos, once 3 means val) + 3 + / \ + 5 1 +We are given such list and our goal is to deserialize it and +find all path sum from root to child. */ + +unordered_map rec[6]; +// ^^ 6 instead of 5 to avoid segmentation fault due to dep+1 +void dfs(vector &nums, int &res, int dep = 1, int pos = 1, int sum = 0) +{ + sum += rec[dep][pos]; + if (rec[dep+1].find(2*pos - 1) == rec[dep+1].end() && rec[dep+1].find(2*pos) == rec[dep+1].end()) res += sum; + + if (rec[dep+1].find(2*pos - 1) != rec[dep+1].end()) dfs(nums, res, dep+1, 2*pos - 1, sum); + if (rec[dep+1].find(2*pos) != rec[dep+1].end()) dfs(nums, res, dep+1, 2*pos, sum); +} +int pathSumIV(vector &nums) +{ + if (nums.empty()) return 0; + for (auto &x : rec) x.clear(); + for (auto &x : nums) + { + int dep = x/100, pos = (x%100)/10, val = x%10; + rec[dep][pos] = val; + } + int res = 0; + dfs(nums, res); + return res; +} +``` + +### Path with Given Sum + +* [https://leetcode.com/problems/path-sum](https://leetcode.com/problems/path-sum) +* [https://leetcode.com/problems/path-sum-ii](https://leetcode.com/problems/path-sum-ii) +* [https://leetcode.com/problems/path-sum-iii](https://leetcode.com/problems/path-sum-iii) + +```cpp +// root to leaf path sum = sum, check +bool hasPathSum(TreeNode* root, int sum) +{ + if (!root) return false; + int val = sum - root->val; + if (val == 0 && !root->left && !root->right) return true; + return hasPathSum(root->left, val) || hasPathSum(root->right, val); +} + +// find all root to leaf paths of given sum +void dfs(TreeNode* root, int sum, vector &cur, vector> &res) +{ + int val = sum - root->val; + if (!root->left && !root->right && val == 0) + { + res.push_back(cur); + return; + } + if (root->left) { cur.push_back(root->left->val); dfs(root->left, val, cur, res); cur.pop_back(); } + if (root->right) { cur.push_back(root->right->val); dfs(root->right, val, cur, res); cur.pop_back(); } +} +vector> pathSum(TreeNode* root, int sum) +{ + vector> res; + if (!root) return res; + vector cur; + cur.push_back(root->val); + dfs(root, sum, cur, res); + return res; +} + +/* What if we want all the paths (not just ending at leaf) +but can start and end anywhere + 10 10 + / \ / \ + 5 -3 15 7 + / \ \ / \ \ + 3 2 11 18 17 18 + / \ \ / \ \ + 3 -2 1 21 16 18 + +idea is simmilar to how we do this kind of problem using +hashing and prefix sum in an array. +we will maintain a prefix sum while doing dfs then use +also maintaing previous prefsums in a hashmap then we +just have to add count of sum-target from hashmap */ +unordered_map cnt; +void dfs(TreeNode *root, int &target, int &res, int sum = 0) +{ + if (!root) return; + sum += root->val; + res += cnt[sum - target]; + cnt[sum]++; + dfs(root->left, target, res, sum); + dfs(root->right, target, res, sum); + cnt[sum]--; +} +int pathSum(TreeNode* root, int sum) +{ + cnt.clear(); + int res = 0; + cnt[0]++; + dfs(root, sum, res); + return res; +} +``` + +### [Delete Node in a BST](https://leetcode.com/problems/delete-node-in-a-bst/) + +```cpp +/* Idea is once we find node with matching key we will swap +it with its successor which is righ to it then all the way left +if right doesnt exist then simply swap it with left. */ +class Solution { +public: + TreeNode* deleteNode(TreeNode* root, int key) + { + if (!root) return NULL; + if (root->val == key) + { + if (!root->right) + { + auto left = root->left; + delete root; + return left; + } + else + { + auto succ = root->right; + while (succ->left) succ = succ->left; + swap(root->val, succ->val); + // having delete succ will cause runtime error + } + } + root->left = deleteNode(root->left, key); + root->right = deleteNode(root->right, key); + return root; + } +}; +``` + +### [Convert BST to Greater Tree](https://leetcode.com/problems/convert-bst-to-greater-tree/) + +every key of the original BST is changed to the original key plus sum of all keys greater than the original key in BST. + +```cpp +/* +Convert BST to greater tree +Input: The root of a Binary Search Tree like this: + 5 + / \ + 2 13 + +Output: The root of a Greater Tree like this: + 18 + / \ + 20 13 +This follows a particular traversal, if taken that path we only have to sum up +numbers */ +int sum = 0; +TreeNode* convertBST(TreeNode* root) +{ + if (!root) return NULL; + convertBST(root->right); + sum += root->val; + root->val = sum; + convertBST(root->left); + return root; +} +``` + +### [Duplicates in Subtree](https://leetcode.com/problems/find-duplicate-subtrees/) + +```cpp +/* +Duplicates in sub tree + 1 + / \ + 2 3 + / / \ + 4 2 4 + / + 4 + + 2 4 are two duplicates + / + 4 +return [[2,4], [4]] +*/ +class Solution { +public: + vector res; + unordered_map rec; + string serialize(TreeNode *root) + { + if (!root) return ""; + string cur = "[" + serialize(root->left) + to_string(root->val) + serialize(root->right) + "]"; + if (rec.find(cur) != rec.end()) + { + if (!rec[cur]) + { + res.push_back(root); + // being true means we have handled that duplicate so no need to handle it later + rec[cur] = true; + } + } + else rec[cur] = false; + return cur; + } + vector findDuplicateSubtrees(TreeNode* root) + { + rec.clear(); res.clear(); + serialize(root); + return res; + } +}; +``` + +### [Trim BST](https://leetcode.com/problems/trim-a-binary-search-tree/) + +```cpp +// Trim BST, remove those which are out of L & R range +class Solution { +public: + TreeNode* trimBST(TreeNode* root, int L, int R) + { + if (!root) return NULL; + if (root->val > R) return trimBST(root->left, L, R); + if (root->val < L) return trimBST(root->right, L, R); + root->left = trimBST(root->left, L, R); + root->right = trimBST(root->right, L, R); + return root; + } +}; +``` + +### [Longest Univalent Path](https://leetcode.com/problems/longest-univalue-path/) + +Find longest path \(between any 2 node of a tree\) having same val + +```cpp +// it returns max depth matching with val +// it makes ans of this subtree +int solve(TreeNode* root, int val, int &ans) +{ + if (!root) return 0; + int resL = 0, resR = 0; + int depL = solve(root->left, root->val, resL); + int depR = solve(root->right, root->val, resR); + ans = max({depL+depR, resL, resR}); + return (root->val == val) ? max(depL, depR)+1 : 0; +} +int longestUnivaluePath(TreeNode* root) +{ + if (!root) return 0; + int ans = 0; + solve(root, -1, ans); + return ans; +} +``` + +### [All Possible Full Binary Tree](https://leetcode.com/problems/all-possible-full-binary-trees/) + +```cpp +unordered_map> cache; +vector allPossibleFBT(int N) +{ + vector res; + if (cache.find(N) != cache.end()) return cache[N]; + if (N == 1) res.push_back(new TreeNode(0)); + else + { + for (int l = 1; l < N; l += 2) + { + int r = N-1-l; + for (auto L : allPossibleFBT(l)) + { + for (auto R : allPossibleFBT(r)) + { + auto root = new TreeNode(0); + root->left = L, root->right = R; + res.push_back(root); + } + } + } + } + return cache[N] = res; +} +``` + +### [Insert Into BST](https://leetcode.com/problems/insert-into-a-binary-search-tree) + +```cpp +TreeNode* insertIntoBST(TreeNode* root, int val) +{ + if (!root) return new TreeNode(val); + TreeNode *cur = root, *prev = NULL; + while (cur) + { + prev = cur; + cur = (val < cur->val) ? cur->left : cur->right; + } + if (val < prev->val) prev->left = new TreeNode(val); + if (val > prev->val) prev->right = new TreeNode(val); + return root; +} +``` + +### [Smallest String Starting from Leaf](https://leetcode.com/problems/smallest-string-starting-from-leaf/) + +```cpp +void dfs(TreeNode *root, string &ans, string str = "") +{ + str = string(1, 'a' + root->val) + str; + if (root->left) dfs(root->left, ans, str); + if (root->right) dfs(root->right, ans, str); + if (!root->left && !root->right) + { + if (ans.empty()) ans = str; + else ans = min(ans, str); + } +} +string smallestFromLeaf(TreeNode* root) +{ + string ans = ""; + if (!root) return ans; + dfs(root, ans); + return ans; +} +``` + +### [Maximum Difference Between Node & Ancestor](https://leetcode.com/problems/maximum-difference-between-node-and-ancestor/) + +```cpp +int maxAncestorDiff(TreeNode* root, int minV = INT_MAX, int maxV = INT_MIN) +{ + if (!root) return maxV - minV; + maxV = max(maxV, root->val); + minV = min(minV, root->val); + return max(maxAncestorDiff(root->left, minV, maxV), + maxAncestorDiff(root->right, minV, maxV)); +} +``` + +### [Binary Tree Coloring Game](https://leetcode.com/problems/binary-tree-coloring-game/) + +```cpp +class Solution { +public: + /* + First player will choose X node next second player + will need to choose some Y such that + it should give better connectivity then X if yes + then second wins otherwise first wins. + Both wont have same points because nodes are odd + 1 + / \ + 2 3 + / \ /\ + 4 5 6 7 + /\ /\ + 8 9 10 11 + X is given 3, we can choose Y as 2, 6, 7... + With + (Y=2) 1st player:4 2nd player:7 so 2nd player + will win return true + */ + TreeNode* find(TreeNode* root, int x) + { + if (!root) return NULL; + if (root->val == x) return root; + auto l = find(root->left, x); + auto r = find(root->right, x); + return (l ? l : r); + } + int count(TreeNode *root) + { + if (!root) return 0; + return count(root->left) + count(root->right) + 1; + } + bool btreeGameWinningMove(TreeNode* root, int n, int x) + { + auto node = find(root, x); + int l = count(node->left); + int r = count(node->right); + int par = (node != root) ? (n-(l+r+1)) : 0; + int blueConnectivity = max({l, r, par}); + int redConnectivity = n - blueConnectivity; + return blueConnectivity > redConnectivity; + } +}; +``` + +### [Upside Down Binary Tree](https://www.lintcode.com/problem/binary-tree-upside-down/description) + +```cpp +/* 1 + / \ + 2 3 + / \ +4 5 +and the output is + 4 + / \ + 5 2 + / \ + 3 1 +Given a binary tree where all the right nodes are either +leaf nodes with a sibling, or empty*/ +TreeNode * upsideDownBinaryTree(TreeNode * root) +{ + if (!root) return root; + TreeNode *cur = root; + vector list; + while (cur) list.push_back(cur), cur = cur->left; + TreeNode* res = list.back(); + list.pop_back(); + while (!list.empty()) + { + cur = list.back(); + list.pop_back(); + cur->left->left = cur->right; + cur->left->right = cur; + cur->left = NULL; + cur->right = NULL; + } + return res; +} +``` + +### [Clone Graph](https://leetcode.com/problems/clone-graph/) + +```cpp +/* +// Definition for a Node. +class Node { +public: + int val; + vector neighbors; + + Node() {} + + Node(int _val, vector _neighbors) { + val = _val; + neighbors = _neighbors; + } +}; +*/ +unordered_map cache; +Node* solve(Node* node) +{ + if (!node) return NULL; + if (cache.find(node->val) != cache.end()) return cache[node->val]; + vector newNeigh; + cache[node->val] = new Node(node->val, newNeigh); + for (auto &x : node->neighbors) + { + auto cur = solve(x); + if (cur) cache[node->val]->neighbors.push_back(cur); + } + return cache[node->val]; +} +Node* cloneGraph(Node* node) +{ + cache.clear(); + return solve(node); +} +``` + +### [Binary Tree Pruning](https://leetcode.com/problems/binary-tree-pruning/) + +Remove every subtree not containing a 1 in it + +```cpp +TreeNode* pruneTree(TreeNode* root) +{ + if (!root) return NULL; + root->left = pruneTree(root->left); + root->right = pruneTree(root->right); + bool containsOnes = (root->val == 1 || root->left || root->right); + if (!containsOnes) + { + delete root; + return NULL; + } + return root; +} +``` + +### Check Subtree + +T1 and T2 are two very large binary trees, with T1 much bigger than T2, Create an algorithm to determine if T2 is a subtree of T1. +A tree T2 is a subtree of T1 if there exists a node n in T1 such that the subtree of n is identical to T2. That is, if you cut off the tree at node n, the two trees would be identical. + +```cpp +bool isSubtree(TreeNode* s, TreeNode* t) +{ + if (!s) return false; + return isSameTree(s, t) || isSubtree(s->left, t) || isSubtree(s->right, t); +} +bool isSameTree(TreeNode *s, TreeNode *t) +{ + if (!s && !t) return true; + if (!s || !t) return false; + if (s->val == t->val) return isSameTree(s->left, t->left) && isSameTree(s->right, t->right); + else return false; +} +``` + +### Random Node + +You are implementing a binary tree class from scratch which, in addition to insert, find, and delete, has a method getRandomNode\(\) which returns a random node from the tree. All nodes should be equally likely to be chosen. Design and implement an algorithm for getRandomNode, and explain how you would implement the rest of the methods. + +```cpp +/* There's an stl random function which generates uniform random number. +To implement it, however we will need to use reservoir sampling */ + +int res; // our rand node +int getRandomNode() { return (tree.empty()) ? -1 : res; } +void insert(int x) +{ + // Insert x in tree + if (rand()%len == 0) res = x; + len++; +} +void remove(int x) +{ + // Delete x in tree + /* Reservoir sampling cannot do removal. So make getRandomNode O(N) + Removal is supported there are some research papers on it. */ +} +``` + +## BFS DFS + +### Connectivity Check + +We can check if a graph is connected by starting at an arbitrary node and finding out if we can reach all other nodes + +### Finding Cycle + +* A graph contains a cycle if during a graph traversal, we find a node whose neighbour \(other than the previous-parent node in the current path\) has already been visited. +* Another way is to simply calculate the number of nodes and edges in every components. For a component to not contain cycle it must have x nodes and x-1 edges. + +### Bipartiteness check + +The idea is to colour the starting node blue, all its neighbours red, all their neighbours blue, and so on. If at some point of the search we notice that two adjacent nodes have the same colour, this means that the graph is not bipartite. + +This algorithm of graph coloring works because of only 2 colors \(choosing whether to paint root as blue or red won't matter\). In general case finding graph coloring is np complete and finding minimum colors reqd is np hard. + +### Finding Bridges + +* A bridge is defined as an edge which, when removed, makes the graph disconnected \(or increase connected components\) +* O\(E + V\) algorithm + +```cpp +int timer = 0; +vector visited; +vector tin, low; +vector bridges; +void DFS(int u, vector adj[], int par = -1) +{ + visited[u] = true; + tin[u] = low[u] = timer++; + for (auto &v : adj[u]) + { + if (v == par) continue; + if (visited[v]) low [u] = min(low[u], tin[v]); + else + { + DFS(v, adj, u); + low[u] = min(low[u], low[v]); + if (low[v] > tin[u]) bridges.push_back({u, v}); + } + } +} +void findBridge(int n, vector adj[]) +{ + timer = 0; + bridges.clear(); + visited.assign(n, false); + tin.assign(n, -1); + low.assign(n, -1); + for (int i = 0; i < n; ++i) + if (!visited[i]) DFS(i, adj); +} +``` + +### Finding Articulation Points + +* An articulation point \(or cut vertex\) is defined as a vertex which, when removed along with associated edges, makes the graph disconnected. +* O\(E + V\) algorithm + +```cpp +int timer = 0; +vector visited; +vector tin, low; +vector articulationPoints; +void DFS(int u, vector adj[], int par = -1) +{ + visited[u] = true; + tin[u] = low[u] = timer++; + int children = 0; + for (auto &v : adj[u]) + { + if (v == par) continue; + if (visited[v]) low [u] = min(low[u], tin[v]); + else + { + DFS(v, adj, u); + low[u] = min(low[u], low[v]); + if (low[v] > tin[u] && par != -1) articulationPoints.push_back(u); + ++children; + } + } + if (par == -1 && children > 1) articulationPoints.push_back(u); +} +void findArticulationPoint(int n, vector adj[]) +{ + timer = 0; + articulationPoints.clear(); + visited.assign(n, false); + tin.assign(n, -1); + low.assign(n, -1); + for (int i = 0; i < n; ++i) + if (!visited[i]) DFS(i, adj); +} +``` + +### Multi-Source BFS + +Rotting Oranges + +```cpp +class Solution { +public: + typedef pair pii; + vector dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; + int orangesRotting(vector>& grid) + { + int n = grid.size(), m = grid[0].size(); + queue q; + int cnt = 0; + for (int i = 0; i < n; ++i) + { + for (int j = 0; j < m; ++j) + { + if (grid[i][j] == 2) q.push({i, j}); + else if (grid[i][j] == 1) cnt++; + } + } + int iter = 0; + while (!q.empty()) + { + int sz = q.size(); + iter++; + while (sz--) + { + auto u = q.front(); q.pop(); + for (const pii delta : dir) + { + pii v = {u.first+delta.first, u.second+delta.second}; + if (v.first >= 0 && v.second >= 0 && v.first < n && v.second < m + && grid[v.first][v.second] == 1) + { + cnt--; + grid[v.first][v.second] = 2; + q.push({v.first, v.second}); + } + } + } + if (cnt == 0) + for (auto &x : grid) + { + for (auto &y : x) cout << setw(3) << y; + cout << '\n'; + } + cout << '\n'; + } + return iter; + } +}; +``` + +[https://codeforces.com/problemset/problem/1294/F](https://codeforces.com/problemset/problem/1294/F) +We want to find 3 points as far away as possible, two of them can be diameter of the tree third one we can by using Multisource BFS with sources \(dA and dB\) then finding farthest point + +```cpp +if (diameter.size() == n) // graph is like linkedlist so pick anything as third + cout << n-1 << '\n' << diameter[0]+1 << ' ' << diameter[1]+1 << ' ' << + diameter.back()+1 << '\n'; +else +{ + queue q; + vector d(n, -1); + for (auto &x : diameter) d[x] = 0, q.push(x); + while (!q.empty()) + { + auto u = q.front(); + q.pop(); + for (auto &v : adj[u]) + { + if (d[v] != -1) continue; + d[v] = d[u] + 1; + q.push(v); + } + } + pii mx = {d[0], 0}; + for (int i = 1; i < n; ++i) mx = max(mx, {d[i], i}); + cout << diameter.size()-1+mx.first << '\n' << diameter[0]+1 << ' ' << + mx.second+1 << ' ' << diameter.back()+1 << '\n'; +} +``` + +### [Surrounded Regions](https://leetcode.com/problems/surrounded-regions/) + +```cpp +/* Observation: If a 'O' is not captured by 'X' then it has to be connected to the boundary. +So apply DFS and do the thing. */ +int n, m; +vector> directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; +void dfs(vector>& board, int i, int j) +{ + if (i < 0 || j < 0 || i >= n || j >= m || board[i][j] != 'O') return; + board[i][j] = '+'; + for (const auto dir : directions) + dfs(board, i+dir.first, j+dir.second); +} +void solve(vector>& board) +{ + if (board.empty() || board[0].empty()) return; + n = board.size(), m = board[0].size(); + for (int i = 0; i < n; ++i) { dfs(board, i, 0); dfs(board, i, m-1); } + for (int j = 1; j < m-1; ++j) { dfs(board, 0, j); dfs(board, n-1, j); } + for (int i = 0; i < n; ++i) + { + for (int j = 0; j < m; ++j) + { + if (board[i][j] == '+') board[i][j] = 'O'; + else if (board[i][j] == 'O') board[i][j] = 'X'; + } + } +} +``` + +### Bidirectional BFS + +[https://leetcode.com/problems/open-the-lock/](https://leetcode.com/problems/open-the-lock/) + +```cpp +// Normal BFS +class Solution { +public: + int openLock(vector& deadends, string target) + { + unordered_set stops; + for (const string x : deadends) stops.insert(x); + + queue q; + unordered_set vis; + q.push("0000"); + int cnt = 0; + while (!q.empty()) + { + int sz = q.size(); + while (sz--) + { + string u = q.front(); q.pop(); + if (stops.find(u) != stops.end() || vis.find(u) != vis.end()) continue; + if (u == target) return cnt; + vis.insert(u); + + for (int i = 0; i < 4; ++i) + { + string v = u; + v[i] = '0' + ((u[i]-'0')+1)%10; + if (stops.find(v) == stops.end()) q.push(v); + v[i] = '0' + ((u[i]-'0')-1+10)%10; + if (stops.find(v) == stops.end()) q.push(v); + } + } + cnt++; + } + return -1; + } +}; + +// Bidirectional BFS optimization +``` + +## Shortest Paths + +### Bellman-Ford Algorithm + +* Finds shortest path from starting node to all other nodes in **O\(VE\)** +* Doesn't work with negative cycle \(works on negative edges unlike Dijikstra, negative cycle is the cycle with total sum negative\) +* Relaxes graph n-1 times, in each relaxation picks every edge and minimises u->v path distance. +* If the graph contains a negative cycle, we can shorten infinitely many times any path that contains the cycle by repeating the cycle again and again. Thus, the concept of a shortest path is not meaningful in that situation. + +```cpp +struct edge { int u, v, w; }; +#define INF (1LL<<61) +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<1, edge> edges(m); + for (auto &x : edges) cin >> x.u >> x.v >> x.w; + + vec<1, int> dist(n+1, INF), par(n+1, -1); + int x; + for (int i = 0; i < n; ++i) + { + x = -1; + for (auto &e : edges) + { + if (dist[e.u] + e.w < dist[e.v]) + { + dist[e.v] = dist[e.u] + e.w; + par[e.v] = e.u; + x = e.v; + } + } + } + + if (x == -1) cout << "NO\n"; + else + { + cout << "YES\n"; + for (int i = 0; i < n; ++i) x = par[x]; + vec<1, int> cycle; + for (int v = x; ; v = par[v]) + { + cycle.push_back(v); + if (v == x && cycle.size() > 1) break; + } + reverse(all(cycle)); + for (auto &x : cycle) cout << x << " "; + cout << '\n'; + } + return 0; +} + +/* Usually we get ans in few phases so terminating early will be better +so introducing a 'changes' check to detect if there's any change can speed up */ +vector findPath(int to, vector &prev) +{ + vector path; + for (int cur = to; cur != -1; cur = prev[cur]) + path.push_back(cur); + reverse(path.begin(), path.end()); + return path; +} +``` + +**Proof:** + +For all unreachable vertices algorithm works fine. + +Let us now prove the following assertion: After the execution of ith phase, the Bellman-Ford algorithm correctly finds all shortest paths whose number of edges does not exceed i. Also any shortest path cannot have more than n-1 vertices so relaxing atmost n-1 times should do it. + +![](.gitbook/assets/image%20%28112%29%20%281%29.png) + +### SPFA Algorithm + +* Fastest algorithm source - all nodes shortest path, average case it's linear however worst case same as Bellman-Ford. +* The algorithm maintains a queue of nodes that is used for reducing the distances. First, the algorithm adds the starting node x to the queue. Then, the algorithm always processes the first node in the queue, and when an edge a→b reduces a distance, node b is added to the queue. + +```cpp +bool spfa(int s, int n, vector adj[], vector &dist) +{ + dist.assign(n, INF); + vector cnt(n, 0); + vector inqueue(n, false); + queue q; + dist[s] = 0; + q.push(s); + inqueue[s] = true; + while (!q.empty()) + { + int u = q.front(); + q.pop(); + inqueue[u] = false; + for (auto &edge : adj[u]) + { + int v = edge.first, w = edge.second; + if (dist[u] + w < dist[v]) + { + dist[v] = dist[u] + w; + if (!inqueue[v]) + { + q.push(v); + inqueue[v] = true; + cnt[v]++; + if (cnt[v] > n) return false; // negative cycle + } + } + } + } + return true; +} +``` + +### Dijkstra Algorithm + +![](.gitbook/assets/image%20%2890%29%20%281%29.png) + +* Priority queue version is O\(E logV\) +* A remarkable property in Dijkstra’s algorithm is that whenever a node is selected, its distance is final + +```cpp +void dijkstra(int s, int n, vector adj[], vector &dist, vector &prev) +{ + dist.assign(n, INF); + prev.assign(n, -1); + dist[s] = 0; + priority_queue, greater> pq; + pq.push({0, s}); + while (!pq.empty()) + { + int u = pq.top().second, d = pq.top().first; + pq.pop(); + if (d != dist[u]) continue; + for (auto &edge : adj[u]) + { + int v = edge.first, w = edge.second; + if (dist[u] + w < dist[v]) + { + dist[v] = dist[u] + w; + prev[v] = u; + pq.push({dist[v], v}); + } + } + } +} +``` + +### 0-1 BFS + +* Used in unweighted graph \(or 0-1 weight graph\), performs in O\(E\) + +```cpp +void zeroOneBFS(int s, int n, vector adj[], vector &dist, vector &prev) +{ + dist.assign(n, INF); + prev.assign(n, -1); + dist[s] = 0; + deque dq; + dq.push_front(s); + while (!dq.empty()) + { + int u = dq.front(); + dq.pop_front(); + for (auto &edge : adj[u]) + { + int v = edge.first, w = edge.second; + if (dist[u] + w < dist[v]) + { + dist[v] = dist[u] + w; + prev[v] = u; + if (w == 1) dq.push_back(v); + else dq.push_front(v); + } + } + } +} +``` + +### Floyd Warshall Algorithm + +```cpp +for (int k = 0; k < n; ++k) +{ + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) + if (dist[i][k] < INF && dist[k][j] < INF) + dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]); +} +``` + +* [Greg and Graph](https://codeforces.com/contest/296/problem/D) - [https://codeforces.com/contest/296/submission/74248854](https://codeforces.com/contest/296/submission/74248854) + +## Disjoint Set Union + +```cpp +int parent[1000]; +void makeSet(int x) { parent[x] = x; } +int findSet(int x) { return (x == parent[x]) ? x : findSet(parent[x]); } +void unionSet(int x, int y) +{ + x = findSet(x), y = findSet(y); + if (x != y) parent[y] = x; +} +// In worst case it's linear in nature (in case of long chain) + +/* If we call find_set(v) for some vertex v, we actually find +the representative p for all vertices that we visit on the path +between v and the actual representative p. The trick is to make +the paths for all those nodes shorter, by setting the parent of +each visited vertex directly to p. */ + +// Path compression modification in findSet() +int findSet(int x) { return (x == parent[x]) ? x : parent[x] = findSet(parent[x]); } +// This makes avg logN + +/* Next optimization is in union operation, In the naive +implementation the second tree always got attached to the first +one. In practice that can lead to trees containing chains of length +O(n). So we will have a size field storing size of subtree and we +will append to make our tree shorter */ + +// Final optimized implementation using path compression +int parent[1000], sz[1000]; +void makeSet(int x) { parent[x] = x, sz[x] = 1; } +int findSet(int x) { return (x == parent[x]) ? x : parent[x] = findSet(parent[x]); } +void unionSet(int x, int y) +{ + x = findSet(x), y = findSet(y); + if (x != y) + { + // size compression + if (sz[x] < sz[y]) swap(x, y); + parent[y] = x; + sz[x] += sz[y]; + /* + // Rank Compression + if (rank[x] < rank[y]) swap(x, y); + parent[y] = x; + if (rank[x] == rank[y]) rank[x]++; + */ + } +} +``` + +If we combine both optimizations path compression & union by size we will reach nearly constant time queries. It's O\(α\(n\)\), where α\(n\) is the inverse Ackermann function, which grows very slowly. Worst case it's logN. + +* **Connected components in a graph** - Initially we have an empty graph. We have to add vertices and undirected edges, and answer queries of the form \(a,b\) - "are the vertices a and b in the same connected component of the graph?" - Used by Kriskal MST algo +* **Search for connected components in an image -** there is an image of n×m pixels. Originally all are white, but then a few black pixels are drawn. You want to determine the size of each white connected component in the final image. Iterate all n\*m cells and if it's white iterate to it's neighbour if they are also white then union them. Thus resulting tree in DSU are desired connected components. +* **Painting subarrays offline -** Given n length array and m queries \(specifying l, r and c\) we are painting from l to r to color c. Now we want to tell final color. Solution is start in reverse of query because what's colored in ith will never get recolored before i. We are basically marking components from l to r. x = findset\(x\) ensures we skip components which are colored before. parent\[x\] = x+1 moves the array. + +```cpp +int n, m; cin >> n >> m; +for (int i = 0; i <= n; ++i) makeSet(i); +vector> query(m); +for (auto &x : query) cin >> x.F.F >> x.F.S >> x.S; +int ans[n] {}; +for (int i = m-1; i >= 0; --i) +{ + int l = query[i].F.F-1, r = query[i].F.S-1, c = query[i].S; + for (int x = findSet(l); x <= r; x = findSet(x)) + ans[x] = c, parent[x] = x+1; +} +``` + +### [Most Stones Removed with Same Row or Column](https://leetcode.com/problems/most-stones-removed-with-same-row-or-column/) + +create a graph connecting edge i & j such that stone\[i\] and stone\[j\] are either in same row or same column. + +Idea is that we can reduce every components \(formed in such a graph\) to 1 node. So N - 1\*components should be the answer + +```cpp +vector parent; +void makeSet(int x) { parent[x] = x; } +int findSet(int x) { return x == parent[x] ? x : parent[x] = findSet(parent[x]); } +void unionSet(int x, int y) +{ + x = findSet(x), y = findSet(y); + if (x != y) parent[y] = x; +} + +int removeStones(vector>& stones) +{ + unordered_map> row, col; + int n = stones.size(); + for (int i = 0; i < n; ++i) + { + row[stones[i][0]].push_back(i); + col[stones[i][1]].push_back(i); + } + parent.resize(n); + for (int i = 0; i < n; ++i) makeSet(i); + for (int i = 0; i < n; ++i) + { + for (int j : row[stones[i][0]]) unionSet(i, j); + for (int j : col[stones[i][1]]) unionSet(i, j); + } + unordered_set res; + for (const int x : parent) res.insert(findSet(x)); + return n - res.size(); +} +``` + +### [Evaluate Division](https://leetcode.com/problems/evaluate-division/) + +Given a list of form a/b = some\_double, find answer for query list of form p/q. Return -1 if not possible for that query. + +```cpp +/* idea is if given some a/b value we are essentially grouping a and b i.e. we can find b/a aswell with +this piece of information. Say given a/b b/c we can find a/c also. So we should group them together +to maintain a record. +When there's a new edge we can associate vals to its individual nodes initially v : 1. We have to +maintain whole other subtree in case it mismatches. Example + +a/b = 3 e/f = 2 (b is 1.5 assuming, a is 4.5, f = 6, e = 3) b/e = 1.5/3 = 0.5 + + (3) a ---> b (1) (2) e ---> f (1) After first 2 insertion + + Inserting b ---> e requires changing it's corresponding subtree aswell + For finding a value we keep multiplying entire subtree, so value of a is 3*1, value of e is 2*1 + so we move to the last node i.e. b & f and connect b ---> f instead and change their value. + va will become v * vb/va i.e. 0.5 * (2/1) + + (3) a ---> b (1) (2) e ---> f (1) + \--------------------/ + + There could be multiple possible values so a, b might not correspond to the one we + assumed initially, but it's correct +*/ +unordered_map> rec; +void makeSet(string x) { rec[x] = {x, 1.0}; } +string findSet(string x, double &val) +{ + while (rec[x].first != x) + { + val *= rec[x].second; + x = rec[x].first; + } + return x; +} +void unionSet(string x, string y, double val) +{ + double vx = 1.0, vy = 1.0; + x = findSet(x, vx), y = findSet(y, vy); + if (x != y) rec[x] = {y, val * vy/vx}; +} + +vector calcEquation(vector>& equations, vector& values, vector>& queries) +{ + rec.clear(); + for (int i = 0; i < equations.size(); ++i) + { + string a = equations[i][0], b = equations[i][1]; + if (rec.find(a) == rec.end()) makeSet(a); + if (rec.find(b) == rec.end()) makeSet(b); + unionSet(a, b, values[i]); + } + vector res; + for (auto &x : rec) + cout << x.first << " " << x.second.first << " " << x.second.second << '\n'; + for (const auto q : queries) + { + if (rec.find(q[0]) == rec.end() || rec.find(q[1]) == rec.end()) + res.push_back(-1); + else + { + double va = 1.0, vb = 1.0; + if (findSet(q[0], va) == findSet(q[1], vb)) res.push_back(va/vb); + else res.push_back(-1); + } + } + return res; +} +``` + +* [Path Queries](https://codeforces.com/contest/1213/problem/G): Consider sorted edges \(according to weight\) to find ans for an arbitary weight w we have to consider DSU unioned tree keep choosing 2 from the chosen, to choose 2 we can simply modify our DFS union set to increment cnt += sz\[x\] + sz\[y\] [https://codeforces.com/contest/1213/submission/78358873](https://codeforces.com/contest/1213/submission/78358873) + +## Spanning Trees + +A spanning tree of a graph consists of all nodes of the graph and some of the edges of the graph so that there is a path between any two nodes. Like trees. A minimum spanning tree is a spanning tree whose weight is as small as possible. + +### Kruskal's Algorithm + +* Finds MST in O\(E logV\) mostly used over Prim's because implementation is small + +```cpp +for (int i = 0; i < n; ++i) makeSet(i); +sort(edges.begin(), edges.end(), [](Edge a, Edge b){ return a.w < b.w; }); +for (auto &edge : edges) +{ + if (findSet(edge.u) != findSet(edge.v)) + { + cost += edge.w; + res.push_back(edge); + unionSet(edge.u, edge.v); + } +} +``` + +### Prim's Algorithm + +* Finds MST in O\(N^2\) however using set \(or heap\) we can find minimum edge in logn time making it O\(E logV\) + +```cpp +set q; // Edge has w & to +st.insert({0, 0}); +vector selected(n, false); +vector minE(n); +minE[0].w = 0; + +for (int i = 0; i < n; ++i) +{ + if (st.empty()) { cout << "NO MST!\n"; return 0; } + int v = st.begin()->to; + selected[v] = true; + cost += st.begin()->w; + st.erase(st.begin()); + if (minE[v].to != -1) cout << v << " " << minE[v].to << '\n'; + for (auto &edge : adj[v]) + { + if (!selected[edge.to] && edge.w < minE[edge.to].w) + { + st.erase({minE[edge.to].w, edge.to}); + minE[edge.to] = {edge.w, v}; + st.insert({edge.w, v}); + } + } +} +``` + +## Directed Graphs + +In Directed graphs Topological sort is very important, in directed acyclic concept of DP can be applied + +### Topological Sort + +```cpp +// General Approach +queue ans; +void DFS(int u) +{ + visited[u] = true; + for (int v : adj[u]) + if (!visited[v]) DFS(v); + ans.push(u); +} +for (int i = 0; i < n; ++i) + if (!visited[i]) DFS(i); +while (!ans.empty()) { cout << ans.front() << '\n'; q.pop(); } + +// Kanh's Algorithm +queue q; +for (int i = 0; i < n; ++i) + if (inDeg[i] == 0) q.push(i); +vector topOrder; +while (!q.empty()) +{ + auto u = q.front(); q.pop(); + topOrder.push_back(u); + for (auto &v : adj[u]) + { + inDeg[v]--; + if (inDeg[v] == 0) q.push(v); + } +} + +// Can check if graph is cyclic by topOrder.size() != n +``` + +#### [Alien Dictionary](https://www.lintcode.com/problem/alien-dictionary/description) + +```cpp +string alienOrder(vector &words) +{ + unordered_map inDeg; + for (auto &x : words) for (auto &y : x) inDeg[y] = 0; + unordered_map> adj; + for (int i = 0; i < words.size()-1; ++i) + { + string word1 = words[i], word2 = words[i+1]; + for (int j = 0; j < min(word1.size(), word2.size()); ++j) + if (word1[j] != word2[j]) { adj[word1[j]].push_back(word2[j]), inDeg[word2[j]]++; break; } + } + + priority_queue, greater> q; + for (auto &x : inDeg) + if (x.second == 0) q.push(x.first); + string res; + while (!q.empty()) + { + auto u = q.top(); q.pop(); + res += u; + for (auto &v : adj[u]) + { + inDeg[v]--; + if (inDeg[v] == 0) q.push(v); + } + } + return (res.size() == inDeg.size()) ? res : ""; +} +``` + +### Counting the number of paths + +![Let's calculate number of paths from node 1 to node 6](.gitbook/assets/image%20%2876%29.png) + +![](.gitbook/assets/image%20%2844%29.png) + +```cpp +void DFS(int u) +{ + DP[u]++; + for (auto &v : adj[u]) DFS(v); +} +DFS(s); +cout << DP[d] << '\n; +``` + +### Extending Dijkstra's Algorithm + +By product of Dijkstra algorithm is a DAG signifying considered shortest path edges. DP can be applied to find number of shortest paths from source to destination like above. + +![](.gitbook/assets/image%20%28136%29.png) + +### Successor Paths + +* Such graphs have outdegree as 1 \(also called functional graph since it defines a function\) + +![succ\(4,6\) = 2 i.e. move 6 units from point 4](.gitbook/assets/image%20%28108%29%20%281%29.png) + +In finding succ\(x, k\) it takes O\(k\) time however with preprocessing query becomes O\(logK\) + +![](.gitbook/assets/image%20%2854%29.png) + +```cpp +// spraseTable[0] will represent succ array +// For query, present k as sum of powers of 2 so 11 = 8 + 2 + 1 +// succ(x,11) = succ(succ(succ(x,8),2),1) +const int MAXN = 2*1e5 + 5; +vec<2, int> sparseTable(32, MAXN); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, q; cin >> n >> q; + for (int j = 1; j <= n; ++j) cin >> sparseTable[0][j]; + for (int i = 1; i < 32; ++i) + for (int j = 1; j <= n; ++j) + sparseTable[i][j] = sparseTable[i-1][sparseTable[i-1][j]]; + + while (q--) + { + int x, k; cin >> x >> k; + vec<1, int> repre; + int cur = 1; + while (k) + { + if (k&1) repre.push_back(cur); + k >>= 1; cur <<= 1; + } + reverse(all(repre)); + int res = x; + for (auto &v : repre) + res = sparseTable[log2(v)][res]; + cout << res << '\n'; + } + return 0; +} +``` + +## Trees + +### Finding kth ancestors + +Above logic in successor paths can be applied here + +![](.gitbook/assets/image%20%2824%29.png) + +![](.gitbook/assets/image%20%28166%29.png) + +### Diameter of a tree + +* Maximum length of a path between two nodes. \(There could be multiple diameters possible\) +* **Algorithm 1:** A general way to approach many tree problems is to first root the tree arbitrarily, after that solve the problem separately for each subtree. For each node we find: toLeaf\(x\): max length of path from x to any leaf. maxLength\(x\): max length of path whose highest point is x. + +![](.gitbook/assets/image%20%2888%29.png) + +```cpp +const int N = 2*1e5; +int n; +vector adj[N], toLeaf(N), maxLength(N); +int DFS(int u = 0, int par = -1, int depth = 0) +{ + int mxDepth = 0, secondMxDepth = 0; + for (auto &v : adj[u]) + { + if (v == par) continue; + int cur = DFS(v, u, depth+1); + if (cur > mxDepth) secondMxDepth = mxDepth, mxDepth = cur; + else if (cur > secondMxDepth) secondMxDepth = cur; + } + maxLength[u] = mxDepth + secondMxDepth + 1; + return toLeaf[u] = mxDepth+1; +} +``` + +* **Algorithm 2:** Another way is using 2 DFS. Go to deepest point from any root using DFS then from that deepest point again apply DFS this will be our second point of diameter. + +```cpp +const int N = 2*1e5; +int n; +vector adj[N], parent(N); +void DFS(int u, pii &res, int par = -1, int dist = 0) +{ + parent[u] = par; + res = max(res, {dist, u}); + for (auto &v : adj[u]) + { + if (v == par) continue; + DFS(v, res, u, dist+1); + } +} +vector findDiameter(pii &pointA, pii &pointB) +{ + DFS(0, pointA); DFS(pointA.second, pointB); + vector diameter; + for (int cur = pointB.second; cur != pointA.second; cur = parent[cur]) + diameter.push_back(cur); + diameter.push_back(pointA.second); + return diameter; +} +``` + +### All Longest Paths + +* Find for every node, the maximum length of path that begins at that node in O\(n\). This can be seen as genralization of above diameter problem. +* Not so optimal but easy to understand strategy is to pick every leaf nodes and find distances considering it as root. + +![Here we are finding length \(edges\), we can generally find nodes and subtract it by 1](.gitbook/assets/image%20%2894%29.png) + +```cpp +const int MAXN = 1e5; +int n; +vector adj[MAXN+1]; +int source[MAXN+1], dist[MAXN+1], secondMaxDist[MAXN+1]; +int DFS(int u = 0, int par = -1) +{ + int mx = 0, pt = -1, secondMx = 0; + for (auto &v : adj[u]) + { + if (v == par) continue; + int cur DFS(v, u); + if (cur > mx) mx = cur, pt = v; + else if (cur > secondMx) secondMx = cur; + } + source[u] = pt, dist[u] = mx+1, secondMaxDist[u] = secondMx+1; + return mx+1; +} +int DFS2(int u = 0, int par = -1) +{ + if (par != -1) + { + dist[u] = max(dist[u], (source[par] == u) ? secondMaxDist[par]+1 : dist[par]+1); + if (dist[u] == dist[par]+1 || dist[u] == secondMaxDist[par]+1) source[u] = par; + } + for (auto &v : adj[u]) + { + if (v == par) continue; + DFS2(v, u); + } +} +``` + +### Re-rooting technique + +[https://atcoder.jp/contests/abc160/tasks/abc160\_f](https://atcoder.jp/contests/abc160/tasks/abc160_f) + +```cpp +/* dp[u] = (cnt[u] - 1)! * (dp[v0]/cnt[v0]!) * (dp[v1]/cnt[v1]!) +After that applying rerooting technique */ +vector adj[MAXN+1]; +int cnt[MAXN+1], dp[MAXN+1]; +vector adj[MAXN+1]; +int cnt[MAXN+1], dp[MAXN+1]; +void precompute(int u, int par = -1) +{ + cnt[u] = 1, dp[u] = 1; + for (auto &v : adj[u]) + { + if (v == par) continue; + precompute(v, u); + cnt[u] += cnt[v]; + dp[u] = multiply(dp[u], divide(dp[v], fact[cnt[v]])); + } + dp[u] = multiply(dp[u], fact[cnt[u]-1]); +} +void reroot(int u, int par = -1) +{ + cout << dp[u] << '\n'; + for (auto &v : adj[u]) + { + if (v == par) continue; + int prev_dp_u = dp[u], prev_dp_v = dp[v], prev_cnt_u = cnt[u], prev_cnt_v = cnt[v]; + dp[u] = divide(dp[u], dp[v]); + dp[u] = multiply(dp[u], fact[cnt[v]]); + dp[u] = divide(dp[u], fact[cnt[u]-1]); + dp[v] = divide(dp[v], fact[cnt[v]-1]); + cnt[u] -= cnt[v]; + cnt[v] += cnt[u]; + dp[u] = multiply(dp[u], fact[cnt[u]-1]); + dp[v] = multiply(dp[v], dp[u]); + dp[v] = multiply(dp[v], fact[cnt[v]-1]); + dp[v] = divide(dp[v], fact[cnt[u]]); + + reroot(v , u); + + dp[u] = prev_dp_u, dp[v] = prev_dp_v, cnt[u] = prev_cnt_u, cnt[v] = prev_cnt_v; + } +} +``` + +[https://codeforces.com/contest/1187/problem/E](https://codeforces.com/contest/1187/problem/E) + +Here dp\[u\] = cnt\[u\] + dp\[v0\] + dp\[v1\] + dp\[v2\] ... + +```cpp +void reroot(int u, int par = -1) +{ + ans = max(ans, dp[cur]); + for (auto &v : adj[u]) + { + if (v == par) continue; + int prev_dp_u = dp[u], prev_dp_v = dp[v], prev_cnt_u = cnt[u], prev_cnt_v = cnt[v]; + dp[u] -= dp[v]; + dp[u] -= cnt[v]; + cnt[u] -= cnt[v]; + cnt[v] += cnt[u]; + dp[v] += cnt[u]; + dp[v] += dp[u]; + + reroot(v , u); + + dp[u] = prev_dp_u, dp[v] = prev_dp_v, cnt[u] = prev_cnt_u, cnt[v] = prev_cnt_v; + } +} +``` + +[https://codeforces.com/contest/1324/problem/F](https://codeforces.com/contest/1324/problem/F) + +[https://codeforces.com/contest/960/problem/E](https://codeforces.com/contest/960/problem/E) + +### Subtree traversal technique + +Using the DFS traversed array we are performing certain queries + +![](.gitbook/assets/image%20%2855%29%20%281%29.png) + +* Each subtree corresponds to subarray, such that first element in root node using this we can - update the value of a node, calculate the sum of values in subtree of a node. Idea is to construct a tree traversal array that contains 3 values for each node -size of subtree and value of node. Now to find say sum of values of node 4 check corresponding size and then sum all those \(as shown in image\). This summation or updation can be done using BIT making query logN + +![](.gitbook/assets/image%20%2851%29.png) + +* Say now problem is change the value of node, calculate sum of values on a path from root to node. Idea is now to contruct a path sum row from root to that node. When the value of a node increases by x, the sums of all nodes in its subtree increase by x. Now query is O\(1\) but updation is O\(logN\) + +![Sum of values from root to 7 is 4+5+5 = 14](.gitbook/assets/image%20%28127%29.png) + +![Updating in node 4 by 1 means +1 in entire subtree](.gitbook/assets/image%20%28161%29.png) + +* Lowest common ancestor of two nodes of a rooted tree is the lowest node whose subtree contains both the nodes. + +![](.gitbook/assets/image%20%28128%29%20%281%29.png) + +![LCA\(5, 8\) = element with min depth between that range i.e. 2](.gitbook/assets/image%20%2895%29.png) + +* Distances of nodes say in image below between 5 & 8. dist\(a, b\) = depth\(a\) + depth\(b\) - 2\*depth\(c\) where c is LCA of a & b. + +![](.gitbook/assets/image%20%28131%29%20%281%29.png) + +## Strongly Connectivity + +### Kosaraju Algorithm + +* Find topological ordering like you do using DFS +* Apply DFS over graph transpose in topological ordering those will be SCC. + +```cpp +const int MAXN = 1e5; +vector adj[MAXN+1], adjRev[MAXN+1], order, component; +vector used; +int n, e; +void DFS(int u) +{ + used[u] = true; + for (auto &v : adj[u]) + if (!used[v]) DFS(v); + order.push_back(u); +} +void DFS2(int u) +{ + used[u] = true; + component.push_back(u); + for (auto &v : adjRev[u]) + if (!used[v]) DFS2(v); +} +int main() +{ + cin >> n >> e; + for (int i = 0; i < e; ++i) + { + int u, v; cin >> u >> v; + adj[u].push_back(v); + adjRev[v].push_back(u); + } + used.assign(n, false); + for (int i = 0; i < n; ++i) + if (!used[i]) DFS(i); + used.assign(n, false); + reverse(order.begin(), order.end()); + for (auto &v : order) + { + if (used[v]) continue; + DFS2(v); + // Process compoenents + component.clear(); + } +} +``` + +* [Submergin Islands](http://www.spoj.com/problems/SUBMERGE/) +* [Good Travels](http://www.spoj.com/problems/GOODA/) +* [Lego](http://www.spoj.com/problems/LEGO/) +* [Chef and Round Run](https://www.codechef.com/AUG16/problems/CHEFRRUN) +* [Come and Go](https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2938) +* [Calling Circles](https://uva.onlinejudge.org/index.php?option=onlinejudge&page=show_problem&problem=183) +* [Prove Them All](https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4955) +* [Water Supply](https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4393) +* [Lighting Away](https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2870) +* [Trouble in Terrorist Town](https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=862&page=show_problem&problem=4805) +* [The Largest Clique](https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2299) +* [Trust groups](https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2756) +* [Wishmaster](https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4598) +* [True Friends](http://www.spoj.com/problems/TFRIENDS/) +* [Capital City](http://www.spoj.com/problems/CAPCITY/) +* [Scheme](http://codeforces.com/contest/22/problem/E) +* [Ada and Panels](http://www.spoj.com/problems/ADAPANEL/) + +### 2SAT Problem + +Problem of assigning Boolean values to variable to satisfy a given Boolean formula. + +![Example: Find assignment of x1, x2, x3, x4 such that formula is true](.gitbook/assets/image%20%28192%29.png) + +Each pair \(a V b\) generates two edges -a -> b and -b ->a + +![Corresponding graph of the Boolean formula](.gitbook/assets/image%20%28139%29%20%281%29.png) + +* First we construct the graph of implications and find all strongly connected components. Done in O\(n+m\) +* Afterwards we can choose the assignment of x by comparing comp\[x\] and comp\[¬x\]. If comp\[x\]=comp\[¬x\] we return false to indicate that there doesn't exist a valid assignment that satisfies the 2-SAT problem. + +```cpp +vector> adj, adjRev; +vector vis, sol, isTrue; +vector mvStk; +bool noSolution; +int N; +void DFS1(int node) +{ + vis[node] = true; + for (auto vec : adj[node]) + if (!vis[vec]) DFS1(vec); + mvStk.push_back(node); +} +void DFS2(int node) +{ + if (isTrue[node]) noSolution = true; + vis[node] = true; + isTrue[node^1] = true; + sol[node/2] = ((node&1) ^ 1); + for (auto vec : adjRev[node]) + if (!vis[vec]) DFS2(vec); +} +inline int get_node(int x) { return (x > 0) ? (2 * (x-1) + 1) : (2 * (-x-1)); } +// USE BELOW FUNCTIONS ONLY +int initialize(int _n) +{ + N = _n; + adj.assign(2*N, vector()); + adjRev.assign(2*N, vector()); + vis.assign(2*N, false); + sol.assign(N, false); + isTrue.assign(2*N, false); + mvStk.reserve(2*N); +} +void addEdge(int p, int q) +{ + int a, b; + a = get_node(-p); b = get_node(q); + adj[a].push_back(b); + adjRev[b].push_back(a); + + a = get_node(-q); b = get_node(p); + adj[a].push_back(b); + adjRev[b].push_back(a); +} +pair> solve2SAT() +{ + fill(vis.begin(), vis.end(), 0); + for (int i = 0; i < 2*N; ++i) + if (!vis[i]) DFS1(i); + noSolution = false; + fill(vis.begin(), vis.end(), 0); + for (int i = 2*N - 1; i >= 0; --i) + if (!vis[mvStk[i]] && !vis[mvStk[i] ^ 1]) DFS2(mvStk[i]); + return {!noSolution, sol}; +} +``` + +* [Rectangles](https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3081) +* [The Door Problem](http://codeforces.com/contest/776/problem/D) +* [Radio Stations](https://codeforces.com/problemset/problem/1215/F) + +## Paths & Circuits + +> Circuit is a path that starts and ends at same node + +### Eulerian Path + +* Goes through each edge exactly once. +* Efficient algorithm exists. +* An unidirected graph has eulerian path when: + * All edge belongs to 1 connected component. + * Deg of each node is even - \(Euler circuit from every node\) or + * Deg of exactly 2 nodes is odd and other even - \(Euler path only from 1st odd node to 2nd\). + +![Node 1, 3 and 4 have deg 2 and node 2 and 5 have deg 3. \(2-5 Euler path no circuit\)](.gitbook/assets/image%20%28100%29.png) + +* A directed graph has eulerian path when: + * All edge belongs to 1 connected component. + * InDeg = OutDeg in each node - \(Euler circuit from every node\) or + * In 1 node InDeg > OutDeg and in other InDeg < OutDeg rest equal - \(Euler path only from those two nodes\). + +![Euler path 2-3-5-4-1-2-5](.gitbook/assets/image%20%28140%29%20%281%29.png) + +```cpp +/* Heirholzer's Algorithm to find Euler path in O(V + E) */ +const int MAXN = 1e5+5; +struct Edge; +typedef list::iterator iter; +vec<1, int> deg(MAXN, 0); +int edgeCnt = 0; +struct Edge +{ + int nextVertex; + iter reverseEdge; + Edge(int _nextVertex) : nextVertex(_nextVertex) { } +}; +int n; +list adj[MAXN+1]; +vector path; +void addEdge(int a, int b) +{ + adj[a].push_front(Edge(b)); + iter ita = adj[a].begin(); + adj[b].push_front(Edge(a)); + iter itb = adj[b].begin(); + ita->reverseEdge = itb; + itb->reverseEdge = ita; + deg[a]++, deg[b]++; + edgeCnt++; +} +void helper(int u) +{ + while (adj[u].size() > 0) + { + int v = adj[u].front().nextVertex; + adj[v].erase(adj[u].front().reverseEdge); + adj[u].pop_front(); + helper(v); + } + path.push_back(u); +} +bool findEulerianPathUndirected(int u, int n) +{ + for (auto &x : deg) + if (x&1) return false; + helper(u); + return (path.size() == edgeCnt+1); +} +``` + +```cpp +vector findEulerianPathDirected(vector adj[], int u) +{ + vector stack, curr_edge(MAXN), res; + stack.push_back(u); + while (!stack.empty()) + { + u = stack.back(); + stack.pop_back(); + while (curr_edge[u] < (int)adj[u].size()) + { + stack.push_back(u); + u = adj[u][curr_edge[u]++]; + } + res.push_back(u); + } + reverse(res.begin(), res.end()); + return res; +} +``` + +### [Reconstruct Itinerary](https://leetcode.com/problems/reconstruct-itinerary/) + +```cpp +class Solution { +public: + unordered_map> adj; + unordered_map ptr; + + void dfs(string u, vector &res) + { + while (ptr[u] < adj[u].size()) + dfs(adj[u][ptr[u]++], res); + res.push_back(u); + } + + vector findItinerary(vector>& tickets) + { + adj.clear(); ptr.clear(); + for (const auto x : tickets) adj[x[0]].push_back(x[1]); + for (auto &x : adj) sort(x.second.begin(), x.second.end()); + vector res; + dfs("JFK", res); + reverse(res.begin(), res.end()); + return res; + } +}; +``` + +{% embed url="https://youtu.be/iPLQgXUiU14" caption="De Bruijn Sequence" %} + +A De Bruijn sequence on set \['0', '1'\] of length 2 is 01100 because its substring contains all possible n length from given set i.e. 00 01 10 11 + +[https://www.geeksforgeeks.org/de-bruijn-sequence-set-1/](https://www.geeksforgeeks.org/de-bruijn-sequence-set-1/) + +Every possible string on st of length _n_ appears exactly once as a substring. n = 3 {0, 1} = 0011101000 in O\(K^n\) + +```cpp +unordered_set done; +vec<1, int> edges; +void DFS(string node, string &st) +{ + for (int i = 0; i < st.size(); ++i) + { + string cur = node+st[i]; + if (done.find(cur) == done.end()) + { + done.insert(cur); + DFS(cur.substr(1), st); + edges.push_back(i); + } + } +} +string deBruijn(int n, string st) +{ + done.clear(); edges.clear(); + string startingNode = string (n-1, st[0]); + DFS(startingNode, st); + string res; + for (auto &x : edges) res += st[x]; + res += startingNode; + return res; +} +``` + +### Hamiltonian Path + +* Goes through each node exactly once. +* NP Hard problem. +* No efficient method is known for testing if a graph contains a Hamiltonian path. + * Dirac's Theorem: If deg of each node is atleast n/2 graph contains hamiltonian path. + * Ore's Theorem: If sum of deg of each non-adjacent pair of nodes is at least n the graph contains hamiltonian path. +* Simple way to search for hamiltonian path is to use backtracking O\(n!\) since there are n! different ways to choose the order of n nodes. + +### Knight's Tours + +A knight’s tour corresponds to a Hamiltonian path in a graph whose nodes represent the squares of the board, and two nodes are connected with an edge if a knight can move between the squares according to the rules of chess. + +![One of knight tour in 5x5 board](.gitbook/assets/image%20%28165%29.png) + +Solve using backtracking. + +> Warnsdorf's rule: simple and effective heuristic for finding a knight’s tour. Idea is to always move the knight so that it ends up in a square where the number of possible moves is as small as possible. + +### Power of Adjancey Matrix + +![V^4\[2\]\[5\] = 2 i.e. there are 2 paths from 2 to 5 with 4 edges](.gitbook/assets/image%20%2887%29.png) + +* [Timofey and a tree](https://codeforces.com/problemset/problem/763/A) - Given a tree of n vertex \(n-1 edges\) also given an array representing color of node i. We want to pick a node and make it root such that all sub tree formed have only one type of color. **Solution:** If we pick a node x such that edge from it goes to y. If x and y are of different colors then it is definite that they can't lie in same subtree means the breaking should occur here so we either take x as root or y as root. Later we also have to check if after picking x condition is valid or after picking y if both fails then print NO. There can be a scenerio in which all nodes are of same color then x & y nodes will not be found we should also handle that. [https://codeforces.com/contest/763/submission/72618301](https://codeforces.com/contest/763/submission/72618301) After finding node x, y we're applying DFS on subtree to find if all elements there have same color or not. [https://codeforces.com/contest/763/submission/72618931](https://codeforces.com/contest/763/submission/72618931) Less intuitive approach of reducing DFS overhead +* [Greg and Graph](https://codeforces.com/contest/296/problem/D) - Given an adjancey matrix, and q queries specifying order to delete that vertex \(removing each of its edges\) Find sum of all pair distance every time before removing the vertex. **Solution:** Idea is similar to all pair shortest time algorithm - Floyd Warshall [https://codeforces.com/contest/296/submission/74248854](https://codeforces.com/contest/296/submission/74248854) +* [Xenia and BIT Operations](https://codeforces.com/problemset/problem/339/D): Use the idea of expression tree that will reduce query time complexity to logN [https://codeforces.com/contest/339/submission/74685358](https://codeforces.com/contest/339/submission/74685358) +* [Tree Cutting \(Easy\)](https://codeforces.com/problemset/problem/1118/F1): Nice problem of showing power of DFS precomputation, simple precompute cnt \(when color in subtree is non zero\) sm \(when color in subtree is non zero\) and also depth. If we pick an edge we can check if it adds up to ans in O\(1\) by counting corresponding non-connected component sum/cnt \(this will give which color that component has, checking with % will make sure than no two different color exists. [https://codeforces.com/contest/1118/submission/74688957](https://codeforces.com/contest/1118/submission/74688957) +* [Swaps In Permutation](https://codeforces.com/contest/691/problem/D): Given a permutation array having elements 1 to n also given m pairs signifying swaps we can perform find such final permutation after performing swaps giving lexiographically largest permutation. **Solution:** If we form a graph based on the swaps and consider all the connected components, when first element of some component shows swap it with available largest from element within that component next time again then second largest and so on. [https://codeforces.com/contest/691/problem/D](https://codeforces.com/contest/691/problem/D) + +## Flows & Cuts + +![](.gitbook/assets/image%20%28110%29.png) + +Given a directed weighted graph with source and sink, edges analogous to pipes, water comes from source and wents to sink. We want to find - Max Flow and Min Cut + +![Maximum flow here is 7 \(out from source and in to sink\)](.gitbook/assets/image%20%28106%29.png) + +In the minimum cut problem, our task is to remove a set of edges from the graph such that there will be no path from the source to the sink after the removal and the total weight of the removed edges is minimum. + +![Minimum size of cut here is 7 \(remove 6 and 1\)](.gitbook/assets/image%20%28120%29.png) + +Max Flow is always equal to min Cut. Why is the flow produced by the algorithm maximum and why is the cut minimum? The reason is that a graph cannot contain a flow whose size is larger than the weight of any cut of the graph. Hence, always when a flow and a cut are equally large, they are a maximum flow and a minimum cut. + +Now the minimum cut consists of the edges of the original graph that start at some node in A, end at some node outside A, and whose capacity is fully used in the maximum flow. + +### Ford-Fulkerson Algorithm + +* It consists of several rounds, on each first find a path from source to sink. + +![](.gitbook/assets/image%20%2889%29.png) + +* Take minimum weight \(x\) of the edge from chosen path and subtract it through residual edges and add x to maxFlow count. + +![](.gitbook/assets/image%20%2881%29.png) + +Similarly + +![](.gitbook/assets/image%20%2898%29.png) + +![Still need 2 more rounds for optimized flow](.gitbook/assets/image%20%28109%29.png) + +The idea is that increasing the flow decreases the amount of flow that can go through the edges in the future. On the other hand, it is possible to cancel flow later using the reverse edges of the graph if it turns out that it would be beneficial to route the flow in another way. + +Now how to choose paths optimally within each ford-fulkerson round? We can use DFS but in worst case, each path only increases the flow by 1 and algorithm is slow. So we can use + +### Edmonds-Karp Algorithm + +Choose path with as small number of edges as possible. This can be done using BFS instead of DFS. It guarantees O\(m^2 n\) complexity + +### Scaling Algorithm + +Uses DFS to find paths where each edge weight is at least a threshold value. Initially, the threshold value is some large number, for example the sum of all edge weights of the graph. Always when a path cannot be found, the threshold value is divided by 2. The time complexity of the algorithm is O\(m^2 log c\) where c is initial threshold value. + +### Dinic Algorithm + +```cpp +struct FlowEdge +{ + int v, u; + ll cap, flow = 0; + FlowEdge(int v, int u, ll cap) : v(v), u(u), cap(cap) {} +}; +struct Dinic +{ + const ll FLOW_INF = 1e18; + vector edges; + vector> adj; + int n, m = 0; + int s, t; + vector level, ptr; + queue q; + Dinic(int n, int s, int t) : n(n), s(s), t(t) + { + adj.resize(n); + level.resize(n); + ptr.resize(n); + } + void addEdge(int u, int v, ll cap) + { + edges.emplace_back(u, v, cap); + edges.emplace_back(v, u, 0); + adj[u].push_back(m); + adj[v].push_back(m + 1); + m += 2; + } + bool bfs() + { + while (!q.empty()) + { + int v = q.front(); + q.pop(); + for (int id : adj[v]) + { + if (edges[id].cap - edges[id].flow < 1) continue; + if (level[edges[id].u] != -1) continue; + level[edges[id].u] = level[v] + 1; + q.push(edges[id].u); + } + } + return level[t] != -1; + } + ll dfs(int v, ll pushed) + { + if (pushed == 0) return 0; + if (v == t) return pushed; + for (int &cid = ptr[v]; cid < (int)adj[v].size(); cid++) + { + int id = adj[v][cid], u = edges[id].u; + if (level[v] + 1 != level[u] || edges[id].cap - edges[id].flow < 1) continue; + ll tr = dfs(u, min(pushed, edges[id].cap - edges[id].flow)); + if (tr == 0) continue; + edges[id].flow += tr; + edges[id ^ 1].flow -= tr; + return tr; + } + return 0; + } + ll flow() + { + ll f = 0; + while (true) + { + fill(level.begin(), level.end(), -1); + level[s] = 0; + q.push(s); + if (!bfs()) break; + fill(ptr.begin(), ptr.end(), 0); + while (ll pushed = dfs(s, FLOW_INF)) f += pushed; + } + return f; + } +}; +// O(N^2 * E) +``` + +## Graph Matching - Hopcraft Korp Algorithm + +```cpp +class GraphMatching +{ +private: + static bool findMatch(int i, const vector> &inp_w, vector &out_row, vector &out_column, vector &seen) + { + // 0 is NO_EDGE here + if (seen[i]) return false; + seen[i] = true; + for (int j = 0; j < inp_w[i].size(); ++j) + { + if (inp_w[i][j] != 0 && out_column[j] < 0) + { + out_row[i] = j, out_column[j] = i; + return true; + } + } + for (int j = 0; j < inp_w[i].size(); ++j) + { + if (inp_w[i][j] != 0 && out_row[i] != j) + { + if (out_column[j] < 0 || findMatch(out_column[j], inp_w, out_row, out_column, seen)) + { + out_row[i] = j, out_column[j] = i; + return true; + } + } + } + return false; + } + static bool dfs(int n, int N, vector> &inp_con, vector &blossom, vector &vis, vector &out_match) + { + vis[n] = 0; + for (int i = 0; i < N; ++i) + { + if (!inp_con[n][i]) continue; + if (vis[i] == -1) + { + vis[i] = 1; + if (out_match[i] == -1 || dfs(out_match[i], N, inp_con, blossom, vis, out_match)) + { + out_match[n] = i, out_match[i] = n; + return true; + } + } + if (vis[i] == 0 || blossom.size()) + { + blossom.push_back(i), blossom.push_back(n); + if (n == blossom[0]) + { + out_match[n] = -1; + return true; + } + return false; + } + } + return false; + } + static bool augment(int N, vector> &inp_con, vector &out_match) + { + for (int i = 0; i < N; ++i) + { + if (out_match[i] != -1) continue; + vector blossom; + vector vis(N, -1); + if (!dfs(i, N, inp_con, blossom, vis, out_match)) continue; + if (blossom.size() == 0) return true; + int base = blossom[0], S = blossom.size(); + vector> newCon = inp_con; + for (int i = 1; i != S-1; ++i) + for (int j = 0; j < N; ++j) + newCon[base][j] = newCon[j][base] |= inp_con[blossom[i]][j]; + for (int i = 1; i != S-1; ++i) + for (int j = 0; j < N; ++j) + newCon[blossom[i]][j] = newCon[j][blossom[i]] = 0; + newCon[base][base] = 0; + if (!augment(N, newCon, out_match)) return false; + int n = out_match[base]; + if (n != -1) + { + for (int i = 0; i < S; ++i) + { + if (!inp_con[blossom[i]][n]) continue; + out_match[blossom[i]] = n, out_match[n] = blossom[i]; + if (i&1) + { + for (int j = i+1; j < S; j += 2) + out_match[blossom[j]] = blossom[j+1], out_match[blossom[j+1]] = blossom[j]; + } + else + { + for (int j = 0; j < i; j += 2) + out_match[blossom[j]] = blossom[j+1], out_match[blossom[j+1]] = blossom[j]; + } + break; + } + } + return true; + } + return false; + } +public: + /* weighted bipartite matching, inp_w[i][j] is cost from row node i to column node j + out vector out_row & out_column is assignment for that node or -1 if unassigned + It has a heuristic that will give excellent performance on complete graphs where rows <= columns. */ + static int bipartiteMatching(const vector> &inp_w, vector &out_row, vector &out_column) + { + out_row = vector (inp_w.size(), -1); + out_column = vector (inp_w[0].size(), -1); + vector seen(inp_w.size()); + int count = 0; + for (int i = 0; i < inp_w.size(); ++i) + { + fill(seen.begin(), seen.end(), 0); + if (findMatch(i, inp_w, out_row, out_column, seen)) count++; + } + return count; + } + // unweighted inp_conn[i][j] = 1 for edge 0 otherwise, returns no. of edges in max matching + static int nonBipartiteMatching(vector> &inp_con, vector &out_match) + { + int res = 0; + int N = inp_con.size(); + out_match = vector(N, -1); + while (augment(N, inp_con, out_match)) res++; + return res; + } +}; +``` + +![](.gitbook/assets/image%20%28124%29.png) + +```cpp +// Bipartite Matching +vector> inp_w = +{ + {1, 1, 0, 0, 0}, + {1, 0, 0, 0, 0}, + {0, 1, 1, 0, 0}, + {0, 0, 1, 1, 1}, + {0, 0, 0, 0, 1}, +}; +vector out_row, out_column; +int res = GraphMatching::bipartiteMatching(inp_w, out_row, out_column); +cout << res << endl; +for (int i : out_row) cout << i << " "; +cout << endl; +for (int i : out_column) cout << i << " "; +cout << endl; +``` + +![](.gitbook/assets/image%20%28129%29.png) + +```cpp +// Non Bipartite Matching +vector> adj_mat = +{ + {0, 1, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 1, 1, 0, 0, 0}, + {1, 0, 0, 1, 0, 0, 0, 0}, + {0, 1, 1, 0, 1, 1, 0, 0}, + {0, 1, 0, 1, 0, 0, 0, 0}, + {0, 0, 0, 1, 0, 0, 1, 0}, + {0, 0, 0, 0, 0, 1, 0, 1}, + {0, 0, 0, 1, 0, 0, 1, 0} +}; +vector match; +int res = GraphMatching::nonBipartiteMatching(adj_mat, match); +cout << res << endl; +for (int i : match) cout << i << " "; +cout << endl; +``` + +## Graph Decomposition + +TODO + diff --git a/greedy.md b/greedy.md new file mode 100644 index 0000000..28eb170 --- /dev/null +++ b/greedy.md @@ -0,0 +1,1359 @@ +# Greedy + +## Why greedy coin problem works? \[TODO\] + +## Scheduling Problems + +Classic problem given start and end time pick max non overlapping schedules. +Strategies: Pick smallest duration first \(fails\), pick that begins as early as possible \(fails\), pick that ends as early as possible + +## Tasks and deadlines + +Given duration and deadlines devise optimal schedule. For each task, we earn d-x points where d is the task's deadline and x is the moment when we finish it. What is largest possible total score. + +![c: 5 points, b: 0 points, a: -7 points, d: -8 points making total -10](.gitbook/assets/image%20%2885%29.png) + +Surprisingly, the optimal solution to the problem does not depend on the deadlines at all, but a correct greedy strategy is to simply perform the tasks sorted by their duration in increasing order. The reason for this is that if we ever perform two tasks one after another such that the first task takes longer than the second task, we can obtain a better solution if we swap the tasks. + +## Minimizing sums + +We are given n numbers a1, a2, ... an and we have to find a value x that minimizes the sum: \|a1 - x\|^c + \|a2 - x\|^c + .... + \|an - x\|^c + +**Case \(c = 1\):** best choice is take x as median of array, because if x is smaller than the median, the sum becomes smaller by increasing x, and if x is larger then the median, the sum becomes smaller by decreasing x. +**Case \(c = 2\):** best choice is take x as mean of array, because we can write it as: + +![Ignore third term since it doesnt depend on x, we can see mean is important](.gitbook/assets/image%20%28191%29.png) + +## Data Compression + +{% embed url="https://youtu.be/co4\_ahEDCho" %} + +## Reservoir Sampling + +Reservoir Sampling is useful when there is an endless stream of data and your goal is to grab a small sample with uniform probability. + +Given a sample of size k with n items processed so far, the chance for any item to be selected is k/n. When the next item comes in, current sample has a chance to survive k/\(n+1\). In general selection uniform random picking scenario k=1 + +## Problems + +### Is Unique + +Implement an algorithm to determine if a string has all unique characters. What if you cannot use additional data structure? + +```text +Clear if string is an ASCII or Unicode. Assuming ASCII it will have 128 +characters make a bool array. Or do it bitwise (int array) - reducing space +by a factor of 8. + +Without data structure: +- Compare every character with every other makes it O(N^2). +- We can sort and then do a linear scan. +- If it was a smaller range say 26 (a-z, we can resize our string to 26. And + for each vis char mark it within string by incrementing char to some const. +``` + +### Check Permutation + +Given two strings, write a method to decide if one is a permutation of the other. + +```text +- Sort the string O(NlogN) +- Count item using a hashtable +``` + +### [Excel Number to Title](https://leetcode.com/problems/excel-sheet-column-title/) + +```cpp +class Solution { +public: + string convertToTitle(int n) + { + string res; + while (n) + { + n -= 1; // We want 1 to be A 26 to be Z 28 to be AB + res = (char)('A' + (n%26)) + res; + n /= 26; + } + return res; + } +}; +``` + +### Excel Title to Number + +```cpp +class Solution { +public: + int titleToNumber(string s) + { + int res = 0; + for (const char ch : s) + res = res*26 + (ch-'A'+1); + return res; + } +}; +``` + +### URLify + +Write a method to replace all spaces in a string with '%20'. You may assume that the string has sufficient space that end to hold the additional character, and that you are given the "true" length of the string. + +```cpp +// start from end we have extra buffer in end, later we can trim if needed +void urlify(string &str, int trueLen) +{ + int j = str.size()-1; + for (int i = trueLen-1; i >= 0; --i) + { + if (str[i] == ' ') + { + str[j] = '0', str[j-1] = '2', str[j-2] = '%'; + j -= 3; + } + else + { + str[j] = str[i]; + j--; + } + } + str = str.substr(j+1); +} +``` + +### Palindrome Permutation + +Given a string, write a function to check if it is a permutation of a palindrome. + +```text +Check count of characters, %2 of them must be 0 except in case of odd length +string we can have one exception character. +``` + +### One Away + +There are 3 types of edits that can be performed on strings: insert a character, remove a character, or replace a character. Given two strings write a function to check if they are one edit \(or zero edits\) away. + +```cpp +bool isOneEditDistance(string &s, string &t) +{ + if (s == t) return true; // zero edit distance also allowed + int n = s.size(), m = t.size(); + if (abs(n-m) > 1) return false; + + int count = 0, i, j; + for (i = 0, j = 0; i < n, j < m;) + { + if (s[i] == t[j]) i++, j++; + else + { + if (n > m) i++; + else if (n < m) j++; + else i++, j++; + count++; + } + if (count > 1) return false; + } + if (i < n || j < m) count++; + return count == 1; +} +``` + +### String Compression + +Implement a method to perform basic string compression using the counts of repeated characters. For example, the string aabcccccaaa would become a2b1c5a3. If the "compressed" string would not become smaller than the original string, your method should return the original string. You can assume the string has only uppercase and lowercase \(a-z\) + +```cpp +string compress(string &str) +{ + if (str.empty()) return str; + string res = ""; + int cnt = 1; + for (int i = 1; i < str.size(); ++i) + { + if (str[i] == str[i-1]) cnt++; + else + { + res += str[i-1] + to_string(cnt); + cnt = 1; + } + } + if (cnt) res += str.back() + to_string(cnt); + return (res.size() < str.size()) ? res : str; +} +``` + +### Rotate Matrix + +Given an image represented by an NxN matrix, where each pixel in the image is 4 bytes, write a method to rotate the image by 90 degrees. Can you do it in place? + +```cpp +void rotate(vector>& matrix) +{ + int n = matrix.size(); + for (int i = 0; i < n/2; ++i) + { + for (int j = i; j < n-1-i; ++j) + { + int a = matrix[i][j]; + int b = matrix[j][n-1-i]; + int c = matrix[n-1-i][n-1-j]; + int d = matrix[n-1-j][i]; + + matrix[i][j] = d; + matrix[j][n-1-i] = a; + matrix[n-1-i][n-1-j] = b; + matrix[n-1-j][i] = c; + } + } +} +``` + +### Zero Matrix + +Write an algorithm such that if an element in an MxN Matrix is 0, its entire row and column are set to 0. + +```text +Iterate on matrix, mark that row and column as 1 in a bool array +if value is 0. Later again iterate and see if that row or col is 1 +then set it to 0. + +Reduce space by a factor of 8 using bit manipulation. + +To make O(1) space use first row and first col, set it to 0 marking +entire row/col zero. +``` + +### Substring Rotation + +Assume you have a method isSubstring which checks if one word is a substring of another. Given two strings, s1 and s2, write code to check if s2 is a rotation of s1 using only one call to isSubstring \(eg: "waterbottle" is rotation of "erbottlewat"\) + +```text +For a rotation we have a rotation point +waterbottle + ---y---- +-x- +erbottlewat + +s1 = xy +s2 = yx +simply do isSubstring(s1s1, s2) +this should give ans +``` + +### [Linked List Random Node](https://leetcode.com/problems/linked-list-random-node/) + +```cpp +// Implementation in linked list (stream of input) +ListNode *root; +Solution(ListNode* head) : root(head) { } +int getRandom() +{ + int res, len = 1; + ListNode *cur = root; + while (cur) + { + if (rand()%len == 0) res = cur->val; + len++; + cur = cur->next; + } + return res; +} +``` + +### [Weighted Reservoir Sampling](https://leetcode.com/problems/random-pick-with-weight/) + +_Given an input list of values w = \[2, 8\], when we pick up a number out of it, the chance is that 8 times out of 10 we should pick the number at index 1 \(zero indexed\)_ + +```cpp +int pickIndex() +{ + int res = 0, sm = nums[0]; + for (int i = 1; i < nums.size(); ++i) + { + if (rand() % (sm + nums[i]) < nums[i]) res = i; + sm += nums[i]; + } + return res; +} +// TLE when nums val is larger, reservoir sampling is not for static type data +// it should be used when we are to introduce new elements +``` + +#### Other method involving prefix sum + +```cpp +vector prefSm; +Solution(vector& w) +{ + prefSm.assign(w.size(), 0); + prefSm[0] = w[0]; + for (int i = 1; i < w.size(); ++i) + prefSm[i] = prefSm[i-1] + w[i]; +} +int pickIndex() +{ + int x = rand()%prefSm.back(); + auto it = upper_bound(prefSm.begin(), prefSm.end(), x); + return (it - prefSm.begin()); +} +``` + +### [Next Permutation](https://www.nayuki.io/page/next-lexicographical-permutation-algorithm) + +![](.gitbook/assets/image%20%28206%29.png) + +```cpp +void nextPermutation(vector& nums) +{ + int i = nums.size()-1; + while (i > 0 && nums[i-1] >= nums[i]) i--; + if (i > 0) + { + int j = nums.size()-1; + while (nums[j] <= nums[i-1]) j--; + int temp = nums[i-1]; + nums[i-1] = nums[j]; + nums[j] = temp; + } + reverse(nums.begin() + i, nums.end()); +} +``` + +### [Container with most water](https://www.interviewbit.com/problems/container-with-most-water/) + +```cpp +class Solution { +public: + int maxArea(vector& height) + { + int res = 0; + for (int i = 0, j = height.size()-1; i < j;) + { + res = max(res, (j-i) * min(height[i], height[j])); + height[i] < height[j] ? i++ : j--; + } + return res; + } +}; +``` + +Wow magic, right? Here's proof by contradiction + +Suppose the returned result is not the optimal solution, then there must exist an optimal solution, say a container with al or ar \(left or right\) such that it has greater volume than the one we got. Since our algorithm stops only if the two pointers meet. So, we must have visited one of them but not the other let's say we visited al \(but not ar\). + +So when a pointer stops at al, it won't move until: + +* The other pointer also points to al, in that case iteration ends but the other pointer must have visited ar on its way from right end to al so contradicting our assumption that we didn't visit ar. +* The other pointer arrives at a value, say ar' that is greater than al before it reaches ar. In this case we does move al but notice that the volume of al and ar' is already greater than al and ar \(as it is wider and heighter\) which means that al and ar is not the optimal solution -- contradiction. + +### [Trapping Rain Water](https://practice.geeksforgeeks.org/problems/trapping-rain-water/0) + +```cpp +// Make two arrays one storing all maxLeft and one maxRight. min for each +// index excpet first and last sum gives final ans +using namespace std; + +int main() +{ + int t; + cin >> t; + while (t--) + { + int n; + cin >> n; + int arr[n]; + for (int i = 0; i < n; ++i) cin >> arr[i]; + + int maxLeft[n], maxRight[n]; + int curMax = 0; + for (int i = 0; i < n; ++i) + { + maxLeft[i] = curMax; + curMax = max(curMax, arr[i]); + } + curMax = 0; + for (int i = n-1; i >= 0; --i) + { + maxRight[i] = curMax; + curMax = max(curMax, arr[i]); + } + maxLeft[0] = -1, maxRight[n-1] = -1; + + int ans = 0; + for (int i = 0; i < n; ++i) + { + if (maxLeft[i] != -1 && maxRight[i] != -1) + { + int val = min(maxLeft[i], maxRight[i]) - arr[i]; + if (val > 0) ans += val; + } + } + cout << ans << endl; + } + return 0; +} + +// O(1) space solution using 2 pointer +int trap(vector& h) +{ + int n = h.size(), ans = 0, lm = 0, rm = 0, l = 0, r = n-1; + if (n <= 2) return 0; + while (l <= r) + { + rm = max(rm, h[r]); + lm = max(lm, h[l]); + if (lm <= rm) ans += lm - h[l++]; + else ans += rm - h[r--]; + } + return ans; +} +``` + +```cpp +class Solution { +public: + typedef pair pii; + int trapRainWater(vector>& heightMap) + { + /* One quick approach is, start iterating from top left to bottom right creating dp[i][j] + as min of dp[i-1][j] and dp[i][j-1] same create another dp from bottom right to top left + dp[i][j] is min of dp[i+1][j] and dp[i][j+1]. For all internal points max of both dp - height + amount of water will get stored. + However it will fail in some cases, reason is simple that bottom left to top right flow is + also important to maintain. + + So a multi-source BFS based solution, put all border elements as source initially. Move in + all 4 directions keeping visited record. + + Go greedy and use min heap based on height to maintain min property from before. */ + if (heightMap.empty()) return 0; + int n = heightMap.size(), m = heightMap[0].size(); + priority_queue, greater> pq; + vector> visited(n, vector(m, false)); + for (int i = 0; i < n; ++i) + { + for (int j = 0; j < m; ++j) + { + if (i == 0 || i == n-1 || j == 0 || j == m-1) + { + pq.push({heightMap[i][j], i*m + j}); + visited[i][j] = true; + } + } + } + int mx = INT_MIN, res = 0; + vector dir = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + while (!pq.empty()) + { + auto cur = pq.top(); pq.pop(); + int height = cur.first, r = cur.second/m, c = cur.second%m; + mx = max(mx, height); + for (auto &x : dir) + { + int _r = r + x.first, _c = c + x.second; + if (_r < n && _r >= 0 && _c < m && _c >= 0 && !visited[_r][_c]) + { + visited[_r][_c] = true; + if (heightMap[_r][_c] < mx) res += (mx - heightMap[_r][_c]); + pq.push({heightMap[_r][_c], _r*m + _c}); + } + } + } + return res; + } +}; +``` + +### Kth Element After Merging 2 Sorted Arrays + +```cpp +/* [1, 2, 3] [2, 4] + k = 4 will give 3 in log(k) time */ +int solve(vector &a, vector &b, int k, int cur1 = 0, int cur2 = 0) +{ + int n = a.size()-cur1, m = b.size()-cur2; + if (k > (n+m) || k < 1) return -1; + if (m < n) return solve(b, a, k, cur2, cur1); // a should be small then b + + if (n == 0) return b[cur2+k-1]; // a is empty now then pick rem from b + if (k == 1) return min(a[cur1], b[cur2]); // if only 1 to choose pick min + + /* Try to take half of rem from both a & b, if that point in a is small take + it otherwise take from b */ + int i = min(n, k/2), j = min(m, k/2); + if (a[cur1+i-1] > b[cur2+j-1]) + return solve(a, b, k-j, cur1, cur2+j); + else + return solve(a, b, k-i, cur1+i, cur2); +} +``` + +* Extension: [https://leetcode.com/problems/median-of-two-sorted-arrays/](https://leetcode.com/problems/median-of-two-sorted-arrays/) + +### Maximum Continuous 1s after B flips + +```cpp +vector Solution::maxone(vector &A, int B) +{ + int i = 0, j = 0, count = 0, bestTillNow = INT_MIN, ansI, ansJ; + while (i < A.size()) + { + if (count <= B) + { + if (A[i] == 0) ++count; + ++i; + } + if (count > B) + { + if (A[j] == 0) --count; + ++j; + } + if (i-j+1 > bestTillNow) bestTillNow = i-j+1, ansI = i, ansJ = j; + } + vector res; + if (bestTillNow == INT_MIN) return res; + for (int i = ansJ; i < ansI; ++i) res.push_back(i); + return res; +} +``` + +### Check if any permutation of a large number is divisible by 8 + +```cpp +bool check(string n, int l) +{ + if (l < 3) + { + if (stoi(n)%8 == 0) return true; + reverse(n.begin(), n.end()); + if (stoi(n)%8 == 0) return true; + return false; + } + int hash[10] = {0}; + for (int i = 0; i < l; ++i) hash[n[i] - '0']++; + for (int i = 104; i < 1000; i += 8) + { + int dup = i, freq[10] = {0}; + freq[dup % 10]++; + dup /= 10; + freq[dup % 10]++; + dup /= 10; + freq[dup % 10]++; + dup = i; + + if (freq[dup % 10] > hash[dup % 10]) continue; + dup = dup / 10; + if (freq[dup % 10] > hash[dup % 10]) continue; + dup = dup / 10; + if (freq[dup % 10] > hash[dup % 10]) continue; + return true; + } + return false; +} +``` + +### [Last Stone Weight](https://leetcode.com/problems/last-stone-weight/) + +```cpp +int lastStoneWeight(vector& stones) +{ + multiset st; + for (auto &x : stones) st.insert(x); + while (st.size() > 1) + { + int p = *st.rbegin(); st.erase(--st.end()); + int q = *st.rbegin(); st.erase(--st.end()); + int cur = abs(p-q); + if (cur != 0) st.insert(cur); + } + return *st.begin(); +} +``` + +### Subarray with given sum + +```cpp +using namespace std; +#define ll long long + +int main() +{ + int t; + cin >> t; + while (t--) + { + int n, s; + cin >> n >> s; + int arr[n]; + for (int i = 0; i < n; ++i) cin >> arr[i]; + + int curr_sum = arr[0], j = 0; + bool found = false; + for (int i = 1; i <= n; ++i) + { + while (curr_sum > s) curr_sum -= arr[j++]; + if (curr_sum == s) + { + cout << j+1 << " " << i << endl; + found = true; + break; + } + if (i < n) curr_sum += arr[i]; + } + if (!found) cout << -1 << endl; + } + return 0; +} +``` + +### [Move Zeroes](https://leetcode.com/problems/move-zeroes/) + +```cpp +class Solution { +public: + void moveZeroes(vector& nums) + { + int n = nums.size(); + for (int i = 0, j = 0; i < n; ++i) + { + if (nums[i] != 0) + swap(nums[i], nums[j++]); + } + } +}; +``` + +### [Sort Colors](https://leetcode.com/problems/sort-colors) + +```cpp +class Solution { +public: + void sortColors(vector& nums) + { + for (int i = 0, l = 0, r = nums.size()-1; i <= r;) + { + if (nums[i] == 0) swap(nums[i++], nums[l++]); + else if (nums[i] == 2) swap(nums[i], nums[r--]); + else i++; + } + } +}; +``` + +### Majority Element - Voting Algorithm + +```cpp +int Solution::majorityElement(const vector &A) +{ + int ans = 0, x = 0; + for (int i : A) + { + if (x == 0) ans = i; + if (ans == i) x++; + else x--; + } + return ans; +} +``` + +### N/3 Repeat Numbers + +```cpp +int Solution::repeatedNumber(const vector &A) +{ + int len = A.size(); + if (A.size() == 0) return -1; + if (A.size() == 1) return A[0]; +​ + int c1 = A[0]; + int c2 = A[1]; + int c1count = 0; + int c2count = 0; +​ + for (int num : A) + { + if (c1 == num) c1count++; + else if (c2 == num) c2count++; + else if (c1count == 0) + { + c1 = num; + c1count = 1; + } + else if (c2count == 0) + { + c2 = num; + c2count = 1; + } + else + { + c1count--; + c2count--; + } + } +​ + // Need to properly find count once again + c1count = 0; + c2count = 0; + for (int num : A) + { + if (c1 == num) c1count++; + else if (num == c2) c2count++; + } +​ + if (c1count > len / 3) return c1; + else if (c2count > len / 3) return c2; + else return -1; +} +``` + +### Triplet with given product + +```cpp +int countTriplets(int arr[], int m, int n) +{ + unordered_map freq; + set< int, pair > res; + for (int i : arr) freq[i]++; + + // Iterate till root m if it is divisible by m and present in arr take it + for (int i = 1; i * i <= m; ++i) + { + if (m % i == 0 && freq[i]) + { + int num1 = m/i; + for (int j = 1; j * j <= num1; ++j) + { + if (num1 % j == 0 && freq[j]) + { + int num2 = num1/j; + if (freq[num2]) + { + // Put {num2, i, j} + int temp[2] = {num2, i, j}; + sort(temp, temp+n); + int prevSize = res.size(); + res.insert({temp[0}, {temp[1], temp[2]}); + // A new triplet is found + if (res.size() != prevSize) + { + // If all no. in triplet are unique + if (i != j && j != num2) + ans += freq[i] * freq[j] * freq[num2]; + else if (i == j && j != num2) + ans += (freq[j] * (freq[j]-1) / 2) * freq[num2]; + else if (j == num2 && j != i) + ans += (freq[j] * (freq[j]-1) / 2) * freq[i]; + else if (i == num2 && j != i) + ans += (freq[i] * (freq[i]-1) / 2) * freq[j]; + else if (i == j && j == num2) + ans += (freq[i] * (freq[i]-1) * (freq[i]-2) / 6; + } + } + } + } + } + } +} +``` + +### Longest Subarray with average greater than x + +```cpp +int maxSubarray(int arr[], int x, int n) +{ + int length = 0, sum = 0, temp = 0, max = 0; + for (int i = 0; i < n; ++i) + { + sum += arr[i]; + temp++; + if (sum > max && sum/temp >= x && temp >= length) + max = sum, length = temp; + if (sum < 0) sum = 0, temp = 0; + } + return length; +} +``` + +### [Fraction to Recurring Decimal](https://leetcode.com/problems/fraction-to-recurring-decimal/) + +```cpp +string fractionToDecimal(int n, int d) { + if (n == 0) return "0"; + if (d == 0) return ""; + + long long num = n, den = d; + + string res = ""; + if ((num < 0) ^ (den < 0)) res += "-"; + num = abs(num), den = abs(den); + long long quo = num/den; + res += to_string(quo); + long long rem = (num % den) * 10; + if (rem == 0) return res; + res += "."; + + // Calculate decimal values + unordered_map rec; + while (rem != 0) + { + if (rec.find(rem) != rec.end()) + { + int beg = rec[rem]; + string part1 = res.substr(0, beg); + string part2 = res.substr(beg, res.size()); + res = part1 + "(" + part2 + ")"; + return res; + } + rec[rem] = res.size(); + long long temp = rem/den; + rem = (rem % den) * 10; + res += to_string(temp); + } + return res; +} +``` + +### Integer to Roman Number + +```cpp +string intToRoman(int num) +{ + string res; + string sym[] = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}; + int val[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; + + for(int i=0; num != 0; i++) + { + while(num >= val[i]) + { + num -= val[i]; + res += sym[i]; + } + } + + return res; +} +``` + +### Roman to Integer Number + +```cpp +int romanToInt(string s) { + unordered_map rec; + rec['I'] = 1; + rec['V'] = 5; + rec['X'] = 10; + rec['L'] = 50; + rec['C'] = 100; + rec['D'] = 500; + rec['M'] = 1000; + int sum = rec[s.back()]; + for (int i = s.size()-2; i >= 0; --i) + { + if (rec[s[i]] < rec[s[i+1]]) sum -= rec[s[i]]; + else sum += rec[s[i]]; + } + return sum; +} +``` + +### Rectangles Overlap/Intersection + +```cpp +bool isRectangleOverlap(vector& rec1, vector& rec2) +{ + int x1 = rec1[0], y1 = rec1[1], x2 = rec1[2], y2 = rec1[3]; + int x3 = rec2[0], y3 = rec2[1], x4 = rec2[2], y4 = rec2[3]; + // using pos + return !(x2 <= x3 || y2 <= y3 || x1 >= x4 || y1 >= y4); + // using area + return (min(x2, x4) > max(x3, x1)) && (min(y2, y4) > max(y3, y1)); +} +``` + +### Circle and Rectangle Overlap/Intersection + +```cpp +bool checkOverlap(int radius, int x_center, int y_center, int x1, int y1, int x2, int y2) +{ + int rectX = x1, rectY = y1, rectWidth = abs(x2-x1), rectHeight = abs(y2-y1); + // (These max terms are closest x and y points to circle from rectangle + int deltaX = x_center - max(rectX, min(x_center, rectX + rectWidth)); + int deltaY = y_center - max(rectY, min(y_center, rectY + rectHeight)); + return (deltaX*deltaX + deltaY*deltaY) <= (radius*radius); +} +``` + +### Binary to Gray Code & Gray to Binary Code + +```cpp +/* +Binary To Gray + 0011 -> 0010 + Take MSB as it is, rest are XOR wiht prev +Gray To Binary + Take MSB as it is, rest if Gray bit is 0 take previous binary bit + else if 1 then negate it +*/ +// Get gray code vector when n bits are there +vector grayCode(int n) +{ + vector res(1, 0); + for (int i = 1; i < (1<& nums) +{ + unordered_map cnt, firstTimeAppeared, lastTimeAppeared; + for (int i = 0; i < nums.size(); ++i) + { + cnt[nums[i]]++; + if (firstTimeAppeared.find(nums[i]) == firstTimeAppeared.end()) + firstTimeAppeared[nums[i]] = i; + lastTimeAppeared[nums[i]] = i; + } + int bestDeg = 0; + for (auto &x : cnt) + bestDeg = max(bestDeg, x.second); + + int res = nums.size(); + for (auto &x : cnt) + { + if (x.second != bestDeg) continue; + res = min(res, lastTimeAppeared[x.first] - firstTimeAppeared[x.first] + 1); + } + return res; +} +``` + +### [Kth Permutation Sequence](https://leetcode.com/problems/permutation-sequence/) + +```cpp +int fact(int n) +{ + if (n > 12) return INT_MAX; + int f = 1; + for (auto i = 2; i<=n; ++i) f *= i; + return f; +} + +string Solution::getPermutation(int n, int k) +{ + vector nums; + for (int i = 1; i <= n; ++i) nums.push_back(i); + string res = ""; + k--; + while (n--) + { + int f = fact(nums.size()-1); + int pos = k / f; + k %= f; + res += to_string(nums[pos]); + nums.erase(nums.begin() + pos); + } + return res; +} +// Memoize factorial to save time in recalculating +``` + +### 4 Partition Problem + +Given an array, we need to partition it into 4 contiguous subarray such that difference of maximum and minimum \(sum of subarrays\) is minimized. + +```cpp +/* +5 +3 2 4 1 2 + +If we divide A as B,C,D,E=(3),(2),(4),(1,2), then P=3,Q=2,R=4,S=1+2=3. +Here, the maximum and the minimum among P,Q,R,S are 4 and 2, with +the absolute difference of 2. We cannot make the absolute difference +of the maximum and the minimum less than 2, so the answer is 2. + +Approach: +0 3 2 4 1 2 +0 3 5 9 10 12 + l i r + [3] [2] [4] [3] +*/ +signed main() +{ + flash; + int n; + cin >> n; + int a[n+1] {}, b[n+1] {}; + for (int i = 1; i <= n; ++i) + { + cin >> a[i]; + b[i] = b[i-1] + a[i]; + } + int l = 1, r = 3, x = 0, y = 0, z = 0, w = 0, ans = INF; + for (int i = 2; i < n-1; ++i) + { + while (l < i && abs(b[l] - b[0] - (b[i] - b[l])) >= abs(b[l + 1] - b[0] - (b[i] - b[l + 1]))) + l++; + while (r < n && abs(b[r] - b[i] - (b[n] - b[r])) >= abs(b[r+1] - b[i] - (b[n] - b[r + 1]))) + r++; + x = b[l] - b[0]; + y = b[i] - b[l]; + z = b[r] - b[i]; + w = b[n] - b[r]; + ans = min(ans, max({x, y, z, w}) - min({x, y, z, w})); + } + cout << ans << '\n'; + return 0; +} +``` + +### [First Non Repeating Character in Stream](https://practice.geeksforgeeks.org/problems/first-non-repeating-character-in-a-stream/0) + +```cpp +#include +using namespace std; +#define ll long long + +int main() +{ + int t; + cin >> t; + while (t--) + { + int n; + cin >> n; + char arr[n]; + for (int i = 0; i < n; ++i) cin >> arr[i]; + unordered_map freq; + + queue q; + for (int i = 0; i < n; ++i) + { + freq[arr[i]]++; + q.push(arr[i]); + while (!q.empty()) + { + if (freq[q.front()] > 1) q.pop(); + else + { + cout << q.front() << " "; + break; + } + } + if (q.empty()) cout << -1 << " "; + } + cout << endl; + } + return 0; +} +``` + +### Circular Tour + +```cpp +int Solution::canCompleteCircuit(const vector &gas, const vector &cost) +{ + int fuel = 0, start_i = 0, sum = 0; + for (int i = 0; i < gas.size(); ++i) + { + sum += (gas[i] - cost[i]); + fuel += (gas[i] - cost[i]); + if (fuel < 0) fuel = 0, start_i = i+1; + } + return (sum >= 0) ? start_i : -1; +} +``` + +### [Product Array Except Self](https://leetcode.com/problems/product-of-array-except-self/) + +```cpp +// without using additional space +vector productExceptSelf(vector& nums) +{ + int n = nums.size(); + vector res(n); + res[0] = 1; + for (int i = 1, cur = nums[0]; i < n; cur *= nums[i++]) + res[i] = cur; + for (int i = n-2, cur = nums[n-1]; i >= 0; cur *= nums[i--]) + res[i] *= cur; + return res; +} +``` + +### [Bitwise AND of Numbers Range](https://leetcode.com/problems/bitwise-and-of-numbers-range/) + +```cpp +int rangeBitwiseAnd(int m, int n) +{ + if (max(m, n) == 0) return 0; + int ans = 0; + for (int i = log2(max(m, n)); i >= 0; --i) + { + if ((m&(1< tx || sy > ty) return false; + if (sx == tx) return ((ty-sy+sx)%sx == 0); + if (sy == ty) return ((tx-sx+sy)%sy == 0); + return reachingPoints(sx, sy, tx-ty, ty) || + reachingPoints(sx, sy, tx, ty-tx); + } +}; +``` + +### [Best Meeting Point](https://www.lintcode.com/problem/best-meeting-point/description) + +```cpp +/* Find median, we can also do multisource BFS that will +also give N^2 but it will be complex and have more space +complexity */ +class Solution { +public: + int minTotalDistance(vector> &grid) + { + vector rows, cols; + for (int i = 0; i < grid.size(); ++i) + for (int j = 0; j < grid[0].size(); ++j) + if (grid[i][j] == 1) rows.push_back(i), cols.push_back(j); + + sort(rows.begin(), rows.end()); + sort(cols.begin(), cols.end()); + + int ans = 0; + for (auto &x : rows) + ans += abs(x - rows[rows.size()/2]); + for (auto &x : cols) + ans += abs(x - cols[cols.size()/2]); + return ans; + } +}; +``` + +### [Max Points On a Line](https://leetcode.com/problems/max-points-on-a-line/) + +```cpp +class Solution { +public: + int maxPoints(vector>& points) + { + if (points.empty()) return 0; + + map, int> rec; + int res = 1; + for (int i = 0; i < points.size()-1; ++i) + { + int duplicates = 0, verticals = 0; + for (int j = i+1; j < points.size(); ++j) + { + if (points[i][0] == points[j][0] && points[i][1] == points[j][1]) + ++duplicates; + else if (points[i][0] == points[j][0]) + ++verticals; + else + { + int dx = points[j][0] - points[i][0]; + int dy = points[j][1] - points[i][1]; + int gcd = __gcd(dx, dy); + rec[{dx/gcd, dy/gcd}]++; + } + } + + res = max({res, duplicates+1, duplicates+verticals+1}); + for (auto &x : rec) + res = max(res, x.second + duplicates + 1); + rec.clear(); + } + return res; + } +}; +``` + +### [Robot Bounded In Circle](https://leetcode.com/problems/robot-bounded-in-circle/) + +Perform the instruction in given instruction and prepare final vector \(position+direction\) out of it. Answer is always false if direction comes out to be north and x-y are non zero + +```cpp +class Solution { +public: + bool isRobotBounded(string instructions) + { + int dir = 0; // [0=North, 1=East, 2=South, 3=West] + int x = 0, y = 0; + const int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0}; + for (auto &ch : instructions) + { + if (ch == 'G') x += dx[dir], y += dy[dir]; + else dir = (dir + (ch == 'L' ? -1 : 1) + 4) % 4; + } + return !(dir == 0 && (x != 0 || y != 0)); + } +}; +``` + +### [Reorganize String](https://leetcode.com/problems/reorganize-string/) + +Reorganize string such that same characters are not adjacent. + +Using greedy strategy and always put that char having higher count. + +```cpp +class Solution { +public: + string reorganizeString(string S) + { + unordered_map cnt; + for (auto &x : S) cnt[x]++; + priority_queue> pq; + for (auto &x : cnt) pq.push({x.second, x.first}); + + string res = ""; + while (!pq.empty()) + { + auto x = pq.top(); pq.pop(); + // If highest cnt char is same as prev then pop another + if (res.size() > 0 && x.second == res.back()) + { + if (pq.empty()) return ""; + auto y = pq.top(); pq.pop(); + res += y.second; + y.first--; + if (y.first) pq.push(y); + pq.push(x); + } + else + { + res += x.second; + x.first--; + if (x.first) pq.push(x); + } + } + return res; + } +}; +``` + +### [Rotate Image](https://leetcode.com/problems/rotate-image/) + +```cpp +class Solution { +public: + void rotate(vector>& matrix) + { + int n = matrix.size(); + for (int i = 0; i < n/2; ++i) + { + for (int j = i; j < n-1-i; ++j) + { + int a = matrix[i][j]; + int b = matrix[j][n-1-i]; + int c = matrix[n-1-i][n-1-j]; + int d = matrix[n-1-j][i]; + + matrix[i][j] = d; + matrix[j][n-1-i] = a; + matrix[n-1-i][n-1-j] = b; + matrix[n-1-j][i] = c; + } + } + } +}; +``` + +### [Max Sum of Rectangle No Larger Than K](https://leetcode.com/problems/max-sum-of-rectangle-no-larger-than-k/) + +```cpp +int maxSumSubmatrix(vector>& matrix, int k) +{ + if (matrix.empty()) return 0; + int n = matrix.size(), m = matrix[0].size(), res = INT_MIN; + for (int l = 0; l < m; ++l) + { + vector sm(n, 0); + for (int r = l; r < m; ++r) + { + for (int i = 0; i < n; ++i) sm[i] += matrix[i][r]; + set st; + st.insert(0); + int curSm = 0, curMx = INT_MIN; + for (const int x : sm) + { + curSm += x; + auto it = st.lower_bound(curSm-k); + if (it != st.end()) curMx = max(curMx, curSm - *it); + st.insert(curSm); + } + res = max(res, curMx); + } + } + return res; +} +``` + +## Extras + +* [BerSU Ball](https://codeforces.com/problemset/problem/489/B) - Given two arrays of n & m length, we have to find pairs between a & b array such that a\[i\] & a\[j\] differs by atmost 1. **Solution:** Sort both arrays and then initialise pointers. If a\[i\] & b\[j\] form a pair then increment both i & j otherwise if a\[i\] < b\[j\] then increment i else increment j. [https://codeforces.com/contest/489/submission/70360917](https://codeforces.com/contest/489/submission/70360917) +* [Random Teams](https://codeforces.com/problemset/problem/478/B) - Given n & m. n peoples form m teams \(can be uneven\) each group members become friends. We need to find minimum & maximum number of friends possible. **Solution:** If we distribute evenly n/m, n/m ... m then it will give minimum number of friends while if we divide like 1 1 ... n-m+1 this will give maximum. Now if there are n peoples then n\*\(n-1\)/2 will be friends pair count. [https://codeforces.com/contest/478/submission/70420746](https://codeforces.com/contest/478/submission/70420746) +* [A and B and Team Training](https://codeforces.com/problemset/problem/519/C) - Given n & m, n is number of experienced peoples & m are newbies. A team can be exp-new-new or exp-exp-new. We have to tell max number of teams possible. **Solution:** Super easy simulation [https://codeforces.com/contest/519/submission/70423733](https://codeforces.com/contest/519/submission/70423733) +* [Anton and currency you all know ](https://codeforces.com/problemset/problem/508/B)- Given a number, swap its element to make max possible even number. **Solution:** If given number is 44443 ans will be 44434 while if it's 22227 -> 72222. So logic is iterate from left and find first even number which is less then last digit. Also iterate from right and find first even number which is greater than last digit. Print max of both two. [https://codeforces.com/contest/508/submission/70432949](https://codeforces.com/contest/508/submission/70432949) +* [Soldier and Badges](https://codeforces.com/problemset/problem/546/B) - Given an array, with possibly duplicate values. We can increment an element by 1 with cost of 1. We need to find minimum cost such that every element become distinct. [https://codeforces.com/contest/546/submission/70433637](https://codeforces.com/contest/546/submission/70433637) +* [Product of Three Numbers](https://codeforces.com/problemset/problem/1294/C) - Given a number we need to find if it's possible to represent it as product of three distinct numbers such that each is atleast 2. If yes then print numbers aswell. **Solution:** Find prime factors of number and then iterate it while maintaining duplicacy property [https://codeforces.com/contest/1294/submission/70434092](https://codeforces.com/contest/1294/submission/70434092) +* [Building Permutation](https://codeforces.com/problemset/problem/285/C) - Given an array we need to convert it into a permutation \(a permutation is an array of size n with distinct elements ranging 1..n\) we can either decrease or increase the element in one move. Find min moves. **Solution:** Sort the elements and then try matching ith element with \(i+1\)th number hence forming permutation [https://codeforces.com/contest/285/submission/70436700](https://codeforces.com/contest/285/submission/70436700) +* [Simple Game](https://codeforces.com/problemset/problem/570/B) - Two people are playing a game where they pick any number from 1 to n and then a random number is generated whosoever number absolute closest to random number wins, in case of draw Misha wins. First Misha chooses m. Now you Andrew has to choose such that probability of winning is maximized. Find number Andrew must choose. **Solution:** The random number c can be anywhere so we must think of a place that makes it most of the time closest. Middle element is always neutral to pick but say if Misha chose a number from beginning \(1.2..\) then we would want to pick m+1. Same if she choose end elements we would want to pick m-1. [https://codeforces.com/contest/570/submission/70438405](https://codeforces.com/contest/570/submission/70438405) +* [Interesting Subarray](https://codeforces.com/problemset/problem/1270/B) - Given t testcases, in each an array of n size. We have to find a subarray such that max of that subarray - min of it >= n. We can print any such subarray or if not possible return NO. **Solution:** For a valid such substring of size x if we keep reducing it's size we eventually reach to a two element subarray which is also valid. So the answer is to keep iterating considering 2 elements and finding if those two max - min >= 2 If yes ans is true [https://codeforces.com/contest/1270/submission/70494617](https://codeforces.com/contest/1270/submission/70494617) +* [Equalize](https://codeforces.com/problemset/problem/1037/C) - Given two binary string a & b. We want to convert a to b. We can either choose two points i & j within a and flip both i and j bits it will take abs\(i-j\) cost or we can flip any bit individually it will take 1 cost. **Solution:** We want to swap ith bit which is turned on in a but not in b to the nearest turned on bit in b. We can use bubble sort like approach here because it's easier to implement. For rest we can simply use 2nd operation. [https://codeforces.com/problemset/problem/1037/C](https://codeforces.com/problemset/problem/1037/C) +* [Block Adventure](https://codeforces.com/problemset/problem/1200/B) - Given t testcases, in each 3 number n, m, k. n is number of block platforms currently player is on 1st block platform. m are number of additional blocks player has he can add or remove blocks from the platform he's currently at and finally k is threshold by which he can jump so if gap between two concecutive block platforms is atmost k he can jump. Next line also contains heights of all n blocks. We need to find out if it's possible to reach the end. **Solution:** Greedy strategy will be to always lower down the block platform height uptil threshold point. [https://codeforces.com/contest/1200/submission/70517364](https://codeforces.com/contest/1200/submission/70517364) +* [Kill 'Em All](https://codeforces.com/problemset/problem/1238/B) - Given t testcases in each two numbers n and r. Next line we have position of n monsters in a 1D line. We can throw a bomb at any point after explosion all the monsters to the left of bomb will go -r and right one +r. Those monsters who are exactly at that point will die. We need to find minimum number of bombs we can throw. **Solution:** Strategy is to always throw bomb to the rightmost point \(remove duplicates\). [https://codeforces.com/contest/1238/submission/70556569](https://codeforces.com/contest/1238/submission/70556569) +* [Prefix Sum Primes](https://codeforces.com/problemset/problem/1150/C) - Given an array of size n containing only 2s & 1s we have to rearrange it such that it's prefix sum will give maximum primes. So \[1 2 1 2 1\] -> \[1 1 1 2 2\] -> prefix\[1 2 3 5 7\] 4 of them are primes. [https://codeforces.com/contest/1150/submission/70518072](https://codeforces.com/contest/1150/submission/70518072) +* [Longe Number](https://codeforces.com/problemset/problem/1157/B) - Given a number string of size n and in next line 9 numbers corresponding to f\[1\] = ? f\[2\] = ? ... and so on meaning that we can swap 1st number with that number instead. We have to choose a subsegment and swap all it's elements according to that mapping function given such that resulting number is maximum. [https://codeforces.com/contest/1157/submission/70560147](https://codeforces.com/contest/1157/submission/70560147) +* [Good Numbers](https://codeforces.com/problemset/problem/1249/C1) - A good number is one with sum of distinct power of 3s. You are given t testcases within each a number n find the smallest number greater than or equal to n. [Hard Version](https://codeforces.com/problemset/problem/1249/C2) **Solution:** Idea is to create a mod 3 number. If it's good then there must be no 2s in it. To convert it into nearest good number add +1 to digit wherever there's 2 and keep adding carry. [https://codeforces.com/contest/1249/submission/70586120](https://codeforces.com/contest/1249/submission/70586120) +* [Nice Garlands](https://codeforces.com/problemset/problem/1108/C) - Given a string of n length containing R G B. We have to recolor minimum elements such that all elements which are same have abs\(i-j\) % 3 = 0. **Solution:** There are 6 possibilities - RGB RBG BGR BRG GBR GRB our string must contain repeated such elements in order to be good. [https://codeforces.com/contest/1108/submission/70593098](https://codeforces.com/contest/1108/submission/70593098) +* [Array Sharpening](https://codeforces.com/problemset/problem/1291/B) - Given an array we can decrease any of it's element by 1 we want to make it sharpened i.e. it must have a strictly increasing peak at some point. a1ak+1>…>an **Solution:** Consider a peaked graph everything above it or equal to it must give ans as YES. For even elements in graph there will be two such peak graphs. [https://codeforces.com/contest/1291/submission/70754281](https://codeforces.com/contest/1291/submission/70754281) +* [Reach Median](https://codeforces.com/problemset/problem/1037/B) - Given an array of n length which is odd. We have to make median of it exactly s. We can increase or decrease a number by 1 [https://codeforces.com/contest/1037/submission/70594011](https://codeforces.com/contest/1037/submission/70594011) +* [Sanatorium](https://codeforces.com/problemset/problem/732/C) - You went on a hotel and stayed. You had b breakfast, d dinner and s suppers. In morning breakfast then dinner then supper. You don't remember when you morning evening or night and when you left. You could also miss some meals in between. Find the minimum number of meals you might have skipped. [https://codeforces.com/contest/732/submission/70721905](https://codeforces.com/contest/732/submission/70721905) +* [Accordion](https://codeforces.com/problemset/problem/1101/B) - An accordian is a string \[:\|\|\|\|:\] this '\|' can appear any number of times possibly zero. We have to transform a string to accordion by deleting minimum of it's character. [https://codeforces.com/contest/1101/submission/70749874](https://codeforces.com/contest/1101/submission/70749874) +* [Good String](https://codeforces.com/problemset/problem/1165/C) - Given a string, it's of even length and every element at odd position is not equal to it's next element. We have to convert a given string to good by removing minimum elements. [https://codeforces.com/problemset/problem/1165/C](https://codeforces.com/problemset/problem/1165/C) +* [Increasing Subsequence](https://codeforces.com/problemset/problem/1157/C1) - Given an array, we can pick numbers from both of it's end after picking we have to maintain an increasing subsequence. Hard version can have same numbers [https://codeforces.com/contest/1157/submission/70756205](https://codeforces.com/contest/1157/submission/70756205) \[EASY\] [https://codeforces.com/contest/1157/submission/70757245](https://codeforces.com/contest/1157/submission/70757245) \[HARD\] +* [Pride](https://codeforces.com/problemset/problem/891/A) - Given an array of size n. If two adjacent elements have gcd g then we can replace anyone of those adjacent element with g in 1 operation. We want to convert entire array to 1s in min operations. **Solution:** First observation is if the array has atleast one 1 then n-\(ones\) will be solution. If not we will have to make atleast one 1 and after that n-\(ones\) logic will be applicable. For that we are looking for all N^2 subarrays finding gcd of all of them and overall finding minimum subsegment having gcd 1. [https://codeforces.com/contest/891/submission/72689850](https://codeforces.com/contest/891/submission/72689850) +* [Party Lemonade](https://codeforces.com/problemset/problem/913/C) - Given n lemonades, ith have 2^i volume \(0 indexing\) and costs c\[i\] \(Given cost c array\) also given a number l. You have to atleast have l volume of lemonade in minimum amount. **Solution:** First scenerio that we must consider is this \[20 30 70 90\] and l = 12. We should first make an optimal array \[20 30 60 90\] here i denotes optimal cost of having 2^i volume. Now we just have to greedily pick from right end. [https://codeforces.com/contest/913/submission/72953693](https://codeforces.com/contest/913/submission/72953693) +* [K For The Price of One](https://codeforces.com/problemset/problem/1282/B2) - Given k items of given cost \(given cost array\) also given we have q cash and there's an offer by which we can pick k items for the price of max\(chosen k items\) we want to maximize items purchased. \(In easy version k = 2\) **Solution:** Simple greedy sort the costs \[1 2 3 9 10\] k = 3 Then make a dp which dp\[i\] indicates min cost required to buy items till i. \[1 3 3 10 13\] [https://codeforces.com/contest/1282/submission/72959571](https://codeforces.com/contest/1282/submission/72959571) +* [Alternative Thinking](https://codeforces.com/problemset/problem/603/A) - Given a binary string on n length we can flip a subsegment out of it in order to maximize alternating subsequence i.e. 0 then 1 then 0... **Solution:** It's a simple dp problem to calculate longest subsegment, before finding that apply a greedy strategy to start flipping when we encounter same bit consecutively until the end. [https://codeforces.com/contest/603/submission/72984127](https://codeforces.com/contest/603/submission/72984127) +* [Standard Free2Play](https://codeforces.com/problemset/problem/1238/C) - You are at height h and there are pillars at all heights however only n of them are in front of you \(given as array\). With a device we can toggle pillar of height x and x-1. There might be a deadlock at some case we can magically change any pillar to hidden or revealed at 1 cost. We have to minimize cost and reach 0 height. Player can land x-2 but not x-3. **Solution:** Say 5 4 3 2 /1/ 0 is the case where /1/ is hidden. Other case is 4 3 2 /1/ 0. Solution is to think if we have continuous blocks then we can switch 5 and 4 still land safely to 3 but in 1st example since 1 is hidden second time it won't be able to land. So if count is even then it won't be able to land so ans++. [https://codeforces.com/contest/1238/submission/73351853](https://codeforces.com/contest/1238/submission/73351853) +* [Color Stripe](https://codeforces.com/problemset/problem/219/C) - Given a string of n length containing capital letters indicating that cell is colored with Ath color. There can be k colors. We have to recolor the string such that finally no adjacent cells are colored same. Solution: Consider 2 cases, if k >= 3 then we just have to greedily pick current cell since only atmost 2 neighbours matters to us but in case k = 2 greedily picking might not give optimal result but we can think there can be only two string possibility here ABABAB or BABABA check both for k=2 see which one is optimal. Again for K >= 3 greedily check is str\[i\] == str\[i-1\] then assign char such that it doesn't coincide with both back and front. Note that if \(str\[i\] == str\[i-1\] \|\| str\[i\] == str\[i+1\) can give wrong answer. [https://codeforces.com/contest/219/submission/73408098](https://codeforces.com/contest/219/submission/73408098) +* [Ayoub's Function](https://codeforces.com/problemset/problem/1301/C?locale=en) - Given t testcases in it 2 integers n & m we have to create a binary string containing only 0 & 1 of n length containing m zeroes such that no. of substrings having atleast 1 zero is maximized. **Solution**: Rightaway if we think greedy we have to form binary string with maximum possible symmetry that will give the optimal answer. And after arranging 1's in it we want to calculate all possible such substrings which is N^2 and since constraints are high we can't do it like this. We can break this problem to all_substrings - substrings\_with\_all\_zeroes number of substrings are \(n\*\(n+1\)\)/2 to calculate substring with all zeroes we have to think about the placing we did before. \_1\_1\_1_ After placing all the 1's \(m\) we will left with \(m+1\) buckets in which we can put 0's. We can leve a bucket empty aswell but we want to fill it uniformly in order to get optimal result. We have \(n-m\) zeroes divided in \(m+1\) buckets: quo = \(n-m\)/\(m+1\) rem = \(n-m\)%\(m+1\) So all buckets will have atleast quo amount of zeroes in it while rem buckets out of them will have quo+1 amount of zeroes [https://codeforces.com/contest/1301/submission/71083396](https://codeforces.com/contest/1301/submission/71083396) +* [Sasha and a Bit of Relax](https://codeforces.com/problemset/problem/1109/A) - Given an array of size n we want to find how many contiguous subarrays are there such that a\[l\] ^ a\[l+1\] ... a\[mid\] = a\[mid+1\] ^ a\[mid+2\] ... a\[r\]. This property must hold and r-l+1 should be even i.e. lhs and rhs have equal number of elements. **Solution:** solving a\[l\] ^ a\[l+1\] ... a\[mid\] = a\[mid+1\] ^ a\[mid+2\] ... a\[r\] we will get a\[l\] ^ a\[l+1\] ... a\[r\] = 0. So basically we want to count subsegment with even length and xor = 0. Create a prefix xor to do it in O\(N\). In prefix xor of i & j element means xor from ith element to jth in original array. So now we just want to find pair in xor prefix with even length and xor = 0. [https://codeforces.com/contest/1109/submission/73284691](https://codeforces.com/contest/1109/submission/73284691) +* [Hard Process](https://codeforces.com/problemset/problem/660/C) - Given a binary array of size n we can perform atmost k flips we want to maximize contiguous 1s or 0s. **Solution:** Use adjusting window technique in order to calculate optimal range like this. [https://codeforces.com/contest/660/submission/73364852](https://codeforces.com/contest/660/submission/73364852) +* [Berry Jam](https://codeforces.com/problemset/problem/1278/C) - Given a 2\*n array having 2 types of jar. Right in middle player is standing and he wants to eat from middle \(minimum jar from both end\) to balance out jar types. **Solution:** Consider prefix array and start from n-1 to 2\*n. For simplicity we can consider jar 1 & -1 so prefix array will be much easier. [https://codeforces.com/contest/1278/submission/73368897](https://codeforces.com/contest/1278/submission/73368897) +* [Anton and Making Potions](https://codeforces.com/contest/734/problem/C) - Given n, m, k you have to create n potions given m spells of type1 and k spells of type 2. Also given x, s. x is initial time to create 1 spell. s is total mana we have. Next given 2 vectors of size m & k representing type1 and type2 spell. Each vector is pair having mana point it requires and \(type1: new rate that it will give\) \(type2: potions that it will instantly create\). Find minimum time we can have to create n potions. **Solution:** Simple 2 pointer sorting problem. [https://codeforces.com/contest/734/submission/73401040](https://codeforces.com/contest/734/submission/73401040) +* [Booking System](https://codeforces.com/problemset/problem/416/C) - Given n groups of people having bookings, each group pays x amt and have y members in it. You have m tables each having distinct capacity. Each table must store only 1 group. Find which all group to take and which to not. **Solution:** It's basic greedy, start from picking those group which pays maximum try to fit them in smallest table possible. [https://codeforces.com/contest/416/submission/73403170](https://codeforces.com/contest/416/submission/73403170) +* [Sagheer, the Hausmeister](https://codeforces.com/problemset/problem/812/B) - Given n floors and m rooms \(0th is left stair m+1th is right stair in between m rooms\) also given bitset representing rooms with light turned on. Initially you are at ground floor left side you want to turn all lights off in minimum time. It consumes 1 unit time to move from any cell to neighbouring one. You cannot go up without turning all lights on same floor. **Solution:** Simple recursive no memoization required [https://codeforces.com/contest/812/submission/73486463](https://codeforces.com/contest/812/submission/73486463) +* [Maximum XOR Secondary](https://codeforces.com/contest/281/problem/D) - You’ve been given a sequence of distinct positive integers. Your task is to find a interval \[l, r\], so that the maximum element xor the second maximum element within the interval is as large as possible. **Solution:** The interval’s meaning can only be reflected on its maximum element and second maximum element, so apparently, there must be a lot of meaningless interval which we needn’t check them at all. But how can we skip them? Maintain a monotone-decreasing-stack can help us. While a new element came into the view, pop the top element in the stack, and check the corresponding interval, until the new element is greater than the top element in the stack. We can easily see it is correct since we won’t lost the answer as long as it exists. [https://codeforces.com/contest/281/submission/74735528](https://codeforces.com/contest/281/submission/74735528) +* [Counting Kangaroos is Fun](https://codeforces.com/contest/372/problem/A) - Given an array we want to find pairs such that a\[i\] <= a\[j\] group those pair and in the end return count of groups. **Solution:** [https://codeforces.com/contest/448/submission/74697633](https://codeforces.com/contest/448/submission/74697633) +* [Single-use Stones](https://codeforces.com/contest/965/problem/D) - [https://codeforces.com/contest/965/submission/76662788](https://codeforces.com/contest/965/submission/76662788) +* [Nauuo and Cards](https://codeforces.com/contest/1173/problem/C) - Observe first two testcases and try to come up with a greedy strategy in 1st we are directly pushing and never considering empty card so first try that strategy next consider picking empty cards so for all i 1 to n: pos\[i\]-\(i-1\) will denote how much empty card we will require to put. If we play these many blank cards so the top of pile \(hand\) above this position are already in our hand. So the ans is max\(pi — i + 1\) + n. We add n for playing the cards 1 to n. [https://codeforces.com/contest/1173/submission/76922325](https://codeforces.com/contest/1173/submission/76922325) +* [Two Small Strings](https://codeforces.com/contest/1213/problem/E) - We can do something like stress test since strings are small so generate all possible permutations and finally check if string matches constraint. [https://codeforces.com/contest/1213/submission/78345167](https://codeforces.com/contest/1213/submission/78345167) + diff --git a/implementation-based.md b/implementation-based.md new file mode 100644 index 0000000..c06ede8 --- /dev/null +++ b/implementation-based.md @@ -0,0 +1,814 @@ +# Implementation Based + +### MinStack \(Stack Modification\) + +```cpp +stack> st; + +// Finding minimum +return st.top().second; + +// Adding an element (newElem) +int newMin = st.empty() ? newElem : min(newElem, st.top().second); +st.push({newElem, newMin}); + +// Removing and element +int removedElement = st.top().first; +st.pop(); +``` + +### MinStack \(Queue Modification\) + +Store only those items which are needed to determine the minimum \(Monotonic queue\). All the elements that we removed can never be a minimum itself, so this operation is allowed. + +When we extract minimum from \(original queue\) it might not be there since we removed it so we should check before removing. + +```cpp +deque q; + +// Finding minimum +return q.front(); + +// Adding an element (newElem) +while (!q.empty() && q.back() > newElem) q.pop_back(); +q.push_back(newElem); + +// Removing an element +if (!q.empty() && q.front() == removeElement) q.pop_front(); +``` + +Storing index of each element \(This doesn't require knowledge of removeElement\) making it independent of original queue + +```cpp +deque q; +int cntAdded = 0, cntRemoved = 0; + +// Finding minimum +return q.front().first; + +// Adding an element (newElem) +while (!q.empty() && q.back() > newElem) q.pop_back(); +q.push_back({newElem, cntAdded}); +cntAdded++; + +// Removing an element +if (!q.empty() && q.front().second == cntRemoved) q.pop_front(); +cntRemoved++; +``` + +### [Insert Delete Get Random O\(1\)](https://leetcode.com/problems/insert-delete-getrandom-o1/) + +Heap like idea of swapping with last element while deleting + +```cpp +class RandomizedSet { +public: + unordered_map rec; + vector arr; + default_random_engine seed; + + RandomizedSet() + { + rec.clear(); + arr.clear(); + } + + /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */ + bool insert(int val) + { + if (rec.find(val) != rec.end()) return false; + rec[val] = arr.size(); + arr.push_back(val); + return true; + } + + /** Removes a value from the set. Returns true if the set contained the specified element. */ + bool remove(int val) + { + if (rec.find(val) == rec.end()) return false; + arr[rec[val]] = arr.back(); + rec[arr.back()] = rec[val]; + arr.pop_back(); + rec.erase(val); + return true; + } + + /** Get a random element from the set. */ + int getRandom() + { + int rand = uniform_int_distribution<>(0, arr.size()-1)(seed); + return arr[rand]; + } +}; +``` + +### Matrix Multiplication + +```cpp +for (int i = 0; i < A.n; i++) +{ + for (int j = 0; j < B.m; j++) + { + res[i][j] = 0; + for (int k = 0; k < A.m; k++) + res[i][j] += A[i][k] * B[k][j]; + } +} +``` + +Stressan's Divide and Conquer approach + +![](.gitbook/assets/image%20%28309%29.png) + +> Pad zeroes in case of non 2 power matrix + +### Sparse Matrix Multiplication + +* Each row can have <= m number of elements. We will keep track of vals and cols of those non-zero entries. +* Size of non-zero elements in a row will be stored in rows \(see get function\) + +```cpp +template +class SparseMatrix +{ +private: + vector *vals; + vector *rows, *cols; + +public: + int n, m; + + SparseMatrix(int _n, int _m) + { + assert(_n > 0 && _m > 0); + n = _n, m = _m; + vals = NULL, cols = NULL; + rows = new vector(n+1, 1); + } + ~SparseMatrix() + { + if (vals) + { + delete vals; + delete cols; + } + delete cols; + } + T get(int i, int j) const + { + assert(i >= 1 && j >= 1 && i <= n && j <= m); + for (int pos = ((*rows)[i-1] - 1); pos < ((*rows)[i] - 1); ++pos) + { + int curCol = (*cols)[pos]; + if (curCol == j) return (*vals)[pos]; + else if (curCol > j) break; + } + return T(); + } + SparseMatrix& set(T val, int i, int j) + { + assert(i >= 1 && j >= 1 && i <= n && j <= m); + int pos = (*rows)[i-1] - 1, curCol = 0; + for (; pos < (*rows)[i] - 1; ++pos) + { + curCol = (*cols)[pos]; + if (curCol >= j) break; + } + if (curCol != j && val != T()) insert(pos, i, j, val); + else if (val == T()) remove(pos, i); + else (*vals)[pos] = val; + return *this; + } + SparseMatrix multiply(const SparseMatrix &x) const + { + assert (m == x.n); + SparseMatrix res(n, x.m); + for (int i = 1; i <= n; ++i) + { + for (int j = 1; j <= x.m; ++j) + { + T cur = T(); + for (int k = 1; k <= m; ++k) + cur += get(i, k) * x.get(k, j); + res.set(cur, i, j); + } + } + return res; + } + +private: + void insert(int index, int i, int j, T val) + { + if (!vals) + { + vals = new vector(1, val); + cols = new vector(1, j); + } + else + { + vals->insert(vals->begin() + index, val); + cols->insert(cols->begin() + index, j); + } + + for (int x = i; x <= n; ++x) (*rows)[x] += 1; + } + void remove(int index, int i) + { + vals->erase(vals->begin() + index); + cols->erase(cols->begin() + index); + + for (int x = i; x <= n; ++x) (*rows)[x] -= 1; + } +}; +``` + +### [Flatten Nested List Iterator](https://leetcode.com/problems/flatten-nested-list-iterator/) + +```cpp +class NestedIterator { +public: + stack::iterator> front, back; + NestedIterator(vector &nestedList) + { + front.push(nestedList.begin()); + back.push(nestedList.end()); + } + + int next() + { + return (front.top()++)->getInteger(); + } + + bool hasNext() + { + while (!front.empty()) + { + auto it = front.top(); + if (it == back.top()) + { + front.pop(); back.pop(); + if (!front.empty()) front.top()++; + } + else if (it->isInteger()) return true; + else + { + front.push(it->getList().begin()); + back.push(it->getList().end()); + } + } + return false; + } +}; +``` + +### [LRU Cache](https://leetcode.com/problems/lru-cache) + +```cpp +/* LRU = Least Recently Used Cache +say a cache of size 4 we insert 0 then 1 then 2 then 3 i.e our cache becomes +3 2 1 0 if we insert another item size becomes 5 we can only have a capacity of 4 +so while insertion least recently used gets deleted i.e. 4 3 2 1 [0 gets deleted] +If we access say 2 then it becomes 2 4 3 1 Now if we insert 5, 1 gets removed +i.e. 5 2 4 3 this get & set function should be in O(1) */ + +class LRUCache { +public: + + struct Node { int key, val; Node *prev, *next; }; + unordered_map rec; + Node *head, *tail; + int sz, maxCapacity; + + LRUCache(int capacity) + { + head = NULL, tail = NULL; + sz = 0, maxCapacity = capacity; + } + + void put(int key, int value) + { + if (rec.find(key) == rec.end()) + { + Node *newNode = new Node({key, value, NULL, NULL}); + rec[key] = newNode; + if (!head && !tail) head = newNode, tail = newNode; + else + { + newNode->next = head; + head->prev = newNode; + head = newNode; + } + sz++; + if (sz > maxCapacity) + { + Node *toDel = tail; + tail = tail->prev; + if (tail) tail->next = NULL; + rec.erase(toDel->key); + delete (toDel); + sz--; + } + } + else + { + get(key); + rec[key]->val = value; + } + } + + int get(int key) + { + auto it = rec.find(key); + if (it != rec.end()) + { + Node *newHead = it->second; + if (newHead == head) return newHead->val; + + Node *p = newHead->prev, *q = newHead->next; + if (p) p->next = q; + if (q) q->prev = p; + if (newHead == tail) tail = p; + newHead->next = head; + newHead->prev = NULL; + head->prev = newHead; + head = newHead; + return newHead->val; + } + else return -1; + } +}; +``` + +### [Design Twitter](https://leetcode.com/problems/design-twitter/) + +```cpp +class Twitter { +public: + unordered_map>> rec; + unordered_map> followers; + int timer = 0; + + Twitter() { rec.clear(); followers.clear(); timer = 0; } + void postTweet(int userId, int tweetId) { rec[userId].push_back({++timer, tweetId}); } + void follow(int followerId, int followeeId) + { + if (followerId == followeeId) return; + followers[followerId].insert(followeeId); + } + void unfollow(int followerId, int followeeId) + { + if (followerId == followeeId) return; + followers[followerId].erase(followeeId); + } + vector getNewsFeed(int userId) + { + vector> tmp; + for (auto &y : rec[userId]) tmp.push_back(y); + for (auto &x : followers[userId]) + for (auto &y : rec[x]) tmp.push_back(y); + int sz = min(10, (int)tmp.size()); + partial_sort(tmp.begin(), tmp.begin()+sz, tmp.end(), greater>()); + + vector res; + for (int i = 0; i < sz; ++i) + res.push_back(tmp[i].second); + return res; + } +}; +``` + +### [Find Median From Data Stream](https://leetcode.com/problems/find-median-from-data-stream/) + +* Sort numbers find median, we can maintain sorted array while addNum it will take O\(logN\) time in lower\_bound and worst case all numbers have to be shifted so O\(NlogN\) + +```cpp +vector arr; +int sz = 0; +MedianFinder() { } +void addNum(int num) +{ + sz++; + if (arr.empty()) arr.push_back(num); + else arr.insert(lower_bound(arr.begin(), arr.end(), num), num); +} +double findMedian() +{ + return sz&1 ? arr[sz/2] : (arr[sz/2 + 1] + arr[sz/2])/2.0; +} +``` + +* Maintain two heaps i.e. left and right half from middle. We are performing 3 push and 2 pop operations making it total O\(5logN\) + +```cpp +priority_queue left; +priority_queue, greater> right; + +MedianFinder() { } +/* Think 3 steps: sz(left) == sz(right), sz(left) > sz(right), sz(left) < sz(right) */ +void addNum(int num) +{ + left.push(num); + right.push(left.top()); + left.pop(); + + if (left.size() < right.size()) + { + left.push(right.top()); + right.pop(); + } +} +double findMedian() +{ + return (left.size() > right.size()) ? left.top() : (left.top() + right.top())/2.0; +} +``` + +* We can use policy based data structure, both insertion and find takes logN & 3logN time here but there's no overhead of inserting 5 times so this might perform better in some scenerios + +```cpp +orderedMultiSet st; +int n = 0; + +MedianFinder() { } +void addNum(int num) +{ + st.insert(num); + n++; +} +double findMedian() +{ + return n&1 ? *st.find_by_order(n/2) : + (*st.find_by_order(n/2 - 1) + *st.find_by_order(n/2))/2.0; +} +``` + +### [Design HashMap](https://leetcode.com/problems/design-hashmap/) + +```cpp +class MyHashMap { +private: + int hashfunction(int key) + { + return key&127; // negative num % 128 may give negative val, but & 127 won't + } + vector> data[128]; + +public: + MyHashMap() { for (auto &x : data) x.clear(); } + void put(int key, int value) + { + int hash = hashfunction(key); + for (auto &x : data[hash]) + if (x.first == key) { x.second = value; return; } + data[hash].push_back({key, value}); + } + int get(int key) + { + int hash = hashfunction(key); + for (auto &x : data[hash]) + if (x.first == key) return x.second; + return -1; + } + void remove(int key) + { + int hash = hashfunction(key); + for (int i = 0; i < data[hash].size(); ++i) + if (data[hash][i].first == key) { data[hash].erase(data[hash].begin() + i); break; } + } +}; +``` + +### [My Calendar I](https://leetcode.com/problems/my-calendar-i/) + +```cpp +class MyCalendar { +public: + set> st1, st2; + MyCalendar() { } + bool book(int s, int e) + { + /* + --- case 1 ----- avoid case 1 + ======= ====== + + ------ case 2 ------ avoid case 2 + ===== ====== + + ------ case 3 + ====== + + -------------- case 4 + ====== + + Above cases can be concluded in two lines: + - find a booking with start atleast s+1 if it's start < e + then it's an overlap + - find a booking with end atleast s+1 if it's start < e */ + + auto it1 = st1.lower_bound({s+1, INT_MIN}); + if (it1 != st1.end() && it1->first < e) return false; + auto it2 = st2.lower_bound({s+1, INT_MIN}); + if (it2 != st2.end() && it2->second < e) return false; + + st1.insert({s, e}); + st2.insert({e, s}); + return true; + } +}; +``` + +### [Encode and Decode Strings](https://www.lintcode.com/en/old/problem/encode-and-decode-strings/#:~:text=Encode%20and%20Decode%20Strings,-Description&text=Design%20an%20algorithm%20to%20encode,the%20original%20list%20of%20strings.) + +```cpp +class Solution { +public: + string encode(vector &strs) + { + string header = "(", body = ""; + for (auto &x : strs) + { + header += to_string(x.size()) + ','; + body += x; + } + header = header.substr(0, header.size()-1) + ')'; + return header + body; + } + vector decode(string &str) + { + string header = str.substr(1, str.find(')')-1); + stringstream ss(header); + string tmp; + vector res; + int i = str.find(')')+1; + while (getline(ss, tmp, ',')) + { + int sz = stoi(tmp); + res.push_back(str.substr(i, sz)); + i += sz; + } + return res; + } +}; +``` + +### [Guess the Word](https://leetcode.com/problems/guess-the-word/) + +We could use tries also but that would be less optimal \(can't guess in 10 options\) + +```cpp +void findSecretWord(vector& wordlist, Master& master) +{ + vector words = wordlist; + for (int i = 0; i < 10; ++i) + { + string guess = words[rand()%words.size()]; + int matches = master.guess(guess); + if (matches == 6) + break; + vector newWords; + for (const string cur : words) + { + int curMatches = 0; + for (int j = 0; j < 6; ++j) + if (guess[j] == cur[j]) curMatches++; + if (curMatches == matches) + newWords.push_back(cur); + } + words = newWords; + } +} +``` + +### [Minesweeper](https://leetcode.com/problems/minesweeper/) + +```cpp +class Solution { +public: + vector> directions = {{1, -1}, {1, 0}, {1, 1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}}; + bool valid(int x, int y, vector> b) + { + return x >= 0 && x < b.size() && y >= 0 && y < b[0].size(); + } + void dfs(vector>& board, int i, int j) + { + if (!valid(i, j, board)) return; + if (board[i][j] == 'E') + { + int cnt = 0; + for (const auto dir : directions) + { + if (valid(i + dir.first, j + dir.second, board) && board[i + dir.first][j + dir.second] == 'M') + cnt++; + } + if (cnt > 0) board[i][j] = ('0' + cnt); + else + { + board[i][j] = 'B'; + for (const auto dir : directions) dfs(board, i + dir.first, j + dir.second); + } + } + } + vector> updateBoard(vector>& board, vector& click) + { + if (board[click[0]][click[1]] == 'M') { board[click[0]][click[1]] = 'X'; return board; } + dfs(board, click[0], click[1]); + return board; + } +}; +``` + +### [My Calendar II](https://leetcode.com/problems/my-calendar-ii/) + +```cpp +map mp; +MyCalendarTwo() { mp.clear(); } +bool book(int start, int end) +{ + int cnt = 0; + mp[start]++, mp[end]--; + for (auto it = mp.begin(); it != mp.end(); ++it) + { + cnt += it->second; + if (cnt == 3) { mp[start]--, mp[end]++; return false; } + } + return true; +} +``` + +### Custom std::vector + +```cpp +#include +using namespace std; + +template +class Vector +{ +private: + T* m_Data = nullptr; + size_t m_Size, m_Capacity; + +public: + Vector() : m_Size(0), m_Capacity(0) { ReAlloc(2); } + void pushBack(const T& value) + { + if (m_Size >= m_Capacity) + ReAlloc(m_Capacity + m_Capacity/2); // growing fx depends on use case + m_Data[m_Size++] = value; + } + void popBack() + { + if (m_Size > 0) + { + m_Size--; + m_Data[m_Size].~T(); + } + } + T& operator[](size_t index) + { + assert(index >= 0 && index < m_Size); + return m_Data[index]; + } + size_t size() const { return m_Size; } + ~Vector() { delete[] m_Data; } + + // Improvements + // this new fxn moves temp data provided as arg and moves instead of copy + void pushBack(T&& value) + { + if (m_Size >= m_Capacity) + ReAlloc(m_Capacity + m_Capacity/2); + m_Data[m_Size++] = std::move(value); + } + template + T& emplaceBack(Args&&... args) + { + if (m_Size >= m_Capacity) + ReAlloc(m_Capacity + m_Capacity/2); + m_Data[m_Size] = T(std::forward(args)...); + return m_Data[m_Size++]; + } + // End of Improvements + +private: + void ReAlloc(size_t newCapacity) + { + /* Functions: Allocate new block of memory, copy/move existing + data, delete old memory block */ + T* newBlock = new T[newCapacity]; + // don't use smart pointers when dealing such low level data structure stuff + + if (newCapacity < m_Size) + m_Size = newCapacity; // In case of shrinking (after pop) + + for (size_t i = 0; i < m_Size; ++i) + newBlock[i] = m_Data[i]; + // improvement -> newBlock[i] = std::move(m_Data[i]); + /* why not memcpy? memcpy is fine for simple flot int types but in custom + classes it won't call copy constructor above ensures that it gets called */ + + delete[] m_Data; + m_Data = newBlock; + m_Capacity = newCapacity; + } +}; + +// For demo +struct point +{ + float x, y, z; + point() {} + point(float _x, float _y, float _z) : x(_x), y(_y), z(_z) { } + ~point() { cout << "DESTROY\n"; } + point& operator=(const point& other) + { + cout << "COPY\n"; + x = other.x, y = other.y, z = other.z; + return *this; + } + point& operator=(point&& other) + { + cout << "MOVE\n"; + x = other.x, y = other.y, z = other.z; + return *this; + } +}; + +int main() +{ + Vector arr; + /* this arg is temp data, which gets constructed then copied then destroy + instead have a T&& method in vector */ + arr.pushBack(point(1, 2, 3)); + arr.pushBack(point(9, 8, 7)); + arr.pushBack(point(0, 1, 0)); + arr.popBack(); + arr.emplaceBack(1, 2, 3); + + for (int i = 0; i < arr.size(); ++i) + cout << arr[i].x << " " << arr[i].y << " " << arr[i].z << '\n'; + return 0; +} +``` + +### Snake Game + +```cpp +class SnakeGame +{ +private: + size_t curFood; + int width, height; + vector> food; + deque> snake; + +public: + SnakeGame(int _width, int _height, vector> _food) : + curFood(0), width(_width), height(_height), food(_food) + { + snake.push_back({0, 0}); + } + + // direction - 'U' = Up, 'L' = Left, 'R' = Right, 'D' = Down + // return the game's score after the move. Return -1 if game over. + int move(string direction) + { + int snakeLen = snake.size(); + if (snakeLen > width*height) return -1; + + auto snakeHead = snake.front().first; + if (direction == "U") snakeHead.first--; + else if (direction == "D") snakeHead.first++; + else if (direction == "L") snakeHead.second--; + else if (direction == "R") snakeHead.second++; + + if (curFood < food.size() && snakeHead == food[curFood]) curFood++; + else snake.pop_back(); + + if (find(snake.begin(), snake.end(), snakeHead) != snake.end()) return -1; + snake.push_front(snakeHead); + + return curFood; + } +}; +``` + +### [Time Based Key Value Store](https://leetcode.com/problems/time-based-key-value-store/) + +```cpp +unordered_map< string, set, greater>> > rec; +TimeMap() { } +void set(string key, string value, int timestamp) +{ + rec[key].insert({timestamp, value}); +} +string get(string key, int timestamp) +{ + auto it = rec[key].lower_bound({timestamp+1, ""}); + if (it != rec[key].end()) return it->second; + return ""; +} +``` + + + diff --git a/linked-list.md b/linked-list.md new file mode 100644 index 0000000..5b2273c --- /dev/null +++ b/linked-list.md @@ -0,0 +1,553 @@ +# Linked List + +### Remove Dups + +Write a code to remove duplicates from an unsorted linked list. +FOLLOW UP: How would you solve this problem if a temporary buffer is not allowed. + +```text +Using hashtable we can do in O(N) +Follow up: +We can do brute force O(N^2) +We can sort the array then the consecutive ones will be dups a linear +scan will do. O(NlogN) +``` + +### Return Kth to Last + +Implement an algorithm to find the Kth to last element of a singly linked list. + +```text +Take 2 points one at head, other at head+k. Keep incrementing both +until j reaches end. Then i is kth last +``` + +### Delete Middle Node + +Implement an algorithm to delete a node in the middle \(i.e. any node but the first and last node not necessarily the exact middle\) of a singly linked list, given only access to that node. + +```cpp +bool deleteNode(Node *n) +{ + if (!n || !(n->next)) return false; + Node *nxt = n->next; + n->val = nxt->val; + n->nxt = nxt->nxt; + return true; +} +``` + +### [Partition](https://leetcode.com/problems/partition-list/) + +Write code to partition a linked list around a value x, such that all nodes less than x come before all nodes greater than or equal to x. If x is contained within the list, the values of x only need to be after the elements less than x \(see below\). The partition element x can appear anywhere in the "right partition"; it does not need to appear between the left and right partitions. + +Input: 3 -> 5 -> 8 -> 5 -> 10 -> 2 -> 1 \[partition = 5\] +Output: 3 -> 1 -> 2 ->10 -> 5 -> 5 -> 8 + +```cpp +ListNode* partition(ListNode* head, int x) +{ + ListNode *left = NULL, *right = NULL, *i = NULL, *j = NULL; + while (head) + { + if (head->val < x) + { + if (!left) left = head, i = head; + else i->next = head, i = i->next; + } + else + { + if (!right) right = head, j = head; + else j->next = head, j = j->next; + } + head = head->next; + } + if (j) j->next = NULL; + if (i) i->next = right; + return (left) ? left : right; +} +``` + +### Intersection + +Given two single linked lists, determine if the two lists intersect. Return the intersecting node. Note that the intersection is defined based on reference, not value. That is if the kth node of the first linked list is the exact same node \(by reference\) as the jth node of the second linked list then they are intersecting. + +```cpp +/* Count length of both the lists. Go exactly |n-m| steps from behind in the +bigger list */ +ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) +{ + ListNode *i = headA, *j = headB; + int n = 0, m = 0; + while (i) { n++; i = i->next; } + while (j) { m++; j = j->next; } + int dif = abs(n - m); + if (m > n) swap(headA, headB); + while (dif--) headA = headA->next; + while (headA != headB) + { + headA = headA->next; + headB = headB->next; + } + return headA; +} +``` + +### Remove nth from end + +Kth from last element \(simply ek loop me linked list ka size pata karlo then dusre me n-k pe chale jaao BUT WHAT ARE OTHER WAYS? say size allowed naaho toh simply k element tak jaao then ek aur pointer lo jo head pe ho now dono ko chalao jabktak null naa hojaye pehla wala dusra wala pointer is the ans\) + +### Detect if List is Palindrome + +Go to the middle of linked list and reverse from middle to the end and break it into two half. Now just iterate both halves for equality. + +To go to middle, slow and fast pointer can be used when fast will become NULL \(reach end\) it will cover 2x distance while x distance will be covered by slow pointer which will be then the middle. + +### Reverse a Linked List + +```cpp +Node *cur = head, *next = NULL, *prev = NULL; +while (cur != NULL) +{ + next = cur->next; + cur->next = prev; + prev = cur; + cur = next; +} +return prev; + +// Reverse groups of K +ListNode* reverse(ListNode* first, ListNode* last) +{ + ListNode* prev = last; + while (first != last) + { + auto tmp = first->next; + first->next = prev; + prev = first; + first = tmp; + } + return prev; +} +ListNode* reverseKGroup(ListNode* head, int k) +{ + auto node = head; + for (int i = 0; i < k; ++i) + { + if (!node) return head; //nothing to do list too sort + node = node->next; + } + auto new_head = reverse(head, node); + head->next = reverseKGroup(node, k); + return new_head; +} + +// Reverse within a range +ListNode* Solution::reverseBetween(ListNode* A, int B, int C) +{ + ListNode *head = A, *cur = A, *next = NULL, *prev = NULL; + int i = 0; + if (B == 1) + { + ListNode *temp = A; + while (cur != NULL && i < C) + { + ++i; + next = cur->next; + cur->next = prev; + prev = cur; + cur = next; + } + temp->next = next; + head = prev; + } + else + { + while (cur != NULL && i < B-2) ++i, cur = cur->next; + ListNode *temp = cur; + cur = cur->next; + prev = NULL; + while (cur != NULL && i < C-1) + { + ++i; + next = cur->next; + cur->next = prev; + prev = cur; + cur = next; + } + temp->next->next = next; + temp->next = prev; + } + return head; +} +``` + +### Loop + +Why Floyd cycle detection Works?: [https://www.youtube.com/watch?v=LUm2ABqAs1w&t=1220s](https://www.youtube.com/watch?v=LUm2ABqAs1w&t=1220s) + +```cpp +int detectloop(Node *head) +{ + Node *slow = head; + Node *fast = head->next; + while (slow && fast && fast->next) + { + slow = slow->next; + fast = fast->next->next; + if (slow == fast) return 1; + } + return 0; +} + +void removeTheLoop(Node *A) +{ + Node *slow = A, *fast = A; + while (slow && fast) + { + slow = slow->next; + if (!fast || !slow || !fast->next) return; + fast = fast->next->next; + if (!fast || !slow || !fast->next) return; + if (slow == fast) break; + } + if (!fast || !slow || !fast->next) return; + fast = A; + Node* prev = NULL; + while (slow !=fast) + { + prev = slow; + slow = slow->next; + fast = fast->next; + } + prev->next = NULL; +} +``` + +### [Copy Linked List with Random Pointer](https://leetcode.com/problems/copy-list-with-random-pointer/) + +Given a linked list with next and random pointer create a copy of it. + +```cpp +/* One way is to iterate over linked list mapping that node with it's newly +created copy (so that we can later use map to random-access that node). +It's O(N) time with O(N) space */ +Node* copyRandomList(Node* head) +{ + unordered_map rec; + Node *cur = head; + while (cur) + { + rec[cur] = new Node(cur->val); + cur = cur->next; + } + + cur = head; + while (cur) + { + if (cur->next) rec[cur]->next = rec[cur->next]; + if (cur->random) rec[cur]->random = rec[cur->random]; + cur = cur->next; + } + + return rec[head]; +} + +/* To do in O(1) space we have to utilize our list only, making it keep all +the relevant informations. What we need is a random access. */ +``` + +![](.gitbook/assets/image%20%28265%29.png) + +```cpp +/* We store next to old_node the new_node next of new_node is next_old_node. +Now to random access a node from old_node just go to it's next. */ +Node* copyRandomList(Node* head) +{ + Node *cur = head; + while (cur) + { + Node *newNode = new Node(cur->val); + newNode->next = cur->next; + cur->next = newNode; + cur = newNode->next; + } + cur = head; + while (cur) + { + if (cur->random) cur->next->random = cur->random->next; + cur = cur->next->next; + } + + cur = head; + Node *p, *q, *newList = NULL, *cur2 = NULL; + while (cur) + { + p = cur, q = cur->next->next; + if (!newList) newList = cur->next, cur2 = cur->next; + else cur2->next = cur->next, cur2 = cur2->next; + cur = cur->next->next; + p->next = q; + } + return newList; +} +``` + +### [Merge K Sorted Linked Lists](https://www.interviewbit.com/problems/merge-k-sorted-lists/) + +```cpp +/* +Interviebit question is bullshit gives correct answer even for high time, in reality this question has tighter constraints and is asked by Google + +Way #1: Brute Force - Array me yaa map me saare element daalo sort kardo then linked list banado Time: O(KNlogKN) Space: O(KN) + +Way #2: Create K pointers, initially pointing to head of each linked list choose smallest increment it's pointer. Keep doing it. Time: O(KN) Space: O(K). Interview bit variation passes this. One optimization in this is use priority queue to avoid comparisons then time will become: O(NlogK) + +Way #3: merge two sorted linked list at a time till (k-1) times. Time: O(KN) Space: O(1) +*/ + +//Way 1: Using maps insertion will be logN so total time will be: log1 + log2 + .... + log(KN) for insertion this is integration from 1 to n logx = nlogn + n i.e. KNlogKN then inside for loop of map theres KN iteration so overall O(KNLogKN) but in case of duplicacy it stores count so it can perform better in that case +ListNode* Solution::mergeKLists(vector &A) +{ + map myMap; + for (auto x : A) + while(x) + myMap[x->val]++, x = x->next; + + ListNode *head = NULL, *cur = NULL; + for (auto it = myMap.begin(); it != myMap.end(); ++it) + { + while (it->second != 0) + { + ListNode *list = new ListNode(it->first); + if (!head) head = list, cur = list; + else cur->next = list, cur = cur->next; + it->second--; + } + } + return head; +} + +//Way 2: Just O(K) space, O(KNK) time +ListNode* mergeKLists(vector& A) +{ + vector ptrs; + for (auto x : A) ptrs.push_back(x); + ListNode *head = NULL, *cur = NULL; + while (true) + { + int minVal = INT_MAX, minIndex = 0; + for (int i = 0; i < ptrs.size(); ++i) + if (ptrs[i] && ptrs[i]->val < minVal) + minVal = ptrs[i]->val, minIndex = i; + + if (minVal == INT_MAX) break; + ListNode *temp = new ListNode(minVal); + if (!head) head = temp, cur = head; + else cur->next = temp, cur = cur->next; + ptrs[minIndex] = ptrs[minIndex]->next; + } + return head; +} + +// O(KNlogK) time, O(K) space +typedef pair pilist; +ListNode* Solution::mergeKLists(vector &A) +{ + priority_queue, greater > ptrs; + for (auto x : A) + ptrs.push({x->val, x}); + ListNode *head = NULL, *cur = NULL; + while (!ptrs.empty()) + { + pilist front = ptrs.top(); + ptrs.pop(); + ListNode *temp = new ListNode(front.first); + if (!head) head = temp, cur = head; + else cur->next = temp, cur = cur->next; + if ((front.second)->next) + { + front.second = (front.second)->next; + front.first = (front.second)->val; + ptrs.push(front); + } + } + return head; +} +// Conclusion: this one is better but if there are many duplicacy present 1st one is better +``` + +### Sort Linked List + +```cpp +// Merge Sort +ListNode* merge(ListNode* A, ListNode* B) +{ + ListNode *head = NULL, *cur = head, *itA = A, *itB = B; + while (itA && itB) + { + if (itA->val < itB->val) + { + if (!head) head = itA, cur = itA; + else cur->next = itA, cur = cur->next; + itA = itA->next; + } + else + { + if (!head) head = itB, cur = itB; + else cur->next = itB, cur = cur->next; + itB = itB->next; + } + } + while (itA) + { + if (!head) head = itA, cur = itA; + else cur->next = itA, cur = cur->next; + itA = itA->next; + } + while (itB) + { + if (!head) head = itB, cur = itB; + else cur->next = itB, cur = cur->next; + itB = itB->next; + } + return head; +} + +ListNode* sortList(ListNode* head) +{ + if (!head || !head->next) return head; + ListNode *start = head, *mid = head, *end = head->next; + while (mid && end && end->next) + { + mid = mid->next; + end = end->next->next; + } + ListNode *tmp = mid->next; + mid->next = NULL; + mid = tmp; + return merge(sortList(start), sortList(mid)); +} +// Insertion Sort +ListNode* Solution::insertionSortList(ListNode* head) +{ + ListNode *sorted = NULL; + ListNode *list = head; + while (list) + { + ListNode *curr = list; + list = list->next; + if (sorted == NULL || sorted->val > curr->val) + { + curr->next = sorted; + sorted = curr; + } + else + { + ListNode *tmp = sorted; + while (tmp) + { + ListNode *c = tmp; + tmp = tmp->next; + if (c->next == NULL || c->next->val > curr->val) + { + c->next = curr; + curr->next = tmp; + break; + } + } + } + } + return sorted; +} +``` + +### [Design Skip List](https://leetcode.com/problems/design-skiplist/) + +{% embed url="https://youtu.be/2g9OSRKJuzM" %} + +We maintain different levels of linkedlist. Let's say we have 2 layers. L1 is the express line and L0 is slower \(having all n\). \|L1\| + \|L0\|/\|L1\| is the worst case analysis, this gives \|L1\|^2 = \|L0\| = n giving size of L1 \(express lane\) as root n for optimal scenario. This 2 layer skip list has root N search, insert and remove complexity. + +2 Lanes gives: 2 ²√n +3 Lanes gives: 3 ³√n +k Lanes gives: k k√n +logN Lanes gives: logN logN√n +simplifying this will give 2 logN + +Takes log\(n\) time to add, erase and search + +![](.gitbook/assets/image%20%28200%29.png) + +Searching is simply start with top most lane, if cur->right is null or > x then switch to down lane which increments slowly. + +To add: + +![](.gitbook/assets/image%20%28198%29.png) + +blue are all the portion iteration leads us to, before changing lanes we keep track of last relevant pos in that lane in the stack. + +We flip a coin after insertion, if tail we move up. Even after finishing all lanes if in the end tail means we create a new tail. So every insertion has a potential of adding a new layer. + +```cpp +class Skiplist +{ +private: + struct Node { int val; Node *right, *down; }; + Node *head; + +public: + Skiplist() { head = new Node{0, NULL, NULL}; } + bool search(int x) + { + Node *cur = head; + while (cur) + { + while (cur->right && cur->right->val < x) cur = cur->right; + if (!cur->right || cur->right->val > x) cur = cur->down; + else return true; + } + return false; + } + void add(int x) + { + Node *cur = head; + stack st; + while (cur) + { + while (cur->right && cur->right->val < x) cur = cur->right; + st.push(cur); + cur = cur->down; + } + + Node *downNode = NULL; + bool insertUp = true; + while (insertUp && !st.empty()) + { + auto tp = st.top(); st.pop(); + tp->right = new Node{x, tp->right, downNode}; + downNode = tp->right; + insertUp = (rand()&1); + } + if (insertUp) + head = new Node{0, new Node{x, NULL, downNode}, head}; + } + bool erase(int x) + { + Node *cur = head; + bool seen = false; + while (cur) + { + while (cur->right && cur->right->val < x) cur = cur->right; + if (!cur->right || cur->right->val > x) cur = cur->down; + else + { + seen = true; + cur->right = cur->right->right; + cur = cur->down; + } + } + return seen; + } +}; +``` + diff --git a/monotonic-structures.md b/monotonic-structures.md new file mode 100644 index 0000000..7f96879 --- /dev/null +++ b/monotonic-structures.md @@ -0,0 +1,1209 @@ +# Monotonic Structures + +## Arithematic Evaluation + +{% tabs %} +{% tab title="Algo" %} +```text +// Infix to postfix +> Push left paranthesis on stack, add right paranthesis to expression. +> Scan left to right and repeat. +> If operand then append in postfix expression otherwise push it on stack. +> If an operator with higher precidence (BODMAS) is already present in stack + when pushing above then pop it and append to expression. If paranthes is + close then pop and append insides. + +// Infix to prefix +> Scan right to left. In the end reverse the expression. The behavior of + paranthesis will also change. () will become )( during traversal + +// Prefix to infix +> Scan right to left. +> If operand push on stack otherwise s1 = pop s2 = pop push (s1 operator s2) + on the stack again. +> Pop the stack to get the output + +// Postfix to infix +> Scan left to right. +> If operand push on stack otherwise s1 = pop s2 = pop push (s1 operator s2) + on the stack again. +> Pop the stack and reverse it to get output + +// Postfix to prefix +> Scan left to right. +> If operand push on stack otherwise s1 = pop s2 = pop push (operator s2 s1) + on the stack again. + +// Prefix to postfix +> Scan right to left. +> If operand push on stack otherwise s1 = pop s2 = pop push (s1 s2 operator) + on the stack again. + +// Evaluation of postfix +> Scan left to right +> If operand push on stack otherwise s1 = pop s2 = pop push evaluation of + (s2 operator s1) on the stack again. +``` +{% endtab %} + +{% tab title="Code" %} +```cpp +#include +#include +#include //For reverse +#include //For pow +using namespace std; + +int getOperatorRank(char oper) +{ + switch(oper) + { + case '^' : return 5; + case '/' : return 4; + case '*' : return 3; + case '+' : return 2; + case '-' : return 1; + } + return -1; +} + +double evaluate(double a, double b, char oper) +{ + switch(oper) + { + // Everything in reverse b/a b^a b-a because it's postfix + case '^' : return pow(b, a); + case '/' : return b/a; + case '*' : return b*a; + case '+' : return b+a; + case '-' : return b-a; + } + return 0; +} + +int main() +{ + //Infix + string expression = "5+(6*7-(7/8-9)*4)*3"; + expression = "(" + expression + ")"; + + //INFIX TO POSTFIX + stack postfixStack; + string postfix = ""; + for (int i = 0; i < expression.size(); ++i) + { + char cur = expression[i]; + if (cur == '+' || cur == '-' || cur == '*' || cur == '/' || cur == '^') + { + while (getOperatorRank(postfixStack.top()) > getOperatorRank(cur)) + { + postfix += postfixStack.top(); + postfixStack.pop(); + } + postfixStack.push(cur); + } + else if (cur == ')') + { + while (postfixStack.top() != '(') + { + postfix += postfixStack.top(); + postfixStack.pop(); + } + postfixStack.pop(); + } + else if (cur == '(') postfixStack.push(cur); + else if (cur != ' ') postfix += cur; + } + cout << "postfix: " << postfix << endl; + + //INFIX TO PREFIX + stack prefixStack; + string prefix = ""; + for (int i = expression.size()-1; i >= 0; i--) + { + char cur = expression[i]; + if (cur == '+' || cur == '-' || cur == '*' || cur == '/' || cur == '^') + { + while (getOperatorRank(prefixStack.top()) > getOperatorRank(cur)) + { + prefix += prefixStack.top(); + prefixStack.pop(); + } + prefixStack.push(cur); + } + else if (cur == '(') + { + while (prefixStack.top() != ')') + { + prefix += prefixStack.top(); + prefixStack.pop(); + } + prefixStack.pop(); + } + else if (cur == ')') prefixStack.push(cur); + else if (cur != ' ') prefix += cur; + } + reverse(prefix.begin(), prefix.end()); + cout << "prefix: " << prefix << endl; + + //PREFIX TO INFIX + stack pre2inStack; + string pre2in = ""; + for (int i = prefix.size()-1; i >= 0; i--) + { + char cur = prefix[i]; + if (cur == '+' || cur == '-' || cur == '*' || cur == '/' || cur == '^') + { + string a = pre2inStack.top(); + pre2inStack.pop(); + string b = pre2inStack.top(); + pre2inStack.pop(); + pre2inStack.push(a + string(1, cur) + b); + } + else if (cur != ' ') pre2inStack.push(string(1, cur)); + } + pre2in = pre2inStack.top(); + cout << "prefix to infix: " << pre2in << endl; + + //POSTFIX TO INFIX + stack post2inStack; + string post2in = ""; + for (int i = 0; i < postfix.size(); ++i) + { + char cur = postfix[i]; + if (cur == '+' || cur == '-' || cur == '*' || cur == '/' || cur == '^') + { + string a = post2inStack.top(); + post2inStack.pop(); + string b = post2inStack.top(); + post2inStack.pop(); + post2inStack.push(a + string(1, cur) + b); + } + else if (cur != ' ') post2inStack.push(string(1, cur)); + } + post2in = post2inStack.top(); + reverse(post2in.begin(), post2in.end()); + cout << "postfix to infix: " << post2in << endl; + + //POSTFIX TO PREFIX + stack post2preStack; + string post2pre = ""; + for (int i = 0; i < postfix.size(); ++i) + { + char cur = postfix[i]; + if (cur == '+' || cur == '-' || cur == '*' || cur == '/' || cur == '^') + { + string a = post2preStack.top(); + post2preStack.pop(); + string b = post2preStack.top(); + post2preStack.pop(); + post2preStack.push(string(1, cur) + b + a); + } + else if (cur != ' ') post2preStack.push(string(1, cur)); + } + post2pre = post2preStack.top(); + cout << "postfix to prefix: " << post2pre << endl; + + //PREFIX TO POSTFIX + stack pre2postStack; + string pre2post = ""; + for (int i = prefix.size()-1; i >= 0; i--) + { + char cur = prefix[i]; + if (cur == '+' || cur == '-' || cur == '*' || cur == '/' || cur == '^') + { + string a = pre2postStack.top(); + pre2postStack.pop(); + string b = pre2postStack.top(); + pre2postStack.pop(); + pre2postStack.push(a + b + string(1, cur)); + } + else if (cur != ' ') pre2postStack.push(string(1, cur)); + } + pre2post = pre2postStack.top(); + cout << "prefix to postfix: " << pre2post << endl; + + //EVALUATION OF POSTFIX + stack evaluateStack; + double solution = 0; + for (int i = 0; i < postfix.size(); ++i) + { + char cur = postfix[i]; + if (cur == '+' || cur == '-' || cur == '*' || cur == '/' || cur == '^') + { + double a = evaluateStack.top(); + evaluateStack.pop(); + double b = evaluateStack.top(); + evaluateStack.pop(); + evaluateStack.push(evaluate(a, b, cur)); + } + else if (cur != ' ') evaluateStack.push(cur - '0'); + } + solution = evaluateStack.top(); + cout << "Solution: " << solution << endl; + return 0; +} +``` +{% endtab %} +{% endtabs %} + +[https://leetcode.com/problems/basic-calculator-ii/](https://leetcode.com/problems/basic-calculator-ii/) + +```cpp +class Solution { +public: + int calculate(string s) + { + stack st; + long long tmp = 0; + char op = '+'; + for (int i = 0; i < s.size(); ++i) + { + if (isdigit(s[i])) tmp = 10*tmp + s[i]-'0'; + if ((!isdigit(s[i]) && !isspace(s[i])) || i == s.size()-1) + { + if (op == '+') st.push(tmp); + else if (op == '-') st.push(-tmp); + else + { + int num = st.top(); st.pop(); + if (op == '*') num *= tmp; + else num /= tmp; + st.push(num); + } + op = s[i]; + tmp = 0; + } + } + int res = 0; + while (!st.empty()) { res += st.top(); st.pop(); } + return res; + } +}; +``` + +## Implementations + +### Stack using Array + +```cpp +#define MAX 5 + +int stackArr[MAX], top = -1; +bool isEmpty() { return (top == -1); } +bool isFull() { return (top == MAX-1); } +void push(int val) +{ + if (isFull()) + { + cout << "Stack is Full!" << endl; + return; + } + ++top; + stackArr[top] = val; +} +void pop() +{ + if (isEmpty()) + { + cout << "Stack is Empty!" << endl; + return; + } + --top; +} +int top() +{ + if (isEmpty()) + { + cout << "Stack is Empty!" << endl; + return -1; + } + return stackArr[top]; +} +``` + +### Stack using linked list + +```cpp +struct Node { int data; Node* next; } *top = NULL; +bool isEmpty() { return top == NULL; } +void push(int value) +{ + Node* temp = new Node{value, NULL}; + if (top != NULL) + temp->next = top; + top = temp; +} +void pop() +{ + if (isEmpty()) + { + cout << "Stack is Empty!" << endl; + return; + } + temp = top; + top = top->next; + delete temp; +} +int top() +{ + if (isEmpty()) + { + cout << "Stack is Empty!" << endl; + return; + } + return top->data; +} +``` + +### Queue using Array + +```cpp +#define MAX 5 +int qArr[MAX], front = -1, rear = -1; +bool isEmpty() { return (front == -1); } +bool isFull() { return (rear == MAX-1); } //In circular queue - (front==0 && rear==MAX-1) || (front == rear+1)) +void enqueue(int val) +{ + if (isFull()) + { + cout << "Queue is Full!" << endl; + return; + } + if (front == -1 && rear == -1) + { + front = 0; + rear = 0; + } + else ++rear; //In Circular queue rear = (rear+1) % MAX; + qArr[rear] = val; +} +void deqeue() +{ + if (isEmpty()) + { + cout << "Queue is Empty!" << endl; + return; + } + if (front == rear) + { + front = -1; + rear = -1; + } + else ++front; //In Circular queue front = (front+1) % MAX; +} +int front() +{ + if (isEmpty()) + { + cout << "Queue is Empty!" << endl; + return -1; + } + return qArr[front]; +} +``` + +> Simmilarly Queue using linked list + +### Priority Queue using Linked List \(Min prior\) + +```cpp +struct Node { int data, prio; Node* next; } *root = NULL; +bool isEmpty() { return (root == NULL); } +void push(int val, int _prio) +{ + Node* newNode = new Node{val, _prio, NULL}; + if (root == NULL) root = newNode; + else if (root->prio > newNode->prio) //Flip sign for max prio + { + newNode->next = root; + root = newNode; + } + else + { + Node* temp = root; + //Flip sign for max prio + while(temp->next != NULL && temp->next->prio < newNode->prio) + temp = temp->next; + newNode->next = temp->next; + temp->next = newNode; + } +} +void pop() +{ + if (isEmpty()) + { + cout << "Queue is Empty!" << endl; + return; + } + Node* temp = root; + root = root->next; + delete temp; +} +int peek() +{ + if (isEmpty()) + { + cout << "Queue is Empty!" << endl; + return -1; + } + return root->data; +} +``` + +### Priority Queue \(min prio\) using Doubly Linked List + +```cpp +struct Node { int data, prio; Node *next, *prev; } *front = NULL, *rear = NULL; +bool isEmpty() { return (front == NULL && rear == NULL); } +void push(int val, int _prio) +{ + Node* newNode = new Node{ val, _prio, NULL, NULL }; + if (front == NULL && rear == NULL) + { + front = newNode; + rear = newNode; + } + else if (newNode->prio <= front->prio) + { + //Front Insert + newNode->next = front; + front->prev = newNode->next; + front = newNode; + } + else if (newNode->prio > rear->prio) + { + //Rear Insert + newNode->next = NULL; + rear->next = newNode; + newNode->prev = rear; + rear = newNode; + } + else + { + Node* temp = front; + while(temp->next != NULL && temp->next->prio < newNode->prio) + temp = temp->next; + newNode->next = temp->next; + newNode->prev = temp; + temp->next = newNode; + (temp->next)->prev = newNode; + } +} +void pop() +{ + if (isEmpty()) + { + cout << "Queue is Empty!" << endl; + return; + } + Node* temp = front; + front = front->next; + delete temp; +} +int peek() +{ + if (isEmpty()) + { + cout << "Queue is Empty!" << endl; + return -1; + } + return front->data; +} +``` + +### Three In One + +Describe how you could use a singly array to implement three stacks + +```cpp +/* Easy solution is to simply have [0, n/3) [n/3, 2n/3) [2n/3, n) section specific +for each stack. But obvious disadvantage is that one stack may end up using all +space while other stack might be empty. +s = {0, 0, 0, 0, 0, 0} + ^ ^ ^ + +If it was just 2 stacks we could have had picked 2 ends and variably modify +their lengths. We can make 3rd pointer from end here also (in 3 stack case) so: +s = {0, 0, 0, 0, 0, 0} + ^ ^ ^ +This should be somewhat more optimized + +Generalized K stacks in 1 +Most optimized way: +arr: [ 0 0 0 0 0] +nxt: [-1 2 3 4 -1] +top: [-1 -1 0] +ptr: 0 + +idea is ptr keeps track where to push. so in push +make arr[ptr] as val, increment ptr as nxt[ptr] nxt will store where +to move there could be scenerios: +We pushed to stk1 [8, 9] and [7] to stk2 + +arr: [ 8 9 7 0 0] +nxt: [-1 0 -1 4 -1] After pushing nxt stores top value after pop +top: [-1 2 1] +ptr: 3 + +If we pop Stk1 then there's a vacancy and new element should be +inserted at that vacant spot. So after pop: + +arr: [ 8 9 7 0 0] [1st elem is garbage val now] +nxt: [-1 3 -1 4 -1] after puting to vacant 1 nxt is pos 3 +top: [-1 2 0] +ptr: 1 */ +class kStacks +{ + int k, n; + vector arr, top, nxt; + int ptr; + +public: + kStacks(int _k, int _n) : k(_k), n(_n), ptr(0) + { + arr.resize(n); top.resize(k, -1); nxt.resize(n); + for (int i = 0; i < n-1; ++i) nxt[i] = i+1; + nxt[n-1] = -1; + } + inline bool isFull() { return (ptr == -1); } + inline bool isEmpty(int stk) { return (top[stk] == -1); } + void push(int x, int stk) + { + if (isFull()) return; + int tp = ptr; ptr = nxt[tp]; + nxt[tp] = top[stk]; + top[stk] = tp; + arr[tp] = x; + } + int pop(int stk) + { + if (isEmpty(stk)) return -1; + int tp = top[stk]; + top[stk] = nxt[tp]; + nxt[tp] = ptr; + ptr = tp; + return arr[tp]; + } +}; +``` + +### Stack of Plates + +Imagine a literal stack of plates. If the stack gets too high, it might topple. Therefore in real life, we would mimics this. SetOfStacks should be composed of several stacks and should create a new stack once the previous ones exceeds capacity. SetOfStacks.push\(\) and SetOfStacks.pop\(\) should behave identically to a single stack that is, pop\(\) should return the same values as it would if there were just a single stack. + +```cpp +const int capacity = 10; +class SetOfStacks +{ + vector> stks; + void push(int x) + { + if (!st.empty() && st.size() != capacity) st.back().push(x); + else + { + stack st(capacity); + st.push(x); + stks.push_back(st); + } + } + int pop() + { + if (stks.empty()) return -1; + int res = stks.back().top(); + stks.back().pop(); + if (stks.back().empty()) stks.pop_back(); + return res; + } +}; +``` + +Follow up: Implement a function popAt\(int index\) which performs a pop operation on a specific sub-stack. + +```cpp +/* [1, 2] [3, 4] [5] +Square brackets denotes seperate stacks +let's call pop at 0 +[1, 3][4, 5] +This should be output */ +int popAt(int i, bool removeTop = true) +{ + int res = (removeTop) ? stk[i].pop() : stk[i].removeBottom(); + if (stk[i].empty()) stk.erase(stk.begin() + i); + else if (stk.size() > i+1) stk[i].push(popAt(i+1, false)); + return res; +} +// Need to create another function removeBottom in our stack +``` + +### Queue via Stacks + +Implement a MyQueue class which implements a queue using two stacks. + +```cpp +class Queue +{ + stack st1, st2; + int dequeue(int x) // O(1) + { + if (st1.empty()) return -1; + int res = st1.top(); st1.pop(); + return res; + } + void enqueue(int x) // O(N) + { + while (!s1.empty()) st2.push(st1.top()), st1.pop(); + st1.push(x); + while (!st2.empty()) st1.push(s2.top()), s2.pop(); + } +}; + +// Using recurssion stack as one stack +class Queue +{ + stack st; + void enqueue(int x) // O(1) + { + st.push(x); + } + int dequeue() // O(N) + { + if (st.empty()) return -1; + int x = st.top(); st.pop(); + if (st.empty()) return x; + int res = dequeue(); + st.push(x); + return res; + } +}; +``` + +### Stack via Queue + +```cpp +class Queue +{ + queue q1, q2; + int sz = 0; + int pop() // O(1) + { + if (q1.empty()) return -1; + int res = q1.front(); + q1.pop(); sz--; + return res; + } + void push(int x) // O(N) + { + q2.push(x); sz++; + while (!q1.empty()) q2.push(q1.front()), q1.pop(); + swap(q1, q2); + } +}; + +class Queue +{ + queue q1, q2; + int sz = 0; + void push(int x) // O(1) + { + q1.push(x); sz++; + } + int pop() // O(N) + { + if (!q1.empty()) return -1; + while (q1.size() != 1) q2.push(q1.front()), q1.pop(); + int res = q1.front(); + q1.pop(); sz--; + swap(q1, q2); + return res; + } +}; +``` + +### Sort Stacks + +Write a program to sort a stack such that the smallest items are on the top. You can use an additional temporary stack, but you may not copy the elements into any other data structure \(such as an array\). The stack supports the following operations: push, pop, peek, and isEmpty. + +```cpp +stack sortStack(stack &x) +{ + stack aux; + while (!x.empty()) + { + int cur = x.top(); x.pop(); + while (!aux.empty() && aux.top() > cur) + { + x.push(aux.top()); + aux.pop(); + } + aux.push(x); + } +} +// O(N^2) : O(N) +``` + +## Two Pointer method + +* Subarray sum problem: We want to find a subarray whose sum is x +* 2SUM problem: given an array of n numbers and a target sum x, find two array values such that their sum is x + +### [Minimize the Absolute difference](https://www.interviewbit.com/problems/minimize-the-absolute-difference/) + +```cpp +// minimize this | max(a,b,c) - min(a,b,c) | +int Solution::solve(vector &A, vector &B, vector &C) +{ + int i = A.size()-1, j = B.size()-1, k = C.size()-1; + int ans = INT_MAX; + while (i >= 0 && j >= 0 && k >= 0) + { + int x = max(A[i], max(B[j], C[k])); + int y = min(A[i], min(B[j], C[k])); + ans = min(ans, abs(x - y)); + if (A[i] == x) --i; + else if (B[i] == x) --j; + else --k; + } + if (ans == INT_MAX) return -1; + else return ans; +} +``` + +### [Count the Triplets](https://practice.geeksforgeeks.org/problems/count-the-triplets/0) + +```cpp +// Count the triplets such that A[i] + A[j] = A[k] +using namespace std; +#define ll long long + +int main() +{ + int t; + cin >> t; + while (t--) + { + int n; + cin >> n; + vector arr(n); + for (int i = 0; i < n; ++i) cin >> arr[i]; + sort(arr.begin(), arr.end(), greater()); + int ans = 0; + for (int i = 0; i < n-2; ++i) + { + int j = i+1, k = n-1; + while (j < k) + { + int sum = arr[j] + arr[k]; + if (sum == arr[i]) ++ans; + if (sum < arr[i]) --k; + else ++j; + } + } + if (ans == 0) cout << -1 << endl; + else cout << ans << endl; + } + return 0; +} +``` + +### 3 Sum Closest + +```cpp +// Same technique - 3 Sum +int Solution::threeSumClosest(vector &A, int B) +{ + sort(A.begin(), A.end()); + int diff = INT_MAX, ansA, ansB, ansC; + for (int i = 0; i < A.size()-2; ++i) + { + int j = i+1, k = A.size()-1; + while (j < k) + { + int sum = A[i] + A[j] + A[k]; + if (abs(sum - B) < diff) ansA = A[i], ansB = A[j], ansC = A[k]; + if (sum > B) k--; + else j++; + } + } + return (diff == INT_MAX) ? -1 : ansA + ansB + ansC; +} +``` + +### [3 Sum \(Without Duplicates\)](https://leetcode.com/problems/3sum/) + +```cpp +vector> threeSum(vector& nums) +{ + sort(nums.begin(), nums.end()); + int n = nums.size(); + vector> res; + int target = 0; + for (int i = 0; i < n-1; ++i) + { + if (i > 0 && nums[i] == nums[i-1]) continue; + int j = i+1, k = n-1; + while (j < k) + { + int sum = nums[i] + nums[j] + nums[k]; + if (sum == target) + { + res.push_back({nums[i], nums[j], nums[k]}); + while (j < k && nums[j] == nums[j+1]) j++; + while (j < k && nums[k] == nums[k-1]) k--; + ++j, --k; + } + else if (sum > 0) k--; + else j++; + } + } + return res; +} +``` + +### [Array 3 Pointers](https://www.interviewbit.com/problems/array-3-pointers/) + +```cpp +// Array 3 pointers - max(abs(A[i] - B[j]), abs(B[j] - C[k]), abs(C[k] - A[i])) is minimized +int getMax(int a, int b, int c) { return max(a, max(b,c)); } +int Solution::minimize(const vector &A, const vector &B, const vector &C) +{ + int i = 0, j = 0, k = 0; + int sol = INT_MAX; + int temp, temp1, temp2, temp3; + while(i < A.size() && j < B.size() && k < C.size()) + { + sol = min(sol, getMax(abs(A[i]-B[j]), abs(B[j]-C[k]), abs(C[k]-A[i]))); + temp1 = (i+1 < A.size()) ? + getMax(abs(A[i+1]-B[j]), abs(B[j]-C[k]), abs(C[k]-A[i+1])) : INT_MAX; + temp2 = (j+1 < B.size()) ? + getMax(abs(A[i]-B[j+1]), abs(B[j+1]-C[k]), abs(C[k]-A[i])) : INT_MAX; + temp3 = (k+1 < C.size()) ? + getMax(abs(A[i]-B[j]), abs(B[j]-C[k+1]), abs(C[k+1]-A[i])) : INT_MAX; + temp = min(temp1, min(temp2, temp3)); + + if(temp == INT_MAX) return sol; + else if(temp == temp1) i++; + else if(temp == temp2) j++; + else k++; + } + return sol; +} +``` + +### [DiffK](https://www.interviewbit.com/problems/diffk/) + +```cpp +// Diffk - A[i] - A[j] = k, i != j +int Solution::diffPossible(vector &A, int B) +{ + int i = 0, j = 0; + while (i < A.size() && j < A.size()) + { + if (i == j) i++; + int cur = A[i] - A[j]; + if (cur == B) return 1; + else if (cur > B) j++; + else i++; + } + return 0; +} +``` + +### Pythagorean Triplet + +```cpp +// Pythagorean Triplet - a^2 + b^2 = c^2 satisfy this +using namespace std; +#define ll long long + +int main() +{ + int t; + cin >> t; + while (t--) + { + int n; + cin >> n; + int arr[n]; + for (int i = 0; i < n; ++i) cin >> arr[i]; + for (int i = 0; i < n; ++i) arr[i] *= arr[i]; + sort(arr, arr + n, greater()); + bool found = false; + for (int i = 0; i < n-2; ++i) + { + int j = i+1, k = n-1; + while (j < k) + { + int b = arr[j] + arr[k]; + if (arr[i] == b) + { + cout << "Yes" << endl; + found = true; + break; + } + else if (arr[i] > b) --k; + else ++j; + } + if (found) break; + } + if (!found) cout << "No" << endl; + } + return 0; +} + +/* +Analysis: +for (int i = 0; i < n-2; ++i) + int j = i+1, k = n-1; + while (j < k) +This technique works for Count the triplets such that A[i] + A[j] = A[k], +sum a b c closest to given number and Pythagorean Triplet - a^2 + b^2 = c^2 +satisfy this. In these three it worked because this technique is basically +for summation problems. In pythagorean triplet however for optimization +in array every number squared is stored instead to avoid recalculating square. +We do both side pointer technique only if there's an addition problem + +minimize this | max(a,b,c) - min(a,b,c) | we start by pointing all i, j, k to n-1. +If max value is contributed by say a then we do i-- if b then j-- else k-- + +max(abs(A[i] - B[j]), abs(B[j] - C[k]), abs(C[k] - A[i])) is minimized, this +questions starts by pointing i, j, k to 0. It doesn't matter we can point it +to end also. what we are basically checking if we increment i, j and k which +one gives best benefit then we increment that only. + +Lastly DiffK we again do linear pointer thing */ +``` + +## Monotonic Queue + +### Sliding Window Max/Min: + +Key observation: Given an input array A when A\[l\] < A\[r\] for l < r, then A\[l\] should never be returned as the sliding max, if A\[r\] has entered the sliding window. +So we maintain a monotonic array with index increasing and value decreasing. + +```cpp +vector slidingWindowMinMax(vector &arr, int k, bool max = true) +{ + deque q; + vector res; + int n = arr.size(); + for (int i = 0; i < n; ++i) + { + while (!q.empty() && q.front() < i-k+1) q.pop_front(); // handles index + if (max) // handles values + { + while (!q.empty() && arr[i] > arr[q.back()]) + q.pop_back(); + } + else + { + while (!q.empty() && arr[i] < arr[q.back()]) + q.pop_back(); + } + q.push_back(i); + if(i >= k-1) res.push_back(arr[q.front()]); + } + return res; +} +``` + +> DP problem where `A[i] = max(A[j:k]) + C` for `j < k <= i` can be solved by Monotonic Queue. Example: [https://atcoder.jp/contests/dp/tasks/dp\_b](https://atcoder.jp/contests/dp/tasks/dp_b) + +### Find Next Element Larger/Smaller: + +Key observation: given `A[k] < A[j] > A[i]` for `k < j < i`, `A[k]` never become the **nearest** element larger than `A[i]` because of `A[j]`. + +So we should have a decreasing monotonic queue here. The arrow indicates that the mapping from element on the right to the nearest element on the left larger than it. The elements in the valley are ignored. + +![](.gitbook/assets/image%20%28168%29.png) + +```cpp +vector nextMonotonicElement(vector &arr, bool greater = true, bool circularArray = false) +{ + vector res(arr.size()); + stack st; + for (int i = (circularArray) ? (2*arr.size()-1) : (arr.size()-1); i >= 0; --i) + { + if (greater) + { + while (!st.empty() && arr[st.top()] <= arr[i % arr.size()]) + st.pop(); + } + else + { + while (!st.empty() && arr[st.top()] >= arr[i % arr.size()]) + st.pop(); + } + res[i % arr.size()] = st.empty() ? -1 : arr[st.top()]; + st.push(i % arr.size()); + } + return res; +} +``` + +### [Length of Longest Substring with K distinct characters](https://www.lintcode.com/problem/longest-substring-with-at-most-k-distinct-characters/description) + +```cpp +int lengthOfLongestSubstringKDistinct(string &s, int k) +{ + unordered_map cnt; + int res = 0; + for (int l = 0, r = 0; r < s.size(); ++r) + { + cnt[s[r]]++; + while (cnt.size() > k) + { + cnt[s[l]]--; + if (cnt[s[l]] == 0) cnt.erase(s[l]); + l++; + } + res = max(res, r-l+1); + } + return res; +} +``` + +### [Count Subarrays with product less than K](https://leetcode.com/problems/subarray-product-less-than-k/) + +```cpp +// Integer overflow +int numSubarrayProductLessThanK(vector& nums, int k) +{ + if (k == 0) return 0; + vector prod(nums.size()+1); + prod[0] = 1; + for (int i = 0; i < nums.size(); ++i) prod[i+1] = prod[i] * nums[i]; + int res = 0; + for (int i = 0; i < nums.size(); ++i) + { + auto it = upper_bound(prod.begin(), prod.end(), prod[i+1]/k); + if (it != prod.end()) + res += (i+1) - (it - prod.begin()); + } + return res; +} + +// Accepted using sliding window +int numSubarrayProductLessThanK(vector& nums, int k) +{ + int res = 0; + if (k == 0) return 0; + for (int l = 0, r = 0, curProd = 1; r < nums.size(); ++r) + { + curProd *= nums[r]; + while (curProd >= k) { curProd /= nums[l++]; } + if (l <= r) res += (r-l+1); + } + return res; +} +``` + +### [Largest Area in Histogram](https://leetcode.com/problems/largest-rectangle-in-histogram/) + +Brute force is to pick two points, find minimum from i to j area within that bound will be min \* \(j-i+1\) just find maximum over all N square i j pairs. Complexity will be N^3 we can optimize it easily to get N^2. + +[https://youtu.be/MhQPpAoZbMc](https://youtu.be/MhQPpAoZbMc) + +```cpp +int largestRectangleArea(vector& heights) +{ + stack st; + int ans = 0; + heights.push_back(-1); + for (int i = 0; i < heights.size(); ++i) + { + while (!st.empty() && heights[i] <= heights[st.top()]) + { + int height = heights[st.top()]; + st.pop(); + // i is rightmost smaller element, st.top() is + // prev top leftmost + int width = i - (st.empty() ? -1 : st.top()) - 1; + ans = max(ans, height * width); + } + st.push(i); + } + return ans; +} +``` + +### [Maximal Rectangle](https://leetcode.com/problems/maximal-rectangle/) + +Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area. + +Idea: Convert 2D Matrix into 1D height array then task becomes largest rectangle in histogram. + +```cpp +int maximalRectangle(vector>& matrix) +{ + if (matrix.empty() || matrix[0].empty()) return 0; + int n = matrix.size(), m = matrix[0].size(); + vector histogram(m, 0); + int res = 0; + for (int i = 0; i < n; ++i) + { + for (int j = 0; j < m; ++j) + histogram[j] = (matrix[i][j] == '1') ? histogram[j]+1 : 0; + res = max(res, largestRectangleArea(histogram)); + } + return res; +} +``` + +### Sort Stack + +```cpp +// Make smallest item on top +/* +One approach is to keep finding minimum put it on the stack but +this will require in total of 3 stacks i.e. 2 extra but we can only use 1 extra. +*/ + +stack addit; +while (!st.empty()) +{ + int temp = st.pop(); + while (!addit.empty() && addit.top() > temp) st.push(addit.pop()); + addit.push(temp); +} +while (!addit.empty()) st.push(addit.pop()); + +// This above one is O(N square) +// If we had infinite stacks then we could have used merge sort tab O(logN) +// hota complexity +``` + +### Shortest Subarray with Sum at Least K + +Return the length of the shortest, non-empty, contiguous subarray of A with sum at least K. + +Idea: We want to find A\[l\] A\[l+1\] ... A\[r\] such that its sum\[l..r\] is >= k We can do prefix sum P\[r\] - P\[l-1\] >= k we basically want P\[r\] - k >= P\[l-1\] so upper\_bound will do it. To do it in logN however we need to maintain a monotonic queue. + +```cpp +int shortestSubarray(vector& arr, int k, int &r, int &l) +{ + deque> dq; + dq.emplace_back(0, -1); + int presum = 0, res = INF; + for (int i = 0; i < arr.size(); ++ i) + { + presum += arr[i]; + while(!dq.empty() && presum - dq.front().first >= k) + { + int cur = i-dq.front().second; + if (cur < res) res = cur, r = i, l = i-(cur-1); + dq.pop_front(); + } + while(!dq.empty() && dq.back().first >= presum) dq.pop_back(); + dq.emplace_back(presum, i); + } + return res == INF ? -1 : res; +} +``` + +TODO: + +* **LC739. Daily Temperatures** +* **LC901. Online Stock Span** +* **LC907. Sum of Subarray Minimums** + diff --git a/number-theory.md b/number-theory.md new file mode 100644 index 0000000..a379a46 --- /dev/null +++ b/number-theory.md @@ -0,0 +1,573 @@ +# Number Theory + +## Primes and factors + +* For every number n > 1, there is a unique prime factorization + +![](.gitbook/assets/image%20%2866%29.png) + +* Number of factors of a number n is: + +![There are αi + 1 ways to choose how many times prime pi appears in the factor](.gitbook/assets/image%20%282%29.png) + +* Sum of factors of n is: + +![](.gitbook/assets/image%20%2878%29%20%281%29.png) + +* Product of factors of n is: + +![we can form τ\(n\)/2 pairs from the factors, each with product n](.gitbook/assets/image%20%2816%29.png) + +* Goldbach’s conjecture: Each num > 2 can be represented as sum of 2 primes [https://codeforces.com/contest/1238/problem/A](https://codeforces.com/contest/1238/problem/A) +* Twin prime conjecture: There is an infinite number of pairs \(p, p+2\) where both are primes. +* Legendre's conjecture: There's always a prime between n^2 and \(n+1\)^2 + +### Find Divisors + +```cpp +vector findDivisors(ll n) +{ + vector res; + for (ll i = 1; i <= sqrt(n); ++i) + { + if (n%i == 0) + { + res.push_back(i); + if (n/i != i) res.push_back(n/i); + } + } + return res; +} +``` + +### Sieve of Eratosthenes + +```cpp +const int MAXN = 1e5; +ll sieve[MAXN+1]; +vector primes; +void makeSieve() +{ + fill(sieve, sieve+MAXN+1, 1); + sieve[0] = 0, sieve[1] = 0; + for (int i = 2; i <= MAXN; ++i) + { + if (sieve[i] != 1) continue; + for (int j = i*2; j <= MAXN; j += i) sieve[j] = 0; + } + for (int i = 0; i <= MAXN; ++i) + if (sieve[i]) primes.push_back(i); +} + +// Almost twice fast sieve can generate upto 3e7 range in 1 second +const int MAXN = 1e7; +int sieve[MAXN+1], primes[MAXN+1], primesSz = 0; +void findprimes() +{ + for (int i = 2; i <= MAXN; ++i) + { + if (sieve[i] == 0) { sieve[i] = i; primes[primesSz++] = i; } + for (int j = 0, x = i*primes[j]; j < primesSz && primes[j] <= sieve[i] + && x <= MAXN; ++j, x = i*primes[j]) + sieve[x] = primes[j]; + } +} +void segmentedSieve(int l) +{ + findprimes(); + memset(sieve, 1, sizeof(sieve)); + for (int i = 0; i < primesSz; ++i) + { + int incr = primes[i] + primes[i]; + int start = max(((l + primes[i] - 1) / primes[i]) * primes[i], primes[i] * primes[i]); + if ((start&1) == 0) start += primes[i]; + start -= l; + for (int j = l; j <= MAXN; j += incr) sieve[j] = 0; + } + primesSz = 0; + for (int i = (l&1) ? 0 : 1; i <= MAXN; i += 2) + if (sieve[i]) primes[primesSz++] = l+i; +} +``` + +### Euler totient function + +```cpp +// Euler totient function in logN +int phi(int n) +{ + int res = n; + for (int i = 2; i*i <= n; ++i) + { + if (n%i == 0) + { + while (n%i == 0) n /= i; + res -= res/i; + } + } + if (n > 1) res -= res/n; + return res; +} + +// Euler totient preprocessing +const int MAXN = 1e5; +int phi[MAXN+1]; +void phiPreprocess() +{ + phi[0] = 0, phi[1] = 1; + for (int i = 2; i <= MAXN; ++i) phi[i] = i-1; + for (int i = 2; i <= MAXN; ++i) + for (int j = 2*i; j <= MAXN; j += i) phi[j] -= phi[i]; +} +``` + +![](.gitbook/assets/image%20%28149%29.png) + +### Eucledian Algorithm + +![If negative number take abs and put it will work just fine. LCM\(a, b\) \* gcd\(a, b\) = a\*b](.gitbook/assets/image%20%28153%29.png) + +```cpp +inline int gcd (int a, int b) { while (b) { a %= b; swap(a, b); } return a; } +inline int lcm (int a, int b) { return a / gcd(a, b) * b; } +``` + +**Correctness Proof:** +[**https://youtu.be/H\_2\_nqKAZ5w**](https://youtu.be/H_2_nqKAZ5w) +****For proof we need to show gcd\(a, b\) = gcd\(b, a%b\) for all a >= 0 & b >= 0. One thing to notice is second argument is strictly decreasing +Let d = gcd\(a, b\) then by definition d\|a and d\|b \(d divides a and d divides b\) +We know a%b = a - b\*floor\(a/b\) +From this we follow that gcd\(b, a%b\) by definition d\|b and d\|\(a%b\) +Say there are 3 integers p, q, r - if p\|q and p\|r then p\|gcd\(q, r\) using this we can get gcd\(a, b\) \| gcd\(b, a%b\) +Thus we have shown left side of the original solution divides right side. The second half of proof is similar. + +**Time Complexity:** +Runtime is estimated by Lame's Theorem which establishes connected with fibonacci sequence \(formed by successive a%b\). Making it O\(log min\(a, b\)\) + +## Modular Arithmetic + +![](.gitbook/assets/image%20%2826%29.png) + +### Modular Exponentiation + +![](.gitbook/assets/image%20%28180%29.png) + +```cpp +int powMod(int a, int b) +{ + int x = 1; + while (b > 0) + { + if (b & 1) x = (x * a) % MOD; + a = (a * a) % MOD; + b >>= 1; + } +} +``` + +![](.gitbook/assets/image%20%2891%29.png) + +* [Leading and Trailing](https://uva.onlinejudge.org/index.php?option=onlinejudge&page=show_problem&problem=1970): `pow(10, fmod(klog10(n), 1))`\*`100;` and `powMod(n, k, 1000);` +* [Locker](http://www.spoj.com/problems/LOCKER/): Simply we want a seq. with max product and sum = n, OEIS [https://oeis.org/A000792](https://oeis.org/A000792) +* [Just add it](http://www.spoj.com/problems/ZSUM/): [https://ideone.com/6E5bc7](https://ideone.com/6E5bc7) +* [Jewel-eating Monsters](https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1723): Final solution becomes: `((x-1) * a^n) - (a(a^n-1 -1))/(a-1)` +* [Parking Lot](http://codeforces.com/problemset/problem/630/I): Consider 3 types of placements: XXXOOOO, OOOOXXX, OOXXXOO i.e. left right or anywhere middle first two conditions are handled by: 2.4.3.4^\(n-3\) middle one is handled by \(n-3\).4.3^2.4^\(n-4\). + +### Fermat's Theorem and Euler Theorem + +![](.gitbook/assets/image%20%2836%29.png) + +### Modular Inverse + +![](.gitbook/assets/image%20%2832%29.png) + +### nCr + +```cpp +int nCr(int n, int r) +{ + if (n < r) return 0; + ll res = 1, rem = 1; + for (ll i = n - r + 1; i <= n; i++) res = multiply(res, i); + for (ll i = 2; i <= r; i++) rem = multiply(rem, i); + return multiply(res, powMod(rem, MOD - 2)); +} +const int MAXN= 1e5; +int fact[MAXN+1], inv[MAXN+1]; +void nCrPreprocess() +{ + fact[0] = inv[0] = 1; + for(int i = 1; i <= MAXN; ++i) + { + fact[i] = multiply(fact[i-1], i); + inv[i] = powMod(fact[i], MOD-2); + } +} +int nCrQuery(int n, int r) +{ + if (n < r) return 0; + int res = 1; res = multiply(res, fact[n]); + res = multiply(res, inv[r]); + res = multiply(res, inv[n-r]); + return res; +} +``` + +**Properties:** + +![](.gitbook/assets/image%20%28172%29.png) + +![](.gitbook/assets/image%20%2837%29.png) + +![](.gitbook/assets/image%20%28126%29.png) + +## Fibonacci Number + +* **Cassini's Identity:** `F(n-1)F(n+1) - F(n)F(n) = (-1)^n` +* **Addition Rule:** `F(n+k) = F(k)F(n+1) + F(k-1)F(n)` +* **Applying previous identity where k = n:** `F(2n) = F(n) (F(n+1) + F(n-1))` +* **From this we can prove by induction that F\(nk\) is multiple of F\(n\)** +* **GCD Identity:** gcd\(F\(m\), F\(n\)\) = F\(gcd\(m, n\)\) + +### Fibonacci Coding + +According to Zeckendorf's theorem, any natural number n can be uniquely represented as a sum of Fibonacci numbers. + +![](.gitbook/assets/image%20%2821%29.png) + +Idea is to represent in binary notation with end as 1 \(to mark ending\) for di = 1 means F\(i+2\) is taken. It can be filled by greedily picking maximum size fibonacci and subtracting. + +### Formulas + +![](.gitbook/assets/image%20%28141%29.png) + +![](.gitbook/assets/image%20%28128%29.png) + + + + + +## Solving Equations + +A diophatine equation is of the for `ax + by = c` where a, b, c are constants and value of x & y have to be found. We want to: + +> If a = b = 0 then either we have no solution or infinite solutions + +```cpp +// Not to be used directly +pii chineaseRemainderTheorem(int x, int a, int y, int b) +{ + int s, t, d = extendedEuclid(x, y, s, t); + if (a%d != b%d) return make_pair(0, -1); + return make_pair(((s*b*x + t*a*y + x*y)%(x*y))/d, x*y/d); +} + +// returns d = gcd(a,b); finds x,y such that d = ax + by +int extendedEuclid(int a, int b, int &x, int &y) +{ + int xx = y = 0, yy = x = 1; + while (b) + { + int q = a/b; + int t = b; b = a%b; a = t; + t = xx; xx = x-q*xx; x = t; + t = yy; yy = y-q*yy; y = t; + } + return a; +} +// finds all solutions to ax = b (mod n) +vector modularLinearEquationSolver(int a, int b, int n) +{ + int x, y; + vector solutions; + int d = extendedEuclid(a, n, x, y); + if (b%d == 0) + { + x = ((x * (b/d) + n) % n); + for (int i = 0; i < d; ++i) + solutions.push_back((x + i*(n/d) + n) % n); + } + return solutions; +} +// computes x and y such that ax + by = c; on failure, x = y =-1 +void linearDiophantine(int a, int b, int c, int &x, int &y) +{ + int d = __gcd(a, b); + if (c%d) x = y = -1; + else + { + x = c/d * inverseMod(a/d, b/d); + y = (c-a*x)/b; + } +} +// finds z such that z % x[i] = a[i] for all i. returns (z, M) on failure M = -1 +// Note: we require a[i]'s to be relatively prime +pii chineaseRemainderTheorem(const vector &x, const vector &a) +{ + pii ret = make_pair(x[0], a[0]); + for (int i = 1; i < x.size(); ++i) + { + ret = chineaseRemainderTheorem(ret.first, ret.second, x[i], a[i]); + if (ret.second == -1) break; + } + return ret; +} +``` + +## Other Results + +### Lagrange's Four Square theorem + +Every natural number can be represented as the sum of four integer squares + +![](.gitbook/assets/image%20%286%29.png) + +Example problem: [https://leetcode.com/problems/perfect-squares/](https://leetcode.com/problems/perfect-squares/) + +> Minimum number of squares required is 4 if n can be written in the form 4^k\(8m + 7\) + +```cpp +// No DP No BFS this method is the best XD +int numSquares(int n) +{ + int srt = sqrt(n); + if (is_square(n)) return 1; + + for (int i = 1; i <= sqrt(n); ++i) + if (is_square(n - i*i)) return 2; + + while (n%4 == 0) n >>= 2; + if (n % 8 == 7) return 4; + + return 3; +} +``` + +### Pythagorean triples + +It's a triple \(a, b, c\) that satisfies Pythagorean theorem a^2 + b^2 = c^2. +If \(a, b, c\) is a valid triple all \(ka, kb, kc\) is also valid where k > 1 + +**Euclid formula:** `(n^2 - m^2, 2nm, n^2 + m^2) +Where 0 1,1,2,5,14,42,132, 429... + +* Number of valid parenthesis expressions that consist of n left parentheses and n right parentheses. +* There are Cn binary trees of n nodes and Cn-1 rooted trees of n nodes. + +![](.gitbook/assets/image%20%28115%29.png) + +![](.gitbook/assets/image%20%28156%29.png) + +![](.gitbook/assets/image%20%28202%29.png) + +```cpp +unordered_map dp; +int cat(int n) // 1 indexed +{ + if (n <= 1) return 1; + if (dp[n] != 0) return dp[n]; + int res = 0; + for (int i = 0; i < n; ++i) + res += cat(i) * cat(n-i-1); + return dp[n] = res; +} +``` + +### Stirling Number of Second Kind + +Given n numbers, grouping them in k subgroups find total possibility. It's defined by stirling number: +S\(n, k\) = k\*\(S\(n-1, k\)\) + S\(n-1, k-1\) + +### Inclusion Exclusion + +\| A ∪ B ∪ C \| = \| A \| + \| B \| + \| C \| - \| A ∩ B \| - \| B ∩ C \| - \| C ∩ A \| + \| A ∩ B ∩ C\| + \| A ∪ B ∪ C ∪ ... \| = { SINGLE SUMS } - { DOUBLE PAIRS SUM } + { TRIPLE PAIRS SUM } - { FOUR PAIRS SUM } + ... + +Find numbers less than 1000 divisible by 2, 3 & 5 + Numbers less then N divisible by m are floor\(\(N - 1\) / m\) So: + Divisible by 2 = 449 + Divisible by 3 = 333 + Divisible by 5 = 199 + Divisible by 2.5 = 99 + Divisible by 3.5 = 66 + Divisible by 2.3 = 166 + Divisible by 2.3.5 = 33 + \| 2 ∪ 3 ∪ 5 \| = 499 + 133 + 199 - 99 - 66 - 166 + 33 = 733 + +Numbers between 1 and n which are divisible by any of the prime numbers less than 20 + +```cpp +ll t; +cin >> t; +while (t--) +{ + ll num; + cin >> num; + ll arr[] = { 2, 3, 5, 7, 11, 13, 17, 19 }; + ll n = sizeof(arr) / sizeof(ll); + ll result = 0; + for (ll i = 1; i < (1< 0) + { + ll lastBit = (mask&1); + if (lastBit) product *= arr[pos]; + mask >>= 1; + ++pos; + } + if (bits&1) result += num/product; + else result -= num/product; + } + cout << result << endl; +} +``` + +### Derangements + +Number of permutations where no element remain in original place. It follows following relation: + +![](.gitbook/assets/image%20%2849%29%20%281%29.png) + +* There are \(n-1\) ways to chose an element x that can replace element 1. +* We swapped x and 1 element so now we are left with f\(n-2\) +* We replace element x with some other element \(than 1\) Now we have to construct n-1 derangements since we cannot replace x with \(1 val\) + +### Burnside's Lemma + +TODO + +### Prüfer code + +Way of encoding a labelled tree into a sequence of n-2 integers in interval \[0, n-1\] +Cayley's formula states that the **number of spanning trees in a complete labeled graph** with n vertices is n^\(n-2\) + +Process: Removes n−2 leaves from the tree. At each step, the leaf with the smallest label is removed, and the label of its only neighbor is added to the code + +![](.gitbook/assets/image%20%2858%29.png) + +![Cayley's Formula](.gitbook/assets/image%20%28118%29.png) + +```cpp +const int MAXN = 1e5; +vector adj[MAXN+1]; +int parent[MAXN+1]; +void DFS(int u) +{ + for (auto &v : adj[u]) + if (v != parent[u]) { parent[v] = u; DFS(v); } +} +vector prueferCode(int n) +{ + parent[n-1] = -1; + DFS(n-1); + int ptr = -1; + vector degree(n); + for (int i = 0; i < n; i++) + { + degree[i] = adj[i].size(); + if (degree[i] == 1 && ptr == -1) ptr = i; + } + vector code(n - 2); + int leaf = ptr; + for (int i = 0; i < n - 2; i++) + { + int next = parent[leaf]; + code[i] = next; + if (--degree[next] == 1 && next < ptr) leaf = next; + else { ptr++; while (degree[ptr] != 1) ptr++; leaf = ptr; } + } + return code; +} +vector prueferDecode(vector &code) +{ + int n = code.size() + 2; + vector degree(n, 1); + for (int i : code) degree[i]++; + int ptr = 0; + while (degree[ptr] != 1) ptr++; + int leaf = ptr; + vector edges; + for (int v : code) + { + edges.emplace_back(leaf, v); + if (--degree[v] == 1 && v < ptr) leaf = v; + else { ptr++; while (degree[ptr] != 1) ptr++; leaf = ptr; } + } + edges.emplace_back(leaf, n-1); + return edges; +} +``` + +[https://codeforces.com/contest/156/problem/D](https://codeforces.com/contest/156/problem/D) + +## Probability + +**Bernoulli Trial:** A dice thrown n times and we want probability for 6 exactly x times. so: nCx \(1/6\)^x \(5/6\)^\(n - x\) + The expected number of trials for ith success is 1/p + +> **Coupon Collector Problem: A certain brand of cereal always distributes a coupon in every cereal box. The coupon chosen for each box is chosen randomly from a set of n distinct coupons. A coupon collector wishes to collect all n distinct coupons. What is the expected number of cereal boxes must the coupon collector buy so that the coupon collector collects all n distinct coupons.** +> +> Probability of collecting first coupon is 1 since the collector has none. Later on for Pi = \(n - \(i-1\)\) / n +> E\(x\) = 1/P \(follows geometric distribution\) we need to calculate summation of E\[x\] +> = E\(1\) + E\(2\) + E\(3\) + E\(4\) + ... + E\(n\) +> = n/n + n/n-1 + n/n-2 + n/n-3 + ... + + n/2 + n/1 +> = n \(1/n + 1/n-1 + 1/n-2 + 1/n-3 + ... + 1/2 + 1\) +> Apply expansion + +### Pigeonhole Principle + +Divisible Subset Problem \(C4\)\([https://www.codechef.com/problems/DIVSUBS](https://www.codechef.com/problems/DIVSUBS)\) + Example: 3 4 3 5 2 3 + Naive approach is by exponential time finding pairs with 1 element only then 2 element only and so on. + Any such problem can be illustrated as \(1+x^3\)\(1+x^4\)\(1+x^3\)\(1+x^5\)\(1+x^2\)\(1+x^3\) solving this will give terms having powers of all subsets we just need to apply % N = 0. + It can be solved in O\(NlogN\) by Fast Fourier Transform or simply in O\(N2\) [https://www.youtube.com/watch?v=QQQpOa3aXew](https://www.youtube.com/watch?v=QQQpOa3aXew) + +```text +Itterate all array elements and apply % N and record it in the array of vector below. +0 1 2 3 4 5 + 0 +Then 4 +0 1 2 3 4 5 + 1 +Then in 4 to 3 so 4 + 3 % N +0 1 2 3 4 5 + 0,1 0 1 +and so on. + +a[] = 3 4 3 5 2 3 +b[] = 0 3 7 10 15 17 20 +b[] = 0 3 1 4 3 5 2 +temp[] = 2 6 1,4 3 5 +This is pigeonhole senerio in every case any temp arr will have two element. +end - start i.e. 4 - 1 = 3 so 3 elements that are 2nd 3rd and 4th (4 + 3 + 5) % 6 = 0 +``` + +* P\(x & y\) = P\(x/y\) P\(y\) +* P\(x/y\) = P\(y/x\) P\(x\)/P\(y\) - Baye's Theorem +* P\(x \| y\) = P\(x\) + P\(y\) - P\(x & y\) +* Independence rule: if x & y are independent events then P\(x & y\) = P\(x\) P\(y\) +* Mutual Exclusive: \(One happens then other cannot\) P\(x \| y\) = P\(x\) + P\(y\) + diff --git a/problem-set/README.md b/problem-set/README.md new file mode 100644 index 0000000..d1c06ef --- /dev/null +++ b/problem-set/README.md @@ -0,0 +1,2 @@ +# Problem Set + diff --git a/problem-set/codeforces-training-set-i.md b/problem-set/codeforces-training-set-i.md new file mode 100644 index 0000000..f7a8870 --- /dev/null +++ b/problem-set/codeforces-training-set-i.md @@ -0,0 +1,1191 @@ +# Training Set I + +## Day 1 \(9\) + +### [632C - The Smallest String Concatenation](https://codeforces.com/problemset/problem/632/C) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, string> arr(n); + for (auto &x : arr) cin >> x; + sort(all(arr), [](string &x, string &y){ return (x+y < y+x); }); + string res = ""; + for (auto &x : arr) res += x; + cout << res << '\n'; + return 0; +} +``` + +### [922D - Robot Vacuum Cleaner](https://codeforces.com/problemset/problem/922/D) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, string> arr(n); + for (auto &x : arr) cin >> x; + auto f = [](string s) + { + int noise = 0, x = 0; + for (auto &ch : s) + { + if (ch == 's') x++; + else noise += x; + } + return noise; + }; + sort(all(arr), [&](string &x, string &y){ return f(x+y) > f(y+x); }); + string res = ""; + for (auto &x : arr) res += x; + cout << f(res) << '\n'; + return 0; +} +``` + +### [489D - Unbearable Controversy of Being](https://codeforces.com/problemset/problem/489/D) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<1, int> adj[n+1]; + while (m--) + { + int u, v; cin >> u >> v; + adj[u].push_back(v); + } + int res = 0; + intHashTable cnts; + for (int i = 1; i <= n; ++i) + { + cnts.clear(); + for (auto &x : adj[i]) + for (auto &y : adj[x]) cnts[y]++; + for (auto &x : cnts) + { + if (x.F == i) continue; + res += (x.S * (x.S-1)) / 2; // x.S choose 2 + } + } + cout << res << '\n'; + return 0; +} +``` + +### [187B - AlgoRace](https://codeforces.com/problemset/problem/187/B) + +```cpp +const int MAXN = 60+3; +int mat[MAXN][MAXN][MAXN], dp[MAXN][MAXN][MAXN], res[MAXN][MAXN][MAXN], cur[MAXN][MAXN]; +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, k, q; cin >> n >> k >> q; + // dp stores if we choose this car then what is shortest time using floyd warshall + for (int w = 0; w < k; ++w) + { + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) { cin >> mat[w][i][j]; dp[w][i][j] = mat[w][i][j]; } + for (int x = 0; x < n; ++x) + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) + dp[w][i][j] = min(dp[w][i][j], dp[w][i][x] + dp[w][x][j]); + } + memset(res, 63, sizeof(res)); + memset(cur, 63, sizeof(cur)); + // cur stores shortest time without changing car + for (int i = 0; i < n; ++i) + { + for (int j = 0; j < n; ++j) + { + for (int x = 0; x < k; ++x) cur[i][j] = min(cur[i][j], dp[x][i][j]); + res[0][i][j] = cur[i][j]; + } + } + for (int w = 1; w < MAXN; ++w) + { + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) + for (int x = 0; x < n; ++x) + res[w][i][j] = min(res[w][i][j], cur[i][x] + res[w-1][x][j]); + } + while (q--) + { + int u, v, t; cin >> u >> v >> t; + cout << res[min(t, n)][u-1][v-1] << '\n'; + } + return 0; +} +``` + +### [1249E - By Elevator or Stairs?](https://codeforces.com/problemset/problem/1249/E) + +```cpp +vec<2, int> dp(200005, 2, (1<<30)); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, c; cin >> n >> c; + vec<1, int> a(n), b(n); + for (int i = 1; i < n; ++i) cin >> a[i]; + for (int i = 1; i < n; ++i) cin >> b[i]; + dp[1][0] = 0; + for (int i = 1; i < n; ++i) + { + for (bool onLift : {false, true}) + { + dp[i+1][false] = min(dp[i+1][false], a[i] + dp[i][onLift]); + dp[i+1][true] = min(dp[i+1][true], b[i] + dp[i][onLift] + (onLift ? 0 : c)); + } + } + for (int i = 1; i <= n; ++i) cout << min(dp[i][0], dp[i][1]) << " "; + cout << '\n'; + return 0; +} +``` + +### [813C - The Tag Game](https://codeforces.com/problemset/problem/813/C) + +```cpp +const int MAXN = 2e5+5; +#define INF (1LL<<61) +vec<1, int> adj[MAXN]; +vec<1, int> dist1(MAXN, INF), dist2(MAXN, INF); +void dfs(int u, vec<1, int> &dist, int prev = -1, int cur = 0) +{ + dist[u] = min(dist[u], cur); + for (auto &v : adj[u]) + if (v != prev) dfs(v, dist, u, cur+1); +} +void dfs2(int u, int &res, int &pt, int prev = -1) +{ + if (dist1[u] <= dist2[u]) return; + if (dist1[u] > res) res = dist1[u], pt = u; + for (auto &v : adj[u]) + if (v != prev) dfs2(v, res, pt, u); +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, x; cin >> n >> x; + int m = n-1; + while (m--) + { + int u, v; cin >> u >> v; + adj[u].push_back(v); + adj[v].push_back(u); + } + dfs(1, dist1); + dfs(x, dist2); + int res = 0, pt = -1; + dfs2(x, res, pt); + cout << 2*max(dist1[pt], dist2[pt]) << '\n'; + return 0; +} +``` + +### [946D - Timetable](https://codeforces.com/contest/946/problem/D) + +dp states would be cur pos and number of skips. On a day we have to choose an optimal substring doing so in N^2 gives TLE. Now the idea is to construct some intermediary dp hours\[i\]\[j\] denotes minimum no of hours on its day with j skips we can find so by sliding window concept now it is linear we basically utilized an already present dp state \(skips\) to optimally find hours. + +```cpp +// TLE Version +int n, m, k; +vec<1, int> arr[505]; +vec<2, int> dp(505, 505, -1); +int solve(int cur = 0, int skipped = 0) +{ + if (skipped > k) return (1LL<<61); + if (cur == n) return 0; + if (dp[cur][skipped] != -1) return dp[cur][skipped]; + + int res = solve(cur+1, skipped+sz(arr[cur])); + for (int l = 0; l < sz(arr[cur]); ++l) + { + for (int r = l; r < sz(arr[cur]); ++r) + { + int alreadyWasted = (arr[cur][r]-arr[cur][l]+1); + if (alreadyWasted > res) continue; + res = min(res, alreadyWasted + solve(cur+1, skipped+(sz(arr[cur])-(r-l+1)))); + } + } + return dp[cur][skipped] = res; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + cin >> n >> m >> k; + for (int i = 0; i < n; ++i) + { + string str; cin >> str; + for (int j = 0; j < sz(str); ++j) + if (str[j] == '1') arr[i].push_back(j); + } + cout << solve() << '\n'; + return 0; +} + +// AC Version +const int MAX = 510; +string s[MAX]; +int hours[MAX][MAX]; // minimum no of hrs on ith day with j skips +int dp[MAX][MAX]; // minimum no of hrs upto ith day with j skips +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int days, hrs, skips; cin >> days >> hrs >> skips; + for (int i = 1; i <= days; i++) cin >> s[i]; + for (int i = 1; i <= days; i++) + { + int lesson_hrs = 0; + for (auto c : s[i]) + if (c == '1') lesson_hrs++; + for (int j = 0; j <= skips; j++) + { + int temp = max(0LL, lesson_hrs - j); + if (temp == 0) { hours[i][j] = 0; continue; } + // find minimum period to attend temp no of lessons using sliding window + int mn = MAX, cnt = 0, idx = -1; + for (int k = 0; k < hrs; k++) + { + if (s[i][k] == '0') continue; + while (cnt < temp && idx + 1 < hrs) + { + idx++; + if (s[i][idx] == '1') cnt++; + } + if (cnt == temp) mn = min(mn, idx - k + 1); + cnt--; + } + hours[i][j] = mn; + } + } + + dp[0][0] = 0; + for (int i = 1; i < MAX; i++) dp[0][i] = MAX * MAX; + for (int i = 1; i <= days; i++) + { + for (int j = 0; j <= skips; j++) + { + dp[i][j] = MAX * MAX; + for (int k = 0; k <= j; k++) dp[i][j] = min(dp[i][j], dp[i-1][j-k] + hours[i][k]); + } + } + cout << dp[days][skips] << endl; + return 0; +} +``` + +### [909C - Python Indentation](https://codeforces.com/problemset/problem/909/C) + +```cpp +vec<2, int> dp(5005, 5005, 0); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + string str = ""; + for (int i = 0; i < n; ++i) { char ch; cin >> ch; str += ch; } + dp[0][0] += 1, dp[0][1] -= 1; + for (int i = 0; i < n; ++i) + { + for (int j = 1; j < n; ++j) (dp[i][j] += dp[i][j-1]) %= MOD; + for (int j = 0; j < n; ++j) + { + if (dp[i][j] == 0) continue; + if (str[i] == 'f') (dp[i+1][j+1] += dp[i][j]) %= MOD, (dp[i+1][j+2] += MOD-dp[i][j]) %= MOD; + else (dp[i+1][0] += dp[i][j]) %= MOD, (dp[i+1][j+1] += MOD-dp[i][j]) %= MOD; + } + } + int res = 0; + for (int j = 0; j < n; ++j) (res += dp[n-1][j]) %= MOD; + cout << res << '\n'; + return 0; +} +``` + +### [766C - Mahmoud and a Message](https://codeforces.com/contest/766/problem/C) + +```cpp +vec<1, int> arr(26); +#define INF (1<<30) +vec<2, int> dp(1005, 3, 0); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + string str; cin >> str; + for (auto &x : arr) cin >> x; + dp[0][0] = 1; dp[0][2] = 0; + for (int i = 1; i <= n; ++i) dp[i][2] = INF; + for (int i = 0; i < n; ++i) + { + for (int j = i+1, mn = INF; j <= n; ++j) + { + mn = min(mn, arr[str[j-1] - 'a']); + if (j-i > mn) break; + (dp[j][0] += dp[i][0]) %= MOD; + dp[j][1] = max({dp[j][1], dp[i][1], j-i}); + dp[j][2] = min(dp[j][2], dp[i][2]+1); + } + } + cout << dp[n][0] << '\n' << dp[n][1] << '\n' << dp[n][2] << '\n'; + return 0; +} +``` + +## Day 2 \(8\) + +### [827A - String Reconstruction](https://codeforces.com/problemset/problem/827/A) + +```cpp +vec<1, char> arr(2000005, 'a'); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + int mx = 0; + for (int i = 0; i < n; ++i) + { + string s; cin >> s; + int sz; cin >> sz; + int ptr = 1; + while (sz--) + { + int x; cin >> x; + for (int j = max(x, ptr); j < x+sz(s); ++j) arr[j] = s[j-x]; + ptr = x+sz(s)-1; + } + mx = max(mx, ptr); + } + for (int i = 1; i <= mx; ++i) cout << arr[i]; + cout << '\n'; + return 0; +} +``` + +### [1290B - Irreducible Anagrams](https://codeforces.com/problemset/problem/1290/B) + +```cpp +/* Its length is equal to 1. +Its first and last characters are different. +It contains at least three different characters. */ +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + string str; cin >> str; + int q; cin >> q; + vec<2, int> cnt(sz(str)+1, 26, 0); + for (int i = 1; i <= sz(str); ++i) + { + for (int j = 0; j < 26; ++j) cnt[i][j] = cnt[i-1][j]; + cnt[i][str[i-1]-'a']++; + } + while (q--) + { + int l, r; cin >> l >> r; + if (l == r || str[l-1] != str[r-1]) cout << "Yes\n"; + else + { + int unique = 0; + for (int j = 0; j < 26; ++j) + if ((cnt[r][j] - cnt[l][j]) > 0) unique++; + if (unique >= 3) cout << "Yes\n"; + else cout << "No\n"; + } + } + return 0; +} +``` + +### [580D - Kefa and Dishes](https://codeforces.com/contest/580/problem/D) + +Nice dp with bit masking + +```cpp +vec<1, int> arr(20); +vec<2, int> adj(20, 20, 0); +vec<2, int> dp((1<<20), 20, -1); +int n, m, k; +int solve(int state, int u) +{ + if (__builtin_popcount(state) == m) return 0; + if (dp[state][u] != -1) return dp[state][u]; + int res = 0; + for (int v = 0; v < n; ++v) + if (!(state&(1<> n >> m >> k; + for (int i = 0; i < n; ++i) cin >> arr[i]; + while (k--) + { + int u, v, w; cin >> u >> v >> w; + adj[u-1][v-1] = w; + } + int ans = 0; + for (int i = 0; i < n; ++i) + ans = max(ans, arr[i] + solve(1< freq(MAXN, 0), cnt(MAXN, 0); +vec<1, bool> isPrime(MAXN, true); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, int> arr(n); + for (auto &x : arr) { cin >> x; freq[x]++; } + for (int i = 2; i < MAXN; ++i) + { + if (!isPrime[i]) continue; + for (int j = i; j < MAXN; j += i) + cnt[i] += freq[j], isPrime[j] = false; + } + for (int i = 1; i < MAXN; ++i) cnt[i] += cnt[i-1]; + int q; cin >> q; + while (q--) + { + int l, r; cin >> l >> r; + l = min(l, MAXN-1); + r = min(r, MAXN-1); + cout << cnt[r]-cnt[l-1] << '\n'; + } + return 0; +} +``` + +### [483B - Friends and Presents](https://codeforces.com/contest/483/problem/B) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int c1, c2, x, y; cin >> c1 >> c2 >> x >> y; + + auto check = [&](int mid) + { + if ((mid - mid/x) < c1) return false; // not divisible by x >= c1 + if ((mid - mid/y) < c2) return false; // not divisible by y >= c2 + if ((mid - mid/lcm(x, y)) < c1+c2) return false; // not divisible by x or y >= c1+c2 + return true; + }; + + int l = 0, r = 1e18; + while (l+1 < r) + { + int mid = l + (r-l)/2; + if (check(mid)) r = mid; + else l = mid; + } + cout << r << '\n'; + return 0; +} +``` + +### [1096D - Easy Problem](https://codeforces.com/contest/1096/problem/D) + +```cpp +const int MAXN = 1e5+5; +int n; +string str; +vec<1, int> arr(MAXN); +#define INF (1LL<<61) +string reqd = "hard"; +vec<2, int> dp(MAXN, 5, -1); +int solve(int cur = 0, int end = 0) +{ + if (end == 4) return INF; + if (cur == n) return 0; + if (dp[cur][end] != -1) return dp[cur][end]; + + return dp[cur][end] = min(arr[cur] + solve(cur+1, end), solve(cur+1, end + (reqd[end] == str[cur]))); +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + cin >> n; + cin >> str; + for (int i = 0; i < n; ++i) cin >> arr[i]; + cout << solve() << '\n'; + return 0; +} +``` + +### [370C - Mittens](https://codeforces.com/problemset/problem/370/C) + +```cpp +// Boring questions +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + sort(all(arr)); + + int ans = 0; + vec<1, pii> res; + for (int i = 0; i < n; ++i) + { + if (arr[i] != arr[(i + n/2)%n]) { ans++; res.push_back({arr[i], arr[(i + n/2)%n]}); } + else res.push_back({arr[i], arr[i]}); + } + cout << ans << '\n'; + for (auto &x : res) + cout << x.F << " " << x.S << '\n'; + return 0; +} +``` + +### [1355C - Count Triangles](https://codeforces.com/contest/1355/problem/C) + +```cpp +const int MAXN = 1000005; +vec<1, int> arr(MAXN); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int a, b, c, d; cin >> a >> b >> c >> d; + for (int x = a; x <= b; ++x) arr[x+b]++, arr[x+c+1]--; + for (int i = 1; i < MAXN; ++i) arr[i] += arr[i-1]; + for (int i = 1; i < MAXN; ++i) arr[i] += arr[i-1]; + int res = 0; + for (int i = c; i <= d; ++i) res += arr[MAXN-1]-arr[i]; + cout << res << '\n'; + return 0; +} +``` + +## Day 3 \(5\) + +### [1354D - Multiset](https://codeforces.com/contest/1354/problem/D) + +Nice binary search \(Using pbds gives MLE\) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, q; cin >> n >> q; + vec<1, int> a(n), k(q); + for (auto &x : a) cin >> x; + for (auto &x : k) cin >> x; + + // counts elements <= mid after considering all queries + auto cnt = [&](int mid) + { + int res = 0; + for (auto &x : a) + if (x <= mid) res++; + for (auto &x : k) + { + if (x > 0 && x <= mid) res++; + if (x < 0 && abs(x) <= res) res--; + } + return res; + }; + + if (cnt(1e9) == 0) { cout << "0\n"; return 0; } + int l = 0, r = 1e6 + 1; + while (l+1 < r) + { + int mid = (l+r)/2; + if (cnt(mid) > 0) r = mid; + else l = mid; + } + cout << r << '\n'; + return 0; +} +``` + +### [1358D - The Best Vacation](https://codeforces.com/contest/1358/problem/D) + +```cpp +const int sumUp(int n) { return (n*(n+1))/2; } +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, x; cin >> n >> x; + vec<1, pii> arr(2*n); + for (int i = 0; i < n; ++i) + { + cin >> arr[i].F; + arr[i].S = sumUp(arr[i].F); + arr[n+i] = arr[i]; + } + + set> rec; + rec.insert({0, 0}); + int ans = 0; + for (int i = 0, smF = 0, smS = 0; i < 2*n; ++i) + { + smF += arr[i].F, smS += arr[i].S; + int reqd = smF-x, res; + if (reqd > 0) + { + auto it = rec.lower_bound({reqd, 0}); + res = smS - it->second - sumUp(reqd - it->F); + } + else res = smS; + ans = max(ans, res); + rec.insert({smF, smS}); + } + cout << ans << '\n'; + return 0; +} +``` + +### [1360F - Spy-string](https://codeforces.com/contest/1360/problem/F) + +```cpp +int n, m; +vec<2, int> visited(15, (1<<15), false); +vec<1, char> res; +bool found = false; +void solve(vec<1, string> &words, int cur = 0, int state = 0) +{ + if (cur == m) + { + for (auto &x : res) cout << x; cout << '\n'; + found = true; + return; + } + if (visited[cur][state]) return; + visited[cur][state] = true; + for (char ch = 'a'; ch <= 'z'; ++ch) + { + bool valid = true; + int newState = state; + for (int i = 0; i < n; ++i) + { + if (words[i][cur] != ch) + { + if (!(newState&(1<> t; + while (t--) + { + cin >> n >> m; + vec<1, string> words(n); + for (auto &x : words) cin >> x; + for (auto &x : visited) for (auto &y : x) y = false; + res.clear(); + found = false; + solve(words); + if (!found) cout << "-1\n"; + } + return 0; +} +``` + +### [1360G - A/B Matrix](https://codeforces.com/contest/1360/problem/G) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t; cin >> t; + while (t--) + { + int n, m, a, b; cin >> n >> m >> a >> b; + if (n*a != m*b) cout << "NO\n"; + else + { + vec<2, int> res(n, m, 0); + int shift = 0; + for (shift = 1; shift < m; ++shift) + if (shift*n % m == 0) break; + for (int i = 0, dx = 0; i < n; ++i, dx += shift) + for (int j = 0; j < a; ++j) + res[i][(j+dx) % m] = 1; + + cout << "YES\n"; + for (auto &x : res) + { + for (auto &y : x) cout << y; + cout << '\n'; + } + } + } + return 0; +} +``` + +### [1353D - Constructing the Array](https://codeforces.com/contest/1353/problem/D) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t; cin >> t; + while (t--) + { + int n; cin >> n; + set st; + st.insert({n, -1}); // stores size of zeros and left pos + int op = 1; + vec<1, int> arr(n+1); + while (!st.empty()) + { + auto cur = *st.rbegin(); st.erase(cur); // pick greatest size leftmost + cur.S *= -1; + int rightPos = (cur.S + cur.F - 1); + int mid = (cur.S + rightPos)/2; + arr[mid] = op++; + if (mid - cur.S) st.insert({mid - cur.S, -cur.S}); + if (rightPos - mid) st.insert({rightPos - mid, -(mid+1)}); + } + for (int i = 1; i <= n; ++i) cout << arr[i] << " "; cout << '\n'; + } + return 0; +} +``` + +## Day 4 \(5\) + +### [1350C - Orac and LCM](https://codeforces.com/contest/1350/problem/C) + +We want to compute GCD\(LCM of all pairs\). If we denote a number as prime factorizations, +say 12 = 2^2 \* 3^1 and 8 = 2^3 \* 3^0 then LCM is pick greatest power for each prime so 2^3 \* 3^1 whereas gcd is take lowest power for each prime so 2^2 \* 3^0. + +So first lets use sieve to create factorizations. Now we can observe through given examples that if that prime number appeared in fewer than n-1 means others have it as 0 so multiply num^0 \(or simply ignore it\) otherwise always take second minimum because we have to work on LCM pairs so one minimum will ultimately get lost. if n==1 we take most minimum because we don't have power 0 case in factors. + +```cpp +const int MAXN = 2e5 + 5; +// creates prime factorization +// so for 12 vector will contain -> {2, 2} {3, 1} means 2^2 . 3 +vector primes[MAXN]; +void sieve() +{ + for (int i = 2; i < MAXN; ++i) + { + if (!primes[i].empty()) continue; + for (int j = i; j < MAXN; j += i) + { + int q = j; + pii nxt = {i, 0}; + while (q%i == 0) q /= i, ++nxt.S; + primes[j].push_back(nxt); + } + } +} +vec<1, int> factors[MAXN]; +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + sieve(); + int n; cin >> n; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + for (auto &x : arr) + for (auto &y : primes[x]) { factors[y.F].push_back(y.S); bug(y.F, y.S); } + int ans = 1; + for (int i = 2; i < MAXN; ++i) + { + sort(all(factors[i])); + if (sz(factors[i]) == n-1) ans *= pow(i, factors[i][0]); + else if (sz(factors[i]) == n) ans *= pow(i, factors[i][1]); + } + cout << ans << '\n'; + return 0; +} +``` + +### [1352C - K-th Not Divisible by n](https://codeforces.com/contest/1352/problem/C) + +Simple Binary Search + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t; cin >> t; + while (t--) + { + int n, k; cin >> n >> k; + int l = 0, r = 1e18; + while (l+1 < r) + { + int mid = (l+r)/2; + int pos = mid - mid/n; + if (pos >= k) r = mid; + else l = mid; + } + int a = r - r/n, b = (r+1) - (r+1)/n; + if (a == k) cout << r << '\n'; + else cout << r+1 << '\n'; + } + return 0; +} +``` + +### [1359C - Mixing Water](https://codeforces.com/contest/1359/problem/C) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t; cin >> t; + while (t--) + { + double h, c, d; cin >> h >> c >> d; + auto func = [&](double mid) + { + double q = (mid*h + mid*c + h) / (2*mid + 1); + if (mid == 0) return fabs(q-d); + double p = (mid*h + mid*c) / (2*mid); + return min(fabs(p-d), fabs(q-d)); + }; + + int l = 0, r = 1e13; + while (l+1000 <= r) + { + int a = l + (r-l)/3, b = r - (r-l)/3; + if (func(a) > func(b)) l = a; + else r = b; + } + double ans = func(l); + int pt = l; + for (int i = l+1; i <= r; ++i) + { + double cur = func(i); + if (cur < ans) ans = cur, pt = i; + } + + double q = (pt*h + pt*c + h) / (2*pt + 1); + if (pt == 0) { cout << 2*pt+1 << "\n"; continue; } + double p = (pt*h + pt*c) / (2*pt); + if (fabs(p-d) < fabs(q-d)) cout << 2*pt << '\n'; + else cout << 2*pt+1 << '\n'; + } + return 0; +} +``` + +### [1359D - Yet Another Yet Another Task](https://codeforces.com/contest/1359/problem/D) + +```cpp +#define INF (1LL<<61) +int solve(vec<1, int> &arr, int x) +{ + int res = -INF; + for (int i = 0; i < sz(arr); ++i) + { + if (arr[i] > x) continue; + int cur = 0; + while (i < sz(arr)) + { + if (arr[i] > x) break; + else cur = max(arr[i], cur+arr[i]); + res = max(res, cur); + ++i; + } + } + res -= x; + return res; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + int ans = 0; + for (int i = -30; i <= 30; ++i) + ans = max(ans, solve(arr, i)); + cout << ans << '\n'; + return 0; +} +``` + +### [1369E - Modular Stability](https://codeforces.com/contest/1359/problem/E) + +Write brute force see observation, [brute force on n=4 k=8](https://paste.ubuntu.com/p/JKSfbcbC5k/) so observation is to go with gaps initially 1 then we want to choose k-1 elements out of n-1. If gap was 2 then we want to choose k-1 out of n/2 - 1 and so on making it choose k-1 from n/x - 1 where x is from 1 to 5e5 + +```cpp +const int MAXN= 1e6+5; +int fact[MAXN+1], inv[MAXN+1]; +void nCrPreprocess() +{ + fact[0] = inv[0] = 1; + for(int i = 1; i <= MAXN; ++i) + { + fact[i] = multiply(fact[i-1], i); + inv[i] = powMod(fact[i], MOD-2); + } +} +int nCrQuery(int n, int r) +{ + if (n < r) return 0; + int res = 1; res = multiply(res, fact[n]); + res = multiply(res, inv[r]); + res = multiply(res, inv[n-r]); + return res; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, k; cin >> n >> k; + nCrPreprocess(); + if (k == 1) cout << n << '\n'; + else + { + int ans = 0; + for (int x = 1; x <= 5e5; ++x) + { + if (x*k > n) break; + (ans += nCrQuery(n/x - 1, k-1)) %= MOD; + } + cout << ans << '\n'; + } + return 0; +} +``` + +## Day 5 \(6\) + +### [1345B - Card Constructions](https://codeforces.com/contest/1345/problem/B) + +Easy but required some long long handling stuff + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t; cin >> t; + while (t--) + { + ll n; cin >> n; + ll ans = 0; + while (n >= 2) + { + int h = (int)(sqrt(1 + 24*n) - 1)/6; + n -= (h*(3*h + 1))/2, ans++; + } + cout << ans << '\n'; + } + return 0; +} +``` + +### [1348B - Phoenix and Beauty](https://codeforces.com/contest/1348/problem/B) + +Easy logical problem, to make all subarray of length k equal we have to make it periodic on k + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t; cin >> t; + while (t--) + { + int n, k; cin >> n >> k; + set st; + for (int i = 0; i < n; ++i) { int x; cin >> x; st.insert(x); } + if (sz(st) > k) cout << "-1\n"; + else + { + cout << n*k << '\n'; + for (int i = 0; i < n; ++i) + { + for (auto &x : st) cout << x << " "; + int rem = k-sz(st); + while (rem--) cout << "1 "; + } + cout << '\n'; + } + } + return 0; +} +``` + +### [1348D - Phoenix and Science](https://codeforces.com/contest/1348/problem/D) + +Nice observation based problem + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t; cin >> t; + while (t--) + { + int n; cin >> n; + vec<1, int> arr; + for (int i = 1; i <= n; i *= 2) { arr.push_back(i); n -= i; } + if (n) arr.push_back(n); + sort(all(arr)); + cout << sz(arr)-1 << '\n'; + for (int i = 1; i < sz(arr); ++i) cout << arr[i]-arr[i-1] << " "; + cout << '\n'; + } + return 0; +} +``` + +### [1341C - Nastya and Strange Generator](https://codeforces.com/contest/1341/problem/C) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t; cin >> t; + while (t--) + { + int n; cin >> n; + intHashTable pos; + for (int i = 1; i <= n; ++i) + { + int x; cin >> x; + pos[x] = i; + } + set st; + multiset curCnts; + for (int i = 1; i <= n; ++i) { st.insert({i, 1}); curCnts.insert(1); } + bool notPoss = false; + for (int i = 1; i <= n; ++i) + { + auto it = st.lower_bound({pos[i], 0}); + if (it->F != pos[i] || it->S < *curCnts.rbegin()) { notPoss = true; break; } + int prevCnt = it->S; st.erase(it); curCnts.erase(curCnts.lower_bound(prevCnt)); + auto nxt = st.lower_bound({pos[i], 0}); + if (nxt != st.end()) + { + curCnts.erase(curCnts.lower_bound(nxt->S)); + curCnts.insert(nxt->S + prevCnt); + st.insert({nxt->F, nxt->S + prevCnt}); + st.erase(nxt); + } + } + if (notPoss) cout << "No\n"; + else cout << "Yes\n"; + } + return 0; +} +``` + +### [1341D - Nastya and Scoreboard](https://codeforces.com/contest/1341/problem/D) + +Nice DP problem, requires top down dp \(for greedy choice\) and backtracking + +```cpp +// DP O(10ND) +int n, k; +const int MAXN = 2005; +#define INF (1LL<<30) +string num2Str[] = {"1110111", "0010010", "1011101", "1011011", "0111010", "1101011", "1101111", "1010010", "1111111", "1111011"}; +vec<2, int> dp(MAXN, MAXN, -1); +vec<2, int> dig(MAXN, MAXN, -1), cnt(MAXN, MAXN, 0); +vec<2, pii> pre(MAXN, MAXN, make_pair(-1, -1)); +bool solve(int cur = 0, int flipCnt = 0) +{ + if (cur == n) return (flipCnt == k); + if (dp[cur][flipCnt] != -1) return dp[cur][flipCnt]; + for (int curDig = 9; curDig >= 0; --curDig) + { + int newCnt = flipCnt + cnt[cur][curDig]; + if (newCnt > k) continue; + if (solve(cur+1, newCnt)) + { + dig[cur+1][newCnt] = curDig, pre[cur+1][newCnt] = {cur, flipCnt}; + return dp[cur][flipCnt] = true; + } + } + return dp[cur][flipCnt] = false; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + cin >> n >> k; + vec<1, string> arr(n); + for (auto &x : arr) cin >> x; + for (int i = 0; i < n; ++i) + { + for (int curDig = 0; curDig <= 9; ++curDig) + { + for (int j = 0; j < 7; ++j) + { + if (arr[i][j] == '1' && num2Str[curDig][j] == '0') { cnt[i][curDig] = INF; break; } + else if (arr[i][j] == '0' && num2Str[curDig][j] == '1') cnt[i][curDig]++; + } + } + } + + if (!solve()) cout << "-1\n"; + else + { + string res; + for (int i = n, j = k; dig[i][j] != -1; tie(i, j) = pre[i][j]) + res = (char)(dig[i][j]+'0') + res; + cout << res << '\n'; + } + return 0; +} +``` + +### [1343D - Constant Palindrome Sum](https://codeforces.com/contest/1343/problem/D) + +We can pick x from 2 to 2\*k, idea is to use some scanline logic. Consider sample testcase: 6 1 1 7 3 4 6 Now we have n/2 pairs: 6+6, 1+4, 1+3, 7+6 i.e. 12, 5, 4, 13 we can store them in a set or array of 2\*k length to basically count how many already pair we have corresponding to x. For a pair a\[i\] a\[j\] min of a\[i\]+1 and a\[j\]+1 and max of a\[i\]+k and a\[j\]+k denotes that range which is achievable by the pair via replacing one number out of pair. If we increase count of each such range \(using difference array logic\) we can compute finally for a particular x the value easily by: \(pairsAchivableHereByOnly1Flip - pairsAlreadyX\)\*1 since these pairs requires 1 flip and \(pairs - pairsAchivableByOnly1Flip\)\*2 since these requires 2 flips + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t; cin >> t; + while (t--) + { + int n, k; cin >> n >> k; + vec<1, int> arr(n), cnt(2*k + 1); + for (auto &x : arr) cin >> x; + for (int i = 0, j = n-1; i < j; ++i, --j) cnt[arr[i]+arr[j]]++; + vec<1, int> prefSm(2*k + 2); + for (int i = 0, j = n-1; i < j; ++i, --j) + { + int l1 = 1+arr[i], r1 = k+arr[i]; + int l2 = 1+arr[j], r2 = k+arr[n-i-1]; + ++prefSm[min(l1, l2)], --prefSm[max(r1, r2)+1]; + } + partial_sum(all(prefSm), prefSm.begin()); + int ans = (1LL<<61); + for (int i = 2; i <= 2*k; ++i) + ans = min(ans, (prefSm[i]-cnt[i]) + (n/2 - prefSm[i])*2); + cout << ans << '\n'; + } + return 0; +} +``` + +## Day 6 + + + diff --git a/problem-set/cses-problem-set-ii.md b/problem-set/cses-problem-set-ii.md new file mode 100644 index 0000000..f17cbfa --- /dev/null +++ b/problem-set/cses-problem-set-ii.md @@ -0,0 +1,208 @@ +# CSES Problem Set - II + +## Range Queries + +### [Range Sum Queries I](https://cses.fi/problemset/task/1646/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, q; cin >> n >> q; + vec<1, int> arr(n+1); + for (int i = 1; i <= n; ++i) { cin >> arr[i]; arr[i] += arr[i-1]; } + while (q--) + { + int l, r; cin >> l >> r; + cout << arr[r] - arr[l-1] << '\n'; + } + return 0; +} +``` + +### [Range Minimum Queries I](https://cses.fi/problemset/task/1647/) + +```cpp +const int MAXN = 2e5+5; +vec<2, int> sparseTable(MAXN, 40, -1); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, q; cin >> n >> q; + int k = log2(n); + for (int i = 0; i < n; ++i) cin >> sparseTable[i][0]; + for (int j = 1; j <= k; j++) + for (int i = 0; i + (1 << j) <= n; i++) + sparseTable[i][j] = min(sparseTable[i][j-1], sparseTable[i + (1 << (j-1))][j-1]); + while (q--) + { + int L, R; cin >> L >> R; + L--, R--; + int j = log2(R-L+1); + cout << min(sparseTable[L][j], sparseTable[R - (1<> n >> q; + for (int i = 1; i <= n; ++i) { int x; cin >> x; update(i, x); } + while (q--) + { + int a, b, c; cin >> a >> b >> c; + if (a == 1) + { + int prev = query(b, b); + update(b, c-prev); + } + else cout << query(b, c) << '\n'; + } + return 0; +} +``` + +### [Range Minimum Queries II](https://cses.fi/problemset/task/1649/) + +```cpp +const int MAXN = 1e6; +int segTree[2*MAXN], _n_; +void build(int n) +{ + _n_ = n; + for (int i = _n_-1; i > 0; --i) + segTree[i] = min(segTree[i<<1], segTree[i<<1|1]); +} +void update(int p, int val) +{ + for (segTree[p += _n_] = val; p > 1; p >>= 1) + segTree[p>>1] = min(segTree[p], segTree[p^1]); +} +int query(int l, int r) // Interval [l, r) +{ + int res = (1LL<<61); + for (l += _n_, r += _n_; l < r; l >>= 1, r >>= 1) + { + if (l&1) res = min(res, segTree[l++]); + if (r&1) res = min(res, segTree[--r]); + } + return res; +} + +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, q; cin >> n >> q; + for (int i = 0; i < n; ++i) cin >> segTree[n+i]; + build(n); + while (q--) + { + int a, b, c; cin >> a >> b >> c; + if (a == 1) update(b-1, c); + else cout << query(b-1, c) << '\n'; + } + return 0; +} +``` + +### [Range Xor Queries](https://cses.fi/problemset/task/1650/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, q; cin >> n >> q; + vec<1, int> arr(n+1, 0); // prefix xors + for (int i = 1; i <= n; ++i) { cin >> arr[i]; arr[i] ^= arr[i-1]; } + while (q--) + { + int l, r; cin >> l >> r; + cout << (arr[r]^arr[l-1]) << '\n'; + } + return 0; +} +``` + +### [Range Update Queries](https://cses.fi/problemset/task/1651/) + +```cpp +const int N = 2e5 + 5; +vector BIT1(N), BIT2(N); +void update(vector &BIT, int i, int val) +{ + while (i <= N) + { + BIT[i] += val; + i += (i & -i); + } +} +int query(vector &BIT, int i) +{ + int sm = 0; + while (i) + { + sm += BIT[i]; + i -= (i & -i); + } + return sm; +} +int summation(int x) { return ((query(BIT1, x)*x) - query(BIT2, x)); } // sum of [1, x] +int queryRange(int l, int r) { return summation(r) - summation(l-1); } // query [l, r] +void updateRange(int l, int r, int val) // update [l, r] +{ + update(BIT1, l, val); update(BIT1, r+1, -val); + update(BIT2, l, val*(l-1)); update(BIT2, r+1, -val*r); +} + +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, q; cin >> n >> q; + for (int i = 1; i <= n; ++i) { int x; cin >> x; updateRange(i, i, x); } + while (q--) + { + int t; cin >> t; + if (t == 1) + { + int a, b, u; cin >> a >> b >> u; + updateRange(a, b, u); + } + else + { + int a; cin >> a; + cout << queryRange(a, a) << '\n'; + } + } + return 0; +} +``` + + + diff --git a/problem-set/cses-problem-set.md b/problem-set/cses-problem-set.md new file mode 100644 index 0000000..e9b39cc --- /dev/null +++ b/problem-set/cses-problem-set.md @@ -0,0 +1,3506 @@ +# CSES Problem Set - I + +{% embed url="https://cses.fi/problemset/" %} + +## Introductory Problems + +### [Weird Algorithm](https://cses.fi/problemset/task/1068) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + while (n != 1) + { + cout << n << ' '; + if (n&1) n = n*3 + 1; + else n /= 2; + } + cout << "1\n"; + return 0; +} +``` + +### [Missing Number](https://cses.fi/problemset/task/1083) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + int sm = 0; + for (int i = 0; i < n-1; ++i) { int x; cin >> x; sm += x; } + cout << ((n*(n+1))/2 - sm) << '\n'; + return 0; +} +``` + +### [Repetitions](https://cses.fi/problemset/task/1069) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + string str; cin >> str; + int ans = 1; + for (int i = 1, cnt = 1; i < str.size(); ++i) + { + if (str[i] == str[i-1]) { cnt++; ans = max(ans, cnt); } + else cnt = 1; + } + cout << ans << '\n'; + return 0; +} +``` + +### [Increasing Array](https://cses.fi/problemset/task/1094) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + int ans = 0; + for (int i = 1; i < n; ++i) + if (arr[i] < arr[i-1]) { ans += (arr[i-1]-arr[i]); arr[i] = arr[i-1]; } + cout << ans << '\n'; + return 0; +} +``` + +### [Permutations](https://cses.fi/problemset/task/1070/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + if (n == 1) cout << "1\n"; + else if (n < 4) cout << "NO SOLUTION\n"; + else + { + for (int i = 2; i <= n; i += 2) cout << i << " "; + for (int i = 1; i <= n; i += 2) cout << i << " "; + cout << '\n'; + } + return 0; +} +``` + +### [Number Spiral](https://cses.fi/problemset/task/1071/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t; cin >> t; + while (t--) + { + int y, x; cin >> y >> x; + int k = max(x, y); + int ans = (k-1)*(k-1); + if (k&1) ans += (x + (k-y)); + else ans += (y + (k-x)); + cout << ans << '\n'; + } + return 0; +} +``` + +### [Two Knights](https://cses.fi/problemset/task/1072/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + for (int i = 1; i <= n; ++i) + { + int res = ((i-1)*(i+4)*(i*i - 3*i + 4)) / 2; + cout << res << '\n'; + } + return 0; +} +``` + +### [Two Sets](https://cses.fi/problemset/task/1092/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + if ((n * (n+1)) % 4 == 0) + { + cout << "YES\n"; + set a, b; + for (int i = 1; i <= n; ++i) a.insert(i); + int x = (n*(n+1))/4; + + for (int i = n; i >= 1; --i) + if (i <= x) { x -= i; a.erase(i); b.insert(i); } + cout << a.size() << '\n'; + for (auto &x : a) cout << x << " "; cout << '\n'; + cout << b.size() << '\n'; + for (auto &x : b) cout << x << " "; cout << '\n'; + } + else cout << "NO\n"; + return 0; +} +``` + +### [Bit Strings](https://cses.fi/problemset/task/1617/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + cout << powMod(2, n) << '\n'; + return 0; +} +``` + +### [Trailing Zeros](https://cses.fi/problemset/task/1618/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + int ans = 0; + for (int x = 5; x <= n; x *= 5) + ans += (n/x); + cout << ans << '\n'; + return 0; +} +``` + +### [Coin Piles](https://cses.fi/problemset/task/1754) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t; cin >> t; + while (t--) + { + int a, b; cin >> a >> b; + if ((2*a - b)%3 == 0 && (2*b - a)%3 == 0) + { + int x = (2*a - b)/3, y = (2*b - a)/3; + if (x >= 0 && y >= 0 && x <= min(a, b) && y <= min(a, b)) cout << "YES\n"; + else cout << "NO\n"; + } + else cout << "NO\n"; + } + return 0; +} +``` + +### [Palindrome Reorder](https://cses.fi/problemset/task/1755) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + string str; cin >> str; + vec<1, int> cnt(26, 0); + for (auto &x : str) cnt[x-'A']++; + bool allow = (str.size()%2 == 1); + string side, m = ""; + for (int i = 0; i < 26; ++i) + { + if (cnt[i] == 0) continue; + if (cnt[i]&1) + { + if (allow) { allow = false; m = string(cnt[i], ('A'+i)); } + else { cout << "NO SOLUTION\n"; return 0; } + } + else side += string(cnt[i]/2, ('A'+i));; + } + string otherSide = side; + reverse(otherSide.begin(), otherSide.end()); + cout << (side + m + otherSide) << '\n'; + return 0; +} +``` + +### [Creating Strings I](https://cses.fi/problemset/task/1622) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + string str; cin >> str; + sort(str.begin(), str.end()); + vector res; + do { res.push_back(str); } + while (next_permutation(str.begin(), str.end())); + cout << res.size() << '\n'; + for (auto &x : res) cout << x << '\n'; + return 0; +} +``` + +### [Apple Division](https://cses.fi/problemset/task/1623) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, int> arr(n); + int sm = 0; + for (auto &x : arr) { cin >> x; sm += x; } + int res = INT_MAX; + for (int i = 1; i < (1<>= 1; + } + y = sm-x; + res = min(res, abs(y-x)); + } + cout << res << '\n'; + return 0; +} +``` + +### [Chessboard and Queens](https://cses.fi/problemset/task/1624) + +```cpp +vec<2, bool> board(8, 8); +int solve(int j = 0, int x = 0, int d1 = 0, int d2 = 0) +{ + if (j == 8) return 1; + int res = 0; + for (int i = 0; i < 8; ++i) + { + if (board[i][j] && !(x&(1<> str; + for (int j = 0; j < 8; ++j) board[i][j] = (str[j] != '*'); + } + cout << solve() << '\n'; + return 0; +} +``` + +### [Grid Paths](https://cses.fi/problemset/task/1625) + +Regular backtracking will time limit, requires pruning. + +* If we reached last pos before last move then return 0 +* If we hit a wall from where left and right both sides are unvisited then no matter which we will visit other will be unvisited so return 0. + +```cpp +const int N = 7; +bool visited[N][N]; +int dx[] = {0, +1, 0, -1}, dy[] = {-1, 0, +1, 0}; +int solve(string &str, int cur = 0, int y = 0, int x = 0) +{ + if (y == N-1 && x == 0) return (cur == (N*N - 1)); + if (((y+1 == N || (visited[y-1][x] && visited[y+1][x])) && x-1 >= 0 && x+1 < N && !visited[y][x-1] && !visited[y][x+1]) || + ((x+1 == N || (visited[y][x-1] && visited[y][x+1])) && y-1 >= 0 && y+1 < N && !visited[y-1][x] && !visited[y+1][x]) || + ((y == 0 || (visited[y+1][x] && visited[y-1][x])) && x-1 >= 0 && x+1 < N && !visited[y][x-1] && !visited[y][x+1]) || + ((x == 0 || (visited[y][x+1] && visited[y][x-1])) && y-1 >= 0 && y+1 < N && !visited[y-1][x] && !visited[y+1][x])) + return 0; + + visited[y][x] = true; + int res = 0; + for (int i = 0; i < 4; ++i) + { + if ((str[cur] == 'U' && i != 0) || (str[cur] == 'R' && i != 1) || + (str[cur] == 'D' && i != 2) || (str[cur] == 'L' && i != 3)) continue; + int _y = y+dy[i], _x = x+dx[i]; + if (_y >= 0 && _x >= 0 && _y < N && _x < N && !visited[_y][_x]) res += solve(str, cur+1, _y, _x); + } + visited[y][x] = false; + return res; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + string str; cin >> str; + cout << solve(str) << '\n'; + return 0; +} +``` + +## Sorting and Searching + +### [Distinct Numbers](https://cses.fi/problemset/task/1621/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + set st; + int x; + for (int i = 0; i < n; ++i) { cin >> x; st.insert(x); } + cout << st.size() << '\n'; + return 0; +} +``` + +### [Apartments](https://cses.fi/problemset/task/1084/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m, k; cin >> n >> m >> k; + vec<1, int> a(n), b(m); + for (auto &x : a) cin >> x; + for (auto &x : b) cin >> x; + sort(all(a)); sort(all(b)); + int res = 0; + for (int i = 0, j = 0; i < n && j < m;) + { + if (abs(a[i] - b[j]) <= k) i++, j++, res++; + else if (a[i] > b[j]+k) j++; + else i++; + } + cout << res << '\n'; + return 0; +} +``` + +### [Ferris Wheel](https://cses.fi/problemset/task/1090/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, x; cin >> n >> x; + vec<1, int> arr(n); + for (auto &v : arr) cin >> v; + sort(all(arr)); + int res = 0; + for (int i = 0, j = n-1; i <= j; ++i, --j) + { + if (i == j) { res++; continue; } + while (i < j && arr[i]+arr[j] > x) --j, ++res; + res++; + } + cout << res << '\n'; + return 0; +} +``` + +### [Concert Tickets](https://cses.fi/problemset/task/1091/) + +We want atmost x value for that we can add greater<int> comparator in our multiset making our lowerbound give atmost x instead of atleast x. + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + multiset> st; + while (n--) { int x; cin >> x; st.insert(x); } + while (m--) + { + int x; cin >> x; + auto it = st.lower_bound(x); + if (it == st.end()) cout << "-1\n"; + else { cout << *it << '\n'; st.erase(it); } + } + return 0; +} +``` + +### [Restaurant Customers](https://cses.fi/problemset/task/1619/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, pii> a(n); + for (auto &x : a) cin >> x.F >> x.S; + sort(all(a)); + priority_queue, greater> pq; + int res = 0; + for (auto &x : a) + { + while (!pq.empty() && pq.top() < x.F) pq.pop(); + pq.push(x.S); + res = max(res, (int)pq.size()); + } + cout << res << '\n'; + return 0; +} +``` + +### [Movie Festival](https://cses.fi/problemset/task/1629/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, pii> a(n); + for (auto &x : a) cin >> x.S >> x.F; + sort(all(a)); + int prev = -1, res = 0; + for (auto &x : a) + { + if (x.S < prev) continue; + res++; + prev = x.F; + } + cout << res << '\n'; + return 0; +} +``` + +### [Sum of Two Values](https://cses.fi/problemset/task/1640/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, x; cin >> n >> x; + vector a(n); + for (int i = 0; i < n; ++i) { int v; cin >> v; a[i] = {v, i}; } + sort(all(a)); + for (int i = 0, j = n-1; i < j;) + { + if (a[i].F + a[j].F == x) { cout << a[i].S+1 << " " << a[j].S+1 << '\n'; return 0; } + if (a[i].F + a[j].F < x) i++; + else j--; + } + cout << "IMPOSSIBLE\n"; + return 0; +} +``` + +### [Maximum Subarray Sum](https://cses.fi/problemset/task/1643/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + vec<1, int> dp(n); + dp[0] = arr[0]; + for (int i = 1; i < n; ++i) dp[i] = max(arr[i], dp[i-1]+arr[i]); + cout << *max_element(all(dp)) << '\n'; + return 0; +} +``` + +### [Stick Lengths](https://cses.fi/problemset/task/1074/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, int> a(n); + for (auto &x : a) cin >> x; + sort(all(a)); + int m = a[n/2], res = 0; + for (int i = 0; i < n; i++) res += abs(a[i]-m); + cout << res << endl; + return 0; +} +``` + +### [Playlist](https://cses.fi/problemset/task/1141/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + map cnt; + int res = 0; + for (int i = 0, j = 0; j < n; ++j) + { + while (cnt[arr[j]] > 0) cnt[arr[i++]]--; + cnt[arr[j]]++; + res = max(res, j-i+1); + } + cout << res << '\n'; + return 0; +} +``` + +### [Towers](https://cses.fi/problemset/task/1073/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + multiset st; + for (int i = 0; i < n; ++i) + { + int x; cin >> x; + auto it = st.upper_bound(x); + if (it != st.end()) st.erase(it); + st.insert(x); + } + cout << st.size() << '\n'; + return 0; +} +``` + +### [Traffic Lights](https://cses.fi/problemset/task/1163/) + +Maintain a timeline initially 0------x then say a cut 0-----z z-----x +We can represent it like this \(x, x\) -> \(z, z\) \(x-z, x\) +Here first means length of the segment and second means end point, if processed under a set rbegin first will store the desired result and processing can be done in logN. However to do processing we need to find segment with second atleast v \(query num\) for that we have to maintain a reverse set with first and second swapped. + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int x, n; cin >> x >> n; + set a, b; + a.insert({x, x}); b.insert({x, x}); + while (n--) + { + int v; cin >> v; + auto it = a.lower_bound({v, 0}); + auto cur = *it; + + a.erase(it); + a.insert({v, cur.S - (cur.F-v)}); + a.insert({cur.F, cur.F - v}); + + b.erase({cur.S, cur.F}); + b.insert({cur.S - (cur.F-v), v}); + b.insert({cur.F - v, cur.F}); + + cout << b.rbegin()->F << ' '; + } + cout << '\n'; + return 0; +} +``` + +### [Room Allocation](https://cses.fi/problemset/task/1164/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, pair> arr(n); + for (int i = 0; i < n; ++i) { cin >> arr[i].F.F >> arr[i].F.S; arr[i].S = i; } + sort(all(arr)); + + set rooms; + for (int i = 1; i <= n; ++i) rooms.insert(i); + priority_queue, greater> pq; + vec<1, int> res(n); + int mx = 0; + for (auto &x : arr) + { + while (!pq.empty() && pq.top().F < x.F.F) { rooms.insert(pq.top().S); pq.pop(); } + int cur = *rooms.begin(); rooms.erase(cur); + res[x.S] = cur; + pq.push({x.F.S, cur}); + mx = max(mx, cur); + } + cout << mx << '\n'; + for (auto &x : res) cout << x << " "; cout << '\n'; + return 0; +} +``` + +### [Factory Machines](https://cses.fi/problemset/task/1620/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, t; cin >> n >> t; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + int l = -1, r = 1e18; + auto check = [&](int mid) + { + int cur = 0; + for (auto &x : arr) + { + cur += (mid/x); + if (cur >= t) return true; + } + return false; + }; + while (l+1 < r) + { + int mid = l + (r-l)/2; + if (check(mid)) r = mid; + else l = mid; + } + cout << r << '\n'; + return 0; +} +``` + +### [Tasks and Deadlines](https://cses.fi/problemset/task/1630/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, pii> arr(n); + for (auto &x : arr) cin >> x.F >> x.S; + sort(all(arr)); + int cur = 0, res = 0; + for (auto &x : arr) + { + cur += x.F; + res += (x.S - cur); + } + cout << res << '\n'; + return 0; +} +``` + +### [Reading Books](https://cses.fi/problemset/task/1631/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + int mx = 0, sm = 0; + for (int i = 0; i < n; ++i) + { + int x; cin >> x; + mx = max(mx, x); + sm += x; + } + cout << (mx > (sm-mx) ? 2*mx : sm) << '\n'; + return 0; +} +``` + +### [Sum of Three Values](https://cses.fi/problemset/task/1641/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, x; cin >> n >> x; + vec<1, pii> arr(n); + for (int i = 0; i < n; ++i) { cin >> arr[i].F; arr[i].S = i+1; } + sort(all(arr)); + for (int i = 0; i < n; ++i) + { + int reqd = x - arr[i].F; + for (int j = i+1, k = n-1; j < k; ) + { + if (arr[j].F+arr[k].F == reqd) { cout << arr[i].S << " " << arr[j].S << " " << arr[k].S << '\n'; return 0; } + else if (arr[j].F+arr[k].F < reqd) ++j; + else --k; + } + } + cout << "IMPOSSIBLE\n"; + return 0; +} +``` + +### [Sum of Four Values](https://cses.fi/problemset/task/1642/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, x; cin >> n >> x; + vec<1, pii> arr(n); + for (int i = 0; i < n; ++i) { cin >> arr[i].F; arr[i].S = i+1; } + sort(all(arr)); + for (int p = 0; p < n; ++p) + { + for (int q = p+1; q < n; ++q) + { + int reqd = x - arr[p].F - arr[q].F; + for (int r = q+1, s = n-1; r < s;) + { + if (arr[r].F+arr[s].F == reqd) { cout << arr[p].S << " " << arr[q].S << " " << arr[r].S << " " << arr[s].S << '\n'; return 0; } + else if (arr[r].F+arr[s].F < reqd) ++r; + else --s; + } + } + } + cout << "IMPOSSIBLE\n"; + return 0; +} +``` + +### [Nearest Smaller Values](https://cses.fi/problemset/task/1645/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + deque dq; + dq.push_back({INT_MIN, 0}); + for (int i = 0; i < n; ++i) + { + int x; cin >> x; + while (dq.back().F >= x) dq.pop_back(); + cout << dq.back().S << ' '; + dq.push_back({x, i+1}); + } + cout << '\n'; + return 0; +} +``` + +### [Subarray Sums I](https://cses.fi/problemset/task/1660/) \(and [Subarray Sums II](https://cses.fi/problemset/task/1661/)\) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, x; cin >> n >> x; + map cnt; + cnt[0]++; + int sm = 0, res = 0; + while (n--) + { + int v; cin >> v; + sm += v; + res += cnt[sm-x]; + cnt[sm]++; + } + cout << res << '\n'; + return 0; +} +``` + +### [Subarray Divisibility](https://cses.fi/problemset/task/1662/) + +If we keep prefix sum, X denotes prefix sum at some point x and Y denotes prefix sum at some other point y. y is always < x. Now we want \(X-Y\) % n = 0 for the condition to hold. opening it we have \(X%n - Y%n + n\) % n = 0. + +So for a point we are simply looking for previously looking reqd var and adding its count. + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, int> arr(n+1); arr[0] = 0; + map cnt; cnt[0]++; + int res = 0; + for (int i = 1; i <= n; ++i) + { + cin >> arr[i]; + (arr[i] += arr[i-1]) %= n; + if (arr[i] < 0) arr[i] += n; + + int reqd = (arr[i] + n) % n; + res += cnt[reqd]; + + cnt[arr[i]]++; + } + cout << res << '\n'; + return 0; +} +``` + +### [Array Division](https://cses.fi/problemset/task/1085/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, k; cin >> n >> k; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + + auto check = [&](int x) + { + int cur = 0, cnt = 0; + for (auto &v : arr) + { + if (v > x) return false; + if (cur+v > x) cnt++, cur = v; + else cur += v; + } + if (cur) cnt++; + return (cnt <= k); + }; + + int l = 0, r = accumulate(all(arr), 0LL); + while (l+1 < r) + { + int mid = l + (r-l)/2; + if (check(mid)) r = mid; + else l = mid; + } + cout << r << '\n'; + return 0; +} +``` + +### [Sliding Median](https://cses.fi/problemset/task/1076/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, k; cin >> n >> k; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + + orderedMultiset st; + auto median = [&]() { return (k&1) ? *st.find_by_order(k/2) : (*st.find_by_order(k/2 - 1) + *st.find_by_order(k/2 - 1))/2; }; + for (int i = 0; i < k; ++i) st.insert(arr[i]); + cout << median() << ' '; + for (int i = k; i < n; ++i) + { + st.erase(st.upper_bound(arr[i-k])); + st.insert(arr[i]); + cout << median() << ' '; + } + cout << '\n'; + return 0; +} +``` + +### [Sliding Cost](https://cses.fi/problemset/task/1077/) + +Extending the code of previous problem, we can iterate over k after finding median to find cost for first window now we have to find subsequent costs by some mathematical logic in constant time. + +First thing we do is add abs\(m - arr\[i\]\) because that's the cost of new element to the window and remove abs\(oldM - arr\[i-k\]\) because that's the cost of old element. Now what about middle common one's? + +![](../.gitbook/assets/image%20%2850%29.png) + +Consider above \*artistic\* drawing. Median is nothing but distance first \(black\) was our median so red lines are distance sum of them is our cost. When we shift the median, individually their distances change but they will cancel out except one \(if it's odd element common otherwise there won't be any affect\). So we are checking k%2 \(k means k-1 common so if k is even we have common elements and we need to manually adjust it. + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, k; cin >> n >> k; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + + orderedMultiset st; + auto median = [&]() { return (k&1) ? *st.find_by_order(k/2) : (*st.find_by_order(k/2 - 1) + *st.find_by_order(k/2 - 1))/2; }; + for (int i = 0; i < k; ++i) st.insert(arr[i]); + + int oldM = median(), d = 0; + for (int i = 0; i < k; ++i) d += abs(arr[i]-oldM); + cout << d << ' '; + for (int i = k; i < n; ++i) + { + st.erase(st.upper_bound(arr[i-k])); + st.insert(arr[i]); + int m = median(); + d += abs(m - arr[i]) - abs(oldM - arr[i-k]); + if (k%2 == 0) d -= (m - oldM); + oldM = m; + cout << d << ' '; + } + cout << '\n'; + return 0; +} +``` + +### [Movie Festival II](https://cses.fi/problemset/task/1632/) + +Extending traditional variant of this problem, multiset denotes persons last watch time initially zero we iterate over all movie and see if there's any person available with atmost current movie start time then take it. For atmost we just use greater comparator initially lower\_bound means atleast due to this comparator its atmost now. + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, k; cin >> n >> k; + vec<1, pii> arr(n); + for (auto &x : arr) cin >> x.S >> x.F; + sort(all(arr)); + multiset> cur; + while (k--) cur.insert(0); + int res = 0; + for (auto &x : arr) + { + auto it = cur.lower_bound(x.S); + if (it != cur.end()) + { + cur.erase(it); + cur.insert(x.F); + res++; + } + } + cout << res << '\n'; + return 0; +} +``` + +### [Maximum Subarray Sum II](https://cses.fi/problemset/task/1644/) + +If we keep prefix sum \(1 based keeping arr\[0\] = 0\) then at some point j we want to find a point i such that i is atleast a index away from b for that we will maintain a sliding window minimum of length k = b-a+1. + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, a, b; cin >> n >> a >> b; + vec<1, int> arr(n+1); + arr[0] = 0; + for (int i = 1; i <= n; ++i) { cin >> arr[i]; arr[i] += arr[i-1]; } + + deque dq; + int k = b-a+1; + int res = LONG_LONG_MIN; + for (int i = 0, j = a; j <= n; ++i, ++j) + { + while (!dq.empty() && dq.front() < i-k+1) dq.pop_front(); + while (!dq.empty() && arr[i] < arr[dq.back()]) dq.pop_back(); + dq.push_back(i); + res = max(res, arr[j]-arr[dq.front()]); + } + cout << res << '\n'; + return 0; +} +``` + +## Dynamic Programming + +### [Dice Combinations](https://cses.fi/problemset/task/1633/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, int> dp(n+1, 0); + dp[0] = 1; + for (int i = 0; i <= n; ++i) + { + if (dp[i] == 0) continue; + for (int j = i+1; j <= min(i+6, n); ++j) (dp[j] += dp[i]) %= MOD; + } + cout << dp[n] << '\n'; + return 0; +} +``` + +### [Minimizing Coins](https://cses.fi/problemset/task/1634/) + +```cpp +#define INF (1LL<<30) +vec<2, int> dp(105, 1000005, INF); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, x; cin >> n >> x; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + + dp[0][0] = 0; + for (int i = 1; i <= n; ++i) + for (int j = 0; j <= x; ++j) + dp[i][j] = (j < arr[i-1]) ? dp[i-1][j] : min(dp[i-1][j], 1 + dp[i][j-arr[i-1]]); + if (dp[n][x] == INF) cout << "-1\n"; + else cout << dp[n][x] << '\n'; + return 0; +} +``` + +### [Coin Combinations I](https://cses.fi/problemset/task/1635/) + +```cpp +vec<1, int> dp(1000005, 0); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, x; cin >> n >> x; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + + dp[0] = 1; + for (int i = 0; i < x; ++i) + for (int j : arr) + if (i+j <= x) (dp[i+j] += dp[i]) %= MOD; + cout << dp[x] << '\n'; + return 0; +} +``` + +### [Coin Combinations II](https://cses.fi/problemset/task/1636/) + +```cpp +/* We want to make this type of dp now (eg: [2 3 5] 9) + 0 1 2 3 4 5 6 7 8 9 +2 - 1 0 1 0 1 0 1 0 1 0 +3 - 1 0 1 1 1 1 2 1 2 2 +5 - 1 0 1 1 1 2 2 2 3 3 */ +vec<1, int> dp(1000005, 0); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, x; cin >> n >> x; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + + dp[0] = 1; + for (int j : arr) + for (int i = 0; i < x; ++i) + if (i+j <= x) (dp[i+j] += dp[i]) %= MOD; + cout << dp[x] << '\n'; + return 0; +} +``` + +### [Removing Digits](https://cses.fi/problemset/task/1637/) + +```cpp +#define INF (1<<30) +vec<1, int> dp(1000005); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + for (int i = 0; i <= 9; ++i) dp[i] = 1; + for (int i = 10; i <= n; ++i) + { + int x = i; + dp[i] = INF; + while (x) + { + dp[i] = min(dp[i], 1 + dp[i - (x%10)]); + x /= 10; + } + } + cout << dp[n] << '\n'; + return 0; +} +``` + +### [Grid Paths](https://cses.fi/problemset/task/1638/) + +```cpp +vec<2, int> dp(1005, 1005); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + for (int i = 0; i < n; ++i) + { + string str; cin >> str; + for (int j = 0; j < n; ++j) dp[i][j] = (str[j] == '*') ? -1 : 0; + } + dp[0][0] = (dp[0][0] != -1); + for (int i = 0; i < n; ++i) + { + for (int j = 0; j < n; ++j) + { + if (i == 0 && j == 0) continue; + if (dp[i][j] == -1) { dp[i][j] = 0; continue; } + if (i-1 >= 0) (dp[i][j] += dp[i-1][j]) %= MOD; + if (j-1 >= 0) (dp[i][j] += dp[i][j-1]) %= MOD; + } + } + cout << dp[n-1][n-1] << '\n'; + return 0; +} +``` + +### [Book Shop](https://cses.fi/problemset/task/1158/) + +```cpp +vec<2, int> dp(1005, 100005, 0); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, x; cin >> n >> x; + vec<1, int> h(n), s(n); + for (auto &x : h) cin >> x; + for (auto &x : s) cin >> x; + + for (int j = h[0]; j <= x; ++j) dp[0][j] = s[0]; + for (int i = 1; i < n; ++i) + for (int j = 0; j <= x; ++j) + dp[i][j] = (j < h[i]) ? dp[i-1][j] : max(dp[i-1][j], s[i] + dp[i-1][j-h[i]]); + cout << dp[n-1][x] << '\n'; + return 0; +} +``` + +### [Array Description](https://cses.fi/problemset/task/1746/) + +```cpp +vec<2, int> dp(105, 100005, -1); +int solve(int &m, vec<1, int> &arr, int prev = -1, int cur = 0) +{ + if (cur == arr.size()) return 1; + if (cur != 0 && arr[cur] != 0 && abs(arr[cur]-prev) > 1) return 0; + if (dp[prev+1][cur] != -1) return dp[prev+1][cur]; + + int res = 0; + if (arr[cur] == 0) + { + if (cur == 0) + { + for (int i = 1; i <= m; ++i) + (res += solve(m, arr, i, cur+1)) %= MOD; + } + else + { + for (int i : {prev-1, prev, prev+1}) + if (i >= 1 && i <= m) (res += solve(m, arr, i, cur+1)) %= MOD; + } + } + else (res += solve(m, arr, arr[cur], cur+1)) %= MOD; + return dp[prev+1][cur] = res; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + cout << solve(m, arr) << '\n'; + return 0; +} +``` + +### [Edit Distance](https://cses.fi/problemset/task/1639/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + string x, y; cin >> x >> y; + int n = x.size(), m = y.size(); + vec<2, int> dp(n+1, m+1); + dp[0][0] = 0; + for (int j = 1; j <= m; ++j) dp[0][j] = j; + for (int i = 1; i <= n; ++i) dp[i][0] = i; + for (int i = 1; i <= n; ++i) + for (int j = 1; j <= m; ++j) + dp[i][j] = (x[i-1] == y[j-1]) ? dp[i-1][j-1] : min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]})+1; + cout << dp[n][m] << '\n'; + return 0; +} +``` + +### [Rectangle Cutting](https://cses.fi/problemset/task/1744/) + +```cpp +#define INF (1<<30) +vec<2, int> dp(505, 505, -1); +int solve(int x, int y) +{ + if (x == y) return 0; + if (x == 2*y || y == 2*x) return 1; + if (dp[x][y] != -1) return dp[x][y]; + int res = INF; + for (int i = 1; i <= x/2; ++i) + res = min(res, 1 + solve(i, y) + solve(x-i, y)); + for (int i = 1; i <= y/2; ++i) + res = min(res, 1 + solve(x, i) + solve(x, y-i)); + return dp[x][y] = res; +} + +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int x, y; cin >> x >> y; + cout << solve(x, y) << '\n'; + return 0; +} +``` + +### [Money Sums](https://cses.fi/problemset/task/1745/) + +```cpp +vec<2, bool> dp(105, 100005, false); +set st; +void solve(vec<1, int> &arr, int cur = 0, int sm = 0) +{ + if (dp[cur][sm]) return; + if (cur == arr.size()) { st.insert(sm); return; } + + solve(arr, cur+1, sm + arr[cur]); + solve(arr, cur+1, sm); + dp[cur][sm] = true; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + solve(arr); + st.erase(0); + cout << st.size() << '\n'; + for (auto &x : st) cout << x << " "; + return 0; +} +``` + +### [Removal Game](https://cses.fi/problemset/task/1097/) + +```cpp +vec<2, pii> dp(5005, 5005, make_pair(0, 0)); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + for (int i = 0; i < n; ++i) cin >> dp[i][i].F; + for (int i = 1; i < n; ++i) + { + for (int j = 0, k = i; k < n; ++j, ++k) + { + pii x = {dp[j][j].F + dp[j+1][k].S, dp[j][j].S + dp[j+1][k].F}; + pii y = {dp[k][k].F + dp[j][k-1].S, dp[k][k].S + dp[j][k-1].F}; + dp[j][k] = (x.F > y.F) ? x : y; + } + } + cout << dp[0][n-1].F << '\n'; + return 0; +} +``` + +### [Two Sets II](https://cses.fi/problemset/task/1093/) + +```cpp +vec<2, int> dp(505, 250005, -1); +int solve(int &n, int &m, int cur = 1, int sm = 0) +{ + if (cur == n) return (sm == m); + if (dp[cur][sm] != -1) return dp[cur][sm]; + + int res = 0; + (res += solve(n, m, cur+1, sm)) %= MOD; + (res += solve(n, m, cur+1, sm+cur)) %= MOD; + return dp[cur][sm] = res; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + int m = (n*(n+1))/2; + if (m&1) cout << "0\n"; + else + { + m /= 2; + cout << solve(n, m) << '\n'; + } + return 0; +} +``` + +### [Increasing Subsequence](https://cses.fi/problemset/task/1145/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, int> arr(n); + for (auto &x : arr) cin >> x; + set st; + for (int i = 0; i < arr.size(); ++i) + { + if (st.lower_bound(arr[i]) != st.end()) + st.erase(st.lower_bound(arr[i])); + st.insert(arr[i]); + } + cout << st.size() << '\n'; + return 0; +} +``` + +### [Projects](https://cses.fi/problemset/task/1140/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + vec<1, tuple> arr(n); + for (auto &x : arr) { int s, e, w; cin >> s >> e >> w; x = {e, s, w}; } + sort(all(arr)); + + vec<1, int> dp(n); + dp[0] = get<2>(arr[0]); + for (int i = 1; i < n; ++i) + { + int e = get<0>(arr[i]), s = get<1>(arr[i]), w = get<2>(arr[i]); + int optimal = lower_bound(all(arr), make_tuple(s, 0, 0)) - arr.begin() - 1; + if (optimal >= 0) dp[i] = max({dp[i-1], dp[optimal] + w, w}); + else dp[i] = max(dp[i-1], w); + } + cout << dp[n-1] << '\n'; + return 0; +} +``` + +## Graph Algorithms + +### [Counting Rooms](https://cses.fi/problemset/task/1192/) + +```cpp +int n, m; +void DFS(vec<2, bool> &mp, vec<2, bool> &visited, int i, int j) +{ + if (i < 0 || i >= n || j < 0 || j >= m || visited[i][j] || !mp[i][j]) return; + visited[i][j] = true; + DFS(mp, visited, i+1, j); + DFS(mp, visited, i-1, j); + DFS(mp, visited, i, j+1); + DFS(mp, visited, i, j-1); +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + cin >> n >> m; + vec<2, bool> mp(n, m, false), visited(n, m, false); + for (int i = 0; i < n; ++i) + { + string str; cin >> str; + for (int j = 0; j < m; ++j) mp[i][j] = (str[j] == '.'); + } + int res = 0; + for (int i = 0; i < n; ++i) + { + for (int j = 0; j < m; ++j) + { + if (visited[i][j] || !mp[i][j]) continue; + DFS(mp, visited, i, j); + res++; + } + } + cout << res << '\n'; + return 0; +} +``` + +### [Labyrinth](https://cses.fi/problemset/task/1193/) + +```cpp +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<2, bool> mp(n, m, false), visited(n, m, false); + pii start, end; + for (int i = 0; i < n; ++i) + { + string str; cin >> str; + for (int j = 0; j < m; ++j) + { + mp[i][j] = (str[j] != '#'); + if (str[j] == 'A') start = {i, j}; + if (str[j] == 'B') end = {i, j}; + } + } + + auto check = [&](int i, int j) { return (i >= 0 && i < n && j >= 0 && j < m && mp[i][j] && !visited[i][j]); }; + + queue q; + q.push(start); + vec<2, pii> prev(n, m); + prev[start.F][start.S] = {-1, -1}; visited[start.F][start.S] = true; + bool possible = false; + while (!q.empty()) + { + auto u = q.front(); + q.pop(); + + if (u == end) { possible = true; break; } + if (check(u.F+1, u.S)) { q.push({u.F+1, u.S}); prev[u.F+1][u.S] = u; visited[u.F+1][u.S] = true; } + if (check(u.F-1, u.S)) { q.push({u.F-1, u.S}); prev[u.F-1][u.S] = u; visited[u.F-1][u.S] = true; } + if (check(u.F, u.S+1)) { q.push({u.F, u.S+1}); prev[u.F][u.S+1] = u; visited[u.F][u.S+1] = true; } + if (check(u.F, u.S-1)) { q.push({u.F, u.S-1}); prev[u.F][u.S-1] = u; visited[u.F][u.S-1] = true; } + } + + if (!possible) cout << "NO\n"; + else + { + cout << "YES\n"; + pii lst = {-1, -1}; + stringstream res; + for (int i = end.F, j = end.S; i != -1 || j != -1; tie(i, j) = prev[i][j]) + { + if (lst == make_pair(-1, -1)) { lst = {i, j}; continue; } + if (i-1 == lst.F && j == lst.S) res << 'U'; + else if (i+1 == lst.F && j == lst.S) res << 'D'; + else if (i == lst.F && j+1 == lst.S) res << 'R'; + else if (i == lst.F && j-1 == lst.S) res << 'L'; + lst = {i, j}; + } + string ans = res.str(); reverse(all(ans)); + cout << ans.size() << '\n' << ans << '\n'; + } + return 0; +} +``` + +### [Building Roads](https://cses.fi/problemset/task/1666/) + +```cpp +const int MAXN = 1e5+5; +vec<1, int> adj[MAXN]; +vec<1, bool> visited(MAXN, false); +void DFS(int u) +{ + visited[u] = true; + for (auto &v : adj[u]) + if (!visited[v]) DFS(v); +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + while (m--) + { + int u, v; cin >> u >> v; + adj[u].push_back(v); + adj[v].push_back(u); + } + + vec<1, int> components; + for (int i = 1; i <= n; ++i) + { + if (visited[i]) continue; + components.push_back(i); + DFS(i); + } + cout << components.size()-1 << '\n'; + for (int i = 1; i < components.size(); ++i) + cout << components[i-1] << " " << components[i] << '\n'; + return 0; +} +``` + +### [Message Route](https://cses.fi/problemset/task/1667/) + +Can use 0-1 BFS \(O\(E\)\) instead of Dijkstra which works in \(O\(V+E\)\) + +```cpp +#define INF (1<<30) +void zeroOneBFS(int s, int n, vector adj[], vector &dist, vector &prev) +{ + dist.assign(n, INF); + prev.assign(n, -1); + dist[s] = 0; + deque dq; + dq.push_front(s); + while (!dq.empty()) + { + int u = dq.front(); + dq.pop_front(); + for (auto &edge : adj[u]) + { + int v = edge.first, w = edge.second; + if (dist[u] + w < dist[v]) + { + dist[v] = dist[u] + w; + prev[v] = u; + if (w == 1) dq.push_back(v); + else dq.push_front(v); + } + } + } +} +bool findPath(int from, int to, vector &prev, vector &path) +{ + for (int cur = to; cur != -1; cur = prev[cur]) + path.push_back(cur); + reverse(path.begin(), path.end()); + return (!path.empty() && *path.begin() == from); +} + +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<1, pii> adj[n+1]; + while (m--) + { + int u, v; cin >> u >> v; + adj[u].push_back({v, 1}); + adj[v].push_back({u, 1}); + } + vec<1, int> dist, prev, path; + zeroOneBFS(1, n+1, adj, dist, prev); + if (!findPath(1, n, prev, path)) cout << "IMPOSSIBLE\n"; + else + { + cout << path.size() << '\n'; + for (auto &x : path) cout << x << " "; + } + return 0; +} +``` + +### [Building Teams](https://cses.fi/problemset/task/1668/) + +```cpp +const int MAXN = 1e5 + 5; +vec<1, int> adj[MAXN], res(MAXN, -1); +vec<1, bool> vis(MAXN, false); +bool notPossible = false; +void DFS(int u, int team = 0) +{ + vis[u] = true; res[u] = team; + for (auto &v : adj[u]) + { + if (!vis[v]) DFS(v, !team); + else if (res[v] == res[u]) { notPossible = true; return; } + if (notPossible) return; + } +} + +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + while (m--) + { + int u, v; cin >> u >> v; + adj[u].push_back(v); + adj[v].push_back(u); + } + for (int i = 1; i <= n; ++i) + if (!vis[i]) DFS(i); + if (notPossible) cout << "IMPOSSIBLE\n"; + else + { + for (int i = 1; i <= n; ++i) cout << res[i]+1 << " "; + cout << '\n'; + } + return 0; +} +``` + +### [Round Trip](https://cses.fi/problemset/task/1669/) + +```cpp +const int MAXN = 1e5 + 5; +vec<1, int> adj[MAXN], vis(MAXN, -1), res; +bool found = false, backtracking = false; int backNode = -1; + +void DFS(int u, int x = 0, int prev = -1) +{ + vis[u] = x; + for (auto &v : adj[u]) + { + if (v == prev) continue; + if (vis[v] == -1) DFS(v, x+1, u); + else + { + int cur = (x+1) - vis[v]; + res.push_back(v); res.push_back(u); + if (cur >= 2) + { + found = true, backtracking = true; backNode = v; + return; + } + } + if (backtracking) + { + res.push_back(u); + if (u == backNode) backtracking = false; + } + if (found) return; + } +} + +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + while (m--) + { + int u, v; cin >> u >> v; + adj[u].push_back(v); + adj[v].push_back(u); + } + for (int i = 1; i <= n; ++i) + { + if (vis[i] == -1) DFS(i); + if (found) break; + } + if (!found) cout << "IMPOSSIBLE\n"; + else + { + cout << res.size() << '\n'; + for (auto &x : res) cout << x << " "; + cout << '\n'; + } + return 0; +} +``` + +### [Monsters](https://cses.fi/problemset/task/1194/) + +```cpp +const int dr[] = {0, 1, 0, -1}, dc[] = {1, 0, -1, 0}; +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<2, bool> isSafe(n, m), vis(n, m, false); + vec<1, pii> monsters; pii character; + for (int i = 0; i < n; ++i) + { + string str; cin >> str; + for (int j = 0; j < m; ++j) + { + isSafe[i][j] = (str[j] != '#'); + if (str[j] == 'M') { monsters.push_back({i, j}); isSafe[i][j] = false; } + else if (str[j] == 'A') character = {i, j}; + } + } + + queue> q; + q.push({character, true}); + for (auto &x : monsters) q.push({x, false}); + + bool found = false; pii foundPos; + vec<2, pii> lst(n, m, make_pair(-1, -1)); + while (!q.empty()) + { + int sz = q.size(); + while (sz--) + { + auto u = q.front(); q.pop(); + if (u.S) + { + if (!isSafe[u.F.F][u.F.S]) continue; + vis[u.F.F][u.F.S] = true; + if (u.F.F == 0 || u.F.F == n-1 || u.F.S == 0 || u.F.S == m-1) { found = true; foundPos = {u.F.F, u.F.S}; break; } + } + else isSafe[u.F.F][u.F.S] = false; + + for (int i = 0; i < 4; ++i) + { + int newR = u.F.F + dr[i], newC = u.F.S + dc[i]; + if (newR >= 0 && newR < n && newC >= 0 && newC < m && isSafe[newR][newC]) + { + if (!u.S || (u.S && !vis[newR][newC])) + { + q.push({{newR, newC}, u.S}); + if (u.S) lst[newR][newC] = {u.F.F, u.F.S}; + } + } + } + } + if (found) break; + } + + if (!found) cout << "NO\n"; + else + { + cout << "YES\n"; + pii prev = {-1, -1}; + string res; + for (int i = foundPos.F, j = foundPos.S; i != -1 || j != -1; tie(i, j) = lst[i][j]) + { + if (prev.F == -1 && prev.S == -1) { prev = {i, j}; continue; } + if (i == prev.F && j+1 == prev.S) res += 'R'; + else if (i == prev.F && j-1 == prev.S) res += 'L'; + else if (i+1 == prev.F && j == prev.S) res += 'D'; + else if (i-1 == prev.F && j == prev.S) res += 'U'; + prev = {i, j}; + } + reverse(res.begin(), res.end()); + cout << res.size() << '\n' << res << '\n'; + } + return 0; +} +``` + +### [Shortest Routes I](https://cses.fi/problemset/task/1671/) + +```cpp +#define INF (1LL<<61) +void dijkstra(int s, int n, vector adj[], vector &dist, vector &prev) +{ + dist.assign(n, INF); + prev.assign(n, -1); + dist[s] = 0; + priority_queue, greater> pq; + pq.push({0, s}); + while (!pq.empty()) + { + int u = pq.top().second, d = pq.top().first; + pq.pop(); + if (d != dist[u]) continue; + for (auto &edge : adj[u]) + { + int v = edge.first, w = edge.second; + if (dist[u] + w < dist[v]) + { + dist[v] = dist[u] + w; + prev[v] = u; + pq.push({dist[v], v}); + } + } + } +} + +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<1, pii> adj[n+1]; + while (m--) + { + int u, v, w; cin >> u >> v >> w; + adj[u].push_back({v, w}); + } + vec<1, int> dist, prev; + dijkstra(1, n+1, adj, dist, prev); + for (int i = 1; i <= n; ++i) cout << dist[i] << " "; + cout << '\n'; + return 0; +} +``` + +### [Shortest Routes II](https://cses.fi/problemset/task/1672/) + +```cpp +#define INF (1LL<<61) +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m, q; cin >> n >> m >> q; + vec<2, int> adj(n+1, n+1, INF); + for (int i = 1; i <= n; ++i) adj[i][i] = 0; + while (m--) + { + int u, v, w; cin >> u >> v >> w; + adj[u][v] = min(w, adj[u][v]); + adj[v][u] = min(w, adj[v][u]); + } + for (int k = 1; k <= n; ++k) + for (int i = 1; i <= n; ++i) + for (int j = 1; j <= n; ++j) + if (adj[i][k] < INF && adj[k][j] < INF) adj[i][j] = min(adj[i][j], adj[i][k] + adj[k][j]); + while (q--) + { + int u, v; cin >> u >> v; + if (adj[u][v] == INF) cout << "-1\n"; + else cout << adj[u][v] << '\n'; + } + return 0; +} +``` + +### [High Score](https://cses.fi/problemset/task/1673/) + +We can use negative edge path finding algorithms like bellman ford, I used SPFA which is more optimized slight modification in it can solve the problem. However the question expects to solve for infinite loops as well \(a cycle with positive sum\) those will result answer to be infinity if the cycle is present within 1 to n so print -1 otherwise if no cycle there simply return result of algorithm. + +```cpp +#define INF (1LL<<61) +set st; +bool spfa(int s, int n, vector adj[], vector &dist, vector &prev) +{ + dist.assign(n, -INF); + prev.assign(n, -1); + vector cnt(n, 0); + vector inqueue(n, false); + queue q; + dist[s] = 0; + q.push(s); + inqueue[s] = true; + bool cycle = false; + while (!q.empty()) + { + int u = q.front(); + q.pop(); + inqueue[u] = false; + for (auto &edge : adj[u]) + { + int v = edge.first, w = edge.second; + if (dist[u] + w > dist[v]) + { + dist[v] = dist[u] + w; + prev[v] = u; + if (!inqueue[v]) + { + cnt[v]++; + if (cnt[v] > n) { st.insert(u); cycle = true; continue; } + q.push(v); + inqueue[v] = true; + } + } + } + } + return !cycle; +} + +int n, m; +void DFS(vec<1, pii> adj[], vec<1, bool> &vis, int u) +{ + vis[u] = true; + for (auto &v : adj[u]) + if (!vis[v.F]) DFS(adj, vis, v.F); +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + cin >> n >> m; + vec<1, pii> adj[n+1]; + while (m--) + { + int u, v, w; cin >> u >> v >> w; + adj[u].push_back({v, w}); + } + vec<1, int> dist, prev; + if (spfa(1, n+1, adj, dist, prev)) cout << dist[n] << '\n'; + else + { + vec<1, bool> vis(n+1, false); + for (auto &x : st) + if (!vis[x]) DFS(adj, vis, x); + if (vis[1] || vis[n]) cout << "-1\n"; + else cout << dist[n] << '\n'; + } + return 0; +} +``` + +### [Flight Discount](https://cses.fi/problemset/task/1195/) + +```cpp +#define INF (1LL<<61) +void dijkstra(int s, int n, vector adj[], vector &dist, vector &prev) +{ + dist.assign(n, INF); + prev.assign(n, -1); + dist[s] = 0; + priority_queue, greater> pq; + pq.push({0, s}); + while (!pq.empty()) + { + int u = pq.top().second, d = pq.top().first; + pq.pop(); + if (d != dist[u]) continue; + for (auto &edge : adj[u]) + { + int v = edge.first, w = edge.second; + if (dist[u] + w < dist[v]) + { + dist[v] = dist[u] + w; + prev[v] = u; + pq.push({dist[v], v}); + } + } + } +} + +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<1, pii> adj[n+1], adjR[n+1]; + vec<1, tuple> edges; + while (m--) + { + int u, v, w; cin >> u >> v >> w; + edges.push_back({u, v, w}); + adj[u].push_back({v, w}); + adjR[v].push_back({u, w}); + } + vec<1, int> dist1, dist2, prev; + dijkstra(1, n+1, adj, dist1, prev); + dijkstra(n, n+1, adjR, dist2, prev); + + int res = dist1[n]; + for (auto &x : edges) + { + int u, v, w; tie(u, v, w) = x; + int cur = dist1[u] + w/2 + dist2[v]; + res = min(res, cur); + } + cout << res << '\n'; + return 0; +} +``` + +### [Cycle Finding](https://cses.fi/problemset/task/1197/) + +```cpp +struct edge { int u, v, w; }; +#define INF (1LL<<61) +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<1, edge> edges(m); + for (auto &x : edges) cin >> x.u >> x.v >> x.w; + + vec<1, int> dist(n+1, INF), par(n+1, -1); + int x; + for (int i = 0; i < n; ++i) + { + x = -1; + for (auto &e : edges) + { + if (dist[e.u] + e.w < dist[e.v]) + { + dist[e.v] = dist[e.u] + e.w; + par[e.v] = e.u; + x = e.v; + } + } + } + + if (x == -1) cout << "NO\n"; + else + { + cout << "YES\n"; + for (int i = 0; i < n; ++i) x = par[x]; + vec<1, int> cycle; + for (int v = x; ; v = par[v]) + { + cycle.push_back(v); + if (v == x && cycle.size() > 1) break; + } + reverse(all(cycle)); + for (auto &x : cycle) cout << x << " "; + cout << '\n'; + } + return 0; +} +``` + +### [Flight Routes](https://cses.fi/problemset/task/1196/) + +```cpp +void dijkstraKShortest(int s, int n, int k, vector adj[], vector> &distance) +{ + int cnt = 0; + distance.assign(n, vector()); + vector dist(n, 0); + priority_queue, greater> pq; + pq.push({0, s}); + while (!pq.empty()) + { + int u = pq.top().second, d = pq.top().first; + pq.pop(); + if (dist[u] > k) continue; + distance[u].push_back(d); + if (u == n-1) + { + cnt++; + if (cnt == k) break; + } + dist[u]++; + for (auto &x : adj[u]) + { + if (dist[x.first] > k) continue; + pq.push({d + x.second, x.first}); + } + } +} +signed main() +{ + ios::sync_with_stdio(0); cin.tie(0); + int n, m, k; cin >> n >> m >> k; + vec<1, pii> adj[n+1]; + for (int i = 0; i < m; i++) + { + int u, v, w; + cin >> u >> v >> w; + adj[u].push_back({v, w}); + } + vector> distance; + dijkstraKShortest(1, n+1, k, adj, distance); + for (auto &x : distance[n]) cout << x << " "; + cout << '\n'; + return 0; +} +``` + +### [Round Trip II](https://cses.fi/problemset/task/1678/) + +```cpp +const int MAXN = 1e5+5; +vec<1, int> adj[MAXN], res; +vec<1, bool> vis(MAXN, false); +int backtrackItem = -1; +bool found = false; +void DFS(int u) +{ + vis[u] = true; + for (auto &v : adj[u]) + { + if (!vis[v]) DFS(v); + else + { + res.push_back(v); + res.push_back(u); + backtrackItem = v; + return; + } + if (backtrackItem != -1) + { + if (!found) + { + res.push_back(u); + if (u == backtrackItem) found = true; + } + return; + } + } +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + while (m--) + { + int u, v; cin >> u >> v; + adj[u].push_back(v); + } + for (int i = 1; i <= n; ++i) + { + if (!vis[i]) DFS(i); + if (found) break; + else res.clear(); + } + if (!found) cout << "IMPOSSIBLE\n"; + else + { + reverse(all(res)); + cout << res.size() << '\n'; + for (auto &x : res) cout << x << " "; + cout << '\n'; + } + return 0; +} +``` + +### [Course Schedule](https://cses.fi/problemset/task/1679/) + +```cpp +vector topologicalSort(int n, vector adj[]) +{ + vector inDeg(n, 0); + for (int i = 0; i < n; ++i) + for (auto &x : adj[i]) ++inDeg[x]; + queue q; + for (int i = 0; i < n; ++i) + if (inDeg[i] == 0) q.push(i); + vector topOrder; + while (!q.empty()) + { + auto cur = q.front(); + q.pop(); + topOrder.push_back(cur); + for (auto &x : adj[cur]) + { + --inDeg[x]; + if (inDeg[x] == 0) q.push(x); + } + } + return topOrder; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<1, int> adj[n+1]; + while (m--) + { + int u, v; cin >> u >> v; + adj[u-1].push_back(v-1); + } + auto res = topologicalSort(n, adj); + if (res.size() != n) cout << "IMPOSSIBLE\n"; + else + { + for (auto &x : res) cout << x+1 << ' '; + cout << '\n'; + } + return 0; +} +``` + +### [Longest Flight Route](https://cses.fi/problemset/task/1680/) + +```cpp +#define INF (1LL<<61) +void zeroOneBFS(int s, int n, vector adj[], vector &dist, vector &prev) +{ + dist.assign(n, INF); + prev.assign(n, -1); + dist[s] = 0; + deque dq; + dq.push_front(s); + while (!dq.empty()) + { + int u = dq.front(); + dq.pop_front(); + for (auto &edge : adj[u]) + { + int v = edge.first, w = edge.second; + if (dist[u] + w < dist[v]) + { + dist[v] = dist[u] + w; + prev[v] = u; + if (w == 1) dq.push_back(v); + else dq.push_front(v); + } + } + } +} +bool findPath(int from, int to, vector &prev, vector &path) +{ + for (int cur = to; cur != -1; cur = prev[cur]) + path.push_back(cur); + reverse(path.begin(), path.end()); + return (!path.empty() && *path.begin() == from); +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<1, pii> adj[n+1]; + while (m--) + { + int u, v; cin >> u >> v; + adj[u].push_back({v, -1}); + } + vec<1, int> dist, prev, path; + zeroOneBFS(1, n+1, adj, dist, prev); + findPath(1, n, prev, path); + if (dist[n] == INF) cout << "IMPOSSIBLE\n"; + else + { + cout << path.size() << '\n'; + for (auto &x : path) cout << x << " "; + } + return 0; +} +``` + +### [Game Routes](https://cses.fi/problemset/task/1681/) + +```cpp +// Naive TLE Solution using BFS +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<1, int> adj[n+1]; + while (m--) + { + int u, v; cin >> u >> v; + adj[u].push_back(v); + } + + priority_queue pq; + vec<1, int> cnt(n+1, 0); + pq.push(1); cnt[1] = 1; + while (!pq.empty()) + { + int sz = pq.size(); + while (sz--) + { + auto u = pq.top(); pq.pop(); + for (auto &v : adj[u]) + { + (cnt[v] += 1) %= MOD; + pq.push(v); + } + } + } + cout << cnt[n] << '\n'; + return 0; +} + +// Accepted Topological Sort solution +vector topologicalSort(int n, vector adj[]) +{ + vector inDeg(n, 0); + for (int i = 0; i < n; ++i) + for (auto &x : adj[i]) ++inDeg[x]; + queue q; + for (int i = 0; i < n; ++i) + if (inDeg[i] == 0) q.push(i); + vector topOrder; + while (!q.empty()) + { + auto cur = q.front(); + q.pop(); + topOrder.push_back(cur); + for (auto &x : adj[cur]) + { + --inDeg[x]; + if (inDeg[x] == 0) q.push(x); + } + } + return topOrder; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<1, int> adj[n], inDeg(n, 0), cnt(n, 0); + while (m--) + { + int u, v; cin >> u >> v; + adj[u-1].push_back(v-1); + inDeg[v-1]++; + } + + cnt[0] = 1; + for (auto &u : topologicalSort(n, adj)) + for (auto &v : adj[u]) (cnt[v] += cnt[u]) %= MOD; + cout << cnt[n-1] << '\n'; + return 0; +} +``` + +### [Investigation](https://cses.fi/problemset/task/1202/) + +```cpp +#define INF (1LL<<61) +void dijkstra(int s, int n, vector adj[], vector &dist, vector &prev, vector &mn, vector &mx) +{ + dist.assign(n, make_pair(INF, 0)); + mn.assign(n, INF); mx.assign(n, -INF); + prev.assign(n, -1); dist[s] = {0, 1}; mn[s] = 0, mx[s] = 0; + priority_queue, greater> pq; + pq.push({0, s}); + while (!pq.empty()) + { + int u = pq.top().second, d = pq.top().first; + pq.pop(); + if (d != dist[u].first) continue; + for (auto &edge : adj[u]) + { + int v = edge.first, w = edge.second; + if (dist[u].first + w == dist[v].first) + { + (dist[v].second += dist[u].second) %= MOD; + mn[v] = min(mn[v], mn[u]+1), mx[v] = max(mx[v], mx[u]+1); + } + if (dist[u].first + w < dist[v].first) + { + dist[v] = {dist[u].first + w, dist[u].second}; + mn[v] = mn[u]+1, mx[v] = mx[u]+1, prev[v] = u; + pq.push({dist[v].first, v}); + } + } + } +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<1, pii> adj[n+1]; + while (m--) + { + int u, v, w; cin >> u >> v >> w; + adj[u].push_back({v, w}); + } + vec<1, pii> dist; + vec<1, int> prev, mn, mx; + dijkstra(1, n+1, adj, dist, prev, mn, mx); + cout << dist[n].first << " " << dist[n].second << " " << mn[n] << " " << mx[n] << '\n'; + return 0; +} +``` + +### [Planets Queries I](https://cses.fi/problemset/task/1750/) + +Refer [https://cses.fi/book/book.pdf](https://cses.fi/book/book.pdf) page 164 successor path + +```cpp +const int MAXN = 2*1e5 + 5; +vec<2, int> succ(32, MAXN); +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, q; cin >> n >> q; + for (int j = 1; j <= n; ++j) cin >> succ[0][j]; + for (int i = 1; i < 32; ++i) + for (int j = 1; j <= n; ++j) + succ[i][j] = succ[i-1][succ[i-1][j]]; + + while (q--) + { + int x, k; cin >> x >> k; + int i = 0; + while (k) + { + if (k&1) x = succ[i][x]; + k >>= 1; + ++i; + } + cout << x << '\n'; + } + return 0; +} +``` + +### [Planets Queries II](https://cses.fi/problemset/task/1160/) + +Consider below two example function graphs built in top bottom fashion, the array next to it denotes len for 1 its 3, 2 is 2 and so on it can easily be visualized through top bottom fashion representation. + +Now if we go k times succ \(lift\) using our log n approach of previous problem, we should choose optimal value of k here there could be 3 things: + +* If y is some bottom successor say in left graph x=1 and y=3 then we need to left k=2 i.e. len\[x\]-len\[y\] times. +* There could be a circular scenerio as well consider right graph if x=4 y=2 then first condition will fail in that case we want x to go back to the initial of the loop here 1 by lifting it len\[x\] times now x=1 y=2 using case 1 will work. +* If above 2 condition fails then return -1 + +![](../.gitbook/assets/image%20%2864%29.png) + +```cpp +const int MAXN = 2*1e5 + 5; +vec<2, int> succ(32, MAXN); +vec<1, bool> vis(MAXN, false); +vec<1, int> len(MAXN, 0); +void DFS(int u) +{ + vis[u] = true; + int v = succ[0][u]; + if (!vis[v]) DFS(v); + len[u] = len[v]+1; +} +int lift(int x, int d) +{ + if (d <= 0) return x; + int i = 0; + while (d) + { + if (d&1) x = succ[i][x]; + d >>= 1; + ++i; + } + return x; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, q; cin >> n >> q; + for (int j = 1; j <= n; ++j) cin >> succ[0][j]; + for (int i = 1; i < 32; ++i) + for (int j = 1; j <= n; ++j) + succ[i][j] = succ[i-1][succ[i-1][j]]; + + for (int i = 1; i <= n; ++i) + if (!vis[i]) DFS(i); + + while (q--) + { + int x, y; cin >> x >> y; + int z = lift(x, len[x]); + if (lift(x, len[x]-len[y]) == y) cout << (len[x]-len[y]) << '\n'; + else if (lift(z, len[z]-len[y]) == y) cout << (len[x]+len[z]-len[y]) << '\n'; + else cout << "-1\n"; + } + return 0; +} +``` + +### [Planets Cycles](https://cses.fi/problemset/task/1751/) + +We are running a DFS to work on a component at a time essentially finding len \(our final result\) for that component at a time. To do so we iterate over entire component until we find a loop, now inside if \(vis\[v\]\) we are doing 2 things once we find our loop, those who are inside loop will have cycLen count and for those outside we run another DFS \(opposite one we have prepared a previous DFS just like successor one\). + +```cpp +const int MAXN = 2e5 + 5; +#define INF (1LL<<61) +vec<1, int> succ(MAXN), presc[MAXN], len(MAXN, INF); +vec<1, bool> vis(MAXN, false); +intHashTable rec; +void DFS2(int u, int x) +{ + if (!vis[u]) vis[u] = true; + len[u] = x; + for (auto &v : presc[u]) + if (len[v] == INF) DFS2(v, x+1); +} +void DFS(int u) +{ + rec.clear(); + for (int v = u, cnt = 0; ; v = succ[v], cnt++) + { + int cycLen = cnt-rec[v]; + if (vis[v]) + { + int v1 = v; + while (len[v] == INF) + { + len[v] = cycLen; + v = succ[v]; + } + for (auto &x : presc[v1]) + if (len[x] == INF) DFS2(x, len[v1]+1); + break; + } + vis[v] = true; + rec[v] = cnt; + } +} + +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + for (int i = 1; i <= n; ++i) + { + cin >> succ[i]; + presc[succ[i]].push_back(i); + } + for (int i = 1; i <= n; ++i) + if (!vis[i]) DFS(i); + for (int i = 1; i <= n; ++i) cout << len[i] << " "; cout << '\n'; + return 0; +} +``` + +### [Road Reparation](https://cses.fi/problemset/task/1675/) + +Simply find MST + +```cpp +const int MAXN = 1e5; +int parent[MAXN+1], sz[MAXN+1]; +void makeSet(int x) { parent[x] = x, sz[x] = 1; } +int findSet(int x) { return (x == parent[x]) ? x : parent[x] = findSet(parent[x]); } +void unionSet(int x, int y) +{ + x = findSet(x), y = findSet(y); + if (x != y) + { + if (sz[x] < sz[y]) swap(x, y); + parent[y] = x; + sz[x] += sz[y]; + } +} + +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + vec<1, tiii> edges(m); + for (auto &x : edges) cin >> get<1>(x) >> get<2>(x) >> get<0>(x); + sort(all(edges)); + for (int i = 1; i <= n; ++i) makeSet(i); + int cost = 0, edgeCnt = 0; + for (auto &x : edges) + { + int u = get<1>(x), v = get<2>(x), w = get<0>(x); + if (findSet(u) != findSet(v)) + { + cost += w, edgeCnt++; + unionSet(u, v); + } + } + if (edgeCnt == n-1) cout << cost << '\n'; + else cout << "IMPOSSIBLE\n"; + return 0; +} +``` + +### [Road Construction](https://cses.fi/problemset/task/1676/) + +Apply DSU and little bit of maths + +```cpp +const int MAXN = 1e5; +int parent[MAXN+1], sz[MAXN+1]; +void makeSet(int x) { parent[x] = x, sz[x] = 1; } +int findSet(int x) { return (x == parent[x]) ? x : parent[x] = findSet(parent[x]); } +void unionSet(int x, int y) +{ + x = findSet(x), y = findSet(y); + if (x != y) + { + if (sz[x] < sz[y]) swap(x, y); + parent[y] = x; + sz[x] += sz[y]; + } +} + +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + for (int i = 1; i <= n; ++i) makeSet(i); + int resX = n, resY = 1; + while (m--) + { + int u, v; cin >> u >> v; + if (findSet(u) != findSet(v)) + { + int p = sz[findSet(u)], q = sz[findSet(v)]; + resX--, resY = max(resY, p+q); + unionSet(u, v); + } + cout << resX << " " << resY << '\n'; + } + return 0; +} +``` + +### [Flight Routes Check](https://cses.fi/problemset/task/1682/) + +Kosaraju Strongly connected component + +```cpp +const int MAXN = 1e5; +vector adj[MAXN+1], adjRev[MAXN+1], order, component; +vector used; +int n, m; +void DFS(int u) +{ + used[u] = true; + for (auto &v : adj[u]) + if (!used[v]) DFS(v); + order.push_back(u); +} +void DFS2(int u) +{ + used[u] = true; + component.push_back(u); + for (auto &v : adjRev[u]) + if (!used[v]) DFS2(v); +} +signed main() +{ + cin >> n >> m; + while (m--) + { + int u, v; cin >> u >> v; + u--, v--; + adj[u].push_back(v); + adjRev[v].push_back(u); + } + used.assign(n, false); + for (int i = 0; i < n; ++i) + if (!used[i]) DFS(i); + used.assign(n, false); + reverse(order.begin(), order.end()); + vec<1, int> res; + for (auto &v : order) + { + if (used[v]) continue; + DFS2(v); + if (!component.empty()) res.push_back(component[0]+1); + if (res.size() >= 2) { cout << "NO\n" << res[1] << " " << res[0] << '\n'; return 0; } + component.clear(); + } + cout << "YES\n"; +} +``` + +### [Planets and Kingdoms](https://cses.fi/problemset/task/1683/) + +Again simple kosaraju + +```cpp +const int MAXN = 1e5; +vector adj[MAXN+1], adjRev[MAXN+1], order, component, res(MAXN); +vector used; +int n, m; +void DFS(int u) +{ + used[u] = true; + for (auto &v : adj[u]) + if (!used[v]) DFS(v); + order.push_back(u); +} +void DFS2(int u) +{ + used[u] = true; + component.push_back(u); + for (auto &v : adjRev[u]) + if (!used[v]) DFS2(v); +} +signed main() +{ + cin >> n >> m; + while (m--) + { + int u, v; cin >> u >> v; + u--, v--; + adj[u].push_back(v); + adjRev[v].push_back(u); + } + used.assign(n, false); + for (int i = 0; i < n; ++i) + if (!used[i]) DFS(i); + used.assign(n, false); + reverse(order.begin(), order.end()); + int cnt = 1; + for (auto &v : order) + { + if (used[v]) continue; + DFS2(v); + for (auto &x : component) res[x+1] = cnt; + cnt++; + component.clear(); + } + cout << cnt-1 << '\n'; + for (int i = 1; i <= n; ++i) cout << res[i] << " "; + cout << '\n'; + return 0; +} +``` + +### [Giant Pizza](https://cses.fi/problemset/task/1684/) + +Standard 2SAT problem + +```cpp +vector> adj, adjRev; +vector vis, sol, isTrue; +vector mvStk; +bool noSolution; +int N; +void DFS1(int node) +{ + vis[node] = true; + for (auto vec : adj[node]) + if (!vis[vec]) DFS1(vec); + mvStk.push_back(node); +} +void DFS2(int node) +{ + if (isTrue[node]) noSolution = true; + vis[node] = true; + isTrue[node^1] = true; + sol[node/2] = ((node&1) ^ 1); + for (auto vec : adjRev[node]) + if (!vis[vec]) DFS2(vec); +} +inline int get_node(int x) { return (x > 0) ? (2 * (x-1) + 1) : (2 * (-x-1)); } +int initialize(int _n) +{ + N = _n; + adj.assign(2*N, vector()); + adjRev.assign(2*N, vector()); + vis.assign(2*N, false); + sol.assign(N, false); + isTrue.assign(2*N, false); + mvStk.reserve(2*N); +} +void addEdge(int p, int q) +{ + int a, b; + a = get_node(-p); b = get_node(q); + adj[a].push_back(b); + adjRev[b].push_back(a); + + a = get_node(-q); b = get_node(p); + adj[a].push_back(b); + adjRev[b].push_back(a); +} +pair> solve2SAT() +{ + fill(vis.begin(), vis.end(), 0); + for (int i = 0; i < 2*N; ++i) + if (!vis[i]) DFS1(i); + noSolution = false; + fill(vis.begin(), vis.end(), 0); + for (int i = 2*N - 1; i >= 0; --i) + if (!vis[mvStk[i]] && !vis[mvStk[i] ^ 1]) DFS2(mvStk[i]); + return {!noSolution, sol}; +} + +signed main() +{ + int n, m; cin >> n >> m; + initialize(m); + while (n--) + { + int a, b; char p, q; cin >> p >> a >> q >> b; + if (p == '-') a *= -1; + if (q == '-') b *= -1; + addEdge(a, b); + } + auto res = solve2SAT(); + if (!res.F) cout << "IMPOSSIBLE\n"; + else + { + for (auto x : res.S) + cout << ((x) ? '+' : '-') << ' '; + cout << '\n'; + } + return 0; +} +``` + +### [Coin Collector](https://cses.fi/problemset/task/1686/) + +![](../.gitbook/assets/image%20%2877%29.png) + +From the given graph we first find all Strongly connected component, because within each SCC we are allowed to freely move anywhere so if we enter any node then all other nodes belonging to that SCC values will add up. In the image 1, 2 belongs to 1st SCC and 3 2nd and 4th 3rd. Now we create a DAG based on original graph property keeping components grouped. Now since it's a DAG we can easily find longest value path using dp. + +```cpp +const int MAXN = 1e5+5; +int n, m, numSCC = 0; +vec<1, int> adj[MAXN], adjRev[MAXN], arr(MAXN), topOrder, comp(MAXN, 0), val(MAXN, 0), SCC[MAXN]; +vec<1, bool> vis(MAXN, false); + +void DFS(int u) +{ + vis[u] = true; + for (auto &v : adj[u]) + if (!vis[v]) DFS(v); + topOrder.push_back(u); +} +void DFS2(int u) +{ + vis[u] = true; + comp[u] = numSCC; + val[numSCC] += arr[u]; + for (auto &v : adjRev[u]) + if (!vis[v]) DFS2(v); +} +vec<1, int> dp(MAXN, -1); +ll solve(int u) +{ + if (dp[u] != -1) return dp[u]; + int res = 0; + for (int v : SCC[u]) res = max(res, solve(v)); + return dp[u] = res + val[u]; +} + +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + cin >> n >> m; + for (int i = 1; i <= n; ++i) cin >> arr[i]; + while (m--) + { + int u, v; cin >> u >> v; + adj[u].push_back(v); + adjRev[v].push_back(u); + } + + // find topological order for kosaraju algorithm + for (int i = 1; i <= n; ++i) + if (!vis[i]) DFS(i); + reverse(all(topOrder)); + + // Apply kosaraju algorithm, find for each node which componentNum it belongs to (comp[x]) then val[x] + // denotes sum of all nodes within that SCC. + fill(all(vis), false); + for (auto &x : topOrder) + if (!vis[x]) numSCC++, DFS2(x); + + // Creating a DAG of components + for (int u = 1; u <= n; ++u) + for (auto &v : adj[u]) + if (comp[u] != comp[v]) SCC[comp[u]].push_back(comp[v]); + + // dp[x] is maximum path we can have starting from that SCC node + int ans = 0; + for (int i = 1; i <= numSCC; i++) + ans = max(ans, solve(i)); + cout << ans; + return 0; +} +``` + +### [Mail Delivery](https://cses.fi/problemset/task/1691/) + +```cpp +/* Heirholzer's Algorithm to find Euler path in O(V + E) */ +const int MAXN = 1e5+5; +struct Edge; +typedef list::iterator iter; +vec<1, int> deg(MAXN, 0); +int edgeCnt = 0; +struct Edge +{ + int nextVertex; + iter reverseEdge; + Edge(int _nextVertex) : nextVertex(_nextVertex) { } +}; +int n; +list adj[MAXN+1]; +vector path; +void addEdge(int a, int b) +{ + adj[a].push_front(Edge(b)); + iter ita = adj[a].begin(); + adj[b].push_front(Edge(a)); + iter itb = adj[b].begin(); + ita->reverseEdge = itb; + itb->reverseEdge = ita; + deg[a]++, deg[b]++; + edgeCnt++; +} +void helper(int u) +{ + while (adj[u].size() > 0) + { + int v = adj[u].front().nextVertex; + adj[v].erase(adj[u].front().reverseEdge); + adj[u].pop_front(); + helper(v); + } + path.push_back(u); +} +bool findEulerianPathUndirected(int u, int n) +{ + for (auto &x : deg) + if (x&1) return false; + helper(u); + return (path.size() == edgeCnt+1); +} + +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + while (m--) + { + int u, v; cin >> u >> v; + addEdge(u, v); + } + if (!findEulerianPathUndirected(1, n)) cout << "IMPOSSIBLE\n"; + else + { + for (auto &x : path) cout << x << " "; + cout << '\n'; + } + return 0; +} +``` + +### [De Bruijn Sequence](https://cses.fi/problemset/task/1692/) + +[https://www.geeksforgeeks.org/de-bruijn-sequence-set-1/](https://www.geeksforgeeks.org/de-bruijn-sequence-set-1/) + +```cpp +unordered_set done; +vec<1, int> edges; +void DFS(string node, string &st) +{ + for (int i = 0; i < st.size(); ++i) + { + string cur = node+st[i]; + if (done.find(cur) == done.end()) + { + done.insert(cur); + DFS(cur.substr(1), st); + edges.push_back(i); + } + } +} +string deBruijn(int n, string st) +{ + done.clear(); edges.clear(); + string startingNode = string (n-1, st[0]); + DFS(startingNode, st); + string res; + int len = pow(st.size(), n); + for (int i = 0; i < len; ++i) res += st[edges[i]]; + res += startingNode; + return res; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n; cin >> n; + string st = "01"; + cout << deBruijn(n, st) << '\n'; + return 0; +} +``` + +### [Teleporters Path](https://cses.fi/problemset/task/1693/) + +```cpp +const int MAXN = 1e5+5; +vec<1, int> adj[MAXN], inDeg(MAXN, 0), outDeg(MAXN, 0); +vector findEulerianPathDirected(int u) +{ + vector stack, curr_edge(MAXN), res; + stack.push_back(u); + while (!stack.empty()) + { + u = stack.back(); + stack.pop_back(); + while (curr_edge[u] < (int)adj[u].size()) + { + stack.push_back(u); + u = adj[u][curr_edge[u]++]; + } + res.push_back(u); + } + reverse(res.begin(), res.end()); + return res; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + while (m--) + { + int u, v; cin >> u >> v; + adj[u].push_back(v); + inDeg[v]++, outDeg[u]++; + } + bool notPossible = !((inDeg[1] > outDeg[1]) && (inDeg[n] < outDeg[n]) || + (inDeg[1] < outDeg[1]) && (inDeg[n] > outDeg[n])); + for (int i = 2; i <= n-1; ++i) + if (inDeg[i] != outDeg[i]) { notPossible = true; break; } + if (notPossible) cout << "IMPOSSIBLE\n"; + else + { + for (auto &x : findEulerianPathDirected(1)) + cout << x << " "; + cout << '\n'; + } + return 0; +} +``` + +### [Hamiltonian Flights](https://cses.fi/problemset/task/1690/) + +DP stores result for vertex and visited elements if ith bit in set in state means ith node is visited. + +```cpp +int n, m; +vec<1, int> adj[20]; +int dp[20][(1<<20)]; +int solve(int u, int state) +{ + if (__builtin_popcount(state) == n) return (u == n-1); + else if (u == n-1) return 0; // heuristic to save from TLE + if (dp[u][state] != 0) return dp[u][state]; + int res = 0; + for (auto &v : adj[u]) + { + if (state&(1<> n >> m; + while (m--) + { + int u, v; cin >> u >> v; + adj[u-1].push_back(v-1); + } + cout << solve(0, (1<<0)) << '\n'; + return 0; +} +``` + +### [Knight's Tour](https://cses.fi/problemset/task/1689/) + +Visit those states first \(via sorting\) which will have more future valid states + +```cpp +vec<2, int> mat(9, 9, 0); +const int dx[] = {-2, -2, -1, -1, 1, 1, 2, 2}, dy[] = {-1, 1, -2, 2, -2, 2, -1, 1}; +int deg(int x, int y) +{ + int d = 0; + for (int i = 0; i < 8; ++i) + { + int _x = x + dx[i], _y = y + dy[i]; + if (_x >= 1 && _x <= 8 && _y >= 1 && _y <= 8 && mat[_x][_y] == 0) d++; + } + return d; +} +bool solve(int x, int y, int cur = 1) +{ + mat[x][y] = cur; + if (cur == 64) return true; + vec<1, tiii> pos; + for (int i = 0; i < 8; ++i) + { + int _x = x + dx[i], _y = y + dy[i]; + if (_x >= 1 && _x <= 8 && _y >= 1 && _y <= 8 && mat[_x][_y] == 0) + pos.push_back({deg(_x, _y), _x, _y}); + } + sort(all(pos)); + for (auto &v : pos) + if (solve(get<1>(v), get<2>(v), cur+1)) return true; + mat[x][y] = 0; + return false; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + solve(m, n); + for (int i = 1; i <= 8; ++i) + { + for (int j = 1; j <= 8; ++j) cout << mat[i][j] << " "; + cout << '\n'; + } + return 0; +} +``` + +### [Download Speed](https://cses.fi/problemset/task/1694/) + +```cpp +struct FlowEdge { int v, u; ll cap, flow = 0; FlowEdge(int v, int u, ll cap) : v(v), u(u), cap(cap) {} }; +struct Dinic +{ + const ll FLOW_INF = 1e18; + int n, m = 0, s, t; + vector edges; vector> adj; + vector level, ptr; queue q; + Dinic(int n, int s, int t) : n(n), s(s), t(t) { adj.resize(n); level.resize(n); ptr.resize(n); } + void addEdge(int u, int v, ll cap) + { + edges.emplace_back(u, v, cap); edges.emplace_back(v, u, 0); + adj[u].push_back(m); adj[v].push_back(m+1); + m += 2; + } + bool bfs() + { + while (!q.empty()) + { + int v = q.front(); q.pop(); + for (int id : adj[v]) + { + if (edges[id].cap - edges[id].flow < 1) continue; + if (level[edges[id].u] != -1) continue; + level[edges[id].u] = level[v] + 1; + q.push(edges[id].u); + } + } + return level[t] != -1; + } + ll dfs(int v, ll pushed) + { + if (pushed == 0) return 0; + if (v == t) return pushed; + for (int &cid = ptr[v]; cid < (int)adj[v].size(); cid++) + { + int id = adj[v][cid], u = edges[id].u; + if (level[v] + 1 != level[u] || edges[id].cap - edges[id].flow < 1) continue; + ll tr = dfs(u, min(pushed, edges[id].cap - edges[id].flow)); + if (tr == 0) continue; + edges[id].flow += tr; edges[id ^ 1].flow -= tr; + return tr; + } + return 0; + } + ll flow() + { + ll f = 0; + while (true) + { + fill(level.begin(), level.end(), -1); + level[s] = 0; + q.push(s); + if (!bfs()) break; + fill(ptr.begin(), ptr.end(), 0); + while (ll pushed = dfs(s, FLOW_INF)) f += pushed; + } + return f; + } +}; +// O(N^2 * E) + +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + Dinic dinic(n+1, 1, n); + while (m--) + { + int u, v, w; cin >> u >> v >> w; + dinic.addEdge(u, v, w); + } + cout << dinic.flow() << '\n'; + return 0; +} +``` + +### [Police Chase](https://cses.fi/problemset/task/1695/) + +```cpp +struct FlowEdge { int v, u; ll cap, flow = 0; FlowEdge(int v, int u, ll cap) : v(v), u(u), cap(cap) {} }; +struct Dinic +{ + const ll FLOW_INF = 1e18; + int n, m = 0, s, t; + vector edges; vector> adj; + vector level, ptr; queue q; + Dinic(int n, int s, int t) : n(n), s(s), t(t) { adj.resize(n); level.resize(n); ptr.resize(n); } + void addEdge(int u, int v, ll cap) + { + edges.emplace_back(u, v, cap); edges.emplace_back(v, u, 0); + adj[u].push_back(m); adj[v].push_back(m+1); + m += 2; + } + bool bfs() + { + while (!q.empty()) + { + int v = q.front(); q.pop(); + for (int id : adj[v]) + { + if (edges[id].cap - edges[id].flow < 1) continue; + if (level[edges[id].u] != -1) continue; + level[edges[id].u] = level[v] + 1; + q.push(edges[id].u); + } + } + return level[t] != -1; + } + ll dfs(int v, ll pushed) + { + if (pushed == 0) return 0; + if (v == t) return pushed; + for (int &cid = ptr[v]; cid < (int)adj[v].size(); cid++) + { + int id = adj[v][cid], u = edges[id].u; + if (level[v] + 1 != level[u] || edges[id].cap - edges[id].flow < 1) continue; + ll tr = dfs(u, min(pushed, edges[id].cap - edges[id].flow)); + if (tr == 0) continue; + edges[id].flow += tr; edges[id ^ 1].flow -= tr; + return tr; + } + return 0; + } + ll flow() + { + ll f = 0; + while (true) + { + fill(level.begin(), level.end(), -1); + level[s] = 0; + q.push(s); + if (!bfs()) break; + fill(ptr.begin(), ptr.end(), 0); + while (ll pushed = dfs(s, FLOW_INF)) f += pushed; + } + return f; + } +}; +// O(N^2 * E) + +vec<2, bool> hasEdge(505, 505, false); +vec<1, int> positive, negative; +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m; cin >> n >> m; + Dinic dinic(n+1, 1, n); + while (m--) + { + int u, v; cin >> u >> v; + dinic.addEdge(u, v, 1); + dinic.addEdge(v, u, 1); + hasEdge[u][v] = true; + hasEdge[v][u] = true; + } + cout << dinic.flow() << '\n'; + for (int i = 1; i <= n; ++i) + { + if (dinic.level[i] >= 0) positive.push_back(i); + else negative.push_back(i); + } + for (auto &x : positive) + for (auto &y : negative) + if (hasEdge[x][y]) cout << x << " " << y << '\n'; + return 0; +} +``` + +### [School Dance](https://cses.fi/problemset/task/1696/) + +```cpp +class GraphMatching +{ +private: + static bool findMatch(int i, const vector> &inp_w, vector &out_row, vector &out_column, vector &seen) + { + // 0 is NO_EDGE here + if (seen[i]) return false; + seen[i] = true; + for (int j = 0; j < inp_w[i].size(); ++j) + { + if (inp_w[i][j] != 0 && out_column[j] < 0) + { + out_row[i] = j, out_column[j] = i; + return true; + } + } + for (int j = 0; j < inp_w[i].size(); ++j) + { + if (inp_w[i][j] != 0 && out_row[i] != j) + { + if (out_column[j] < 0 || findMatch(out_column[j], inp_w, out_row, out_column, seen)) + { + out_row[i] = j, out_column[j] = i; + return true; + } + } + } + return false; + } + static bool dfs(int n, int N, vector> &inp_con, vector &blossom, vector &vis, vector &out_match) + { + vis[n] = 0; + for (int i = 0; i < N; ++i) + { + if (!inp_con[n][i]) continue; + if (vis[i] == -1) + { + vis[i] = 1; + if (out_match[i] == -1 || dfs(out_match[i], N, inp_con, blossom, vis, out_match)) + { + out_match[n] = i, out_match[i] = n; + return true; + } + } + if (vis[i] == 0 || blossom.size()) + { + blossom.push_back(i), blossom.push_back(n); + if (n == blossom[0]) + { + out_match[n] = -1; + return true; + } + return false; + } + } + return false; + } + static bool augment(int N, vector> &inp_con, vector &out_match) + { + for (int i = 0; i < N; ++i) + { + if (out_match[i] != -1) continue; + vector blossom; + vector vis(N, -1); + if (!dfs(i, N, inp_con, blossom, vis, out_match)) continue; + if (blossom.size() == 0) return true; + int base = blossom[0], S = blossom.size(); + vector> newCon = inp_con; + for (int i = 1; i != S-1; ++i) + for (int j = 0; j < N; ++j) + newCon[base][j] = newCon[j][base] |= inp_con[blossom[i]][j]; + for (int i = 1; i != S-1; ++i) + for (int j = 0; j < N; ++j) + newCon[blossom[i]][j] = newCon[j][blossom[i]] = 0; + newCon[base][base] = 0; + if (!augment(N, newCon, out_match)) return false; + int n = out_match[base]; + if (n != -1) + { + for (int i = 0; i < S; ++i) + { + if (!inp_con[blossom[i]][n]) continue; + out_match[blossom[i]] = n, out_match[n] = blossom[i]; + if (i&1) + { + for (int j = i+1; j < S; j += 2) + out_match[blossom[j]] = blossom[j+1], out_match[blossom[j+1]] = blossom[j]; + } + else + { + for (int j = 0; j < i; j += 2) + out_match[blossom[j]] = blossom[j+1], out_match[blossom[j+1]] = blossom[j]; + } + break; + } + } + return true; + } + return false; + } +public: + /* weighted bipartite matching, inp_w[i][j] is cost from row node i to column node j + out vector out_row & out_column is assignment for that node or -1 if unassigned + It has a heuristic that will give excellent performance on complete graphs where rows <= columns. */ + static int bipartiteMatching(const vector> &inp_w, vector &out_row, vector &out_column) + { + out_row = vector (inp_w.size(), -1); + out_column = vector (inp_w[0].size(), -1); + vector seen(inp_w.size()); + int count = 0; + for (int i = 0; i < inp_w.size(); ++i) + { + fill(seen.begin(), seen.end(), 0); + if (findMatch(i, inp_w, out_row, out_column, seen)) count++; + } + return count; + } + // unweighted inp_conn[i][j] = 1 for edge 0 otherwise, returns no. of edges in max matching + static int nonBipartiteMatching(vector> &inp_con, vector &out_match) + { + int res = 0; + int N = inp_con.size(); + out_match = vector(N, -1); + while (augment(N, inp_con, out_match)) res++; + return res; + } +}; + +vector> inp_w; +vector out_row, out_column; +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int n, m, k; cin >> n >> m >> k; + inp_w.assign(n, vector(m, 0)); + while (k--) + { + int u, v; cin >> u >> v; + inp_w[u-1][v-1] = 1; + } + cout << GraphMatching::bipartiteMatching(inp_w, out_row, out_column) << '\n'; + for (int i = 0; i < n; ++i) + { + if (out_row[i] == -1) continue; + cout << i+1 << " " << out_row[i]+1 << '\n'; + } + return 0; +} +``` + +### [Distinct Routes](https://cses.fi/problemset/task/1711/) + +```cpp +struct FlowEdge { int v, u; ll cap, flow = 0; FlowEdge(int v, int u, ll cap) : v(v), u(u), cap(cap) {} }; +struct Dinic +{ + const ll FLOW_INF = 1e18; + int n, m = 0, s, t; + vector edges; vector> adj; + vector level, ptr; queue q; + Dinic(int n, int s, int t) : n(n), s(s), t(t) { adj.resize(n); level.resize(n); ptr.resize(n); } + void addEdge(int u, int v, ll cap) + { + edges.emplace_back(u, v, cap); edges.emplace_back(v, u, 0); + adj[u].push_back(m); adj[v].push_back(m+1); + m += 2; + } + bool bfs() + { + while (!q.empty()) + { + int v = q.front(); q.pop(); + for (int id : adj[v]) + { + if (edges[id].cap - edges[id].flow < 1) continue; + if (level[edges[id].u] != -1) continue; + level[edges[id].u] = level[v] + 1; + q.push(edges[id].u); + } + } + return level[t] != -1; + } + ll dfs(int v, ll pushed) + { + if (pushed == 0) return 0; + if (v == t) return pushed; + for (int &cid = ptr[v]; cid < (int)adj[v].size(); cid++) + { + int id = adj[v][cid], u = edges[id].u; + if (level[v] + 1 != level[u] || edges[id].cap - edges[id].flow < 1) continue; + ll tr = dfs(u, min(pushed, edges[id].cap - edges[id].flow)); + if (tr == 0) continue; + edges[id].flow += tr; edges[id ^ 1].flow -= tr; + return tr; + } + return 0; + } + ll flow() + { + ll f = 0; + while (true) + { + fill(level.begin(), level.end(), -1); + level[s] = 0; + q.push(s); + if (!bfs()) break; + fill(ptr.begin(), ptr.end(), 0); + while (ll pushed = dfs(s, FLOW_INF)) f += pushed; + } + return f; + } +}; +// O(N^2 * E) +// TO FIND MINIMUM CUT: https://cses.fi/problemset/task/1695/ (problem) https://ideone.com/90rVfx (solution) +// TO FIND ALL PATHS OF FLOW: https://cses.fi/problemset/task/1711/ (problem) https://ideone.com/wMvHeK (solution) + +vec<2, bool> chosenFlow(505, 505, false); +vec<1, bool> vis(505, false); +vec<1, int> adj[505]; +vec<1, int> res; +int n, m; +void DFS(int u) +{ + if (u == n) + { + cout << res.size() << '\n'; + for (auto &x : res) cout << x << " "; + cout << '\n'; + return; + } + vis[u] = true; + for (auto &v : adj[u]) + { + if (!vis[v] && chosenFlow[u][v]) + { + res.push_back(v); + DFS(v); + res.pop_back(); + chosenFlow[u][v] = false; + } + } +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + cin >> n >> m; + Dinic dinic(n+1, 1, n); + while (m--) + { + int u, v; cin >> u >> v; + dinic.addEdge(u, v, 1); + adj[u].push_back(v); + adj[v].push_back(u); + } + cout << dinic.flow() << '\n'; + for (auto &x : dinic.edges) + if (x.flow == -1) chosenFlow[x.u][x.v] = true; + res.push_back(1); + DFS(1); + return 0; +} +``` + diff --git a/puzzles.md b/puzzles.md new file mode 100644 index 0000000..190f041 --- /dev/null +++ b/puzzles.md @@ -0,0 +1,176 @@ +# Puzzles + +### The Heavy Pill + +You have 20 bottles of pills, 19 bottles have 1.0 gram pills, but one has pills of weight 1.1 grams. Given a scale that provides an exact measurement, how would you find the heavy bottle? You can only use the scale once. + +```text +Pick 1 pill from bottle 1, 2 from bottle 2, 3 from bottle 3 and so on +total weight would be: (1 + 2 + 3 + ... + 20) + 0.1(k) +so, (weight - 210)/0.1 will tell which bottle has heavy pill +``` + +### Backetball + +You have a basketball hoop and someone says that you can play one of two games. +Game 1: You get one shot to make the hoop +Game 2: You get three shots and you have to make two of three shots +If p is the probability of making a particular shot, for which values of p should you pick one game or the other? + +```text +Prob of game 1: p +Prob of game 2: +[Making exactly 2 shots] [Making exactly 3 shots] + 3C2 * p^2 * (1-p) p^3 + 3(1-p)p^2 + = 3p^2 - 2p^3 + +p > 3p^2 - p^3 +1 > 3p - p^2 +(2p - 1)(p - 1) > 0 +So we should play Game 1 if 0 < p < 0.5 and Game 2 if 0.5 < p < 1 +``` + +### Dominos + +There is an 8x8 chessboard in which two diagonally opposite corners have been cur off. You are given 31 dominos, and single domino can cover exactly two squares. Can you use the 31 dominos to cover the entire board? Prove your answer \(by providing an example or showing why its impossible\). + +```text +We removed diagonal opposite corners which have same colors. On placing domino +each different color is covered. so 62 tiles are left out of 30 are white and +30 are black but there are 2 left overs of same color which we can never cover. +``` + +### Ants on a Triangle + +There are three ants on different vertices of a triangle. What is the probability of collision \(between any two or all of them\) if they start walking on the sides of the triangle? Assume that each ant randomly picks a direction, with either direction being equally likely to be chosen, and that they walk at the same speed. Similarly find the probability of collision with n ants on a n-vertex polygon. + +```text +P(colliding) = 1 - P(Not Colliding) +Ants will not collide if they all either move clockwise or counter clockwise +P(Not colliding) = (1/2)^n + (1/2)^n = (1/2)^(n-1) +``` + +### Jugs of Water + +You have a five-quart jug, a three-quart jug, and an unlimited supply of water \(but no measuring cups\). How would you come up with exactly four quarts of water? Note that the jugs are oddly shaped, such that filling up exactly "half" of the jug would be impossible. + +```text +Remeber we can make 5-3 quarts easily, fill 5q jug then empty it to 3q jug you +will be left with 2. +Transfer 2quart from jug1 to 2. Now again pour all 5q to jug1. And again pour +from jug1 to 2. This time 1 additional will go and we are left with 4 in jug1 +and 3 in jug2. + +If jugs sizes are relatively prime, we can measure any value between 1 and sum +of jug sizes. It can be represented as a linear diaphotine equation: +ax + by = c +where a and b are size of jugs we have and c is amount that we form +The theory of Diophantine equations states you can create an amount c iff +it is a multiple of the gcd of a and b which is 1 (since they are +relative prime) +``` + +### Blue-Eyes Island + +A bunch of people are living on an island, when a visitor comes with a strange order: all blue eyed people must leave the island as soon as possible. There will be a flight out at 8 pm every evening. Each person can see everyone else's eye color, but they do not know their own \(nor is anyone allowed to tell them\). Additionally they do not know how many people have blue eyes, although they do know that at least one person does. How many days will it take the blue-eyed person to leave? + +```text +Assume there are n people in island and b have b eyes + +Case b = 1: (exactly 1 person has blue eyes) +Everyone knows, atleast 1 has blue eyes and special person will see no one else +having blue eyes so he will assume he has so he will leave that evening. + +Case b = 2: (exactly 2 persons have blue eyes) +Two special people see each other, but are unsure whether b is 1 or 2. So they +do nothing next day if they meet again means that b is not 1 since if it was +then the person would have left. so b = 2. Which means he himself has blue eyes + +Case b > 2: (General case) +Say if b = k then those k people will immediately know that there are either k +or k-1 people with blue eyes. If there were k-1 then those would have left on +second night. So it follows dp relation. For b blue eyes it will take b nights. +``` + +### The Apocalypse + +In the new post-apocalyptic world, the world queen is desperately concerned about the birth rate. Therefore, she decrees that all families should ensure that they have one girl or else they face massive fines. If all families abide by this policy - that is, they have continue to have children until they have one girl, at which point they immediately stop - what will be the gender ratio of the new generation be? \(Assume that the odds of someone having a boy or girl on any given pregnancy is equal\) + +```text +G -> 1/2 +BG -> 1/4 +BBG -> 1/8 +Infinite GP sum giving 1. This would mean that gender ratio is even +Families on an avg contribute exactly 1 boy and 1 girl. + +It's wrong to think that way. Biology hasn't been changed. Half +of newborn babies are boys and girls abiding by some rule about +when to stop having children doesn't change this fact. + +Concatenate all house hold data G - BBG - BBBBG on a whole it seems +just as probable as new born baby prob. + +Therefore gender ratio is 50-50 + +We can simulate this on C++, for larger values it should give 0.5 +probability +``` + +### 100 Lockers + +There are 100 closed lockers in a hallway. A man begins by opening all 100 lockers. Next, he closes every second locker. Then, on his third pass, he toggles every third locker. This process continues for 100 passes, such that one pass i, the man toggles every ith locker. After his 100th pass in the hallway, in which he toggles only locker \#100, how much lockers are open. + +```text +For door 100 its: +1 - on +2 - off +3 - off +4 - on +It will toggle for every factor +cnt_of_factors&1 == 1 means door is open + +cnt_of_factors is odd when x(100) is a perfect square) + +so there are 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 +10 perfect square so 10 lockers will be open in the end +``` + +### Poison + +You have 1000 bottles of wine, and one them is poisoned. To test you let rats drink it. Minimize number of rats. + +```text +Way 1 (999 Rats) drink one of bottle, if out of those one dies means +that bottle was poisoned, if no one dies means 100th bottle which +wasn't tested was poisoned + +Way 2 (32 rats) Divide search space by say half so we need 500 rats +each will taste 2 wines. If a kth rat dies means 2*k or 2*k+1 could +be that bottle so we will need additional to check those 2 bottles +so we need 1 rat, making 501 +Generalising it: +-> require 1000/k + (k-1) rats + +Let's find out minima of above function: +yk = 1000 + k^2 - k ....(i) +differentiate both sides and put dy/dk = 0 +we will get k = (1+y)/2 ....(ii) +put this in eq i and solving quadratic equation: +y^2 + 2y - 3999 = 0 we get y = 62.246 putting in ii we get +k = 32 (take integer ignore fraction) +so we need 32 rats + +Way 3 (log2(1000) rats) Why 32 in above? Let's denote each wine in +binary: +00001 -> feed to 1st rat +00010 -> feed to 2nd rat +00011 -> feed to 1st and 2nd rat +00100 -> feed to 3rd rat +00101 -> feed to 1st and 3rd rat +00110 -> feed to 2nd and 3rd rat +00111 -> feed to 1st, 2nd and 3rd rat + +If a wine x is poisned then all it's set bit rats must be dead +``` + diff --git a/range-queries.md b/range-queries.md new file mode 100644 index 0000000..53e467f --- /dev/null +++ b/range-queries.md @@ -0,0 +1,351 @@ +# Range Queries + +## Prefix Sum + +## Prefix XOR + +## Difference Array + +## Sparse Table + +Every positive integer can easily be represented as a sum of powers of 2 given by its decimal representation. Similarly, any interval \[l, r\] can be broken down into smaller intervals of powers of 2. + +![](.gitbook/assets/image%20%28138%29.png) + +Now imagine if we could precompute the range query answer for all those intervals and combine them. Precompute answers for all intervals of size 2^x + +It can query in logarithmic time but for overlap friendly functions i.e. f\(f\(a, b\), f\(b, c\)\) = f\(a, f\(b, c\)\) it can do it in constant time. + +![Highlighted ones are overlap friendly](.gitbook/assets/image%20%2863%29.png) + +**Building:** dp\[i\]\[j\] = min of array from i to i + 2^j. j goes from 0 till floor\(log2\(n\)\) + +![](.gitbook/assets/image%20%28122%29%20%281%29.png) + +![](.gitbook/assets/image%20%2833%29.png) + +![](.gitbook/assets/image%20%2860%29%20%281%29.png) + +```cpp +int st[MAXN][K + 1]; +// Build O(NlogN): here f is function of operation like sum or min +for (int i = 0; i < N; i++) st[i][0] = f(array[i]); +for (int j = 1; j <= K; j++) + for (int i = 0; i + (1 << j) <= N; i++) + st[i][j] = f(st[i][j-1], st[i + (1 << (j - 1))][j - 1]); + +// Sum query: O(logN) +int sm = 0; +for (int j = p; j >= 0; --j) + if ((1 << j) <= R-L+1) { sm += st[L][j]; L += (1<= l; --i) sparseTable[lvl][i] = func(sparseTable[lvl][i+1], arr[i])%p; + if (m+1 < r) + { + sparseTable[lvl][m+1] = arr[m+1]%p; + for (int i = m+2; i < r; ++i) sparseTable[lvl][i] = func(sparseTable[lvl][i-1], arr[i])%p; + } + if (l+1 != r) { build(lvl+1, l, m); build(lvl+1, m, r); } +} +int query(int L, int R) +{ + if (L == R) return arr[L]%p; + int k = __builtin_clz(L^R) ^ 31; + int lvl = maxLvl - 1 - k; + int res = sparseTable[lvl][L]; + if (R & ((1<> n; + for (int i = 0; i < n; ++i) cin >> arr[i]; + INIT; + build(); + int q; cin >> q; + while (q--) + { + int l, r; cin >> l >> r; + bug(l, r); + cout << query(l, r) << '\n'; + } + return 0; +} +``` + +## Fenwick Tree + +It is used to calculate prefix sum of an array. It's not as powerful as Segment Tree but it's simpler to implement. + In the image, BIT will be stored in array of n+1 length. \(indexing starts with 1 because binary operation used later on will be anomoly for 0\) for each say 3 find 3 & -3 this will flip right most set bit giving the parent from tree. +Now to fill all value say 4 we find 4 = 0 + 2^2 means we go from 0th index to next 4 elements or for 11 = 2^3 + 2^1 + 2^0 from 10-10 ![](res/BIT.png) + If we need to find sum from 0 to 5 we first go to value 6 take it here it's 9 then we go to it's parent it's 10 so ans is 19 + +![In BIT: say 4th element is responsible for 1-4 elements \(last set bit\)](.gitbook/assets/image%20%2880%29.png) + +```cpp +void update(int BIT[], int n, int i, int incr) +{ + while (i <= n) + { + BIT[i] += incr; + i += (i & -i); + } +} +int query(int BIT[], int n, int i) +{ + int ans = 0; + while (i > 0) + { + ans += BIT[i]; + i -= (i & -i); + } + return ans; +} +``` + +### Binary Search in BIT + +Given a data of heights: \[1, 8\] \[2, 2\] \[3, 10\] \[4, 100\] \[5, 1\] \[6, 2\] Basically 8 peoples are of height 1, 2 of height 2, 10 of height 3 and so on. We can query to determine the kth tallest person. Or we can update number of people count for a particular height. + +![](.gitbook/assets/image%20%28143%29.png) + +Approach \#1: For query we can apply binary search, so check middle height say 3 then find it's count using fenwick tree and so on. It will be O\(nlogn\) + +Approach \#2: Given below is how the fenwick tree will look like. Start off with the highest bit on which is 16 then check middle which can be find by right shifting again check refer diagram. O\(logn\) + +![](.gitbook/assets/image%20%2843%29%20%281%29.png) + +### Above the Median + +Given an array representing height of ith member. We need find count of possible subarrays such that there median \(a\[ceil\(n/2\)\]\) is greater than or equal to x. + +Example: \[10, 5, 6, 2\] x = 6 +Answer is: 7 => {10}, {6}, {10, 5}, {5, 6}, {6, 2}, {10, 5, 6}, {10, 5, 6, 2}. + +We can replace element in arr with 1 if it's >= x and -1 if it's less +\[1, -1, 1, -1\] +Now our problem is reduced to finding subarrays with non-negative sum. +Calculate prefix sum +\[1, 0, 1, 0\] +Now we basically want to find L & R such that p\[R\] - p\[L\] is >= 0 this simply reduces down to inversion count problem. + +### Read Single Element + +* Simply do BIT\[i\] - BIT\[i-1\] but it will be 2logn Time +* Maintain an array storing actual elements as well N space +* Third way is based on the fact that when we do BIT\[i\] - BIT\[i-1\] both i and i-1 will eventually converge at a point which may be zero + +```cpp +int readSingle(int i) +{ + int sum = BIT[i]; + if (i > 0) + { + int z = i - (i & -i); + i--; + while (i != z) sum -= BIT[i], i -= (i & -i); + } + return sum; +} +``` + +### Find index with given cumulative frequency + +Naive way is to iterate keep having cumulativeFreq in logN and check linearly which will be Nlogn. In case of negative frequencies that's the only way. In non-negative scenario we can use binary search modification making it just logN. + +```cpp +int find(int cumFreq, int n) +{ + int i = 0; + int bitMask = (int)(pow(2, (int)(log2(n)))); + while (bitMask) + { + int temp = i + bitMask; + bitMask >>= 1; + if (temp > n) continue; + if (cumFreq == BIT[temp]) return temp; + else if (cumFreq > BIT[temp]) i = temp, cumFreq -= BIT[temp]; + } + if (cumFreq != 0) return -1; + else return i; +} +``` + +### 2D BIT + +Say you have a plane with dots \(with non-negative coordinates\) There are three queries. + +* Set a dot at \(x, y\) +* Remove the dot from \(x, y\) +* Count the number of dots in rectangle \(0, 0\) \(x, y\) - \(down-left and top-right corner\) + +```cpp +void update(int x, int y, int val) +{ + while (x <= MAX_X) + { + int _y = y; + while (_y <= MAX_Y) + BIT[x][_y] += val, _y += (_y & -_y); + x += (x & -x); + } +} +void query(int x, int y) +{ + int sum = 0; + while (x) + { + int _y = y; + while (_y) + sum += BIT[x][_y], _y -= (_y & -_y); + x -= (x & -x); + } + return sum; +} +``` + +### Range Update & Range Query + +```cpp +const int N = 1005; +vector BIT1(N), BIT2(N); +void update(vector &BIT, int i, int val) +{ + while (i <= N) + { + BIT[i] += val; + i += (i & -i); + } +} +int query(vector &BIT, int i) +{ + int sm = 0; + while (i) + { + sm += BIT[i]; + i -= (i & -i); + } + return sm; +} +int summation(int x) { return ((query(BIT1, x)*x) - query(BIT2, x)); } // sum of [1, x] +int queryRange(int l, int r) { return summation(r) - summation(l-1); } // query [l, r] +void updateRange(int l, int r, int val) // update [l, r] +{ + update(BIT1, l, val); update(BIT1, r+1, -val); + update(BIT2, l, val*(l-1)); update(BIT2, r+1, -val*r); +} +``` + +## Wavelet Trees + +```cpp +#undef int +const int MAXN = 3e5 + 10; +const int MX = 1e6; +int arr[MAXN]; +struct wavelet_tree +{ +private: + int lo, hi; + wavelet_tree *l, *r; + vec<1, int> b; + +public: + wavelet_tree(int *from, int *to, int x, int y) + { + lo = x, hi = y; + if (lo == hi || from >= to) return; + int mid = (lo + hi)/2; + auto f = [mid](int x){ return x <= mid; }; + b.reserve(to - from + 1); b.push_back(0); + for (auto it = from; it != to; it++) b.push_back(b.back() + f(*it)); + auto pivot = stable_partition(from, to, f); + l = new wavelet_tree(from, pivot, lo, mid); + r = new wavelet_tree(pivot, to, mid+1, hi); + } + + ~wavelet_tree() + { + delete l; + delete r; + } + + int kthSmallest(int l, int r, int k) // [l, r] + { + if (l > r) return 0; + if (lo == hi) return lo; + int inLeft = b[r] - b[l-1], lb = b[l-1], rb = b[r]; + if (k <= inLeft) return this->l->kthSmallest(lb+1, rb, k); + return this->r->kthSmallest(l-lb, r-rb, k-inLeft); + } + + int lessThanEqualToK(int l, int r, int k) // [l, r] + { + if (l > r or k < lo) return 0; + if (hi <= k) return r - l + 1; + int lb = b[l-1], rb = b[r]; + return this->l->lessThanEqualToK(lb+1, rb, k) + this->r->lessThanEqualToK(l-lb, r-rb, k); + } + + int equalToK(int l, int r, int k) // [l, r] + { + if (l > r or k < lo or k > hi) return 0; + if (lo == hi) return r - l + 1; + int lb = b[l-1], rb = b[r], mid = (lo+hi)/2; + if (k <= mid) return this->l->equalToK(lb+1, rb, k); + return this->r->equalToK(l-lb, r-rb, k); + } +}; +/* + // CODE + int n; cin >> n; + for (int i = 1; i <= n; ++i) cin >> arr[i]; + wavelet_tree T(arr+1, arr+n+1, 1, MX); + int q; cin >> q; + while (q--) + { + int t, l, r, k; cin >> t >> l >> r >> k; + if (t == 1) cout << "kthSmallest [" << l << "," << r << "]: " << T.kthSmallest(l, r, k) << '\n'; + else if (t == 2) cout << "lessThanEqualToK [" << l << "," << r << "]: " << T.lessThanEqualToK(l, r, k) << '\n'; + else if (t == 3) cout << "equalToK [" << l << "," << r << "]: " << T.equalToK(l, r, k) << '\n'; + } + + // INPUT -> OUTPUT + 7 + 1 2 3 3 5 4 2 + 4 + 1 5 7 1 1thSmallest [5,7]: 2 + 1 5 7 2 2thSmallest [5,7]: 4 + 2 2 6 4 lessThanEqualTo4 [2,6]: 4 + 3 2 5 3 equalTo3 [2,5]: 2 +*/ +``` + +## Segment Tree + +## Square Root Decomposition + diff --git a/searching.md b/searching.md new file mode 100644 index 0000000..8c54808 --- /dev/null +++ b/searching.md @@ -0,0 +1,883 @@ +# Searching + +## Complete Search + +The idea is to generate all possible solutions to the problem using brute force, and then select the best solution or count the number of solutions, depending on the problem. + +```cpp +// Generating subsets +void search(int k) +{ + if (k == n) // process subset + else + { + search(k+1); + subset.push_back(k); + search(k+1); + subset.pop_back(); + } +} + +// Generating subsets - Iterative (using bitmanipulation) +for (int i = 0; i < (1< permutation(n); +for (int i = 0; i < n; ++i) permutation[i] = i+1; +do +{ + // Process permutation +} while(next_permutation(permutation.begin(), permutation.end())); +``` + +## Backtracking + +Smart Complete Search + +```cpp +// N queens problem +void search(int y) +{ + if (y == n) { found++; return; } + for (int x = 0; x < n; ++x) + { + if (col[x] || diag1[x+y] || diag2[x-y+n-1]) continue; + col[x] = diag1[x+y] = diag2[x-y+n-1] = true; + search(y+1); + col[x] = diag1[x+y] = diag2[x-y+n-1] = false; + } +} +/* Let q(n) be ans for n. +There is no known way to efficiently calculate larger values of q(n). +The current record is q(27) = 234907967154122528 */ +``` + +## Pruning the Search + +We can often optimize backtracking by pruning the search tree. The idea is to add ”intelligence” to the algorithm so that it will notice as soon as possible if a partial solution cannot be extended to a complete solution. + +Let us consider the problem of calculating the number of paths in an n x n grid from upper-left corner to lower-right corner such that the path visits each square exactly once. + +![For 7x7 there are 111712 such paths](.gitbook/assets/image%20%2839%29.png) + +* Optimization 1 \(Simple backtracking\) **Running time 783 seconds, 76 billion Recursive calls** +* Optimization 2 \(If path reaches lowest right square before it has visited all other squares of the grid, it is clear that it will not be possible to complete the solution. **Running time 119 seconds, 20 billion Recursive calls** + +![Terminate search immediately if we reach lower-right square too early](.gitbook/assets/image%20%2823%29.png) + +* Optimization 3 \(If path touches the wall it can either go left or right in that split two-part case one part will get unvisited\) **Running time 1.8 seconds, 221 million Recursive calls** + +![](.gitbook/assets/image%20%2882%29.png) + +* Optimization 4 \(Idea of previous optimization can be genralized: if path cannot continue forward but can turn either left or right, the grid splits into two pat that both contain unvisited squares\) **Running time 0.6 seconds, 69 million Recursive calls** + +> Optimzation made it over 1000 times faster now + +## Meet in the middle + +Meet in the middle is a technique where the search space is divided into two parts of about equal size. A separate search is performed for both of the parts, and finally the results of the searches are combined. + +For example, suppose that the list is \[2,4,5,9\] and x = 15. First, we divide the list into A = \[2,4\] and B = \[5,9\]. After this, we create lists SA = \[0,2,4,6\] and SB = \[0,5,9,14\]. \(SA is total subset sum possible in A\) Next we can find original problem solution by using hashmap SA\[i\] + SA\[j\] = targ. + +This makes the complexity O\(2^\(n/2\)\) which is also O\(root 2^n\) + +## Binary Search + +```cpp +// Simple style +int l = 0, r = n-1; +while (l <= r) +{ + int mid = l + (r-l)/2; + if (arr[mid] == x) return true; + if (arr[mid] > x) r = mid-1; + else l = mid+1; +} +return false; + +// Constraint-bound style +int l = 0, r = n-1; +while (l < r) +{ + int mid = l + (r-l)/2; + if (check(mid)) l = mid+1; + else r = mid; +} +return l; + +/* Jump-based style +Idea is to make jumps and slow the speed when we get closer to the target +element. Search goes from left to right, and initial jump length is n/2. +At each step, the jump length is halved. After the jump either the target +element has been found or we know that it does not appear in the array. */ +int j = 0; +for (int i = n/2; i >= 1; i /= 2) +{ + while (i+j < n && arr[i+j] <= x) // run atmost twice + j += i; +} +return (arr[j] == x); +``` + +### Unbounded Binary Search + +Consider that there's a monotonically increasing function f\(x\) with f\(0\) some negative value we need to find some value n for which f\(n\) will be the first non negative number of the function. +Naive approach is linearly searching till we get number greater than 0, it will take O\(n\) +Other approach is using Unbounded Binary Search. The idea is to proceed with f\(0\) then f\(1\) f\(2\) f\(4\) f\(8\) f\(16\) ... till f\(x\) every other is ''''''''''''''''''''''x2 of previous. Now f\(x\) is first non negative in the above exponentiated series. Now we need to apply binary search from O\(x/2\) to O\(x\) x/2 is previous term of the series. This will give a time complexity of O\(logn\) + +### STL Implementations + +Following STL functions revolve around binary search \(assumption array is sorted\): + +* lower\_bound: first array element whose value is at least x +* upper\_bound: first array element whose value is larger than x +* equal\_range: returns both above pointers + +```cpp +auto a = lower_bound(array, array+n, x); +auto b = upper_bound(array, array+n, x); +cout << b-a << "\n"; + +auto r = equal_range(array, array+n, x); +cout << r.second-r.first << "\n"; +// Both are equivalent +``` + +## [Codeforces Edu - Binary Search](https://codeforces.com/edu/course/2/lesson/6) + +### [Step 1 A - Binary Search](https://codeforces.com/edu/course/2/lesson/6/1/practice/contest/283911/problem/A) + +```cpp +int n, k; cin >> n >> k; +vector arr(n); +for (auto &x : arr) cin >> x; +while (k--) +{ + int x; cin >> x; + int l = 0, r = n-1; + bool found = false; + while (l <= r) + { + int mid = l + (r-l)/2; + if (arr[mid] == x) { found = true; break; } + if (arr[mid] > x) r = mid-1; + else l = mid+1; + } + if (found) cout << "YES\n"; + else cout << "NO\n"; +} +``` + +### [Step 1 B - Closest to the Left](https://codeforces.com/edu/course/2/lesson/6/1/practice/contest/283911/problem/B) + +```cpp +int n, k; cin >> n >> k; +vector arr(n); +for (auto &x : arr) cin >> x; +while (k--) // k queries of how many numbers > x in arr +{ + int x; cin >> x; + int l = 0, r = n, res = 0; + while (l < r) + { + int mid = l + (r-l)/2; + if (arr[mid] <= x) l = mid+1, res = mid+1; + else r = mid; + } + cout << res << '\n'; +} +``` + +### [Step 1 C - Closest to the Right](https://codeforces.com/edu/course/2/lesson/6/1/practice/contest/283911/problem/C) + +```cpp +int n, k; cin >> n >> k; +vector arr(n); +for (auto &x : arr) cin >> x; +while (k--) // k queries of how many numbers atleast x in arr +{ + int x; cin >> x; + int l = 0, r = n, res = n+1; + while (l < r) + { + int mid = l + (r-l)/2; + if (arr[mid] >= x) r = mid, res = mid+1; + else l = mid+1; + } + cout << res << '\n'; +} +``` + +### [Step 1 D - Fast search](https://codeforces.com/edu/course/2/lesson/6/1/practice/contest/283911/problem/D) + +```cpp +int n; cin >> n; +vector arr(n); +for (auto &x : arr) cin >> x; +sort(arr.begin(), arr.end()); + +auto cnt = [&](int x) +{ + int l = 0, r = n, res = 0; + while (l < r) + { + int mid = l + (r-l)/2; + if (arr[mid] > x) r = mid; + else l = mid+1, res = mid+1; + } + return res; +}; + +int k; cin >> k; // Given k queries find count of numbers b/w [L,R] in arr +while (k--) +{ + int L, R; cin >> L >> R; + cout << (cnt(R) - cnt(L-1)) << ' '; +} +cout << '\n'; +``` + +### [Step 2 A - Packing Rectangles](https://codeforces.com/edu/course/2/lesson/6/2/practice/contest/283932/problem/A) + +```cpp +int w, h, n; cin >> w >> h >> n; +auto check = [&](int x) { return ((x/w) * (x/h) >= n); }; + +int l = 0, r = 1; +while (!check(r)) r *= 2; +while (l+1 < r) +{ + int mid = l + (r-l)/2; + if (!check(mid)) l = mid; + else r = mid; +} +cout << r << '\n'; +``` + +### [Step 2 B - Ropes](https://codeforces.com/edu/course/2/lesson/6/2/practice/contest/283932/problem/B) + +```cpp +const double EPS = 1e-6; +int n, k; cin >> n >> k; +vector arr(n); +for (auto &x : arr) cin >> x; +double l = 0, r = 1e9; +while (l + EPS < r) +{ + double mid = (l + r)/2; + int cnt = 0; + for (const int x : arr) cnt += x/mid; + if (cnt < k) r = mid; + else l = mid; +} +cout << setprecision(6) << fixed << l << '\n'; +``` + +### [Step 2 C - Very Easy Task](https://codeforces.com/edu/course/2/lesson/6/2/practice/contest/283932/problem/C) + +```cpp +int n, x, y; cin >> n >> x >> y; +auto check = [&](int v) +{ + v -= min(x, y); + if (v < 0) return (n == 0); + int copies = (n-1) - max(0LL, v/x) - max(0LL, v/y); + return (copies <= 0); +}; +int l = 0, r = 1; +while (!check(r)) r *= 2; +while (l+1 < r) +{ + int mid = (l + r)/2; + if (check(mid)) r = mid; + else l = mid; +} +cout << r << '\n'; +``` + +## Hashing + +> Searching takes O\(1\), Terminologies - Hashing, Hashfunction, Hashtable + +Hashfunction requirements - Uniformly distributed, Easy to compute, minimize collision. + +* **Division Method:** h\(k\) = k mod n where n is size of hashtable. +* **Folding Method:** divide in group of 2 and add like 123456 = 12+34+56 = 102 ignore 1 map it to 02 +* **Mid Square Method:** 125 square is 15625 taking mid 56 \(If non even digits then append zero at begining\) +* **MAD \(Multiplication Addition & Division\):** h\(k\) = \(a.k + b\) % n +* **Multiplication Method:** \(kA % 1\)\*n where A is golden ratio constant 0.618, 0 < A < 1 + +### Collision Resolution + +![](.gitbook/assets/image%20%28218%29.png) + +Closed Hashing \(Open Addressing\) - We don't utilize any thing extra then hash table everything is still mapped in it unlike linked list like ADT + +Open Hashing + +* Chaining: Using linked list like chain to store collisions. + +Closed Hashing H\(i\) = \(h\(k\) + f\(i\)\) % n + +* Linear Probing: f\(n\) = i +* Quadratic Probing: f\(n\) = i^2 + +We go for H\(0\) first if collision H\(1\) and so on. + +![Linear Probing](.gitbook/assets/image%20%28263%29.png) + +The main problem with linear probing is clustering, many consecutive elements form groups and it starts taking time to find a free slot or to search an element. + +> Modulo n where n is there in good hash functions so that collision reduces. + +## Solve Monotonically increasing functions + +[https://www.youtube.com/watch?v=Y2AUhxoQ-OQ](https://www.youtube.com/watch?v=Y2AUhxoQ-OQ) + +Given p, q, r, s, t, u we want to find x +p_e^-x + q_sin\(x\) + r_cos\(x\) + s_tan\(x\) + t\*x2 + u = 0 + +```cpp +#include +using namespace std; + +int p, q, r, s, t, u; +#define EPS 1e-7 +double f(double x) { return p*exp(-x) + q*sin(x) + r*cos(x) + s*tan(x) + t*x*x + u; } + +// Bisection method +double bisection() +{ + double l = 0, r = 1; + while (l + EPS < r) + { + double mid = (l + r)/2; + if (f(l) * f(mid) <= 0) r = mid; + else l = mid; + } + return (l + r)/2; +} +int main() +{ + while (cin >> p >> q >> r >> s >> t >> u) + { + // Here f is a non-increasing function [0,1] + // So if signs are same then no solution + if (f(0) * f(1) > 0) cout << "No solution\n"; + else cout << fixed << setprecision(4) << bisection() << '\n'; + } + return 0; +} + +// More efficient +double secant() +{ + if (f(0) == 0) return 0; + for (double x0 = 0, x1 = 1; ;) + { + double d = f(x1)*(x1-x0) / (f(x1)-f(x0)); + if (fabs(d) < EPS) return x1; + x0 = x1; + x1 = x1 - d; + } +} + +// Most efficient +double fd(double x) // derrivative of f(x) +{ + return -p*exp(-x) + q*cos(x) - r*sin(x) + s/(cos(x)*cos(x)) + 2*t*x; +} +double newton() +{ + if (f(0) == 0) return 0; + for (double x = 0.5; ;) + { + double x1 = x - f(x)/fd(x); + if (fabs(x1-x) < EPS) return x; + x = x1; + } +} +``` + +## Ternary Search + +Ternary Search is also there which is same as binary search except instead of dividing in 2 parts we divide it in 3 parts. +Binary search is better than ternary search because + T\(n\) = T\(n/2\) + 2 \[In Binary Search\] + T\(n\) = T\(n/3\) + 4 \[In Ternary Search\] + in binary search: $$2log_2n$$ complexity while in ternary search:$$4log_3n$$ calculating mathematically binary search is better. + +> Ternary search can find value for a bell shaped curve \(unimodal function\) + +## Additional Questions + +### Duplicate Number problem + +* Given array containing n+1 numbers of range: 1 to n \(inclusive\). There's 1 duplicate find it. + +```cpp +/* bruteforce (n^2) -> sorting (nlogn) -> hashing (requires space) +To do in O(1) space we want to store hashing info to the array itself. +Given range 1 to n and there are n+1 numbers we can maybe make a number +negative. + +We can also get summation sm - n(n+1)/2 */ +for (const int x : nums) +{ + if (nums[abs(x)-1] < 0) return abs(x); + nums[abs(x)-1] *= -1; +} + +/* If we are not allowed to modify the array, cycle detection +extending upon previous idea only [1, 2, 3, 4, 2] 1 points to ind 1, 2 to ind 2 +1 -> 2 -> 3 -> 4 -> 2 + | | + ---------- +cycle exists means thats the duplicate, using floyd cycle detection algo */ +int slow = nums[0], fast = nums[nums[0]]; +while (slow != fast) { slow = nums[slow]; fast = nums[nums[fast]]; } +fast = 0; +while (slow != fast) { slow = nums[slow]; fast = nums[fast]; } +return slow; +``` + +* Now more than 1 elements can occur twice others once. Find all such duplicate numbers + +```cpp +// Above idea only +vector res; +for (const int x : nums) +{ + if (nums[abs(x)-1] < 0) + res.push_back(abs(x)); + else + nums[abs(x)-1] *= -1; +} +return res; + +/* Extending above cycle detection idea. Instead of keeping visited +we are kinda caching it with cycling swaps. */ +vector res; +for (int i = 0; i < nums.size(); ++i) +{ + while (nums[i] != i+1 && nums[i] != nums[nums[i]-1]) + swap(nums[i], nums[nums[i]-1]); // swaping makes code O(N) time +} +for (int i = 0; i < nums.size(); ++i) + if (nums[i] != i+1) res.push_back(nums[i]); +return res; +``` + +* Find one duplicate in sorted array, with \[0, n\] numbers \(no number in between is missing\) + +```cpp +int l = 0, r = n - 1; +while (l < r) +{ + int mid = l + (r - l) / 2; + if (arr[mid] == mid + 1) l = mid+1; + else + { + if (mid > 0 && arr[mid] == arr[mid-1]) return mid; + r = mid-1; + } +} +``` + +### [Peak Element](https://leetcode.com/problems/find-peak-element) + +```cpp +int findPeakElement(vector &nums) +{ + int l = 0, r = nums.size() - 1; + while (l < r) + { + int mid = l + (r - l) / 2; + if (nums[mid] > nums[mid + 1]) r = mid; + else l = mid + 1; + } + return l; +} +``` + +### Square root of a number + +```cpp +int Solution::sqrt(int A) +{ + if (A == 0) return 0; + if (A == 1 || A == 2 || A == 3) return 1; + int l = 0, r = A, ans = -1; + while (l < r) + { + int mid = l + (r - l) / 2; + if (mid <= A / mid) l = mid + 1, ans = mid; + else r = mid; + } + return ans; +} +``` + +### [First and Last position of elements in sorted array](https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/) + +```cpp +class Solution +{ +public: + int lower_bound(vector &nums, int target) + { + int l = 0, r = nums.size() - 1; + if (nums[r] < target) return r + 1; + while (l < r) + { + int mid = l + (r - l) / 2; + if (nums[mid] < target) l = mid + 1; + else r = mid; + } + return l; + } + vector searchRange(vector &nums, int target) + { + if (nums.size() == 0) + return {-1, -1}; + int idx1 = lower_bound(nums, target); + int idx2 = lower_bound(nums, target + 1) - 1; + if (idx1 < nums.size() && nums[idx1] == target) return {idx1, idx2}; + else return {-1, -1}; + } +}; +``` + +### Rotated Sorted Array Search + +```cpp +/* If we look at middle, either all left side is sorted or right one is. +We can check that by checking first and last element of the partition */ +bool search(vector &nums, int target) +{ + int l = 0, r = nums.size() - 1; + while (l <= r) + { + int mid = l + (r - l) / 2; + if (nums[mid] == target) return true; + // If there can be duplicates then add this cond. + // Eg: [3 1 2 3 3 3 3] + if (nums[l] == nums[mid] && nums[r] == nums[mid]) ++l, --r; + else if (nums[l] <= nums[mid]) + { + if (nums[l] <= target && nums[mid] >= target) r = mid - 1; + else l = mid + 1; + } + else + { + if (nums[mid] <= target && nums[r] >= target) l = mid + 1; + else r = mid - 1; + } + } + return false; +} +``` + +### Minimum in rotated sorted array + +```cpp +int findMin(vector &nums) +{ + int l = 0, r = nums.size() - 1; + while (l < r) + { + if (nums[l] < nums[r]) + return nums[l]; + int mid = l + (r - l) / 2; + if (nums[mid] > nums[r]) l = mid + 1; + else r = mid; + // In case of equal instead of else, these 2 lines: + else if (nums[mid] < nums[l]) r = mid, l++; + else r--; + } + return nums[l]; +} +``` + +### [Matrix Median](https://www.interviewbit.com/problems/matrix-median/) + +```cpp +/* Binary search from min to max element of the matrix +upper bound works on sorted array only it tells how many +elements are lesser then or equal to specified Toh we check +mid se kam kitne elements he humeshaa +[1, 3, 5][2, 6, 9][3, 6, 9] +l = 1 r = 9 mid = 5 +cur = 3 + 1 + 1 = 5 +l = 1 r = 5 mid = 3 +cur = 2 + 1 + 1 = 1 +l = 4 r = 5 mid = 4 +cur = 2 + 1 + 1 = 4 +l = 5, r = 5 = ans 5(n*m+1)/2 is 5 which signifies upperbound +must be 5 for median but if matrix is like [[1, 1, 3, 3, 3, 3]] +our check for upperbound of 3 will not be (m*n+1)/2 although +it is clearly the median. But it clear if cur is greater then +count then our answer must be from l to mid and reverse in vice versa. */ + +int Solution::findMedian(vector> &A) +{ + int l = INT_MAX, r = INT_MIN; + for (auto x : A) + for (int i : x) + l = min(l, i), r = max(r, i); + while (l < r) + { + int mid = l + (r - l) / 2; + int places = 0; + for (auto x : A) + places += upper_bound(x.begin(), x.end(), mid) - x.begin(); + if (places < ((A.size() * A[0].size()) + 1) / 2) + l = mid + 1; + else + r = mid; + } + return l; +} +/* Suppose there's a very big array which cannot be stored as +one but only as 100 different arrays in sorted order each. +find the median of it as one collective array. The answer is to +treat it like a matrix and then simply do it. */ +``` + +### [Median of two sorted arrays](https://leetcode.com/problems/median-of-two-sorted-arrays/) + +```cpp +class Solution { +public: + double solve(const vector &A, const vector &B, int l, int r, int count) + { + while (l < r) + { + // using mid = (l+r)/2 can cause TLE in case [0,0,0,0,0] [-1,0,0,0,0,0,1] + // because division of negative i.e. (l+r)/2 can act in reverse sense of floor + // l + (r-l)/2 on the other hand divides positive r-l which is always positive + int mid = l + (r-l)/2; + int cnt = (upper_bound(A.begin(), A.end(), mid) - A.begin()) + + (upper_bound(B.begin(), B.end(), mid) - B.begin()); + if (cnt > count) r = mid; + else l = mid+1; + } + return l; + } + double findMedianSortedArrays(vector& nums1, vector& nums2) + { + int n = nums1.size(), m = nums2.size(); + if (n == 0 && m == 0) return 0; + else if (m == 0) return (n&1) ? nums1[n/2] : (nums1[n/2 - 1] + nums1[n/2])/(double)2; + else if (n == 0) return (m&1) ? nums2[m/2] : (nums2[m/2 - 1] + nums2[m/2])/(double)2; + + int l = min(nums1[0], nums2[0]), r = max(nums1.back(), nums2.back()); + return ((n+m)&1) ? solve(nums1, nums2, l, r, (n+m)/2) : + (solve(nums1, nums2, l, r, (n+m)/2 - 1) + solve(nums1, nums2, l, r, (n+m)/2)) / (double)2; + } +}; +``` + +### [Painter's Partition Problem](https://www.interviewbit.com/problems/painters-partition-problem/) + +```cpp +/* Given boards and we have 3 painters: 100 200 300 400 500 | 600 700 | 800 900 +This way each painter would have to: 1500 | 1300 | 1700 so variance is less +Way like calculating total paint and then dividing by k and trying to match +each partition as close to it could not evaluate all possibilities systematically +and thus do not always produce the correct solution. */ +int partition(vector &arr, int &k, int cur = 0, int cnt = 0) +{ + if (cnt > k) return INT_MAX; + if (cur == arr.size()) + return (cnt == k ? 0 : INT_MAX); + int sm = 0, res = INT_MAX; + for (int i = cur; i < arr.size(); ++i) + { + sm += arr[i]; + res = min(res, max(sm, partition(arr, k, i+1, cnt+1))); + } + return res; +} +// It's O(K N^2) after memoization + +// Binary Search Approach O(N log(sum of arr)) +/* example - [1, 2, 3, 4, 5, 6, 7, 8, 9] +9-------45 +low high +low is when there are n painters. high is when there is 1 painter +find mid = 27 find what mid corresponds to 1+2+3+4+5+6 and 7+8+9 this way array partitions +such that parts sum is less then mid. (2 parts) +6------2------1 +low mid high +apply binary search on low and mid */ + +#define ll long long +bool isPossible(int painters, vector &boards, int val) +{ + ll count = 1, sum = val, i = 0; + while (i < boards.size()) + { + if (sum - boards[i] < 0) + sum = val, count++; + else + sum -= boards[i++]; + if (count > painters) + return false; + } + return true; +} +int Solution::paint(int A, int B, vector &C) +{ + ll l = 0, r = accumulate(C.begin(), C.end(), 0); + while (l < r) + { + int mid = l + (r - l) / 2; + if (isPossible(A, C, mid)) + r = mid; + else + l = mid + 1; + } + return (l * B) % 10000003; +} +``` + +## Codeforces + +* [Maximum Median](https://codeforces.com/contest/1201/problem/C): [https://codeforces.com/contest/1201/submission/76923324](https://codeforces.com/contest/1201/submission/76923324) +* [Mafia:](https://codeforces.com/contest/348/problem/A) In a game in one round there is 1 moderator and rest n-1 people are player. Given an array of n people signifying times they want to be player. Tell minimum number of games they must play to fulfil that condition of atleast playing ai times. **Solution:** [https://codeforces.com/contest/348/submission/76647058](https://codeforces.com/contest/348/submission/76647058) +* [Multiplication Table](https://codeforces.com/contest/448/problem/D) - Easy binary search, initially our search space l = 1, r = n\*m signifies our answer can be anything between 1 to n\*m we are searching over value. For every mid we find count of items by iterating over row and finding <= mid count **Solution:** [https://codeforces.com/contest/448/submission/74697633](https://codeforces.com/contest/448/submission/74697633) +* [Hamburgers](https://codeforces.com/problemset/problem/371/C) - Given a string denoting recipe of hamburger B means bun S means Sausage and C means cheese in order L to R. We already have nb ns nc amount already and can purchase addition at cost pb ps pc. What is maximum hamburger we can make given we have r amount. **Solution**: n\[i\] + x = cur \* cnt\[i\], here cnt is cnt of that item required and x is additional item we want. We want to make cur amount of hamburger and want to see if it's possible. x = \(cur\*cnt\[i\] - n\[i\]\) \* p\[i\] will give additional cost we have to spend. Take care of case when that item is not at all reqd \(cnt\[i\] = 0\) and difference is negative. Finally also take care of binary search range, you cant make r 1e18 otherwise calculation will give ll overflow. [https://codeforces.com/contest/371/submission/74009612](https://codeforces.com/contest/371/submission/74009612) +* [Present](https://codeforces.com/contest/460/problem/C) - Given 3 integers n, m, w and an array of n numbers denoting height of ith plant. We can choose a subsegment of length w and increase height by 1 it will require one operation \(-1 of m\) find maximal \(minimum height\) across array we can get. **Solution:** Apply binary search on value \(x means we can form that maximal minimum height\) Now check if it's possible. This part is main, reqd holds how much operation that element required and cur is carry over operation from previous subsegment. Pure greedy strategy. [https://codeforces.com/contest/460/submission/76685479](https://codeforces.com/contest/460/submission/76685479) +* [Renting Bikes](https://codeforces.com/contest/363/problem/D) - Given n, m, a : denoting n peoples m bikes available for renting and a \(shared money they have\) An array b denotes personal money ith person has. Another array p represents price of bike. What minimum sum of personal money will they have to spend in total to let as many schoolchildren ride bikes as possible? **Solution:** Greedy binary search type of problem. Check if we can give x people bikes \(sort bike based on price in asc while people in desc based on personal money\) Idea is for x person to have bike xth richest person must be able to afford it \(that's why such sorting\) then simple greedy check function. [https://codeforces.com/contest/363/submission/76699115](https://codeforces.com/contest/363/submission/76699115) +* [One-Dimensional Battle Ships](https://codeforces.com/contest/567/problem/D) - Given a 1 x n matrix where Alice placed k ships each of width a, there must be a gap of atleast 1 within each ship. Given m queries which bob will ask and Alice will tell if that place is a hit or miss, Alice always cheats and keep telling bob it's a miss find the first point at which Bob can tell Alice is lying. **Solution:** Binary search over the point which is our optimal answer point and check if it's optimal by using a fill like approach of simple dp. [https://codeforces.com/contest/567/submission/76719058](https://codeforces.com/contest/567/submission/76719058) +* [Memory for Arrays](https://codeforces.com/contest/309/problem/C) - Really a nice problem, Given two arrays a and b of size n and m respectively. Array a denotes free space which needs to be allocated by task in array b. Array b is in bit \(so 3 means it require 8 space\) If there are two processes of 2, 2 \(means require 8-8 space\) one block of 16 can be used there. Find maximum task we can finish. **Solution:** Create a allocation table with rows 0, 1, 2.. means 2^0 can fit how many in given situation then we can apply greedy in reverse manner keeping track of used space \(multiplying it by 2\) [https://codeforces.com/contest/309/submission/76757279](https://codeforces.com/contest/309/submission/76757279) +* [Degenerate Matrix](https://codeforces.com/contest/549/problem/H) - Solution involve finding a point x \(using binary search\) such that a +- x, b +- x, c +- x, d +- x denotes new matrix which should give determinant zero and d should be minimal. Now in the code we return true if det = 0 but for > 0 and < 0 we mark a variable true that's because simple det=0 will detect peak point we want to if x gives true then x-1 also give true in that case our condition will hold [https://codeforces.com/contest/549/submission/76795248](https://codeforces.com/contest/549/submission/76795248) +* [R2D2 and Droid Army](https://codeforces.com/contest/514/problem/D) - Solution involves binary search over optimal length using maximum window search technique using deque in linear time over each of 5 columns to see if it's possible to pick such length. [https://codeforces.com/contest/514/submission/76804227](https://codeforces.com/contest/514/submission/76804227) +* [New Year Snowmen](https://codeforces.com/contest/140/problem/C) - Binary Search over pair\_count and maximize it. Sort our array in ascending order and inside check function distribute numbers \(taken linearly\) from array to mid x 3 ans matrix in column major form such that mat\[i\]\[0\] < mat\[i\]\[1\] < mat\[i\]\[2\] is satisfied for all i. Call check function last time before printing values since some false check might have changed ans values. [https://codeforces.com/contest/140/submission/76955210](https://codeforces.com/contest/140/submission/76955210) +* [K-Dominant Character](https://codeforces.com/contest/888/problem/C) - Binary search to minimize optimal subarray length, now the problem becomes given a length x find if all string subarrays of that length has anything in common. Maintain a table storing frequency of characters for window ending at i \(of length x\) In the end we just need to check for each char if all of them are > 1 if none of 26 chars hold that that means there's nothing common. [https://codeforces.com/contest/888/submission/76990330](https://codeforces.com/contest/888/submission/76990330) +* [Road to Cinema](https://codeforces.com/contest/729/problem/C) - Binary search over volume \(from minVal-1 to maxVal+1 because while\(l+1 < r\) searches from \(l, r\) exclusive\) We want to see if we can make it with minimum volume fuel tank and then later pick the one corresponding to minimum price for that volume. Our check function sees adjacent distance. If dist > x i.e. distance is greater than available fuel we cannot reach otherwise min\(x, dist-x\) denotes minimum kilometers accelerated mode we used. So in the end checking it with time we have. [https://codeforces.com/contest/729/submission/77025244](https://codeforces.com/contest/729/submission/77025244) +* [Energy Exchange](https://codeforces.com/contest/68/problem/B) - Binary search over the final equalized values that we can make then check it by greedily iterating over desc order sorted array and performing operations. [https://codeforces.com/contest/68/submission/77031113](https://codeforces.com/contest/68/submission/77031113) +* [Three Base Stations](https://codeforces.com/contest/51/problem/C) - Binary search over the optimal value of d and try to minimize it, in check greedily place the tower right after \(+ d\) of an uncovered area. Do keep in mind that in `while (i < arr.size() && arr[i] < end)` Writing arr\[i\] <= end would have given WA because of weird floting point precision thing in c++ so check = condition in next line using abs and EPS logic. [https://codeforces.com/contest/51/submission/77035869](https://codeforces.com/contest/51/submission/77035869) +* [Frodo and Pillows](https://codeforces.com/contest/760/problem/B) - [https://codeforces.com/contest/760/submission/77058869](https://codeforces.com/contest/760/submission/77058869) +* [String Game](https://codeforces.com/contest/779/problem/D) - [https://codeforces.com/contest/779/submission/77066382](https://codeforces.com/contest/779/submission/77066382) +* [Success Rate](https://codeforces.com/contest/807/problem/C) - Interesting problem, new x is k\*p same with y, new y = k\*q. Applying binary search on k \(on anything else will not lead to monotonicity\) x' = p\*k = x + succ i.e. succ = p\*k - x simmilarly y' = q\*k = y + succ + unsucc i.e. unsucc = q\*k - y - succ [https://codeforces.com/contest/807/submission/77076898](https://codeforces.com/contest/807/submission/77076898) +* [Motorack's Birthday](https://codeforces.com/problemset/problem/1301/B) + +```cpp +/* Apply ternary search on values then replace every -1 with that +value and find corresponding adjacent element diff (we have to +minimize this) this function is bell shaped. */ +int solve(vector &arr, int x) +{ + int ans = 0; + for (int i = 1; i < arr.size(); ++i) + { + int p = (arr[i-1] == -1) ? x : arr[i-1]; + int q = (arr[i] == -1) ? x : arr[i]; + ans = max(ans, abs(p-q)); + } + return ans; +} +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t; + cin >> t; + while (t--) + { + int n; + cin >> n; + vector arr(n); + for (auto &x : arr) cin >> x; + int l = 0, r = 1e9; + while (l+3 <= r) + { + int a = l+(r-l)/3, b = r-(r-l)/3; + if (solve(arr, a) > solve(arr, b)) l = a; + else r = b; + } + int ans = solve(arr, l), pt = l; + for (int i = l+1; i <= r; ++i) + { + int cur = solve(arr, i); + if (cur < ans) ans = cur, pt = i; + } + cout << ans << " " << pt << '\n'; + } + return 0; +} +``` + +* [Mixing Water](https://codeforces.com/contest/1359/problem/C) - Given 3 values in each test case h, c, t. You can put hot cold hot cold order to minimize abs diff between final tmp and t. + +```cpp +// Apply ternary search to minimize the function +signed main() +{ + ios_base::sync_with_stdio(false); cin.tie(NULL); + int t; cin >> t; + while (t--) + { + double h, c, d; cin >> h >> c >> d; + auto func = [&](double mid) + { + double q = (mid*h + mid*c + h) / (2*mid + 1); + if (mid == 0) return fabs(q-d); + double p = (mid*h + mid*c) / (2*mid); + return min(fabs(p-d), fabs(q-d)); + }; + + int l = 0, r = 1e13; + while (l+1000 <= r) + { + int a = l + (r-l)/3, b = r - (r-l)/3; + if (func(a) > func(b)) l = a; + else r = b; + } + double ans = func(l); + int pt = l; + for (int i = l+1; i <= r; ++i) + { + double cur = func(i); + if (cur < ans) ans = cur, pt = i; + } + + double q = (pt*h + pt*c + h) / (2*pt + 1); + if (pt == 0) { cout << 2*pt+1 << "\n"; continue; } + double p = (pt*h + pt*c) / (2*pt); + if (fabs(p-d) < fabs(q-d)) cout << 2*pt << '\n'; + else cout << 2*pt+1 << '\n'; + } + return 0; +} +``` + diff --git a/semester/README.md b/semester/README.md new file mode 100644 index 0000000..0e4cbc2 --- /dev/null +++ b/semester/README.md @@ -0,0 +1,2 @@ +# Semester + diff --git a/semester/c++.md b/semester/c++.md new file mode 100644 index 0000000..ae20f17 --- /dev/null +++ b/semester/c++.md @@ -0,0 +1,1292 @@ +# C++ + +### Object Oriented Language + +Data representation in programming should have - correctness, maintainability, reusability, openness and interoprability, portability, security, integrity and user friendliness. + +Softwares have evolved from - Machine Language \(01\), Assembly Language \(CPU instructions MOV - move instruction, LSR - logical shift right, ROR - rotate right\), Procedure orientate \(C - function based\), Object oriented. + +**In procedure orientated langage:** + +1. Emphasis is on doing things \(algorithms\) +2. Large programs are divided into smaller programs known as functions. +3. Most of the function share global data. +4. Data move openly around the system from function to function. +5. Function transform data from one form to another. +6. Employs top-down approach in program design. + +**However, in Object Oriented language:** + +1. Emphasis is on data rather than procedure. +2. Programs are divided into what known as objects. +3. Data structure is designed such as they categorize the objects. +4. Functions that operate on data of an object are tied together in the data structure. +5. Data is hidden and cannot be accessed from external source. +6. Object may communicate with each other through functions. +7. New data and functions can be easily added whenever necessary +8. Employs bottom-up approach in program design. + +bottom up means we analyze objects which are entities \(lower part\) then that performs task assosiated linked in object class. In top down it's a simple function performing lineraly. + +Basic concepts of OOPS- Objects, Classes, Data abstraction \(abstracting or summarising data which are required only\) and encapsulation \(setting getter and setter for private variables providing data protection - encapsulation from outside\), Inheritence \(using members from some other parent class\), Polymorphism \(ability to display in more than one form like function, operator overloading or function overriding - overriding is using function from parent class\), Dynamic binding or Dynamic Dispatch \(It is also known as late binding it basically binds data or object with methods or implementation defined in it at runtime examples are virtual functions\), Message passing + +**Benefits Of OOPS:** + + +1. Elimination of redundant and duplicate code through inheritence. +2. We can build programs from the standard working module which will communicate with one another in order of task completion. In this way debugging any operation will also get easier. +3. Data encapsulation provides unenesessary data editing. +4. Software complexity can be easily managed. +5. Upgradation of system can be easilty done. + +### Introduction To C++ + +Using C++ we can literally control any instruction of CPU. Other languages like C\# and Java differs because they run on a virtual machine that's why many platforms applications can be developed through C++. It's native so it's fast but a bad C++ code will be slower whears in C\# and Java there are optimizations done by their compilers which makes them handle fast without worrying much about code. + +**Tokens** +Smallest individual units in a program are known as token. C++ has + +* Keywords \(asm, auto, break, case, catch, char, const, continue, default, delete, do, double, else, enum, extern, float, for, friend, goto, if, inline, int, long, new, operator, private, protected, public, register, return, short, signed, sizeof, static, struct, switch, template, this, throw, typedef, union, unsigned, virtual, void, volatile, while, bool, const\_char, dynamic\_cast, explicit, export, false, mutable, namespace, reinterpret\_cast, static\_cast, true, typeid, typename, using, wchar\_t\) +* Identifiers \(Name of the variables, functions, array, classes, etc.\) +* Constants +* Strings +* Operators \(:: Scope resolution operator, ::\* Pointer-to-member declaration, -> Pointer-to-member operator, .\* pointer-to-member operator, delete, endl, new, setw, <<, >>\) + +**\#statements** is a pre processor statement it preprocesses before the actual process. main function is the entry point. Even though int main we don't need to return any value for it. it assumes that we are returning value 0. + +Header files are not compiled they are included C++ files are compiled only. Every C++ file gets compiled individually and converted to an object file. Linker takes all obj files of c++ and makes an executable. + +Declaration is like telling compiler that hey this function exists. And defination is telling that this is the body of this function. + +```cpp +//Defination +void Log(const char* msg) +{ + cout << msg << endl; +} + +//Declaration +void Log(const char* msg); +``` + +To call a function from other c++ file just add declaration. While compiling compiler will trust that the function exists and if the function doesnt exists compiler won't give any error linker will give error. Linker job is to link up the functions. + +**\#include** copy pastes data from header file to our's +**\#define** find and replaces +**\#if** for conditions + +```cpp +//setw +cout << setw(10) << "Basic:" << setw(10) << basic << endl; +cout << setw(10) << "Allowance:" << setw(10) << allowance << endl; +cout << setw(10) << "Total:" << setw(10) << total << endl; + +//output +// Basic 940 +//Allowance 50 +// Total 12 +``` + +### Compilation + +Functions linking done through linker even if it's a project of one c++ file linker job is to define the entry point. If a file with no main function only present no compiler error but linker error. functions have signatures which are used for linking. + +Static are called only for that file and if it is included in some other file then it won't work. Inline makes the compiler replace the code block into a line where it is used so making execution time faster. + +```cpp +class Item +{ +public: + void getData(int a, int b); +}; +inline void Item::getData(int a, int b) +{ + ... +} +``` + +**int** 2 bytes \(32 bit\) 4 bytes \(64 bytes\) compiler based +1 bit is for sign 2^31 maximum number that can be stored. +**unsigned int** means only positive +**char** 1 byte +**short** 2 byte +**long** 4 byte +**long long** 8 byte **float** 4 byte with f prefix **double** 8 byte **bool** 1 byte it uses 1 bit only for 0 or 1 but to address memory 1 byte has to be occupied. + +For creating function a stack for the function is created then all parameters are pushed there also return address is pushed to the stack. Jumping from one memory instruction to another for function then return back to the original. So all of this slows down program aswell. + +Headers are basically used to store declarations. Since declarations are not required in modern java and C\# programs no header files in it. in header file \#pragma once it tells compiler to include the header file only once in a translation unit. + +```text +One way to replace pragma once is +#ifndef _BOOL +#define _BOOL +.... +#endif +``` + +Basically it will check if **\_BOOL** is not defined then it will define and end the condition. Angle brackets are used to include header files that are in the system include directory otherwise for custom we use " + +Quotes can be also used for include director aswell C++ header files like iostream don't have .h extension while math.h kind of has because to distinguish between C++ header files and C header files by the developer + +Constant folding: During debug mode it doesn't happen but in release mode when compiler optimizations take place compiler just reduce code for constant aritmetic operations simplifing the program. + +Compiler also improves many operations such as one given below to bitshift operations which are faster in performance. + +There are some compiler centric definations like \#if \_DEBUG in Visual Studio means the debug configuration condition of the program. + +In a class 'this' keyword is used to reference current instance of the class + +```cpp +class Entity +{ +public: + int x, y; + Entity(int x, int y) + { + Entity* e = this; + e->x = x; + } +}; +``` + +![](../.gitbook/assets/image%20%28261%29.png) + +**Function Prototyping:** declaring a function like the way headers do +void func\(int a, int b = 5\) this function can also be called with a value only. This is called default argument. + +### Memory Allocation + +Dynamic Allocation is allocation at runtime +Stack Allocation is allocation at compiletime + +```cpp +//creates a char and stores it address. +char* buffer = new char[8]; +//assigns 8 zeroes in buffer address memory +memset(buffer, 0, 8); +//delete buffer from memory +delete[] buffer; +``` + +Pointers also gets stored in stack so pointer to pointer is meaningful. + +We can use void\* ptr \(null pointer\) but then derefrencing and adding value will be a problem. + +```cpp +void increment(int& value) +{ + value++; +} +``` + +This function when executed from main function will reference the parameter inputted and make changes in it so basically it is a cleaner way for pointer implementation. + +Once reference declared it cannot be changed + +```cpp +int a = 5; +int b = 8; +int& ref = a; +ref = b; +``` + +In this case ref will not become b but a's value will get to b + + +> A pointer can be re-assigned whereas a reference cannot be reassigned. A pointer has it's own memory address and size on stack whereas reference shares same memory address but new size on stack. Pointers can be null pointers. + +Array created through heap - + +```cpp +int* array = new int[5]; +delete[] another; +``` + +normal array is created on stack and hence will get removed once memory is free by moving out of function heap created will be alive and need to be manually deleted. + +Arrays occupies on contiguous block of memory. + +![](../.gitbook/assets/image%20%28210%29.png) + +A 2D array is also stored linearly. i.e. \(0,n\) & \(1,0\) will have address gap of 4 bytes aswell. + +![](../.gitbook/assets/image%20%28257%29.png) + +This type of memory allocation in 2D array where \(0, n\) & \(1, 0\) have a gap of 4 bytes is called row major. There is column major form aswell in which \(n, 0\) & \(0, 1\) will have a gap of 4 bytes. +2D Arrays can also be used to evaluate polynomial expressions by creating matrix and solving equations. + +New object will be created in heap so it will be stored unless manually deleted stacks are used basically in heap we can have memory leaks if we forget to free memory so heaps are used when we need to extend visibility of objects. smart pointers are something which can be created on heap and also deleted. + +finding memory allocation in memory say when we declare an int 4 bytes of memory needed to be searched in memory. There's a free list in memory which tracks pointer of free memory. + +```cpp +malloc(bytes of memory) +//returns a pointer of heap memory it is simmilar to new keyword of C++ +calloc(elementsCount, sizeOfEachElement) +//Systax is different in calloc but it also returns a pointer to heam memory however it also initializes it to ZERO + +int* temp = (int*) malloc(sizeof(int)); +int* temp = new int; +``` + +### + +### Derrived Data Types: + +```cpp +class Player +{ +public: + int x, y; + int speed; + + void Move(int xa, int ya) + { + x += xa * speed; + y += ya * speed; + } +}; + +int main() +{ + Player player; + player.Move(5, 9); +} +``` + +Functions inside a class are called method. + +Struct and class has no difference except default it's private in class but it's public in struct. It exists because of compatibility for C in C++ because C has no class. + +static in C++ has two meanings for OOPS based it is same for all instance while for non OOPS it means that linker will not look for that variable while linking and that variable is for that translation unit only. + +```cpp +//main.cpp +int myvar = 5; +//new.cpp +int myvar = 6; +``` + +This will give a linker error If static int myvar = 6 then no linker error and value of main.cpp myvar will be 5. + +```cpp +//main.cpp +extern int myvar; +``` + +This makes it 6 as it will look for external linking for the variable. + +```cpp +class Entity +{ + static int x, y; +public: + int size; +}; + +int Entity::x; +int Entity::y; + +int main() +{ + Entity e; + Entity::x = 2; + Entity::y = 5; + e.size = 5; +} +``` + +```cpp +void Function() +{ + //It will log 1 per function call + //If it was static int i = 0 then it would have logged 1, 2, 3, 4 + int i = 0; + std::cout << ++i << std::endl; +} +int main() +{ + Function(); + Function(); + Function(); + Function(); +} +``` + +Exception handling can be done using try catch block + +```cpp +try +{ + x = new float[1000]; +} +catch (bad_alloc e) +{ + throw "Out of memory exception!"; + exit(1); + //Exit will exit the entire program. It is used to debug that something wrong has happened. +} +``` + +There are some defined exceptions: std::exception, std::bad\_alloc, std::bad\_cast, std::bad\_exception, std::bad\_typeid, std::logic\_error, std::domain\_error, std::invalid\_argument, std::length\_error, std::out\_of\_range, std::runtime\_error, std::overflow\_error, std::range\_error, std::underflow\_error + +A new exception can be even defined like this + +```cpp +struct MyException : public exception +{ + const char * what () const throw () + { + return "C++ Exception"; + } +}; +//Fun fact the default return type of a function in c++ is int so instead of int main() we can have just main() however this might give a warning. +``` + +```cpp +enum level +{ + A, B, C +}; +level cur = A; +``` + +Here A=0, B=1, C=2 +if A=0, B, C +B and C will automatically get 1, 2 +enum names doesn't mean anything in C++ + +```cpp +class Entity +{ +public: + int x, y; + + Entity() + { + x=0; + y=0; + } +}; +``` + +There's a default constructor in C++ if we have + +```cpp +class Foo +{ +public: + Foo() = delete; +}; +``` + +that constructor is also deleted meaning we cannot create instance of the method however we can still do it from the class's member function: + +```cpp +class Foo +{ + private: + Foo() {} + public: + static void foo(); +}; + +void Foo::foo() +{ + Foo f; //legal +} +``` + +```cpp +#include +using namespace std; + +class MyClass +{ +public: + MyClass() = delete; + MyClass(int a) + { + cout << a << endl; + } +}; + +int main() +{ + MyClass test(5); + return 0; +} +``` + +If we throw an exception inside a constructor then the constructor won't call hence desrupting the creation of the object. Exceptions are used to signal the occurence of an error. + +```cpp +throw "Incorrect parameter exception"; +``` + +**Copy Constructor** It initializes an object with the constructor parameters of some other object. + +```cpp +class Point +{ +private: + int x, y; +public: + Point(int x1, int y1) { x = x1; y = y1; } + + // Copy constructor + Point(const Point &p2) {x = p2.x; y = p2.y; } + + int getX() { return x; } + int getY() { return y; } +}; +int main() +{ + Point p1(10, 15); // Normal constructor is called here + Point p2 = p1; // Copy constructor is called here + return 0; +} +``` + +A constructor which assigns memory dynamically at runtime using new/calloc/malloc that constructor is called Dynamic Constructor. + +A destructor method will call after the object will destroy. + +```cpp +~Entity() +{ + x=0; + y=0; +} +``` + +```cpp +int main() +{ + { + Function(); + void* ptr = new Function(); + } +} +``` + +Here the function's address is stored in stack which will be cleared right after the code exits from a brace \(if condition, function end, loop body, etc...\) + +However using new operator for creating will create it in heap memory so it won't get cleared unless **delete ptr;** is called. + +```cpp +class sub : public parent +{ + ... +}; +``` + +Inherting will give access to all parent class member. If we do sizeOf\(sub\) it will be size of all variables in sub and parent. Virtual method in parent class can be overrided from sub class + +```cpp +int main() +{ + Entity* e = new Entity(); + std::cout << e->GetName() << std::endl; +} +//cout << something << something_else; this appending to stream is called cascading +``` + +Virtual functions do something called dynamic dispatch it is implemented by v table. V table is a table that contains mapping for all the virtual tables. + +```cpp +std::string GetName() override +{ + return name; +} +``` + +Virtual functions has memory cost first at the time of initialization of v table and then at every time while looking through the table + +pure virtual function or interface in C++ they are abstract functions in Java & C\# + +```cpp +class Entity +{ +public: + virtual std::string GetName() = 0; +}; +``` + +GetName is a virtual abstract function means it will have implementation in sub class only and also instance of Entity class cannot be created. All abstract functions are needed to be implemented in sub class otherwise an error will show. + +**Private:** visible to current and friend class +**Public:** visible to all +**Protected:** visible to current and sub class only + +```cpp +int main() +{ + const char* name = "che\0rno"; + std::cout << strlen(name) << std::endl; + std::cin.get(); +} +``` + +Here it will give 3 + +```cpp +/* +wchar_t char16_t char32_t all are used to represent strings. wchar_t represent distinct codes for all members of the largest extended character. char16 is smaller char32 is bigger than that. char* is the smallest. +*/ + +const char* name = u8"Cherno"; +const wchar_t* name2 = L"Cherno"; +const char16_t* name3 = u"Cherno"; +const char32_t* name4 = U"Cherno"; +``` + +Const keyword: It is like a promise to the compiler that this won't change it will stay constant then the compiler performs compilation performance improvements based on that. We can break this promise however by changing the value from memory resource manager but it's not good. + +```cpp +const int MAX_AGE = 90; +const int* a = new int; +*a = 2; //ERROR since a is constant +a = (int*)&MAX_AGE; //No Error now +//Can't change content of the pointer here but can change pointer address + +const int MAX_AGE = 90; +int* const a = new int; +//or int const* a = new int; +*a = 2; //No Error here +a = (int*)&MAX_AGE; //ERROR since pointer of a is constant +//Can't change the pointer address here + +const int* const a = new int; +//can't change anything now +``` + +Const in a method means that it can only read variables and not change them however a mutable variable can be still changed from inside of the const method + +```cpp +class Entity +{ +private: + int m_x, m_y; + int GetX() const + { + return m_x; + } +}; +``` + +Member Initializer Lists in C++ are used to initialize values in class constructor. It should be used for style purpose as it makes things in one line and also because normally initializing variables inside class will create a new object and then remove previous objects so using this is more optimized. + +```cpp +class Entity +{ +private: + int a, b; +public: + Entity() : a(0), b(0) + { + Init(); + } +}; +``` + +Must be initialized in proper sequence so b\(0\), a\(0 is not correct. + +```cpp +int main() +{ + Entity a("abc"); + //is simillar to + Entity a = "abc"; + //implicit conversion is happening +} + +//if a function +void Function(Entity& entity) +{ +} + +int main() +{ + Function("abc"); + //this will work because string is a valid constructor for Entity object and hence implicit coversion will take place +} +``` + +If there is explicit keyword before constructor then implicit conversion won't take place + +```cpp +Entity +{ +private: + std::string m_Name; +public: + explicit Entity(std::string& name) : m_Name(name) {} +}; +``` + +There's function overloading in which we have two functions with same name but different parameters and different implementations. + +Operator overloading can be done here we have a struct for maths vector which we want to work with cout. + +```cpp +struct Vector2 +{ + float x, y; + Vector2(float _x, float _y) : x(_x), y(_y) {}; + Vector2 Add(const Vector2& other) const + { + return Vector2(x+other.x, y+other.y); + } + Vector2 operator+(const Vector2& other) const + { + return Add(other); + } +}; + +std::ostream& operator<<(std::ostream& stream, const Vector2& other) +{ + stream << other.x << ", " << other.y; +} + +int main() +{ + Vector2 posA(5.0f, 7.0f); + Vector2 posB(9.0, 10.0f); + cout::cout << (posA + posB) << cout::endl; +} +``` + +### Advanced Pointers Concepts: + +Member Function Pointers: + +```cpp +int main() +{ + CPoint p1(6.0, 5.0); + CPoint p2(2.0, 2.0); + cout << p1.distance(p2) << endl; + + //Another way using member pointer + double (CPoint::*pDistance)(CPoint&); + pDistance = &Cpoint::distance; + cout << p1.*pDistance(p2) << endl; + return 0; +} +``` + +```cpp +#include +using namespace std; + +class CMessage +{ +public: + CMessage() {} + void Print1() { cout << "#1"; } + void Print2() { cout << "#2"; } + void Print3() { cout << "#3"; } +}; + +int main() +{ + void (CMessage::*pfnArray[3])(); + pfnArray[0] = &CMessage::Print1; + pfnArray[1] = &CMessage::Print2; + pfnArray[2] = &CMessage::Print3; + + CMessage func; + for (int i = 0; i < 3; ++i) + (func.*pfnArray[i])(); + return 0; +} + +//Output: #1#2#3 +``` + +Smart pointer is allocated on heap but it gets automatically deleted after specific time. + +1. Unique pointer : + +```cpp +class uniquePtr +{ +private: + Entity* m_Ptr; +public: + uniquePtr(Entity* ptr) : m_Ptr(ptr) {} + ~uniquePtr(Entity* ptr) + { + delete m_Ptr; + } +}; + +int main() +{ + { + uniquePtr e = new Entity(); + } +} +``` + +This heap allocation will get destroyed once out of the scope + +OR + +```cpp +#include +int main() +{ + { + std::unique_ptr e = std::make_unique(); + //OR + std::unique_ptr e(new Entity()); + + e->ANYFUNCTION(); + } +} +``` + +Using new Entity\(\) from constructor is not preffered using make\_unique is better because of exception safety. It is slightly safer if constructor happens to throw exception it will end up with dangling points with no reference and hence memory leaks. + +```cpp +//Copying unique_ptr is not possible +std::unique_ptr e1 = std::make_unique(); +//It will give error +``` + +1. Shared\_Ptr: + +```cpp +#include +int main() +{ + { + std::shared_ptr e0; + { + std::shared_ptr sharedEntity = std::make_shared(); + e0 = shared_ptr; + } + } +} +``` + +It gives copying ptr ability and once all copy gets out of scope then the memory gets free. First shared ptr dies after end of first scope but it gets copied to e0 shared\_ptr so when that scope dies then only Entity is destroyed + +1. Weak\_Ptr: + +```cpp +Same as shared pointer but it doesn't matter if it is alive it won't keep Entity alive +#include +int main() +{ + { + std::weak_ptr e0; + { + std::shared_ptr sharedEntity = std::make_shared(); + e0 = shared_ptr; + } + } +} +``` + +Here now entity gets destroyed after first scope. We can use entity object from e0 but it's presence won't keep entity alive. + +Smart pointers are very useful it is very memory managed so it can be used any time. it doesn't replace new and delete it is a smart defined way to handle heap allocations. + +```cpp +struct Vector2 +{ + float x, y +}; + +int main() +{ + Vector2 a = { 1.0f, 2.0f }; +} + +memcpy(m_Buffer, string, m_Size); +m_Buffer & string are of type char* + +class String +{ +private: + char* m_Buffer; + unsigned int m_size; +public: + String(const char* string) + { + m_Size = strlen(string); + m_Buffer = new char[m_Size + 1]; + memcpy(m_Buffer, string, m_Size); + m_Buffer[m_Size] = 0; + } + + ~String() + { + delete[] m_Buffer; + } + + char& operator[](unsigned int index) + { + return m_Buffer[index]; + } + + friend std::ostream& operator<<(std::ostream& stream, const String& string); +}; + +std::ostream& operator<<(std::ostream& stream, const String& string) +{ + stream << string.m_Buffer; + return stream; +} + +int main() +{ + String string = "Cherno"; + String string2 = string; + string2[2] = 'a'; + + std::cout << string << std::endl; + std::cout << string2 << std::endl; +} +``` + +Because of the function operator << of cout declared as friend of String class it can access it's private variable m\_Buffer In this case both string will output will be Charno and at the end of scope an error will occur. It is because while copying the exact pointer gets coppied so when destructor is called m\_Buffer is deleted and then the next class also tries to delete the already deleted m\_Buffer which gives the error so we need that when we copy the class the pointer gets a new block of memory this is called deep copying + +inside class + +```cpp +String(const String& other) = delete +this will make it un coppiable like in unique pointer +String(const String& other) : m_Size(other.m_Size) +{ + m_Buffer = new char[m_Size + 1]; + memcpy(m_Buffer, other.m_Buffer, m_Size + 1); +} +``` + +Usages Of Friend Functions & Friend Class: + +```cpp +class XYZ +{ +private: + int data; +public: + void setVal(int val) + { + data = val; + } + friend void show(XYZ); +}; +void show(XYZ xyz) +{ + cout << xyz.data << endl; +} +``` + +```cpp +class ABC; +class XYZ +{ +private: + int data; +public: + void setVal(int val) + { + data = val; + } + friend void add(XYZ, ABC); +}; +class ABC +{ +private: + int data; +public: + void setVal(int val) + { + data = val; + } + friend void add(XYZ, ABC); +}; +void show(XYZ xyz, ABC abc) +{ + cout << (xyz.data + abc.data) << endl; +} +``` + +```cpp +#include +using namespace std; + +class ABC; + +class XYZ +{ +private: + int data; +public: + void setValue(int value) + { + data = value; + } + friend class ABC; + friend void getXYZData(XYZ); +}; + +class ABC +{ +public: + int data; + void setValue(int value, XYZ xyz) + { + data = value + xyz.data; + } +}; + +void getXYZData(XYZ xyz) +{ + cout << xyz.data << endl; +} + +int main() +{ + XYZ x; + ABC a; + x.setValue(5); + a.setValue(4, x); + getXYZData(x); + cout << a.data << endl; + return 0; +} +``` + +### Extra Concepts: + +```cpp +Struct Vector3 +{ + float x, y, z; +}; + +int main() +{ + int offset = (int)&((Vector3*)nullptr)->z; +} +``` + +offset is 8 for z 4 for y 0 for x + +Standard Template Library \(STL\) is a set of C++ template classes to provide common programming data structures and functions such as lists, stacks, arrays, etc. It is a library of container classes, algorithms and iterators. It is a generalized library and so, its components are parameterized. + +It containts - Sorting, Searching, reversing, max element, min element, accumulate which is sum of elements of an itterator, count in itterator, find, binary\_search, lower\_bound which is the itterator, first or lower occurence of the element in the itterator, upper\_bound, erase, distance which is distance between two iterators, next\_permutation, prev\_permutation. + +```cpp +int myints[] = {1,2,3}; +do +{ + std::cout << myints[0] << ' ' << myints[1] << ' ' << myints[2] << '\n'; +} +while (next_permutation(myints,myints+3)); +``` + +5 10 15 20 20 23 42 45 +Vector after performing next permutation: +5 10 15 20 20 23 45 42 +Vector after performing prev permutation: +5 10 15 20 20 23 42 45 + +Array Algorithms include all\_of\(\) which is like running a loop on the array. + +```cpp +all_of(ar, ar+6, [](int x) { return x>0; })? + cout << "All are positive elements" : + cout << "All are not positive elements"; +``` + +any\_of\(\) it is same as all\_of except it will return after finding any true case, none\_of\(\) + +copy\_n\(\) to copy arrays + +```cpp +copy_n(ar, 6, ar1); +``` + +iota\(\) it assigns constant values to the array. like - 20 21 22 23 24 25 + +```cpp +iota(ar, ar+6, 20); +``` + +There are helpers for - vector, list, deque, arrays, forward\_list, queue, priority\_queue, stack, set, multiset, map, multimap, Functors, Iterators, pair. + +Foreach loops are a short hand + +```cpp +std::vector vertices; +vertices.push_back({1, 2, 3}); + +for(Vertex& v : vertices) + std::cout << v << endl; +``` + +vector will resize like 1 then 2 then 4 then 8 so if we are planning to have atleast 4 elemets then we can reserve it in that way unecessary copying and deletion of previous memory allocation can be avoided. std::vertices.reserve\(3\); + +Second optimization strategy is that using push\_back results in copying of object to the vector memory which can be avoided by vertices.emplace\_back\(1, 2, 3\); + +Linking projects with external libraries. Static linking is in which the source code gets included in the final exe whearas in dynamic linking, linking libraries is done at runtime. \(DLL file - Dynamic Linking Library\) Static linking is faster. + +To return multiple values from the function we can return a struct with those values, or we can return a vector containing that values or pointer to the values, or we can return a tuple + +```cpp +#include +std::tuple returnsomevalue() +{ + return std::make_pair("as", 12); +} + +int main() +{ + //std::tuple sources = returnsomevalue(); + auto sources = returnsomevalue(); + std::string a = std::get<0>(sources); + int b = std::get<1>(sources); +} +``` + +same way we can use pair it will have 2 non simmilar values only. then we can use + +```cpp +auto sources = returnsomevalue(); +std::string a = sources.first; +``` + +or sources.second + +struct is more better because it is much clearer and easy to read instead of first second we can use direct variable name. + +Function pointers are void\* + +```cpp +void HelloWorld() +{ + std::cout << "Hello World" << std::endl; +} + +int main() +{ + auto function = HelloWorld; + //or void(*functionName)() = HelloWorld; + function(); + function(); +} +``` + +This gets meaningful if we want to pass function to another function. This will retrieve the memory location of the function + +```cpp +void ForEach(const std::vector &values, void(*func)(int)) +{ + for (int value : values) + func(value); +} + +int main() +{ + std::vector values = { 1, 2, 3, 4 }; + ForEach(values, [](int value) { std::cout << "Value: " << value << std::endl; }); +} + +Inline functions which is to replace function pointers are the lambda functions + +std::vector values = { 1, 5, 4, 2, 3 }; +auto it = std::find_if(values.begin(), values.end(), [](int value) { return value > 3; }); +std::cout << *it << std::endl; +//5 +``` + +Threads in C++ + +```cpp +static bool s_Finished = false; + +void DoWork() +{ + using namespace std::literals::chrono_literals; + while (!s_Finished) + { + std::cout << "Working...\n"; + std::this_thread::sleep_for(1s); + } +} + +int main() +{ + std::thread worker(DoWork); + std::cin.get(); + s_Finished = true; + worker.join(); + std::cin.get(); +} +``` + +Output- +Working... +Working... +Working... +Working... +unless something is input by user then the thread get's completed. + +Timer functions to precisely calculate time of the system is very important for example to find the duration of time taken by an algorithm. + +```cpp +#include +#include +#include + +int main() +{ + using namespace std::literals::chrono_literals; + + auto start = std::chrono::high_resolution_clock::now(); + std::this_thread::sleep_for(1s); + auto end = std::chrono::high_resolution_clock::now(); + + std::chrono::duration duration = start - end; + std::cout << duration.count() << "s" << std::endl; + + std::cin.get(); +} +``` + +```cpp +int** a2d = new int*[50]; +for(int i=0; i<50; ++i) + a2d[i] = new int[50]; + +int*** a3d = new int**[50]; +for(int i=0; i<50; ++i) +{ + a3d[i] = new int*[50]; + for(int j=0; j<50; ++j) + a3d[i][j] = new int[50] +} + +a2d[0][0] = 1; +a3d[0][0][0] = 1; + +for(int i=0; i<50; ++i) + delete[] a2d[i]; +delete[] a2d; + +for(int i=0; i<50; ++i) +{ + for(int j=0; j<50; ++j) + delete[] a2d[i][j]; + delete[] a2d[i]; +} +delete[] a2d; +``` + +Here we are reserving different block of memory for different rows or columns that we are making and hence it can be far in the memory address. Fetching those far memories can result in slow speed hence we should essentially make our own allocator that can allocate memory for us nearer. + +```cpp +#include +#include +#include +#include + +int main() +{ + std::vector values = { 3, 5, 1, 4, 2 }; + std::sort(values.begin(), values.end(), [](int a, int b) + { + return a < b; + }); +} +``` + +Output: 1 2 3 4 5 + +instead of lambda we can pass inbuilt functions from functional std::greater\(\) + +compare function if return true then a will be placed before b otherwise opposite. + +struct or class occupies sum of memory occupied by individuals however a union occuies memory of the most memory costly item. + +```cpp +struct Vector2 +{ + float x, y; +}; + +struct Vector4 +{ + union + { + struct + { + float x, y, z, w; + }; + struct + { + Vector2 a, b; + }; + }; +}; +``` + +Now here if we set b value of the vector4 struct then z also get's changed to the same + +```cpp +class Base +{ + Base() { std::cout << "Base Constructed\n;" } + ~Base() { std::cout << "Base Destructed\n;" } +} +class Derrived : public Base +{ + Derrived() { std::cout << "Derrived Constructed\n;" } + ~Derrived() { std::cout << "Derrived Destructed\n;" } +} + +int main() +{ + Base* base = new Base(); + delete base; + + //Base Constructed + //Base Destructed + + Derrived* derrived = new Derrived(); + delete derrived; + + //Base Constructed + //Derrived Constructed + //Derrived Destructed + //Base Destructed + + Base* poly = new Derrived(); + delete poly; + + //Base Constructed + //Derrived Constructed + //Base Destructed +} +``` + +making destructor virtual of the base class will make polymorphic function call destructor as well hence avoiding memory leaks. + +Type casting done explicitly by paranthesis is the c style type casting whereas C++ type castings are - static\_cast, dynamic\_cast, const\_cast, interpret\_cast + +```cpp +double s = static_cast(integer); +``` + +dynamic cast will perform type casting at runtime if it is possible. value gets null if the conversion is not possible. + +C++ type casting makes code readiblity better. C style and C++ both are equivalent + diff --git a/semester/dbms.md b/semester/dbms.md new file mode 100644 index 0000000..fb527e3 --- /dev/null +++ b/semester/dbms.md @@ -0,0 +1,535 @@ +# DBMS + +Data: Raw and isolated facts about an entity\(recorded\) eg - text, audio, video, image, etc +Information: Processed, meaningful, usable data is Information +Database: Collection of similar data. + +Database Management System is a collection of interrelated data representing information relevant to an enterprise and a set of programs to store and retrieve those data in the most efficient and convenient manner and the collection of data is usually refereed as a database +Where is database needed? How was data stored before computers + +Disadvantage Of File System: + +1. Data Redundancy +2. Data Inconsistency +3. Difficulty in accessing data +4. Data isolation +5. Security problem +6. Atomicity problem +7. Concurrent access anomalies +8. Integrity problem + +In a database it can happen that 90% of data is historic 10% is new which is used daily. So we separately store them in order to reduce space ultimately reducing the memory access time. OLAP \(Online Analytical Processing\) - Historic, OLTP \(Online Transaction Processing\) + +Query Language - Procedural \(Relational Algebra\), Non Procedural \(Relational Calculus\) +Structured Query Language \(SQL\) + +* In practical implementation we use RDBMS, SQL is to write query on it +* So relational model is a conceptual/theoretical framework and RDBMS is it's implementation +* Relational algebra and calculus are mathematical system of query language used on relational model. + +## Data Models + +* **Relational Model:** Data is stored in tables called relational. Attributes \(Columns\) Tuple \(Rows\). Degree = no. of attributes. Cardinality = no. of tuples. Advantages: Simplicity, Structural Independance \(only concerned about data and not with structure\), Easy to use, Query capability, Scalable. Disadvantages: Structured limit \(field length limit, type, etc\), Cost \(of softwares and implementing\). +* **ER \(Entity Relationship\) Model:** It defines the conceptual view of a database. It works around real world entities and the assosiation among them. At view level it is considered a good option for designing database. An entity is a person or a thing which has logical or physical existence in the real world. For example, in a school database, students, teachers, classes, and courses. An entity set is a collection of similar types of entities. Entities are represented by means of their properties, called attributes. For example, a student entity may have name, class, and age as attributes. Advantages: Better understanding \(graphical\), Easy conversion to other models, easy and straightforward. Disadvantages: Popular for high-level design, No industry standard for notation. +* **Object Oriented Model:** This data model is another method of representing real world objects. It considers each object in the world as objects and isolates it from each other. It groups its related functionalities together and allows inheriting its functionality to other related sub-groups. Advantages: Codes are reused because of inheritance, More flexible to change, More organized. Disadvantage: Complex to implement, Not widely used. + +> Both ER & Object Oriented Model are Object based model since they use real world objects + +* **Semi-Structured Model:** The data is modelled as a tree or rooted graph where the nodes and edges are labelled with names and/or have attributes associated with them. The data can exist without there being a schema, although it is possible that there is one. \(XML, JSON\) Advantages - It can represent the information of some data sources that cannot be constrained by schema, Data transfer is portable, flexible, schema can be easily changed, useful for browsers. Disadvantages - Queries are less efficient then in strucuted models. +* **Hierarchial Model:** In hierarchical model, data is organized into a tree like structure with each record is having one parent record and many children. The main drawback of this model is that, it can have only one to many relationships between nodes. Rarely used. +* **Network Model:** The network model was created to represent complex data relationships more effectively than the hierarchical model, to improve database performance. Advantages - Conceptual simplicity, handles more relationship type, data access flexibility, promotes data integrity. Disadvantages - system complexity, lack of structural dependencies. + +> A database schema is the skeleton structure that represents the logical view of the entire database. It defines how the data is organized and how the relations among them are associated. + +> Database users - Naive user, application programmer, sophisticated users, specialised users + +> Database administrator - schema defination, access control, routine maintainance, storage structure and access method defination + +## Keys + +* **Superkey:** A combination of one or more attributes that uniquely defines a tuple in a relation are called superkey. +* **Key:** Any combination of one or more attributes that uniquely defines a tuple in a relation and there is no proper subset of that combination of attributes that will uniquely define a tuple in a relation. Then this combination of attribute is called a key. + +![](../.gitbook/assets/image%20%28239%29.png) + +* **Candidate Keys:** For any relational scheme if more then one key exist then each key is called a candidate key. +* **Primary Key:** It is a candidate key that is chosen during the time of designing schema of the table. +* **Secondary Key:** All candidate keys which are not primary key are secondary key. +* **Foreign Key:** Foreign key is an attribute or a combination of attributes that refrences the primary key of some other relation. +* **Composite Key:** Any key which is a combination of 2 or more attributes. + +{% embed url="https://youtu.be/x\_inLVXPlSU?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV" %} + +## Database Languages + +1. DDL \(Data Defination Language\) + * Define schema + * Define integrity constraints \(PRIMARY KEY, FOREIGN KEY, UNIQUE, NOT NULL, CHECK\) +2. DML \(Data Manipulation Language\) + * Retrive data + * Insert data + * Update data + * Delete data +3. Query language \(Data retrieval\) + * Relational Algebra \(Procedural\) + * SQL \(Declarative or Non Procedural\) + +## SQL \(Structured Query Language\) + +It offers - DDL, DML, Integrity, View defination, Transaction control, Embedded SQL & Dynamic SQL, Authorization. +Basic data type - char\(n\), varchar\(n\), int, small int, numeric\(p, d\), float\(n\), date, time, timestamp + +Key functions of DBA: + +* Schema defination +* Storage structure and access method defination +* Schema and physical organization modification +* Granting of authority for data access +* Routine maintainance \(periodically backups, ensuring enough free space, monitoring jobs running and ensuring performance\) + +```sql +CREATE TABLE STUDENT +( + Roll_no varchar(12), + Name char(50), + Contact_no int, + email_id varchar(12), + PRIMARY KEY (Roll_no), + FOREIGN KEY (Name) refrences (REC.Name) +); + +INSERT INTO STUDENT values(...); +DELETE table_name; +DROP table_name; +ALTER TABLE table_name add (last_name VARCHAR(50), ...); +ALTER TABLE table_name DROP COLUMN last_name; +``` + +> Constraints - Keys \(primary, foreign\), Unique, Not Null + +## Relational Algebra + +* Selection \(σ\) σaddress = "Rohini" \(table\_name\) +* Projection \(π\) πname, address \(student\) +* Rename \(ρ\) ρs\(student\) +* Cartesian Product \(x\) student x student\_course\_grade +* Joins \(student ⋈ student\_course\_grade\) + * Theta join\(⋈θ\): Say two tables mobile & laptop wit prices. purchase both but laptop price should be more than mobile then Mobile ⋈mobile.price < laptop.price Laptop + * Equi join\(⋈e\): Equi join is a theta join with equal condition + * Natural join\(⋈\): It's equi join without having equal column twice. Optimized way. +* Outer Joins - Left Outer Join, Right Outer Join, Full Outer Join \(Simply append other part with matching values rest set NULL, Full outer join includes elements from both table\). + +![](../.gitbook/assets/image%20%28256%29.png) + +* Aggregate functions - SUM\(\), COUNT\(\), AVG\(\), MIN\(\), MAX\(\) Gsum \(Marks\)\(student\_course\_grade\) +* Generalisation - Only aggregate \(above\), Only grouping cidG \(table\), both cidGsum \(Marks\) \(table\) This last one will show a table with grouped values for distinct cid with corresponding summed up marks in each groups +* Division: Result contains all tuples appear in R1\(z\) in combination with every tuple from R2\(y\) where Z = \(x U y\). Result will contain R1-R2 attributes. Best suited to queries that include 'for all' + +![](../.gitbook/assets/image%20%28216%29.png) + +* Set Union \(Applies on relation\) R1 U R2 +* Set Intersection \(Applies on relation\) R1 ∩ R2 +* Set Difference \(Applies on relation\) R1 - R2 + +![](../.gitbook/assets/image%20%28262%29.png) + +![](../.gitbook/assets/image%20%28228%29.png) + +![](../.gitbook/assets/image%20%28238%29.png) + +![](../.gitbook/assets/image%20%28225%29.png) + +> Relational Algebra do not considers duplicacy as it is based on set theory matlab table me same tuple hue toh sql will show it but relational algebra won't + +> Natural join, division, intersection these are derived operators and it means that other operators can make these but still these derived ones are there to speed up the task + +[https://cs.stackexchange.com/questions/29897/use-count-in-relational-algebra](https://cs.stackexchange.com/questions/29897/use-count-in-relational-algebra) + +> Referential integrity refers to the accuracy and consistency of data within a relationship. It requires that, whenever a foreign key value is used it must reference a valid, existing primary key in the parent table. For example, if we delete record number 15 in a primary table, we need to be sure that there’s no foreign key in any related table with the value of 15. We should only be able to delete a primary key if there are no associated records. So it will prevent - Adding records to a related table if there is no associated record in the primary table, Changing values in a primary table that result in orphaned records in a related table, Deleting records from a primary table if there are matching related records. + +## Entity Relation Model + +* A non-technical design method works on conceptual level based on the perception of real world. +* Consists of collection of basic objects called entities and of relationship among there objects and attributes which define their properties. +* Free from ambigutes and provides a standard and logical way of visualizing data. +* Basically it is a diagramatic representation easy to understand even by non-technical user. +* Conversion of ER model to Relation model is simple. + +ER model describes data as entity, relationship and attributes. An entity is a real world thing that has an independent existence. Entity may have physical existence or conceptual existence. eg - a particular person, car, book, house or a course, a department, a university, a job, etc. 3 markers of same company same appearance cannot be called entity \(Independent existence\) they are still objects. With each entity, a set of attributes are associated that describe the properties of that entity. + +Entity type is defined as a collection of entities that have the same attributes. +Entity set is the collection of all the entities of a particular entity type in a database at any point of time. Entity set is represented by rectangle. + +Table of Relational Model, each values of student table is an entity while the student table is entity set. + +![](../.gitbook/assets/image%20%28226%29.png) + +Attributes are the units that describe the characterstics of entities such that each entity can be differentiated. + +* For each attribute there is a set of permitted values called domains +* In ER diagram represented by ellipse or oval while in relational model by a seperate column. + +Types: + +1. Simple-Composite : Simple cannot be divided any further represented by simple oval. Composite can be divided further in simple attributes, oval connected to oval. +2. Single-Multivalued : Single can have only one value at an instance of time. Multivalued can have more then one value at an instance of time. Multivalued is double oval represented. +3. Stored-Derrived : Stored is how value is stored in the database. Derrived is how value can be computed in runtime using stored attributes. Derrived is represented by dotted. \(Age is derrived by DOB or distance in google maps derrived by destination and source\) + +Relationship: +Relationship is an assosiation between two or more entities of same or different entity set + +* No representation in ER diagram as it is an instance or data +* In relational model represented either using a row in table + +Relationship Type: a set of simmilar type of relationship + +* In ER diagram represented using diamond +* In relational model either by a seperate table or by seperate column \(foreign key\) +* Every relationship type has 3 components + * Name + * Degree + * Cardinality Ratio/Participation Constraint + +![](../.gitbook/assets/image%20%28255%29.png) + +![](../.gitbook/assets/image%20%28247%29.png) + +Degree of a relationship set: Means number of entity set associated \(participated\) in a relationship set. Most of the relationship set in ER diagram are binary. Unary relationship is also possible like in above image student-student student can be a monitor + +Mapping Cardinalities Ratio: Express the number of entities to which other entities can be related via a relationship. Can be used in describing a relationship set of any degree but is most useful in Binary relationship + +* 1 : 1 \(One to One\) Entity of a set can relate atmost one entity of other set and vice versa. Atmost means there can be an entity not in relationship. Indian Citizen & Aadhar number +* 1 : N \(One to Many\) Indian Citizen & Mobile Number +* N : 1 \(Many to One\) Mobile Number & Indian Citizen +* M : N \(Many to Many\) Teacher & Students + +In relationship representation 1 n will be written. Arrow will denote a one one relationship simple line means many + +> Every one to one relationship is one to many or many to one or many to many relationship as well but not vice versa + +Participation Constraint: Specifies weather the existence of an entity depends on its being related to another entity via a relationship type. These constraint specify the minimum and maximum number of relationship instances that each entity can/must participate in. +Maximum Cardinality, It defines the maximum number of times an entity occurence participating in a relationship while Minimum Cardinality is the minimum number of times an entity occurence participating in a relationship. + +* Partial Participation \(Minimum cardinality = 0\) Not bounded to be in a relationship +* Total Participation \(Minimum cardinality > 0\) Example: A project employee relationship. Each project must have min 5 employee and max 12 employee. Each employee must be in atmost 2 projects. Here project min cardinality is 5 and max 12 while for employee its 0 and 2. Project to employee is total participation while employee to project it's partial participation. \(Double line in total participation\) + +> The Strong Entity is the one whose existence does not depend on the existence of any other entity in a schema while a weak entity is the one that depends on its owner entity i.e. a strong entity for its existence. A weak entity is denoted by the double rectangle. + +![](../.gitbook/assets/image%20%28242%29.png) + +Conversion to Relational Model: + +* Converting Entity Sets to table: Simply put entity set as table and all entities as values +* Composite and multi valued attributes: Forget about main attribute \(name forget take fname lname in table\) +* Weak Entity set: + * 1:1 - Include primary key attribute of strong entity set and all other attribute of weak entity set + * M:N - take primary key of both + * 1:N/N:1 - take all attributes of entity set it total participation and for other take primary key + +![](../.gitbook/assets/image%20%28233%29.png) + +## Functional Dependency + +The functional dependency is a relationship that exists between two attributes. It typically exists between the primary key and non-key attribute within a table. + +A functional dependency between two sets of attributes X and Y that are subsets if R specifies a constraint on the possible tuples that can form a relation state 'r' of R. The constraint is that, for any 2 tuples t1 and t2 in r that have t1\[x\] = t2\[x\] they must also have t1\[y\] = t2\[y\] + +X → Y +The left side of FD is known as a determinant, the right side of the production is known as a dependent. +For example: Assume we have an employee table with attributes: Emp\_Id, Emp\_Name, Emp\_Address. Here Emp\_Id attribute can uniquely identify the Emp\_Name attribute of employee table because if we know the Emp\_Id, we can tell that employee name associated with it. Functional dependency can be written as: Emp\_Id → Emp\_Name + +Types of functional dependencies - Trivial A B → A \(returns what we already know\), Non trivial A → B + +Attribute Closure/Closure on attribute set: Attribute closure of an attribute set A can be defined as a set of attributes which can be functionally determined from it. denoted by f+ + +```text +uss attribute ki pahuch kaha tak he +A → B, B → C +then A+ = A B C +A → B, C → D E, A C → F, D → A F, E → C F +then D+ = D A F B +``` + +Full functional dependency: Functional Dependency denoted by X → Y where X & Y are sets of attributes of R X → Y is said to be full FD iff there exists no functional dependency, denoted by A → X such that A is a proper subset of X A ⊂ X + +Partial FD: .... if there exists some functional .... + +Armstrong's Axioms: + +* Axiom is a statement that is taken true and serve as a permise or starting point for further argument +* Armstrong axioms hold on every relational database and can be used to generate closure set. + +Primary rules: + +* Reflexivity - if Y ⊆ X then X → Y +* Augmentation - if X → Y then XZ → YZ +* Transivity - if X → Y & Y → Z then X → Z + +We can prove secondary rules from primary rules + +Secondary Rules: + +* Union - X → Y & X → Z then X → Y Z +* Decomposition - if X → Y Z then X → Y & X → Z + +> Union & Decomposition need to be done on right side, union we can do on left side but usse nuksaan hi hoga [https://youtu.be/vs65S6Nku5g?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV&t=959](https://youtu.be/vs65S6Nku5g?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV&t=959) + +* Psuedo Transitive - if X → Y & W Y → Z then W X → Z +* Composite - if X → Y & Z → W then X Y → Y W + +[https://youtu.be/NeITRksKLzs?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV](https://youtu.be/NeITRksKLzs?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV) +[https://youtu.be/0XmHRycmrp0?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV](https://youtu.be/0XmHRycmrp0?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV) +[https://youtu.be/o0GQQFu-5C0?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV](https://youtu.be/o0GQQFu-5C0?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV) +[https://youtu.be/\_-F6QfdheEk?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV](https://youtu.be/_-F6QfdheEk?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV) + +During finding candidate keys we first find which attribute doesn't have any incoming relation then we take it first verifying through closure for finding candidate keys. Attributes inside the final candidate key are prime attributes and left over are non prime attributes. + +![](../.gitbook/assets/image%20%28222%29.png) + +## Normalization + +![](../.gitbook/assets/image%20%28240%29.png) + +Idea: In the table studentInfo we have tried to store entire data about student +Result: Entire branch data of a branch must be repeated for every student of the branch. +Redundancy: When some data is stored multiple time unnessarily in a database. +Disadvantages: + +* Insertion, deletion and modification anomalies +* Inconsistency \(data\) +* Increase in data size and increase in time Insertion Anomalie: like say civil dept me koi banda nahi toh info table me dept ki bhi nahi hogi. Deletion Anomalie: agar akela banda he dept ka usse delete nahi karsakte warna branch khatam Updatation Anomalie: update karna ho branch related kaa usse multiple jagah karna padega + +Solution in Normalization. It is a logic of decomposing a table until the most optimal result is obtained. It is done on the basis of functional dependencies. Functional dependency can decompose till BCNF only for later on scenerios we need to consider lossy decomposition. + +![](../.gitbook/assets/image%20%28221%29.png) + +1NF implications: + +* A table is said to be in 1NF if every cell contains atomic values. Value can be null. +* Every column should also contain values from the same domain. +* Order of rows or column is irrelevant +* Every column should have unique name + +2NF implications: + +* Check for 1NF then the table must not have partial dependency + +![](../.gitbook/assets/image%20%28252%29.png) + +* In the above example AB is the key and D is dependent on AB which is complete key so total complete dependency but for C it depends only on B not AB so it is in partial dependency so not in 2NF to make it in 2NF we will decompose it into two tables such that this property still holds. [https://youtu.be/yIN6k57OB3U?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV](https://youtu.be/yIN6k57OB3U?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV) + +3NF implications: + +* If it's in 2NF & has no transitive dependancy +* Transitive dependance is a functional dependency from A → B is called transitive if A, B are non-prime. [https://youtu.be/9H4aJqYyd9s?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV](https://youtu.be/9H4aJqYyd9s?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV) + +BCNF \(Boyce Codd Normal Form\) implications: + +![](../.gitbook/assets/image%20%28253%29.png) + +Here in this example below, there's no partial dependancy and transitive dependancy so last is checking if right one is prime and left one can be prime as well as non prime. Here it is both prime in C → B so it's not in BCNF. If C would have been anything else which is a super key then we can ignore it + +![](../.gitbook/assets/image%20%28227%29.png) + +[https://youtu.be/mzxnbsmIRNw?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV](https://youtu.be/mzxnbsmIRNw?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV + +) + +## File Structures + +SRS -> ER Diagram -> Relation Model -> Normalization -> File Structure\(Indexing & Physical Strucutre such that accessing data gets faster\) + +Files can be managed in secondary memory in three ways - contiguous allocation, linked allocation & indexed allocation. + +The order of rows & columns are significant however their might be some benefits of having them in sorted. Their might be a case when whole record cannot fit inside the memory block then we use spanned or unspanned memory allocation. + +In sorted, searching fast \(binary search\) but insertion and deletion is difficult opposite in unsorted. + +If we have say a block of size 1024B and our record \(tuple/row of table\) has size 100B there are n tuples. After filling 10 records 24B space is left now we can either utilize that 24B by splliting record 24-76 putting 76 in next block. This is spanned mapping if we don't then unspanned. Spanned mapping make sure there's no internal fragmentation. + +![](../.gitbook/assets/image%20%28258%29.png) + +Spanned increases search time but reduces space used. + +Indexing on the otherhand is done by keeping index file say with key \(like roll number\) and values \(Block pointer that matches it\). After finding block we simply go to it in O\(1\) then in block it will contain like 10 records searching it linearly is also no deal. If Index file is small then then actual memory blocks it is beneficial. + +* Now index file just have two columns key-value unlike actual with all information. \(Reduces width\) +* Index file maps to block pointer each block holds like 10 records so index file will be /10 smaller. \(Reduces height\) + +> Our Index file will have roll numbers 1, 11, 21, 31 if we are looking for 9th rollnumber applying binary search we know it's 1 since it's immediate lesser than 11. Keeping just few pointers is sparse indexing but let's say in our blocks records are not sorted then we need to map all pointers then it is dense indexing. + +> Sparse ka matlab har record ko entry naa milna par dense ka matlab har value ko entry milna. So example ki values repeat ho rahi he 1, 1, 1, 2, 3 and 1 2 3 are mapped in index other two 1s are left so this is sparse kyuki kuch record rehgaye par also dense kyuki har value hogaya. Toh ye dono he. + +* Index file only contains frequently accessed elements. \(Different case, Reduces height\) + +> Indexing is a secondary mean for accessing tuples, it optimizes search we could simply search over blocks. Even indexing over dense is still beneficial in time. In space it definitely takes new additional space. + +Types Of Indexing: + +* Single-level Indexing + * Primary Indexing: Tab use karte he jab main file sorted ho usme primary key uthaake index kardete he \(search attribute\). It is a example of sparse indexing. No. of enteries in index file = No. of blocks acquired by the main file. No. of access recquired = logN + 1. [https://www.youtube.com/watch?v=mbjE4WsWYCA&list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV&index=47](https://www.youtube.com/watch?v=mbjE4WsWYCA&list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV&index=47) + * Clustered Indexing: Main file is sorted on some non-key attribute. There will be one entry for each unique value of the non-key attribute. If number of block acquired by index file is n, then block access required will be logN + 1. It is both sparse and dense + +![](../.gitbook/assets/image%20%28223%29.png) + +* * Secondary Indexing: Non sorted he primary key ho naa ho koi naa kyuki this is dense indexing saare index me hote he. This is used only non sorted jab ho. Why do we need ki non sorted? Like sometimes we want to find based on non sorted multiple index file ho sakte he for a single main file it won't change main file toh ek ko karsakte he sort dusre ko ek saath nahi. Since it's dense indexing index file ka height main file jitna hoga still index file kaa faayda he because width kam he toh space toh kam lega comparitively main file ke. And we can now apply binary search aswell. [https://www.youtube.com/watch?v=Tmbv15xiIPo&list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV&index=50](https://www.youtube.com/watch?v=Tmbv15xiIPo&list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV&index=50) +* Multi-level indexing: Index eetna bada jo search ke liye dusri indexing. We use B & B+ tree typically kyuki uska structure resemble karta he. + +## Transactions + +Transaction is maintainance of database. + +![](../.gitbook/assets/image%20%28231%29.png) + +A transaction is set of instructions. Instructions are atomic in nature they get either performed or not performed. Whole transaction is not atomic but it should also be atomic. In this case we have to roll back. Pese kat jaayenge A se par nahi jaayenge B me toh inconsistency hogaya. + +ACID Properties, a transaction should follow these: + +* Atomicity \(saare instruction execute ho yaa to koi bhi nahi\) +* Consistency \(Transaction ke baad database ka state change ho jata he as in saare data change so pehle database consistent thaa abb bhi rahe we want this then we can say consistency maintained he. In above bank case consistency is checked with A+B constant rahe throughout\) +* Isolation \(Kisi transaction par kisi dusre transaction ka farak nahi padna chahiye. It's logical isolation ofcourse physically aesa kare ki series me transaction run hoye then system will be slow so we just want it logically, parallaly hoye par user ko lage isolation me horaha he\) +* Durability \(Transaction completion ke baad durable rahe uske changes no software hardware failure commit hogaya\) + +> Transaction Management Component is a part of DBMS which ensures Atomicity + +> No DBMS component ensures consistency kyuki Atomicity, Isolation, Durability ensured he tab ye bhi automatically he + +> Concurrency Control Component is a part of DBMS which ensures Isolation + +> Recovery Management Component is a part of DBMS which ensures Durability + +![](../.gitbook/assets/image%20%28241%29.png) + +All the instructions within the transaction is performed on a local buffer of main database after failure the buffer is discarded and if no failure that partially commited local buffer is copied to main database. + +Advantages Of Concurrency \(Ek baar me ek se zyada transactions\): + +* Waiting Time reduces +* Response Time reduces \(response is pehla interaction like restaurant me waiter aaya sabse pehle is response in the end food aane me kitna time is total waiting time. We may sometimes even want ki response time less ho althought waiting time zyada rah jaaye\) +* Resource utilization is more +* Efficiency increases + +Kabhi kabhi inconsistency aasakti he due to concurrency, manage karna mushkil hoga. + +> Transactions are run together as schedule + +**Dirty Read Problem:** Koi transaction database ki value read naa karke koi aesi uncommited local buffer ki value read kare then it's dirty read. + +![](../.gitbook/assets/image%20%28237%29.png) + +In this example T1 & T2 run concruently. T1 does some changes on local buffer say changes 10 to 11 and at the same time T2 also reads, reading first takes from local buffer if there's no existence in primary memory then it will move to secondary memory. T2 then commits. Now later on if T1 has some failure then it will rollback this will create inconsistency. This can be avoided if T2 commited later on i.e. after T1 commits. + +**Unrepeatable Read Problem:** Jab ek value ko repeatedly read kara and values alag aayi then ye problem he. + +![](../.gitbook/assets/image%20%28251%29.png) + +Now eesme read jab dusri baar hua value change kardi kisi dusre transaction ne so inconsistency hogayi. + +**Phantom Read Problem:** + +![](../.gitbook/assets/image%20%28229%29.png) + +Now abb humne dusre read se pehle delete hi kardia toh again inconsistency aajayegi. + +**Lost Update Problem \(Write-Write Conflict\):** + +![](../.gitbook/assets/image%20%28214%29.png) + +T1 ne value 10 se 11 kardi but then T2 ne firse change kardi \(yaha T2 ne read karke change nahi kara to a constant i.e. 50 this is blind update\) now T2 ne commit kardia jab T1 commit kar raha he it is commiting it's changes par T2 ne uske changes ko change kardia toh isolation nahi raha T1 kaa T1 kaa change nahi raha. + +**Serial Schedule:** Serial running of transactions. Slow. No problems as mentioned above. Let's say there are n transactions in the schedule T1, T2, T3, ... Tn then we have n \* n-1 \* n-2 ... 1 = n! ways of designing a serial schedule. + +**Non Serial Schedule:** Concurrent, Fast, May have above mentioned problems. Say we have n transactions in schedule T1, T2, T3, ... Tn with n1, n2, n3, ... nn instructios in each transaction then we have \(\(n1+n2+n3+n4+...+nn\)! / \(n1! n2! + n3! + ... nn!\)\) - n! + +## Conflict Serializability in DBMS + +![](../.gitbook/assets/image%20%28217%29.png) + +Basically we want to check humara non-serial schedule consistent he ya nahi \(problems naa hona is consistent\). If we can swap instructions within transactions \(transaction ke andar ki relative ordering nahi that we should never change\) and swaps ke baad if it becomes serial kyuki serial is always consistent then we can say S1 is consistent as well. If it fails then we are not sure it may or may not be consistent. Like in the image we can do it. If instructions happen on different variable then it won't matter order. Or if it's read-read then no matter konsa transaction pehle read +karta he swap can be done, but if its read-write, write-read or write-write then we cannot swap. +[https://youtu.be/QkROSmKbVFQ?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV](https://youtu.be/QkROSmKbVFQ?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV) +[https://youtu.be/6feqtT3e-vA?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV](https://youtu.be/6feqtT3e-vA?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV) + +## View Serializability + +It is weaker than conflict serializability that means if a schedule is VS then it may or may not CS but if it's CS then it's definitely VS. VS is an NP complete problem so that's why we tend to go with CS first. Agar CS nahi he but usme blind write nahi he then VS nahi hoga but agar he blind write then wo ho sakta he. + +![](../.gitbook/assets/image%20%28243%29.png) + +[https://youtu.be/FJteasXARxg?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV](https://youtu.be/FJteasXARxg?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV) + +To check this we basically make all possible arrangements, then compare it with non-concurrent schedule like before. This time we check - initial read same, final write same, intermediate read same then we say it's view serializable. + +## Recoverable Schedule + +![](../.gitbook/assets/image%20%28215%29.png) + +Although ye schedule consistent he par still failure kahi bhi ho sakti he say failure hui \(line\) then T1 roll back hua par T2 ne commit kardia toh inconssistency reh jaayegi it should be 5 \(initially A is 10\) but it will be 15. This is irrecoverable schedule and we don't want it. Here T2 ka R\(A\) is dirty read agar transaction me dirty read nahi he then transaction humesha recoverable hoga kyuki uss case me ek ke rollback se dusre ko farak nahi padta. Dirty read hone ke baad bhi recoverable ho sakta he agar jis order me dirty read he ussi order me commit he like + +![](../.gitbook/assets/image%20%28254%29.png) + +> Cascadeless Schedule [https://youtu.be/qH2iYtuJEwQ?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV](https://youtu.be/qH2iYtuJEwQ?list=PLmXKhU9FNesR1rSES7oLdJaNFgmuj0SYV) \[we don't want dirty read\] + +## Strict Schedule + +Dirty read kehta tha ki write ho raha he kisi pe toh bina commit ke read nahi, strict kehta he read write dono nahi. It doesn't mean serial ho pura see S3. S1 is not strict schedule. S2-S3 are + +![](../.gitbook/assets/image%20%28209%29.png) + +## B and B+ Trees + +[https://www.youtube.com/watch?v=aZjYr87r1b8](https://www.youtube.com/watch?v=aZjYr87r1b8) + +![](../.gitbook/assets/image%20%28232%29.png) + +M way search tree are simmilar to BST we can say that a 2 degree M way ST is BST. + +![](../.gitbook/assets/image%20%28248%29.png) + +We need to modify the m way ST to use as Index. It stores now child pointer, key, and record pointer. + +Now B Trees are the above tree but with rules since in above tree we can put it like this then it will have more time complexity + +![](../.gitbook/assets/image%20%28260%29.png) + +so we have rules while insertion in B trees + +* Next node can be created if current node is atleast ceil\(m/2\) filled except root and leafs +* All leafs must be at same level +* Creation process is bottom-up + +> In B+ Trees we will not have record pointer at every node, we'll just have record pointers at leaf nodes + +* A B/B+ tree with order p has maximum p pointers and hence maximum p children. +* A B/B+ tree with order p has minimum ceil\(p/2\) pointers and hence minimum ceil\(p/2\) children. +* A B/B+ tree with order p has maximum \(p – 1\) and minimum ceil\(p/2\) – 1 keys. + +[https://www.youtube.com/watch?v=k3ODdIez0-8](https://www.youtube.com/watch?v=k3ODdIez0-8) +[https://www.youtube.com/watch?v=TXIqXYUT2NE](https://www.youtube.com/watch?v=TXIqXYUT2NE) +[https://www.youtube.com/watch?v=YZECPU-3iHs](https://www.youtube.com/watch?v=YZECPU-3iHs) + +## Lock based protocols + +A transaction begin by acquiring a lock on the entire database, other transaction cannot acquire the lock and only after the end of first transaction the lock gets unlocked this way isolation is achieved. It becomes trivially serial. poor performance. cascedless schedule. + +Modes in which data item may be locked: + +* Shared: Transacation can read but cannot write ---- lock-S\(Q\) +* Exclusive: Both Read Write ----- lock-X\(Q\) +* unlock\(Q\) + +Transaction proceed by making request to concruenct-control manager which grants the lock to the transaction. Agar turant grant hojaye toh it's compatible function + +```text +lock-X(B) +read(B) +B = B-50 +write(B) +unlock(B) +lock-X(A) +read(A) +A = A+50 +write(A) +unlock(A4+-) +``` + diff --git a/semester/oops.md b/semester/oops.md new file mode 100644 index 0000000..6bd5602 --- /dev/null +++ b/semester/oops.md @@ -0,0 +1,846 @@ +# OOPS + +### Issues in Software\(s\): + +Correctness, Maintainability, Reusability, Openness and interoperability, portability, security, integrity, user friendliness + +### Evolution of Software\(s\): + +Machine Language, Assembly Language, Procedure Language, Object-Oriented Programming. + +* Procedure Oriented language emphasis is on doing things \(algorithms\) +* Large programs are divided into smaller programs known as functions. +* Most of the functions share global data. +* Data move openly around the system from function to function +* Functions transform data from one form to another. +* Employs top-down approach in program design. +* OOP is an approach to program organization and that attempts to eliminate some of the pitfalls of conventional programming methods by incorporating the best of structured programming features with several powerful new concepts. +* It is a new way of organizing and developing programs and has nothing to do with any particular language +* It models real world problem very well unlike Procedure oriented languages +* Emphasis is on data rather than procedure +* Programs are divided into what are known as objects. +* Data structures are designed such that they characterize the objects. +* Functions that operates on the data of an object are tied together in the data structure +* Data is hidden and cannot be accessed by external functions. +* Objects may communicate with each other through functions. +* New data and functions can be easily added whenever necessary +* Follows bottom-up approach in program design. + +> Max no limit length in identifier. only a-z, A-Z, numbers \(not in beginning\) and \_ + +Basic terms - Objects, Classes, Data Abstractions & Encapsulation, Inheritance, Polymorphish, Dynamic Binding, Message Passing + +### Objects + +* Basic runtime entities in an Object oriented system +* It may represent a person, a place, a table of data or any item that the program has to handle. +* Objects interact by sending messages to one another. + +### Classes + +* A class is a collection of objects of similar type on which the object operates +* Could be a user defined data type + +### Data Abstraction + +* Wraping up of data and function into a single unit \(class\) is known as encapsulation +* Data is not accessible to the outside world +* Functions wrapped in class can only access it +* These functions provide the interface between object's data and the program. +* Abstraction refers to act of representing essential features without including the background details and explanations +* Since classes use the concept of data abstraction, they are known as ADT + +![](../.gitbook/assets/image%20%28197%29.png) + +### Inheritance + +* It is the process by which objects of one class acquire the properties of objects of another class. +* It provides the idea of re usability. This means we can add additional features to an existing class without modifying it. +* Reuse existing class along with tailor it in such a way that it does not introduce any undesirable side-effects into the rest of classes. + +### Polymorphism + +* Greek word meaning ability to take more than one form +* The operation may exhibit different behavior in different instances. Behavior depends upon the type of data used in operation. +* Operator Overloading & Functions Overloading +* It plays an important role in allowing objects having different internal structures to share the same external interface. +* Polymorphism is extensively used in implementing inheritance +* It is early binding or static binding or static linking. \(Compile Time Polymorphism\) + +#### Dynamic Binding + +* Binding refers to the linking of a procedure call to the code to be executed in response to the call. +* Code associated with given procedure call is not known until the time of the call at run-time. +* Runtime-Polymorphism. +* Also known as late binding + +| Compile Time Polymorphism | Run Time Polymorphism | +| :--- | :--- | +| Call resolved by compiler | Call not resolved by compiler | +| Also known as static binding, early binding, overloading | Also known as Dynamic binding, late binding, overriding | +| Overloading is compile time polymorphism where more than one methods share the same name with different parameters or signature and return type | Overriding is run time polymorphism having same method with same parameter or signature but associated in a class or it's subclass | +| It is achieved by function overloading & operator overloading | It is achieved by virtual functions | +| It provides fast execution because known early at compile time | Slow execution | +| It is less flexible as all things execute at compile time | More flexible | + +### Benefits Of OOPS + +* Through inheritance we can eliminate redundant code and extend the use of existing classes. +* We can build programs from the standard working modules the communicate whith one another, rather than having to start writing everything from scratch. +* The principle of data hiding helps the programmer to build secure programs. +* It is possible to have multiple instances of an object to co-exist without any interference. +* The data centric design approach enables us to capture more details of a model. +* Object oriented system can be easily upgraded from small to large systems +* Message passing techniques for communication between objects makes the interface description with external systems much simpler. +* Software complexity can be easily managed. + +> Object-based programming \(ADA\) do not support inheritance and dynamic binding but object oriented programming do so + +> Member functions \(Functions inside a class\) are also known as methods + +> In C main\(\) by default returns the void type but in C++ it returns integer by default + +> Old C has /\* \*/ while in C++ // + +> Zero divided by zero error is an example of runtime error. Will stll compile. Error at runtime. There's compiler error if during compilation. Lastly there's a linker error. + +> Farenheit to celcius = \(\(f-32\)/9\)\*5 + +Tokens are the smallest individual units in a program. C++ has following tokens - Keywords, Identifiers, Constants, Strings, Operators + +> C 32 keywords C++ 64 keywords + +```text +enum color { RED, BLUE, GREEN, YELLOW }; +//RED, BLUE = 5, GREEN = 6, YELLOW then RED is 0 Yellow is 7 +//RED = 3, BLUE, GREEN, YELLOW then automatically 4, 5, 6, 7 +color bg = BLUE; +color bg = 1; //Error in c++ okay in C +color bg = (color) 1; +int bg = BLUE; +``` + +```text +const int MAX_AGE = 90; +const int* a = new int; +//or int const* a = new int; +*a = 2; //ERROR since a is constant +a = (int*)&MAX_AGE; //No Error now +//Can't change content of the pointer here but can change pointer address + +//Constant Pointer +const int MAX_AGE = 90; +int* const a = new int; +*a = 2; //No Error here +a = (int*)&MAX_AGE; //ERROR since pointer of a is constant +//Can't change the pointer address here + +const int* const a = new int; +//can't change anything now +``` + +C++ new operators - + +* :: \(Scope resolution operator\) +* ::\* \(To declare pointer to a member of a class\) - Member derefrencing operator +* \* \(To access a member using object name and pointer to that member\) - Member derefrencing operator +* ->\* \(To access a member using a pointer to the object and a pointer to that member\) - Member derefrencing operator +* .\* \(Pointer-to-member operator\) +* delete \(Memory release operator\) +* new \(Memory allocation operator\) +* endl \(Line feed operator\) +* setw \(Field width operator\) + +> A void pointer can be used to create generic pointer + +> Expressions - Combination of constant, operator & variables it may also include function call that may return value. Types - Constant expression, Integral expression, float expression, pointer expression, relational expression, bitwise expression, logical expression + +```text +int m = 10; +int main() +{ + int m = 20; + { + int k = m; + int m = 30; + // k is 20 m is 30 ::m is 10 + } + // m is 20 ::m is 10 +} +``` + +typedef int int32; can be declared at the beginning in case the architecture has 4 bytes of int if say on other it's 2 and we want 4 we can replace int with long and at every place were we used int32 it's 4 bytes long int now. + +We can mix data types expressions m = 2+2.75; is valid. Automatic conversion happens called implicit conversion. Likewise explicit conversion + +**The const was taken from C++ and incorporated in ANSI C, although quite differently.** +In C++ const we can use it with methods it will act like read only function however in C there are no methods. Other difference we cannot use const int size as array size in C but C++ we can. In C++ const are local whearas in C it's global. + +Advantages of new over malloc: + +* It automatically determines the size of data object we don't need to use operator sizeof +* It automatically returns correct pointer size, malloc return void\* +* Like any operator new and delete can be overloaded +* New calls the constructor too hence initializing while malloc doesnt +* We use delete for new operator and free for malloc + +Int - 4 bytes i.e. 0 to 24.8-1 \[Unsigned\] or -24.8/2 to 24\*8-1 \[Signed\] + +void func\(\); //Function prototyping it is not important to specify argument name in it +void func\(...\) //This is correct + +#### Inline Functions + +Objective of using function is to save time which become more if it's called multiple times. Lot of time in executing a series of instructions for tasks such as jumping the function, saving registers, pushing arguments on the stack. One solution is to use \#define preprocessor however we cannot perform complex stuffs with it since it's not really a function. Inline functions eliminates the cost of small functions it is expanded in-line when it is invoked i.e. the compiler replaces the function call with it's corresponding function code \(something simillar to macros expansion\). It makes the program runs faster however the trade off is it takes more memory because the statement that defines inline functions are reproduces at each point where the function is called. + +Use inline functions when + +* Instead of \#define +* When functions are very small and called often, faster code smaller executable +* Not I/O bound +* Don't use with constructors and destructors even when empty they have built-in functionalities +* Don't use with functions having - Loops, Jump statements like goto, switch & Recursive calls or having static variables + +Preprocessor macros are just substitution patterns applied to your code. They can be used almost anywhere in your code. Inline functions are actual functions whose body is directly injected into their call site. They can only be useful where a function call is appropriate. + +* Macros are not type safe, and can be expanded regardless of whether they are syntatically correct +* Macro done by preprocessor Inline done by compiler +* Macros can expand other macros inline functions cannot +* Inline functions are not always guaranteed to be inlined + +void perform\(int a = 5\) //Default argument + + +```text +int func() { return 1; } +float func() { return 1.0f; } +``` + +Function Overloading doesn't work like this We gotta use templates for this + + +**Merits** + +* Friend function acts as a bridge between two classes by operating on their private datas +* Must have access to source code for the class to make a function into friend +* Able to access without need of inheriting +* Can be used to increase versatility of operator overloading + +**Demerits** + +* Gives access to private members +* Conceptually messy +* Cannot do any run time polymorphism in it's member +* Maximum size of memory will be occupied by objects according to the size of friend members + +Usages Of Friend Functions & Friend Class: + +```text +class XYZ +{ +private: + int data; +public: + void setVal(int val) + { + data = val; + } + friend void show(XYZ); +}; +void show(XYZ xyz) +{ + cout << xyz.data << endl; +} +``` + +```text +class ABC; +class XYZ +{ +private: + int data; +public: + void setVal(int val) + { + data = val; + } + friend void add(XYZ, ABC); +}; +class ABC +{ +private: + int data; +public: + void setVal(int val) + { + data = val; + } + friend void add(XYZ, ABC); +}; +void show(XYZ xyz, ABC abc) +{ + cout << (xyz.data + abc.data) << endl; +} +``` + +```text +#include +using namespace std; + +class ABC; //Forward Declaration + +class XYZ +{ +private: + int data; +public: + void setValue(int value) + { + data = value; + } + friend class ABC; +}; + +class ABC +{ +public: + int data; + void setValue(int value, XYZ xyz) + { + data = value + xyz.data; + } +}; + +int main() +{ + XYZ x; + ABC a; + x.setValue(5); + a.setValue(4, x); + getXYZData(x); + cout << a.data << endl; + return 0; +} +``` + +Advantages of passing by reference: + +* No new copy of variable is made, so overhead of copying is saved. This makes program execute faster specially when passing objects of large struct or class. +* Array or objects can also be passed. +* Sometimes function need to change the original value like in sorting so this gets useful. +* Can manipulate multiple values passed by reference in argument unline in pass by value where we can return single return value. + +```text +class myClass +{ +public: + void doShit(int); +}; + +void myClass::doShit(int val) { } //Member function defination +//inline void myClass::doShit(int val) { } We can even make it inline outside +``` + +Static Data Members: + +* It is initialized to zero when the first object of its class is created. +* Only one copy of the entire class is created for the entire class and is shared by all the objects of that class, no matter how many objects are created. +* It is visible only within the class but it's lifetime is within the program. + +Static Member Functions: + +* A static function can have access to only other static members \(functions or variables\) declared in the same class. +* It is called with class name instead of object + +```text +class Test +{ +public: + static int val; + static void print() + { + cout << val << endl; + } +}; + +int Test::val = 1; +int main() +{ + cout << Test::val << endl; + Test::print(); + return 0; +} +``` + +![](../.gitbook/assets/image%20%28196%29.png) + +#### Pointers To Members + +```text +class MyClass +{ +private: + int x, y; +public: + void show() { } + friend int sum(MyClass m); +}; +int sum(MyClass m) +{ + int MyClass::* ptrx = &MyClass::x;s + int MyClass::* ptry = &MyClass::y; + MyClass *cl = &m; + int S = m.*ptrx + cl->*ptry; + return S; +} +``` + +classes can be defined and used inside a function or a block. Such classes are called local. + +* It can use global variables \(declared above\) and static variables the function. Should use scope resolution operator :: +* Static data members are not allowed in local class. It need to be defined in global scope instead. + +C++ supports struct mainly to support backward compatibility with C however there are still some difference in structs in C & C++ + +* C++ structs can have both data members and functions. C only allow data members +* struct keyword is necessary in C to create struct type variable +* Empty struct in C is violation +* C structs cannot have static members C++ can have +* Members cannot directly be initialized in struct in C but with C++11 it can +* Both pointer & reference is allowed in C++ struct but only pointer in C + +Characterstics of constructors + +* They should be declared in the public section +* They are invoked automatically when the objects are created +* They do not have return type not even void +* They can have default argument like any other function +* Constructors cannot be virtual only destructors +* We cannot refer to their address +* Can be overloaded +* Type - Default, Copy, Parametrized, Dynamic initialization in constructor +* Can also explicitly delete a constructor then we cannot create instance of the method however we can still do it from the class's member function: + +```text +A a = A(5,190); //Explicit +A a(5,190); +``` + +```text +MyClass(const MyClass &other) { curX = other.curX; } + +Time t2(t1); //Explicit call of copy constructor +Time t2 = t1; //Implicit call of copy constructor +``` + +> Destructors never take any arguments. There can be a virtual destructor too. + +```text +MyClass +{ +public: + MyClass() { } + MyClass(int val = 8) { } +} +//This will give error since both constructors are default constructor +``` + +We cannot overload + +* Class member access operators \(. .\*\) +* Scope resolution operator \(::\) +* Size operator \(sizeof\) +* Conditional Operator \(?:\) + +```text +vector operator+(vector); //vector addition +vector operator-(); //unary minus +vector operator++(); //pre-increment +vector operator++(int); //post-increment +friend vector operator+(vector, vector); //vector addition +friend vector operator-(vector); //unary minus +vector operator-(vector); //subtration +int operator==(vector); //comparison +friend int operator==(vector, vector); //comparison +friend ostream& operator<<(ostream, vector); +void * operator new(size_t size); +void operator delete(void * p); +``` + +Rules for operator overloading + +* Only existing operators can be overloaded. New operators cannot be created +* The overloaded operator must have atleast one user defined operand +* We shouldn't change the basic meaning of an operator i.e. + operator should add and not subtract +* They cannot be overriden +* Some operators cannot be overloaded +* There are operators on which friend cannot be used: = \(\) \[\] -> because compiler is already providing it so it will create ambiguity if used friend function + +The compiler does not support automatic type conversion from human defined data types so we need to define it + +```text +//Basic to class type: Simply in constructor - Only single argument constructor behaves like type caster +//Class to basic type: +operator double() +{ + return x / 2; +} +``` + +#### Namespace + +* In each scope naming it in brief means namespacing. +* Namespacing is required so as we can still use same name for variables on different scope +* It was added in C++ and not present in C + +```text +namespace something +{ + class MyCoolClass + { + ... + }; +} +using namespace something; +``` + +#### Inheritance + +If public then base class variables are accessible through ABC class object. Private of base class are not inherited. Base constructor first gets called then derieved. + +```text +class ABC : public XYZ //Derives XYZ it can be private too simple XYZ means private +{ +} + +Derrived* derrived = new Derrived(); +delete derrived; + +//Base Constructed +//Derrived Constructed +//Derrived Destructed +//Base Destructed + +Base* poly = new Derrived(); +delete poly; + +//Base Constructed +//Derrived Constructed +//Base Destructed +That's why we use virtual destructors +``` + +A protected visibility modifier is accessible by the member functions within its class and any immediately derrived from it. It cannot be accessed outside these two classes. In child class also that protected variable becomes protected. + +Single Inheritance, Multilevel Inheritance, Multiple Inheritance, Hierarchial Inheritance \(One has hierarchially like many childs\), Hybrid Inheritance\(Mixture of all\) + +Using class ABC : public virtual XYZ we declare virtual base class. C++ takes necessary steps to see that only one copy of that class is inherited, regardless of how many inheritance paths exists between them. + +```text +class student { ... }; +class test : public virtual student { ... }; +class sports : public virtual student { ... }; +class result : public test, public sports { ... }; +``` + +* Abstract class is one that is not used to create objects +* Acts only as a base class +* Other classes are built through it + +> Private members of base class are not inherited is there any way - assign public getter or setter for it in base class + +#### This Pointer + +* It represents pointer to an object that invokes the member function +* Example calling a.getMax\(\); using this pointer in getMax function will return address of object a +* No need to explicitly tell this in member function but needed if there's a variable name clash + +> We can make pointer to derrived class object of type base class It's type compatible + +```text +Derrived d; +Base *ptr = &d; +``` + +#### Virtual Function + +* When we use same function in both base & derrived class. The function in base is declared as virtual +* Declared with virtual keyword like - virtual void doSomething\(\) { } +* If redefined in derrived class then redefined function will be called when derrived object is used otherwise if not redefined then base function + +Rules for Virtual Functions + +* Virtual functions must be a member of some class +* They cannot be static members +* They are accessed using object pointers +* A virtual function can be a friend of another class +* A virtual function of base class must be defined even if it may not be used +* If a virtual function is defined in base class it need not to be necessarily redefined in derrived class in that case call will invoke the base function +* Cannot have virtual constructors but virtual destructors + +```text +XYZ *d = new XYZ(); +ABC *base = d; +delete base; +``` + +Doing this will make base gets destroyed but derrived is not destroyed. If we call delete on d then both will be destroyed. But we want to avoid memory leaks for delete base too so we make destructor virtual + +Pure Virtual Function: + +* It is normal practice to declare a function virtual then redefine it +* The function inside the base class acts as a placeholder used for performing any task +* A do nothing function which gets redefined in derrived class is pure virtual function +* A class with only pure virtual functions cannot be used to declare any objects of their own and are called abstract class. +* Main objective of abstract class is to provide some traits to the derrived classes as it serves as a placeholder +* The implications of making a function a pure virtual function is to achieve run time polymorphism + +> Abstract class have at least one virtual function + +```text +virtual void doSomething() = 0; +``` + +#### Calling function 2 ways + +```text +perf(); + +void (*func)() = &(perf); +(*func)(); +``` + +#### C++ Streams + +* The I/O systems in C++ cout & cin uses streams as data format +* A stream is a sequence of bytes +* It acts either as a source from which the input data can be obtained \(Input Stream\) or as destination to which the output data can be sent \(Output stream\) +* In cin cout << >> operators are overloaded to provide stream of data functionality +* Cin has get and put function to handle single character I/O. Likewise - cin.getLine\(lineStr, size\), write function displays entire line. cout << setw\(5\) or setprecision\(5\) + +```text +cout << setfill('A') << std::right << setw(5) << ""; //or if in end "PP" +//output AAAAA & AAAPP +``` + +> \#include is required - The header file iomanip provides a set of functions called manipulators which can be used to manipulate the output formats ios is parent class derrives - istream and ostream class + +```text +char c; +cin >> c; //This will skip white space +cin.get(c); +``` + +```text +#include + +ofstream oS("file.txt"); +oS << "OUT" << endl; +oS.close(); + +ifstream iS("file.txt"); //We can also create fstream object +// or ifstream iS; ifstream.open("...", mode); like ios::in | ios::nocreate +while(iS) //Detects end of file +{ + iS >> str; + cout << str << endl; +} +iS.close(); +``` + +Different modes: + +* ios::app - Append to end of file +* ios::ate - Go to end of file on opening +* ios::binary - Binary file +* ios::in - opening file in reading only +* ios::nocreate - open fails if file doesn't exists +* ios::noreplace - open fails if file already exists +* ios::out - open file for writing only +* ios::trunc - delete the content of file if it exists + +```text +iS.seekg(0, ios::beg) //Moves get pointer +iS.seekp(0, ios::beg) //Moves put pointer +iS.tellg() //Moves get pointer +iS.tellp() //Moves put pointer +ios::beg //start of file +ios::cur //cur pos of pointer +ios::end //end of file +``` + +> iS.get\(\), put\(\), read\(\), write\(\) - Read and Write performs in binary format + +```text +infile.read((char*) &val, sizeof(val)); +``` + +Error Handling in I/O + +* File not exists +* File name for saving already exists +* Invalid operation such as reading past the end of file +* No space in disk to save file + +```text +if (iS.bad()) //report it's bad +else iS.clear(); +``` + +move the pointer by 15 positions backwards from current - fout.seekg \(-15,ios::cur\); + +#### Command line arguments + +```text +int main(int argc, char *argv[]) { return 0; } +//argc is argument count argv is argument vector +//like we enter g++ -g main.cpp && ./a These are goddamn arguments then 4 arguments will go there +``` + +* argv\[0\] contains name of the program. argv\[1...argc\] contains our arguments + +> What is the difference between opening fule through constructor or open function? It's that through constructor say we get out of scope then automatically destructor will be called so we don't have to worry about calling close but using open function we do have to close it to avoid memory leaks. Other difference is we provides modes using the function + +Advantages of using binary format in files + +* Compact size +* Faster to process as no conversion +* Others cannot easily interpret it +* Some of the encryption or compression algoritms are more easy to implement + +#### Templates + +* Templates is a new feature in C++ +* It enables us to define generic classes and functions & thus providing support for generic programming +* Generic programming is an approach in which generic types are used as parameters +* Avoids code duplication +* It works like macros during run time gets copy pasted + +```text +template //or template or multiple can also be assigned template +class MyClass +{ + T something; +}; +//or even function overloading - we can use T as parameter or even return type too +template +void f(T s) +{ + std::cout << s << '\n'; +} +int main() +{ + MyClass obj; + return 0; +} +//Even non template type can be used as argument to template +template +void f(T s) +{ + int arr[size]; + ... +} +``` + +Difference between templates & macros + +* Templates obey C++ syntatically +* Templates are more powerful +* Templates are slower as say it has functionality such as during recursive calls it will still act generic and thus macros are limited to single expansion +* Syntax difference +* macros are preprocessor means it gets processed before actual code + +#### Exception Handling + +An exception is a situation, which occured by the runtime error. In other words, an exception is a runtime error. An exception may result in loss of data or an abnormal execution of program. + +* Find the problem \(Hit the exception\) +* Inform that an error has occured \(Throw the exception\) +* Recieve the error information \(catch the exception\) +* Take corrective actions \(Handle the exception\) + +```text +try +{ + if (b != 0) cout << a/b << endl; + else throw(x); +} +catch(int i) +{ + cout << "Exception " << i << endl; +} +catch(int i) { ... } //multiple catch can be there +``` + +Try is to used to invoke a function that contains an exception + +Class Type Exception + +```text +class Error +{ + ... +}; +try +{ + throw Error("Shitty Error", 5000); +} +catch(Error e) +{ + ... +} +//catch(...) will catch all exceptions +//using throw inside catch is rethrowing an exception +``` + +> strcpy\(s1, s2\) function to copy string, int n = strlen\(str\) to get string length + +* Threads are smaller part of a process. +* In current generation of mult core CPU we can perform many task at a time so in order to utilize it we use Multi threading + +```text +#include +... +int main() +{ + thread thr1(func, params); + thr1.join(); + return 0; +} +``` + +Thread synchronization is the concurrent execution of two or more threads that share critical resources. Threads should be synchronized to avoid critical resource use conflicts. Otherwise, conflicts may arise when parallel-running threads attempt to modify a common variable at the same time. + +#### Java + +```text +import java.io.* +public class Test +{ + public static void main(String args[]) + { + Scanner S = new Scanner(System.in); + int a = S.nextInt(); + system.out.println(a + "~"); + } +} +``` + +* In C++ to support backward compatibility with C can still follow non OOP standards but In Java, everything is Object Oriented. +* It is platform independent as it runs on a virtual platform JVM \(Java Virtual Machine\) unlike C++ which runs on native machine and hence if machine doesn't support C++ it won't compile. +* Java is more secure since there is no pointer concept so no explicit pointers or memory leaks harming performance. +* There are some inbuilt exception handling & memory management which makes java more robust. +* Applets allows us to even run java program in a web browser. +* Java supports call by value only \(No call by reference\). +* Java has built in multi threading support. +* Inbuilt Java Swing functionality allows user to create window-based applications which is not possible in C++ without third party libraries. + +> Java bytecode is the instruction set for the Java Virtual Machine. + +> Servlet is Java EE server driven technology to create web applications in java. + +> JRE \(Java Runtime Environment\) are set of tools required for java development it include JDK \(Java Development Kit\) & Some support libraries + +> Template class & Class template are not the same. Template class is wrong it's only class template or function template because classes do not define templates, templates define classes \(and functions\). + +* diff --git a/semester/os.md b/semester/os.md new file mode 100644 index 0000000..6a733f7 --- /dev/null +++ b/semester/os.md @@ -0,0 +1,857 @@ +# OS + +## Introduction + +* A program that acts as an intermediary b/w a user of a computer and the hardware. +* Direct hardware access is neither simple nor convenient \(using machine language\) that's why OS interface \(CLI, GUI\) +* Resource Manager: Manages system resources in an unbiased manner also resolves conflicting requests. +* Provides a platform on which other application programs are installed. +* Efficient utilization of computer hardware +* Protection and Security: Protection is all access to system resource is controlled. Security of the system from outsiders by requiring user authentication. +* One program running all the time in computer is kernel others are either system or user program. +* Kernel is a core part, it acts like a bridge between applications and hardwares. + + + + + + + + + + + + + + +
Operating SystemKernel
+
    +
  1. OS is a system software
  2. +
  3. OS provides interface between user and hardware
  4. +
  5. It also provides protection and security.
  6. +
  7. All system needs OS to run
  8. +
  9. Types: Single user, multi user, Multi processor, Realtime, Distributed
  10. +
  11. It is the first program to load when the computer boots up.
  12. +
+
+
    +
  1. Kernel is a system software which is a part of OS
  2. +
  3. Kernel provides interface between application and hardware.
  4. +
  5. It's main purpose is memory, disk, process and task management
  6. +
  7. All OS needs kernel to run
  8. +
  9. Types: Monolithic, Micro
  10. +
  11. It is the first program to load when OS runs.
  12. +
+
+ +Bootstrap program is loaded at power up or reboot. Typically stored in ROM generally known as firmware. Initializes all aspects of system - CPU registers, device controllers, memory contents, Loads OS kernel and starts execution. BIOS \(Basic Input Output System\) and UEFI \(Unified Extensible Firmware Interface\) + +## Computer System Organization + +### Computer System Operation + +* One or more CPU devices controllers connected through common bus providing access to shared memory +* Concurrent execution of CPUs and device competing for memory cycles +* I/O devices and CPU can execute concurrently +* Each device controller is in charge of particular device type. +* Each device controller has a local buffer. +* CPU moves data from/to main memory to/from local buffer. +* I/O is from the devices to local buffer of controller +* Device controller informs CPU that it has finished its operation by causing an interrupt. + +### Interrupts + +* Occurrence of an event is signaled from either - Hardware \(send signal via system bus to CPU\) or Software \(by invoking system call\) +* Interrupt architecture must save the address of the interrupted instructions. +* Incoming interrupts are distributed while another interrupt is being processed to prevent a lost interrupt. + +> If an asynchronous interrupt is triggered, it means that the processor will \(most likely at the next clock cycle\) save its current executing environment, and service the interrupt request. This is an example of a hardware interrupt \(one that is triggered by an external connection to the processor\). +> Hardware device signals a need for 'attention' via interrupt request line. +> +> Software generated interrupt is called trap. Like zero by zero or invalid memory. + +### Interrupt Handling + +* The OS preserves the state of the CPU by storing registers and program counters +* Determines which type of interrupt has occured: + * Polling \(Microcontroller keeps polling/checking devices for pending requests\) + * Vectored interrupt system \(Devices directs to the microcontroller appropriate service routine\) + +### Storage Structure + + + + + + + + + + + + + + + + +
Main Memory (RAM)Secondary MemoryMagnetic Disks
+
    +
  • Contains programs to execute
  • +
  • Too small for storage of all programs permanently
  • +
  • Volatile Storage
  • +
+
+
    +
  • Extensive
  • +
  • Backup purpose
  • +
  • Non-volatile
  • +
+
+
    +
  • Rigid metal or glass platters covered with magnetic recorded material.
  • +
  • Disk surface is logically divided into tracks which are sub divided into + sectors.
  • +
  • The disk controller determines the logical interaction b/w the device + and computer
  • +
+
+ +> Cache Memory, Registers + +Device controller transfers entire block of data directly to/from its buffer storage to memory with no intervention from CPU. DMA \(Direct Memory Access\) + +## Types of OS + +### Batch OS: + +* Does not interact with computers directly. +* A operator takes similar jobs having same requirements and groups them into batches. +* It is the job of the operator to sort the jobs with similar needs. +* Advantages: + * Processor of the batch system knows how long the job would be when it is in the queue + * Multiple users can share the batch system + * Idle time is very less + * It is easy to manage large work repeatedly in batch system +* Disadvantages: + * Hard to debug + * If a job fails other job has to wait for an unknown amount of time. +* Eg: Bank statements, Payroll system, etc. + +### Time sharing / Multi tasking OS: + +* Each task is given some time to execute so that all the tasks work smoothly. +* Multitasking is multi programming with time sharing. +* Multi programming - maximizes CPU utilization, more than one process ready to execute in main memory, context switch during a program idle/IO task, CPU never idle unless there's no process ready to execute. **Adv:** High CPU utilization, less waiting response time, can be extended to multiple users, Nowadays very useful. **Dis adv:** Difficult scheduling, main memory management is reqd, memory fragmentation, paging \(non-contiguous\) memory allocation + +### Multi processing OS: + +* 2 or more CPU within a single computer inclosed communication sharing the system bus. memory and other IO. +* Different process may run on different CPU, true parallel execution. +* Symmetric: CPUs are identical and they share main memory. Assymetric: CPUs are not identical and they follow master-slave relationship Assymetric is easy to design but less efficient. +* Adv: higher throughput, higher reliability, cost saving, battery saving, true parallel processing. Dis adv: More complex, Overhead on coupling, Large main memory. + +### Distributed OS: + +* Various autonomous interconnected computers communicates each other using a shared communication network. +* Independent system processes their own memory unit and CPU. +* Also refereed as loosely coupled system. +* Adv: Failure of one will not affect other as all are independent, Load on host reduces delay in data processing Dis adv: Failure of main network will stop all communication, expensive, complex. + +### Network OS: + +* These system run on a server +* Allows shared access +* All the users are well aware of the underlying configuration, of all other users within the network, their individual connections, etc. That's why these computers are popularly known as tightly coupled system. +* Adv: Highly stable centralized servers, security concerns are handled well, New technology and hardware upgrades are easily integrated, remote server access is possible. Dis adv: Costly, Requires regular maintenance, user has to depend on central location for most operations, latency. +* Windows server, BSD, etc. + +### Real time OS: + +* Used when time requirements are very string - missile, rocket, robots, etc. +* Adv: + * Maximum consumption \(maximum utilization of devices and system thus more output from all resources\) + * Task shifting is very less + * Focus on application + * Since size of programs are very small RTOS can also be used in embedded systems. + * Error free + * Memory allocation is best managed in these system. +* Dis adv: + * Limited tasks + * use heavy system resources + * complex + * Thread priority as these systems are very less prone to switching tasks. + +## Operations + +### Dual Mode + +Dual mode operations allows OS to protect itself and other system components + +* User mode and kernel mode +* Mode bit provided by hardware +* Some instructions designated as only executable in kernel mode to protect OS from errant users +* OS puts CPU in user mode when a user program is executing so that user program do not interfere with OS programs. + +Works through API \(Application program interface\) using System call + +* Provides means for user program to ask the OS to perform tasks reserved for OS on user program itself. +* Leads to invocation of trap to specific location in the interrupt vector. +* Control passes to service routine and mode bit +* After executing control set back to user mode + +> Timer to prevent infinite loop resource hogging processes + +### Process Management + +* A process is a program in execution. It is a unit of work within the system. Program is a passive entity, process is an active entity.This means that a program can be considered as a bunch of code, or sequence of instructions, whereas a process is any such program that is currently active. A process can have several states, and is completely described in a PCB, or Process Control Block +* Process needs resources to accomplish its task \(CPU, memory, IO\) +* Process terminates requires reclaim of any reusable resources. +* Single threaded process has one program counter specifying location of next instruction. Process executes instructions sequentially one at a time. +* Provide mechanism for process synchronization, communication, deadlock handling, suspending and resuming process. + +### I/O Buffering + +* Process of temporarily storing data that is passing between a processor and its peripheral to smooth out the rate of speed. + +### Memory Management + +* Optimize CPU utilization +* Keep track of which part of memory are currently being used and by who +* Deciding which process \(or part\) and data into and out of memory. +* Allocating and deallocating memory space as needed. + +### I/O Subsystem is responsible for + +* I/O Scheduling: Determining a good order in which to execute a set of I/O requests - Optimal utilization. +* Buffering: It is done to cope with the speed mismatch between producer and consumer of data stream. + * If an output device say printer is slow it has a buffer the computer can fill it and then go do other tasks while printer will read buffer. + * If an input device say keyboard is slow it gives data to buffer the CPU reads it all at once. + * Concurrency with two or more buffer is possible for applications to be filling one while I/O is happening on other. +* Caching: Buffer may hold only in secondary memory, caching it is faster +* Spooling \(Simultaneous Peripheral Operation Online\): It is a buffer that holds output of a device such as a printer that cannot accept continuous data. \(because I/O devices are slow to match up with speed difference\) +* Error Handling: Protected memory guards against many kind of software and hardware glitches. +* I/O protection: User cannot directly issue I/O access \(illegal\) requires high privilege. + +> Micro kernel: Small in size, slow execution, easily extensible, if a service crash it does effect on working on the micro kernel, More implementation code. +> +> Monolithic: Larger, Faster, Hard to extend, If crashed It effects OS, Less implementation code. + +## System Calls + +* Programming interface to the service provided by OS. +* Typically written in high level language \(C++ Java\) or few low level tasks may be written in assembly. +* Mostly accessed by programs via API rather then direct system call. +* Examples: + * unix fork\(\) or windows CreateProcess\(\) creates a separate, duplicate process \(different pid\) this new process is child process. + * unix exit\(\) or windows ExitProcess\(\) + * unix getpid\(\) or windows GetCurrentProcessID\(\) + * exec\(\) system call used after a fork to replace process memory space with a new program \(replaces a process with another process, pid will be same content will differ\) + +```cpp +// 1 - Fork +int main() +{ + fork(); + printf("%d ", getpid()); // Output: 5962 5973 + return 0; +} +// If there are 3 forks 2^n process would be created + +// 2 - Exec +int main() +{ + printf("1. %d ", getpid()); + char *args[] = {"a", "b", "c", NULL}; + execv("path of new file ./o", args); + printf("Back to 1"); + return 0; +} +int main() +{ + printf("2. %d", getpid()); +} + +// 3 - wait +int main() +{ + if (fork() == 0) exit(0); + else + { + wait(); + cout << "process id has terminated"; + } +} +``` + +> Java Virtual Machine \(JVM\): It consists of a class loader and a java interpreter that executes the architectural neural byte code. The class loader, loads the compiled .class files from both Java API and Java Program for execution by Java interpreter. +> +> JVM also automatically manages garbage collection \(reclaim memory for object no longer in use\) Used on top of native OS or on chips specifically to run JAVA programs. + +### OS Design and Implementation Approaches: + +* Start by defining goal and specification +* Affected by choice of hardware, type of system +* Define user goal \(convenient to use, easy to learn, reliable, safe, fast\) System goal \(easy to design, implement and maintain, flexible, reliable, reliable, error free and efficient\). +* Mechanism determine how to do something, policies decide what will be done, The separation of policies from mechanism is very important principle, it allows maximum flexibility if policy decision are to be changed later. +* Once an OS is designed it has to implemented. Implementation in high level language has advantages such as easy to understand and debug. + +### MS DOS: + +It provides most functionality in least space, not divided into modules, its interfaces and level of functionality are not well separated in structure. + +## Process + +### A process includes: + +* Program code \(text section\) +* Current activity represented by program counter and processor registers. +* Stack \(temporary data, function parameter, return addresses, and local variables\) +* Data section \(global variables\) +* Heap \(memory dynamically allocated during process run time\) + +Program: Passive entity \(File containing list of instructions\) - executable file, becomes a process when loaded into memory. +Process: Active entity \(Program counter + Next instruction\) + +### Process State: + +* new \(The process is being created\) +* running \(Instructions are being executed\) +* waiting \(Process is waiting for some event I/O\) +* ready \(Process is waiting to be assigned by processor\) +* terminated \(finished execution\) + +### Process Control Block \(PCB\) + +* Information associated with each process. +* Process state +* Program counter +* CPU registers +* CPU scheduling information \(Process priority, pointer to scheduling queues\) +* Memory management information \(base and limit registers, page tables\) +* Accounting information \(Amount of CPU and real time used, time limits, account numbers, process numbers\) +* I/O status information \(list of I/O devices allocated, open files, etc.\) + +> PCB is kept in a memory area that is protected from the normal user access. +> This is done because it contains important process information. Some of the OS place the PCB at the beginning of kernel stack for the process in it is a safe location. + +### Scheduling Queues + +* Job queue \(set of all processes\) - as it enters the system +* Ready queue \(linked list, pointer to first and last PCB's in list\) +* Device queue \(set of processes waiting for an I/O device\) + +> CPU bound process: Process which requires most of time on CPU +> I/O bound process: Process which requires most of time on I/O +> Both I/O and CPU overhead must be maintained by scheduler. + +## Schedulers + + + + + + + + + + + + + + +
DispatcherScheduler
+
    +
  • Loads the program selected by short term scheduler
  • +
  • There's no different type of dispatcher
  • +
  • Dependent on short term scheduler
  • +
  • It has no specific algorithm for its implementation
  • +
  • Time taken by dispatcher is called dispatch latency
  • +
  • Also responsible for context switching, switching to user mode, jumping + to proper location when process again started.
  • +
+
+
    +
  • Scheduler is something which selects a process among various processes.
  • +
  • Types - long term, short term, medium
  • +
  • Independent
  • +
  • Various algos like - FCFS, SJF, RR, etc.
  • +
  • Time taken by scheduler is usually neglected.
  • +
  • Only work is selection of process.
  • +
+
+ +Scheduler selects process from the queues to be scheduled for execution + +* Long Term or Job Scheduler: + * It brings new process to the ready state by selecting from the spool. + * It controls degree of multi-programming i.e. no. of process present in ready queue at a point. + * It is important that long term scheduler make a careful selection of both I/O and CPU bound process. + * Executes at much less frequency \(in frequently\) Must be slow +* Short term or CPU scheduler: + * It is responsible for selecting one process from ready state for scheduling it on running state. \(It only selects not load the process on running\) + * Dispatcher is responsible for loading the process \(Switching context, switching to user mode, jumping to proper location in the newly loaded program\) +* Mid term scheduler: + * It is responsible for suspending and resuming the process \(It mainly does swapping i.e. moving processes from main memory to disk and vice versa\) + * Required to remove processes from memory to reduce degree of multi programming. + +### Context Switches: + +* CPU switches to another process \(system must save state of old process, load saved state for new process from PCB\) +* Context switch overhead +* Speed depends on - Hardware \(register\), content + +### Inter process communication \(IPC\): + +* Mechanism for process to communicate and to synchronize their actions + * Shared Memory: \(Allows max speed since there's memory access\) + * Message Passing: \(Useful for small data easier to implement, slow since it requires system calls involving kernel intervention\) +* Message passing implementation - Physical \(Shared memory, hardware bus\), Logical \(Logical properties\) +* Message passing may be either: + * Blocking \(synchronous\): Blocking send has the sender block until the message is received, Blocking receive has the receiver block until a message is available. + * Non Blocking \(asynchronous\): Non blocking send has the sender send the msg and continue. Non blocking receive has the receiver receive a valid msg or null. + +### Direct Communication + +* Links are established automatically. +* A link is associated with exactly one pair of communicating process +* Between each pair their exists exactly one link. +* The link may be unidirectional but is usually bidirectional. + +### Indirect Communication + +* Messages are directed and received from ports. Each port has an Id. Process can communicate only if they share that port. +* A link may be shared with many process +* Each process pair may share several lines. + +### Shared Buffer + +```cpp +#define BUFFER_SIZE 10 +typedef struct +{ + ... +} item; +item buffer[BUFFER_SIZE]; +int in = 0, out = 0; +/* (next free pos) (first full pos) +Empty buffer when in = out +Full buffer when (in+1)%BUFFER_SIZE = out */ +``` + +### Producer Consumer Problem: + +* Producer process produces info consumed by consumer process. +* Example: Webserver producing pages and browser consuming the web pages. +* Shared buffer filled by producer and emptied by the consumer in a synchronous manner. + * Unbounded buffer: No limit on size of the buffer \(Producer can always produce\) + * Bounded buffer: Assumes there's a fixed buffer size \(Producer have to wait for buffer empty\) + +```cpp +// Producer +item nextProduced; +while (true) +{ + while ((in+1)%BUFFER_SIZE == out); + buffer[in] = nextProduced; + in = (in+1)%BUFFER_SIZE; +} + +// Consumer +while (true) +{ + while (in == out); + nextConsumed = buffer[out]; + out = (out+1) % BUFFER_SIZE; + return nextConsumed; +} +``` + +Problems in Producer Consumer Problem + +* Producer should produce data only when buffer is not full. +* Consumer should consume only when buffer is not empty. +* Producer and consumer must not access the buffer at same time. + +### Remote Procedural Calls + +* RPC is a protocol that one program can use to request a service from a program located on another computer on a network without having to understand the network details. +* Follows client server architecture +* Also known as function call or subroutine call + +> RMI \(Remote Method Invocation\) is a Java mechanism similar to RPCs that allow Java program on one machine to invoke a method on a remote object. + +## CPU Scheduling + +### Non Preemptive + +* When a process completes its execution +* When a process leaves CPU voluntarily to perform some I/O operation or to wait for an event. + +### Preemptive + +* If process enters in the ready state either from new or waiting state i.e. high priority task. +* If a process switches from running state to ready state because time quanta expires. + +### Scheduling Criteria: + +* CPU utilization +* Throughput \(number of processes that complete their execution per time unit\) +* Turnaround time \(Time spent by a particular process in system\) +* Waiting time \(Time spent by process in ready queue\) +* Response time \(Amount of time when first submitted then response\) - considered major criteria + +### First Come First Served \(FCFS\): + +* Simplest scheduling algorithm that schedules according to arrival time. +* Process that requests the CPU first is allocated the CPU first. +* Implement using FIFO queue. +* When a process enters the ready queue, it's PCB is linked onto the tail of the queue. When the CPU is free, it is allocated to the process at the head of the queue, Running process is then removed from the queue. +* Always non-preemptive. +* Easy to understand and implement +* Suffers convoy effect: Say a process comes early but Burst time of it is very high then scheduling it first will result in convoy effect. + +### Shortest Job First \(SJF\): + +> SJF, LJF \(Non preemptive\) +> SRTF, LRTF \(Preemptive\) + +* Process with the shortest burst time are scheduled first. +* In case of tie FCFS is used. +* Can be used as preemptive as well as non-preemptive +* Preemptive SJF guarantees optimal ans as it is pure greedy approach. Also making it standard for other algorithms comparison. +* Cannot be implemented because burst time is not known can only be predicted by past data +* Process with larger CPU burst time requirement will go into starvation. + * Starvation Fix: Aging -> Gradually increase the priority of process that wait in system for a long time. + +### Round Robin + +* Always preemptive in nature +* Each process is assigned a fixed time in a cyclic way \(time quanta\) +* There's a selfish round robin \(+ priority\) +* It is designed specifically for time sharing system \(A time sharing system allows many users to share the computer resources simultaneously\) +* Ready queue is treated as a circular queue +* CPU scheduler goes around the ready queue allocating CPU to each process for a specified time quanta. +* After time quantum expires, timer interrupts the process, then the process is dispatched from process and new process comes. + +### Multilevel queue + +* Ready queue is partitioned \(foreground to background\) into separate queues. High priority processes are placed in top level. +* Each queue has its own scheduling algorithm - Foreground \(Round Robin\) Background \(FCFS\) +* Scheduling must be done between the queues + * Fixed priority scheduling \(Serve all from foreground then background\) + * Time slice +* Multi level Feedback Queue: + * A process can move between the various queries - aging can be implemented this was + * Multi level feedback queue schedules defined by follwoing parameters: + * No. of queues + * Scheduling algo for each queues + * Method used to determine when to upgrade a process + * Method used to determine when to demote a process + * Method used to determine which queue a process will enter that process needs service. + +## Process Synchronization + +* On the basis of synchronization processes are categorized as + * Independent Process \(Execution of one process doesn't affect the other\) + * Cooperative Process +* Process synchronization problem arises in cooperative process also because of shared data access. +* Concurrent access to shared data may result in data inconstancy. +* Maintenance requires orderly execution of cooperative process. + +### Race Condition: + +* When more than one process are executing the same code or accessing same memory there is a possibility that the output of the shared variable is wrong. +* All the process using that variable doing race to say that my output is correct, this is race condition. +* In this scenario outcomes depends on the particular order in which access takes place. + +### Critical Section Problem: + +* Critical section is a code segment that can be accessed by only one process at a time. +* Critical section contains shared variables which must be synchronized to maintain consistency. + +```text +do { + [Entry section] + CRITICAL SECTION + [Exit section] + REMAINDER SECTION +} while (true); +``` + +* Solution to critical section problem requires: + * Mutual Exclusion: If process is executing in critical section then no other process is allowed then. + * Progress: If no process in CS and other process waiting outside CS then only those process not in remainder section can participate in deciding which will enter CS next. \(P1->P2->P3->P1\) + * Bounded waiting: Basically starvation doesnt happen, one who's waiting gets the resource. +* Test and Set is a hardware solution to the synchronization problem. Here we share lock variable which is 0 \(unlock\) or 1 \(locked\) +* Before entering CS a process takes enquires about the lock. If locked then wait otherwise lock it execute the task and make it free. -> fixes mutual exclusion, progress, but not bounded wait + +### Turn Variable Solution: + +```text +while (true) +{ + while (turn != 0); + [CRITICAL_SECTION] + turn = 1 + [REMAINDER_SECTION] +} + +while (true) +{ + while (turn != 1); + [CRITICAL_SECTION] + turn = 0 + [REMAINDER_SECTION] +} + +Mutual Exlusion (TRUE) +Violates Progress P0 -> P1 -> P0 +``` + +Introducing boolean flag, if i is true means that process wants to go in CS + +```text +while (true) +{ + flag[0] = true; ......(1) + while (flag[1]); + [CRITICAL_SECTION] + flag[0] = false; + [REMAINDER_SECTION] +} + +while (true) +{ + flag[1] = true; .......(2) + while (flag[0]); + [CRITICAL_SECTION] + flag[1] = false; + [REMAINDER_SECTION] +} + +Both Mutual Exclusion and Progress is maintained +One problem: Say context switch occur after (1) and then later at (2) +That will mark both the processes flag true Hence system will go in a deadlock. +``` + +### Peterson's Solution: + +```text +do { + flag[0] = true; // flag 0 means p0 is interested in entering in CS + turn = 1; + while (turn == 1 && flag[1]); + [CRITICAL SECTION] + flag[0] = false; + [REMAINDER SECTION] +} while (true); +``` + +### Semaphores: + +* A semaphore is an integer variable that apart from initialization is accessed only through 2 atomic operations - wait\(s\) and signal\(s\) + +```text +s = 1; + +do{ + wait(s); + [CRITICAL_SECTION] + signal(s); + [REMAINDER_SECTION] +} while (true); + +wait(s): + while(s <= 0); + s = s-1; + +signal(s): + s = s+1; +``` + +* Disadvantages: + * Requires busy waiting + * Bounded wait violated +* Applications: + + * Solving critical section problem \(above\) + * Deciding order of execution: Say we have 3 processes and we want P2 -> P1 -> P3 OS considers all of them equal chance we want to maintain order + + ```text + wait(s1) wait(s2) + p1 p2 p3 + signal(s2) signal(s1) + + s1 = 0, s2 = 0 + ``` + + * For managing resource: If we want n resources to have access just initialize s with n + +### Reader Writer Problem + +* Concurrent read is fine but no concurrent write i.e. no RW WR WW +* This problem is CS for writers but not for readers multiple readers can be there at once. + +```text +write = 1 + +For writer: +wait(write) + [WRITE] +signal(write) + +For reader: +wait(mutex) // mutex is used to synchronize between different reader +readCnt++; +if (readCnt == 1) + wait(write) // If we're first reader then don't allow other writer +signal(mutex) + [READ] +wait(mutex) +readCnt--; +if (readCnt == 0) signal(write) +signal(mutex) + +For reader above few lines act as a small CS to update readerCnt which is shared +``` + +### Dining Philosopher's Problem + +* 5 philosophers are sitting at dining circular table. In center there's rice. Each philosopher has 1 chopstick so when hungry pick closest pair and eat. +* Represent each chopstick with a semaphore. A philosopher tries to grab a chopstick by executing a wait\(\) operation on that semaphore. she releases the chopstick by signal\(\) operation on that semaphore. +* Shared data -> Bowl of rice \(data set\) and semaphore chopstick\[5\] initialized to 1 + +```text +do { + wait(chopstick[i]); + wait(chopstick[(i+1)%5]); + [EAT] + signal(chopstick[i]); + signal(chopstick[(i+1)%5]); + [THINK] +} while (true); +``` + +* It fails and can cause deadlock, suppose all 5 philosopher became hungry simultaneously and grabs chopstick. When each philosopher tries to grab her right chopstick she will be delayed forever. +* Solution to above problem: + * Allow at most 4 philosopher sitting simultaneously + * Allow philosopher to pick up her chopsticks only if both sticks are available. + * Use asymmetric solution i.e. odd philosopher picks her left and then right whereas even one picks in reverse order + + + + + + + + + + + + + + +
MutexSemaphore
+
    +
  • A program object that allow multiple process to take turns to share the + same resources
  • +
  • Locking mechanism
  • +
  • An object
  • +
  • No categorization
  • +
  • If the mutex is locked the process that requests the lock waits until + the system releases the lock
  • +
  • Process uses acquire() and release() to access and release mutex.
  • +
+
+
    +
  • A variable that is used to control access to a common resource by multiple + processes in a concurrent system such as multi tasking OS.
  • +
  • Signalling mechanism
  • +
  • An integer
  • +
  • Categorized as binary and counting semaphore
  • +
  • If the semaphore value is 0 the process perform wait() operation until + the semaphore becomes > 0
  • +
  • Process use wait() and signal() to modify semaphore.
  • +
+
+ +### Monitors + +* It is a collection of condition variables and procedures combined together in a special kind of module or a package. +* The process running outside the monitor can't access the internal variable of the monitor but can call procedures of the monitor. +* Only one process at a time can execute code inside monitors + +Two different operations are performed on condition variables of monitor + +* Wait: Process performing wait operation on any condition variable are suspended. Suspended process are placed in block queue. \(each condition variable has its own block queue\) +* Signal: When a process performs signal operation on condition variable one of blocked process is given chance + +Adv: Makes parallel programming easier and part less error prone than semaphore. +Disadv: Have to be implemented as part of programming language. Compiler must generate code for them adding extra burden. + +### Monitor Solution to Dining Philosopher + +```cpp +monitor DP +{ + enum {THINKING, HUNGARY, EATING} state[5]; + condition self[5] + void pickup(int i) + { + state[i] = HUNGARY; + test(i); + if (state[i] != EATING) self[i].wait; + } + void putdown(int i) + { + state[i] = THINKING; + test[(i+4)%5]; + test[(i+1)%5]; + } + void test(int i) + { + if (state[(i+4)%5] != EATING && state[i] == HUNGARY && state[(i+1)%5] != EATING) + self[i].signal(); + } + void initializeCode() + { + for (int i = 0; i < 5; ++i) state[i] = THINKING; + } +}; +``` + +## Deadlock + +* In a multi programming system a number of process compete for limited no. resources and if a resource is not available at that instance then the process enters into waiting state. +* If a process is unable to change its state indefinitely because the resource requested by it are held by another waiting process then system is said to be in deadlock. + +### Necessary condition for deadlock + +* Mutual Exclusion: At least one resource type in the system which can be used in non-shareable i.e. mutual exclusion \(one at a time / one by one\) eg: printer +* Hold and Wait: A process is currently holding at least one resource and requesting additional resources which are held by other process otherwise starvation will occur. +* No preemptive: A resource cannot be preempted from a process by any other process. Resources can be released only voluntarily by the process holding it. +* Circular wait: Each process must be waiting for a resource which is being held by another process, which in turn is waiting for the first process to release resources. + +### Deadlock Handling Methods: + +Based on severity and frequency + +* Prevention: Means design such system which violate at least one of four condition of deadlock and ensure independence from deadlock -> RTOS +* Avoidance: System maintains a set of data using which it takes a decision whether to entertain a new request or not be in safe state. +* Detection and Recovery: Here we wait until a deadlock occur and after detecting we do something. +* Ignorance: Most OS unix and windows. Application developers need to handle deadlock themselves. + +### Violating Deadlock Conditions: + +* Mutual Exclusion: Make it shareable +* Hold and Wait: + * Conservative approach: Process is allowed to start executing iff it has acquired all resources \(less efficient, not implementable because we cannot determine what resources are needed beforehand, easy to understand\) + * Do not hold: Process will acquire only desired resources but before making any fresh request it must release all the resources that it is currently holding. \(Efficient and implementable\) + * Wait timeout: we place a max time upto which a process can wait after which process must release all the holding resources and exit. +* No Preemption: + * Forceful preemption: We allow a process to forcefully preempt the resources holding by other process. + * This method may be used by higher priority process. + * The process which are in waiting state must be selected as a victom instead of process in running stack. +* Circular Wait: + * Give natural number label to every resource R1 R2 R3... and allow every process to either take only in increasing order or decreasing order. Say P1 & P2 both wants R1 & R2. first P1 tries to fetch R1 it will get if P2 tries now he cant get R1 so he will release holded ones and exit. + diff --git a/semester/web-technologies.md b/semester/web-technologies.md new file mode 100644 index 0000000..e0ce14c --- /dev/null +++ b/semester/web-technologies.md @@ -0,0 +1,766 @@ +# Web Technologies + +## INTERconnected NETwork: Internet + +### History + +* With gradual decrease of price of computers ability to share resources, share information and facilitate communication came in role. +* Building computer network, as a meta-network or network of networks, the Internet \(INTERconnected NETwork\) get promising. +* ARPANET first started as a research project \(Advanced Research Project Agency Network\) linking researches remotely to other computer centers allowing them to share hardware and software resources. +* Later it was renamed to the Internet. +* This inter-network operated with a technique called packet switching where digital data is transmitted in small bundles called packets. +* These packets contains the information about the address, error, error control, and the sequence in which packets are to be sent. +* The network was designed to operate without centralized control. If a portion of the network failed, the remaining working portion would still route packets from senders to receivers over alternative paths. +* ARPANET used TCP \(Transmission Control Protocol\) for communication. +* TCP ensured that messages were properly routed from sender to receiver. +* As internet evolved Inter as well as Intra communication came in picture so ARPA developed Internet Protocol which truely made it Network Of Networks. + +### Internet: The Giant Wide Area Network \(WAN\) + +* A network hence is connecting end-systems \(hosts, PCs, workstations\). +* Internetwork or Internet \(INTERconnected NETwork\) is an arbitary Global collection of physical networks interconnected by routers to provide some sort of host-to-host packet delivery service. + +Local Area Network \(LAN\) is used for communicating among computer devices, usually within an office building or home. +Low cost and high security +Speed: 10 Mbps to 10 Gbps + +Metropolitan Area Network \(MAN\) is used for larger geographical area then LAN. Several block to entire city. Allows sharing of regional resources. Might be operated or owned by a single organization but typical used by many individuals and organizations. +High cost due to fibre optics installation. +Speed typically as high as in LAN + +Wide Area Network \(WAN\) covers area such as country, continent or even whole world. It uses multiple LANs connected using routers, bridges or gateways which enables them to share resources. + +* Transmission medium can be wired \(unshielded twisted-pair cables, shielded twisted-pair cables, coaxial cables, fiber-optic cables\) or wireless. +* Shape or layout of network can be point-to-point \(PTP\) or multi-access \(ring, star, or bus\) +* Network can be categorized as Client/Server network or Peer-to-Peer network \(P2P\) application centric architecture. +* There are 2 types of P2P network - Pure P2P network \(Workgroups in Microsoft Windoes\) or Hybrid P2P network \(Skype, BitTorrent\) + +> BitTorrent is a protocol, not a provider. Saying i downloaded from bitTorrent is wrong instead file is downloaded from other individuals using BitTorrent protocol. + +### Communication Over The Internet + +* Two popular models - Open Systems Intercommunication \(OSI\) reference model and the TCP/IP model +* In OSI, Open denotes the ability to connect any two systems which supports the defined rules from reference mdel and associated standards. It divides the problem of moving information between computers over a network medium into seven smaller and more managable layers. This layer breaking reduces complexity. Each layer provides the service to layer above it in rotocol specification. Each layer communicates with the same layer's software or hardware on other computers. + +![](../.gitbook/assets/image%20%28220%29.png) + +* Last 4 layers \(transport, network, data link and physical\) are concerned with the flow of data from end to end through network. Upper 3 \(application, presentation, and session\) are oriented towards services to the applications. +* The OSI model was generic, protocol independent. TCP/IP provided application viewpoint to the network. The OSI model conceptually defined the services, interfaces and protocols. The TCP/IP model provided its successful implementation. + +![](../.gitbook/assets/image%20%28224%29.png) + +### Protocol Layering + +The Internet Protocol stack \(TCP/IP Protocol Suite\) is based on the divide-and-conquer + +1. Application Layer: Combines the functions of top two layers \(Presentation & Application\) of OSI reference model. Telnet\(Remote Login\), FTP \(File Transfer Protocol, SMTP \(Simple Mail Transfer Protocol\), DNS \(Domain Naming System\), HTTP\(HyperText Transfer Protocol\). +2. Transport Layer: It is responsible for reliable source-to-destination delivery of the entire message. TCP \(Transmission Control Protocol\) & UDP \(User Datagram Protocol\). TCP is a reliable connection-oriented protocol whearas UDP is connectionless \(datagram\) protocol. Like in audio calls we need skip of audio packets which were failed to send instead of delay in response over destination so we use UDP instead of TCP. +3. Internet Layer: IP \(Internet Protocol\) it is connectionless or datagram. Data recieving is not guaranteed. It may be out of order or damaged or duplicated. +4. Link Layer: To communicate on a directly connected network. It specifies how to organize data into frames and how to deliver a fram over a network. +5. Physical Layer: Defines rules by which bits are passed from one system to another on physical communication medium. + +![This is also an Hourglass model. IP which is most important protocol is waist of horglass.](../.gitbook/assets/image%20%28244%29.png) + +### Internet Addressing + +IP Address is a 32 bits \(four 8-bit fields\) unique global address for a network interface. xxx.xxx.xxx.xxx \(0-255 since 255 is max 8-bit binary number\). +IP Address has prefix \(identifies the physical network to which the host is attached\) & suffix \(identifies a specific computer host/node on network\). + +URL \(Uniform Resource Locators\) specifies the Internet address of a file stored on a host computer \(server\) connected to the Internet. URLs are translated into numeric addresses using DNS which is an application-layer service. + +> protocol://domain name /path/filename + +Recently, URL is now considered to be a subset of URI \(Uniform Resource Identifier\). It's a string of characters used to identify a name or a resource on the Internet and is recognized as a more general form of URL. URI has - URN \(Uniform Resource Name\) & URL. +URNs identifies a resource by a unique & persistent name. It usually starts with the prefix urn: URNs can be ideas and conecpts. They are not restricted to identifying documents. When URN does represent a document it can be translated into a URL by a "resolver". The document can be then downloaded. For example: urn: isbn: 0451450523 to identify a book by its ISBN number. + +### Internet Configuration + +ISP \(Internet Service Provider\) provides Internet access. The ISP, in turn may connect to a large network such as NSP \(Network Service Provider\). They together acts like an Internet Backbone. The backbones carry Internet traffic around the world and meet at NAPs \(Network Access Points\). +Internet backbone is a collection of routers \(worldwide\). NAP is a router that connects multiple backbones \(sometimes referred as peers\). POP \(Point Of Presence\) is a machine that is connected to the Internet. ISP provides dial-up or direct access to POPs. + +1. Dial-up access: Dial-Up Connections works over an ordinary phone line using analog modems establishing the Point-to-Point Protocol \(PPP\). Mostly computers comes equipped with analog modems so no additionla hardware required. +2. High-speed access: Also known as the broadband connection compises - DSL \(Digital Suscriber Line\), ISDN \(Integrated Services Digital Network\) Lines, Leased Line, and Cable Internet Connections. DSL is family of all-digital high-speed lines that use normal phone wires with special modems. ISDN lines are also like DSL all-digital high-speed you need an ISDN adapter. DSL is mostly common in US wheras in Europe ISDN. A leased line provides point-to-point high-speed typically used by an organization. DSS \(Digital Satellite Systems\) or direct broadcast satellite is a method by which Internet content is downloaded to a satellite dish and then transmitted directly from your dish to the user's PC. +3. Wireless access + +### Web Browser + +The primary function of a browser is to identify the URL and bring the information resource to user. To identify a web pages' exact location, a web browser relies on a URL. Other basic functions: + +* Interpret HTTML markup and present documents visually. +* Support hyperlinks. +* Use HTML form and the HTML protocol to send & recieve requests. +* Maintain cookies \(name-value pairs\) stored on client computers by a web application and send all cookies back to a website. + +### Internet Organizations + +No one actually owns the Internet, and no single person or organization controls the Internet in its entirety. It is more of a concept. A number of loosely coupled organizations are concernet with governing the development of the Internet. + +* Internet Society \(ISOC\) : It is concerned with long-term coordination of the Internet development. +* Internet Engineering Task Force \(IETF\): It's mission is providing high quality technical documents for improving Internet's quality and performance. +* Internet Research Task Force \(IRTF\): Conducts research on protocols, applications, architecture, and technology. +* World Wide Web Consortium \(W3C\): It develops web technology standards. + +### Cyber Ethics + +* Communicating, sharing and contributing to e-society in a positive manner. +* To be respectful and courteous in communication \(do not use rude or offensive language\). +* Avoide harming others \(do not spread pictures, viruses, gossip, information about others, do not use others' usernames and passwords i.e. do not impersonate others and do not trespass in other's files\) +* Sharing network resources, being honest and trustworthy. +* Honor proporty rights and copyrights, and giving proper credit for intellectual property. + +## Internet Applications + +### Electronic Mail \(Email\) + +Email is a method of sending a message from a user at a computer to a recipient on another computer. Email system is based on a store-and-forward model in which email computer server system accept, forward, deliver and store messages on behalf of users, who only need to connect to the email server. + +When an email is sent the message is routed from server t server all the way to recipient's mail server tasked with MTA \(Mail Transport Agent\) to the recipient's MTA. MTAs communicate using SMTP. The recipient's MTA then delivers the email to the incoming mail server called MDA \(Mail Delivery Agent\) which stores the email as it waits for the user to accept it. Protocols for retrieval from MDA - POP3 \(Post Office Protocol\) and IMAP \(Internet Message Access Protocol\). MTAs act like a post office while MDA as mailboxes which stores mail until recipient check the box. This means that it is not necessary for recipient to be connected in order for them to be sent email. MDA is protected by username and password. MAU \(Mail User Agent\) a software for mail retrieving such as - Outlook, Gmail \(web interface not software\). + +![](../.gitbook/assets/image%20%28207%29.png) + +* SMTP is a client-server protocol. It allows reliable data transfer built on top of TCP. It is a push protocol where the sending server pushes the file to the receiving server rather than waiting for the receiver to request it. It is synchronous as the sender awaits a response before issuing next command. It has three phrases of transfer - Handshaking, Transfer of messages, and closure. +* POP does not handles mails in seperate folders for spam and important ones MAU does it. Most even deletes the mail from server once transferred to recipient. It is poor in handling multiple-client access like from phone, laptop. It has high network bandwidth overhead and it transfers all the email messages, often well before they are read. +* IMAP keep mail on server where user can keep or delete them. Multiple client can connect to mailbox at once. Enables server side searches i.e. search on server before downloading message. + +### File Transfer + +Application layer protocol, connection-oriented based on client-server architecture that relies on TCP for transferring files or copying it from sender to reciever machine. Problems dealt are two system may use different file system or different directory structure all these problems FTP solve. + +![](../.gitbook/assets/image%20%28259%29.png) + +We need FTP client software and FTP server with it's username and password. +FTP uses TCP ports for all communications between server and user. + +1. COMMAND Port: This is the main TCP port created when a session is connected. It is used for passing commands and replies. +2. DATA Port: Each time when files or directories are transffered between server and client, a random TCP data connection is established and data transfer commences over the connection. Once data transfer is complete the connection is closed. Subsequent data connection are establised and termination as required. Data connections are never left open. + +Transfer modes- + +1. Active Mode: The client issues a PORT command to the server signalling that it will "actively" provide an IP and port number to open the Data Connection back to the client. +2. Passive Mode: The client issues a PASV command to indicate that it will wait "passively" for the server to supply IP and port number after which the client will create a Data Connection to the server. + +#### Real-Time User Communication + +Voice Over Internet Protocol \(VoIP\) application layer protocol in TCP/IP protocol stack. Voice first converted into digital data which is then organized into small packets. These packets are stamped with the destination IP address and routed over the Internet. After recieving packets are recombined and converted digitally to the speaker. Like XBOX Voice, Skype. +Computers, even landlines with ISP connection can do VoIP calls. +Basic components in VoIP are - Phones \(End point device\), Gateways \(Allows non VoIP analog device to communicate\), Application Servers, Gatekeeps \(Maps phone numbers to IP addresses and grant permission for call setup\), Call agents \(Handles call routing and setup\). +DSP \(Digital Signal Processors\) are used by devices to perform alaog-to-digital and digital-to-analog conversion. + +### **IRCs \(Internet Relay Chat\)** + +Most popular text based interactive service using TCP/IP on the Internet. It allows text messages exchange in real time. It is multi-user, multi-channel teleconferencing system. It works in client/server architecture. The entire process is - Locating client, relaying message, channel hosting and management. + +![](../.gitbook/assets/image%20%28219%29.png) + +Architecural Issues Of Internet Relay Chat: + +* Scalibility: This protocol does not scale sufficiently well when used in large arena because all the servers maintain information about all other servers and clients. +* Reliability: As the only network configuration allowed for IRC servers is that of a spanning tree, each link between two servers is an obvious and quite serious point of failure. +* Network Congestion +* Privacy + +### Remote Login + +Telnet \(TErminal NETwork\) The Telnet protocol offers a user the possibility to connect and log on to any other host in the network from the user's own computer by offering a remote log-in capability. For the connections, Telnet uses the TCP protocol. The user intereacts with Telnet client which is a terminal accepting any keystrokes from keyboard and interpreting them displaying output. +Network Originated and Terminated at the NVT \(Network Virtual Terminal\) it host both ends so that neither has to store the data. Telnet has set of options and these options can be negotiated through a simple protocol inside the Telnet. The negotiation protocol contains commands DO, WILL, WON'T, DON'T +Telnet does not download or upload like FTP. + +### Usenet \(USErNETwork\) + +It is like mailing lists, it is also a way of sharing information. It is a collection of special interest groups, called newsgroups. Each newsgroup is devoted to a certain topic. Under each newsgroup, there are many messages called news articles. NNTP \(Network News Transfer Protocol\) is used for posting, distributing, retriving USENET news articles among news servers. + +## World Wide Web + +WWW \(World Wide Web\) is often confused with the Internet. Web is a large transformable-information construct. It is a service, an application of the Internet. It provides a hypertext-hypermedia interface to information resources on the Internet. +Web is a set of technologies that allow information on the Internet to be linked together through the use of links, or connections, in documents. The language used to write these documents with links is HTML \(Hypertext Markup Language\). +Normal way of say reading is linearly it's a common text while in Hypertext it allows in a nonlinear fashion as it contains links to other file \(audio, text\) or page. +The Web is a client-server system. Web browsers act as clients, making requests to web servers. + +### Web Page + +It is a document that can be displayed in a web browser. Webpages can be either static or dynamic. Static means the page is constant or unchanging while dynamic means the page changes. Therefore, static web pages contain the same pre-built content each time the page is loaded, while the content of dynamic web pages can be generated on the fly. Stamdard HTML pages are static. Dynamic on the other hand contain server-side code such as PHP, ASP that allows the server to generate unique content each time the page is loaded. For example the server might display current date and time. Many dynamic pages use server-side code to access database information, which enables the web page content to be generated from information stored in a database. The dynamic page request is addressed by a two-level response system that includes a web server and an application server. The web server's primary job is to display the site content while the application server is in charge of the logic, the interaction between the user and displayed content. + +### Web Site + +A website is a collection of web pages that are under one domain. A webpage can be accessed by one URL and it can also be generated on the fly. + +### Web Application + +While websites can be primarily infomormational a Web Application \(or Web Apps\) allow the user to perform actions. A web app is a client-server software application for which the client runs in a web browser. + +### Web Service + +A web application is an application that is accessed through a web browser running on client machine, whereas a web service is a system of software that allows different machines to interact with each other through a network. A web service does not necessarily have a UI. Example like Paypal. + +### Web Architecture + +Architecture can be two-tier client-server architecture, three-tier or multitier. Each tier is a platform \(client or server\) with unique responsibility. More tier means more scalability but also expensive. + +### World Wide Web Challenges + +* Abundance: With phenomenal growth of web volume is very high. The web is noisy. +* Web search results usually have low precision and recall. +* Heterogeneity: data online is all type table, image, etc. hence unstructured +* Duplication + +## Hypertext Transfer Protocol \(HTTP\) + +Websites interacts with webservers with a simple application level protocol called HTTP which runs on top of TCP/IP. HTTP is a client-server protocol that defines how messages are formatted and transmitted and what action web servers and browser should take in response to various commands. + +It uses a request/response paradigm. It is a pull protocol the client pulls information from server instead of server pushing information down to the client. HTTP is also a stateless protocol i.e. each request-response exchange is treated independently. It is also media independent any kind of data can be sent with it. +Initially HTTP 0.9 came which was simple protocol for raw data transfer across the Internet. Then HTTP 1.0 and later HTTP 1.1. HTTP 2.0 was released in 2015 it recieved critism allowing binary instead of textual, allowed push from server unlike pull and has some encryption issues too. + +### Non-Persistent HTTP + +Non-Persistent connection is in which only one object can be sent over a TCP connection. HTTP 1.0/1.1 use this. Two RTT \(Round Trip Time\) time taken to send a small packet to travel from client to server and back: + +* One RTT to initiate TCP connection +* Second for HTTP request and first few bytes of HTTP response to return +* Rest of the time is taken in transmitting the file. Non-persistent HTTP causes OS overhead hence many browsers open parallel TCP connections to fetch response. + +![Total Time for 10 objects = 10 \* 2 = 20 RTT](../.gitbook/assets/image%20%28212%29.png) + +### Persistent HTTP + +To over non-persistent came persistent connection through which multiple objects can be sent over a single TCP conenction between server and client. +Client initiates a TCP connection to server \(Handshake\) Server accepts and acknowledges. Client sends HTTP request to which server responds. + +![Total Time for 10 objects = 1 \* 1 + 10 = 11 RTT](../.gitbook/assets/image%20%28230%29.png) + +### Communication + +* Handshaking: For opening a TCP connection, the user on client side inputs the URL containing address. Web browser ask DNS for IP address of the URL. Then a connection is established. +* Client Request +* Server Response +* Closing \(Optional\) + +### Request Message + +![](../.gitbook/assets/image%20%28236%29.png) + +* Request Method: GET, HEAD\(Return header of response\), POST, PUT\(Store the body of response for future GET request\), DELETE\(Respond no file for future requests\), TRACE\(Request server to return a copy of complete HTTP request\), OPTIONS\(Returns options available for URL\), CONNECT\(It is used to convert a request connection into transparent TCP/IP tunnel. It is usually done to facilitate SSL Secured Socket Layer encryption\), COPY, MOVE +* Request-URI: It identifies the resource for which the request needs to be applied. +* HTTP Version: 1.1 is used nowadays +* Headers: They are a form of message metadata. Enlighted way of it's usage makes application sophisticated by maintaining sessions, control authentications, etc. Header name is not case sensitive. Three types of headers - **General Headers:** Provides information about the message and do not describe the body. Used for like time purpose or indicating if connection is closed. **Request Headers:** Provides additional informations to request data like data format, output format, etc. **Entity Headers:** Contains information about body in case request message has no body. Like content type, length, etc. +* Message Body + +### Response Message + +![](../.gitbook/assets/image%20%28250%29.png) + +* Status Line: It consists three parts - HTTP version, status code, status phrase. + +> **1xx series \(Informational\)** - Represents provisional responses +> 100 \(continue\) - server recieved initial part now want other +> 101 \(switching\) - server switching protocol +> 102 \(processing\) + +> 2xx series \(Success\) - Indicates that the client's request are recieved, understood and accepted successfully. +> 201 \(created\) +> 202 \(accepted\) + +> 3xx series \(Re-directional\) - Indicates additional actions must be taken like HEAD or GET method by user. +> 301 \(moved permanently\) +> 302 \(found\) + +> 4xx series \(Client error\) +> 400 \(bad reques\) +> 401 \(unauthorized\) - The request has failed to authorized +> 403 \(forbidden\) - Request is valid but server is refusing +> 404 \(not found\) +> 408 \(request timeout\) +> 415 \(unsupported media type\) + +> 5xx series \(Server error\) +> 500 \(Internal Server Error\) +> 501 \(Not Implemented\) +> 502 \(Bad Gateway\) +> 503 \(Service Unabailable\) +> 504 \(Gateway timeout\) +> 505 \(HTTP version not supported\) +> 511 \(Network authentication required\). + +### Hypertext Transfer Protocol Secure \(HTTPS\) + +It provides secure connection. It is not a protocol but it is just the result of combination of HTTP and SSL/TLS \(Secure Socket Layer/Transport Layer Security\) protocol. It sends and recieves everything in the encrypted form, adding the element of safety. + +* It verifies that you are directly to the server that you think you are talking to. +* Ensuring that only the server can read what you send it, and only you can read what it sends back. + +### Cookies + +HTTP is stateless protocol. Cookies \(name value pair\) are an application-based solution provide state retention over a stateless protocol. They are small piece of information that are sent in response from the webserver to the client. Cookies are the simplest technique used for storing client state. It cannot be a software means cannot be programmed hence cannot contain viruses. However it can be used by spyware to track user's browsing activites. They are stored on client's computer and have a lifespan and are destroyed after that. Cookies are browser specific. + +Creating a cookie is simple after recieving an HTTP request, a server can send a Set-Cookie header with the response. + +> Set-Cookie: = + +Cookies types - Session Cookie, Persistent or tracing cookie, Secure Cookie \(When HTTPS connection encrypted cookies are secure\), Zombie Cookie \(Ther are automatically recreated after the deletion\) + +### Cache + +Fetching something over the network is both slow and expensive. Large response require roundtrips between the client and server. Ability to cache as result provides reuse previously fetch resource. It can reduce network latency. + +* Browser Cache +* Intermediary Caching Proxies \(Web Proxies\): Any server in between the client and your infrastructure can cache certain content as desired. +* Reverse Cache: Server Infrastructure can implement it's own cache for backend services. + +A web proxy is the most commonly used caching service. A proxy is an application program or a computer system that behaves like an intermediary between servers and clients looking for services from these servers. To access a resource, a client sends the request to proxy instead of the original web server. The proxy in turn searches for the resource in its cache. If the resource is found, it is delivered to the client. Otherwise it contacts the specified server and gets the resource puts that resource in local cache and finally returns it to the client. + +**Cache Consistency:** It maintains that the cached copies are updated. + +* Pull method: In this mechanism, each web page cached is assigned a time-to-serve field, which indicates the time of storing the web page in the cache. An expiration time is also maintained if time expires a fresh copy is maintained. +* Push method: In this method the web server is assigned the responsibility of making all cached copies consistent with the server copy. Advantage of this is modification only happens when server is modified hence no wastage but it provides load to the server. + +## Evolution Of Web + +### Web 1.0 + +It was defined as a system of interlinked, hypertext documents accessed via the Internet. It was static and somewhat monodirectional model with websites publishing the information for anyone at any time. This early Web was primarily informational in nature offering an online presence for resources, allowing the retrieving of relevant information, and reading it. It was one person or organization pushing content out to many people via websites and e-mail newsletters as a one-way communication. + +### Web 2.0 + +Internet was reimagined as a generic exchange platform, where any user becomes a content provider. Web 2.0 also known as Read-Write Collabrative Web. Technologies like - comments, blogs and wikis. + +> RSS Feeds \(Rich Site Summary\) is a tool with Web 2.0 that allows users to access updates to online content in a standardized computer-readable format. + +1. Blogging: It allows sharing thoughts to the world. Weblog \(personal journal or newsletter\), Blogger \(someone who writes blog\), Blogosphere \(online community of bloggers and their writings\), Permalink \(permanent link: these are static link say for an article the URL can be dynamic with dynamic factors on it that may change we don't want that it will not be good for search engine ranking or for our blogs cite so we provide permalink\), Blog-roll\(Online community that a blogger targets or finds interesting\) Example: Blogger, Wordpress +2. Social Networking Sites +3. Podcasts: It is basically just an audio \(or video\) file however difference is when new podcasts are released its automatically delivered to the suscriber's device. Podcatcher software is used for delivery. +4. Wikis +5. Micro-blogging: It is the practice of posting small pieces of digital content which could be text, pictures, links, short videos or other media on the Internet. Microblogging enables user to write brief messages. Example - Twitter. +6. Social Bookmarking: It is a way to store, organize, search, manage and share collections of websites. Users save links to websites. These bookmarks are usually public and can be shared among a group. Example - Digg, Technorati. +7. E-portfolios + +### Web 3.0 + +Currently most of web content is suitable for human use. The Web now has a huge amount of decentralized data which can be accessed by various simple and standardized methods. Though this decentralized data is primarily machine accessible. It should also be made machine understandable. Web 3.0 is also known as the semantic web. According to W3C Sementaic Web provides a common framework that allows data to be shared and reused across application, enterprise and community boundaries. +The core of Semantic Web Technologies includes four components - metadata \(it is machine processable\), ontologies \(It adds meanings to make data machine understandable\), Logic modules \(For interface mechanism\) and finally software agents \(to accomplish intelligent tasks\). + +Metadata captures part of the meaning of data. We annotate the natural language of web content explicitly with semantic metadata. The semantic metadata encodes the meaning\(semantics\) of the content, which can be interpreted by machines. + +### Big Data + +It is defined as high-volume, high-velocity & high-varity of information assets that demand cost-effective, innovation forms of information processing for enhanced insight and decision making. Like - Social Network data, Buisness Data, IOT \(Internet Of Things\) Data generated by other machines to communicate. + +## WebIR + +### Web Information Retrieval + +**Information retrieval** is retrieving the amount of information a user needs in a specific situation for solving his/her current problem. It models documents and rank them based on a user query + +Web IR is different from classical IR for two reasons, Concept and technologies: Web is unlimited source of information with users from wide cross-section of society seeking to find information efficiently. + +WebIR Tools - Search Tools\(General Purpose, Directories\), Search Services + +Search tool provides a UI where user specify query and browse the result. It employs 'robots' that index web documents. It searched that indexed document for query. General Purpose \(google, altavista\) hides the organization & content of index. Directories \(yahoo\) shows the directory like hirerarchy. + +Search Services broadcasts query to different search engines & various other IR sources and then later combine the results removing duplicates. \(metacrawler\) + +### Indexing Process + +![](../.gitbook/assets/image%20%28208%29.png) + +The indexing process filters document to relevant information for query processor to work efficiently. It involves + +1. Text Acquisition: Search engines have crawler or bots which is programmed to visit websites and read their pages. It gathers the document and stores it in document repository. +2. Text Transformation: Once text is acquired, we need to capture it in index terms. parsing\(Identifying text tokens in documents to recognize structural elements. Markup language defines struture in tag which gets identified\), stop-word removal\(Commonly occuring words are removed like the, is\), stemming\(removing suffixes like games become just game\), link analysis and information extraction\(Identifies classes of indexed terms\) takes place. +3. Index Creation: Document statistics such as count of words occurence is maintained in index. + +### Query Process + +![](../.gitbook/assets/image%20%28213%29.png) + +### Google Page Rank + +Google search uses multiple crawlers on different single threaded asynchronous machines to fetch data from over 300 web servers in parallel. All pages get downloaded on disk. Then indexer reads from disk and extracts relevant part then store in other disk. The ranking algorithm of Google tells priority, it was proposed by Larry Page & Sergey Brin. + +The general idea is when one page links to another page, it is effectively casting a vote for other page. More votes implies more importance to that page. + +## Web Development Basics + +![](../.gitbook/assets/image%20%28235%29.png) + +Most of the times the terms web server & application server are interchangable, key differences are: + +* Web server is mostly designed to server static content though web servers have plugins to support scripting languages like Perl, PHP, ASP through which these servers can also be dynamic +* Most application servers have web servers as integral part. Means an application server can do whatever web servers are capable of plus having application level services like connection pooling, messaging services. +* Web Servers \(Apache, Tomcat\) Application Server \(Oracle, WebSphere\) + +**Markup Languages**: HTML, CSS +**Programming Languages**: Javascript, Python, Ruby, PHP, Objective-C, Swift, Java +**Framework \(Built to make working with programming languages easier\)**: Meteor \(Full stack javascript\), Node.js\(Server side javascript\), Ruby on rails\(Full stack ruby\), Django \(Full stack python\), Ionic \(Mobile\), Bootstrap \(UI for HTML, CSS, Javascript\), Content Management System - CMS \(Wordpress, Drupal\), NET \(Fullstack\), Angular \(Front end javascript\) +**Libraries \(Enables large functionality without writing\)**: jQuery +**Databases:** MongoDB\(No SQL\), MySQL, Oracle\(Enterprise SQL\), Neo4j\(Graph based NoSQL\) +**Protocols:** HTTP\(How data from website gets to browser\), Distributive Data Protocol - DDP\(It uses websockets to maintain consistent website connection without refreshing update\), Representation State Transfer - REST\(Used by API for HTTP requests\) +**Data Formats:** JSON, XML, CSV + +| Client-Side Scripting | Server-Side Scripting | +| :--- | :--- | +| User browser has all the code and page is altered | Dynamic pages are created, browser requests server | +| Executed on user's computer | Executed on server's computer | +| Cannot access database | Can access database | +| Faster Response Time | Slower Response Time | +| Uses - Interactive webpages, make page work dynamically, interact with storage, provide an interface between user and server, send request to the server | Uses - Processing user inputs, displays requested pages, structured web applications, interaction with server and storage, interact with databases | +| Advantages - Allow for more interactive by immediately responding to user's actions, improve usability of web sites, can be substituted with HTML if user browser doesn't support scripts | User does not need to download plugins like java or flash, scripts are hidden from view making them more secure, Generally quicker to load then client side scripting | +| Disadvantages - Not all browsers supports scripts, Different browser may even support differently, More development time & effort might require | Disadvantages - Requires scripting softwares to be installed on the server, Nature of dynamic scripts create security but in some cases giving access to servers by hackers, Many tools Requires databases in order to store dynamic data | +| Javascript, VB Script, HTML, CSS, AJAX, jQuery | PHP, ASP.NET, Javascript, Java and JSP, Python \(Django\), Ruby \(Rails\) | + +### Model-View-Controller Architecture + +![](../.gitbook/assets/image%20%28245%29.png) + +Advantages- + +* **Simultaneous Development** \(Multiple developers can work simultaneously on model, controller & views\) +* **High Cohesion** \(Enables logical grouping of related actions on a controller\) +* **Low Coupling** Low coupling between M-V-&-C +* **Ease Of Modification** +* **Multiple Views For a Model** + +Disadvantages- + +* Code navigation can be complex +* more skillset requirement +* decomposing a feature in 3 requires more user consistency + +## Client Side Technologies + +### HTML \(HyperText Markup Language\) + +| Tag | Usage | Attributes | +| :--- | :--- | :--- | +| html | Specifies HTML document | | +| head | header | | +| title | browser title | | +| body | main browser contetn | link, alink, vlink, background, bgcolor, text | +| br | brings new line | | +| p | Paragraph | align | +| h1, h2, h3, h4... | headings | align | +| b | bold | | +| i | italic | | +| u | underline | | +| center | center aligns | | +| tt | displays text in typewriter font | | +| hr | horizontal line | | +| sub | sub text like H2O | | +| sup | sup text like x2 | | +| ol | ordered list | start, Type="A,a,1,I or i" | +| ul | unordered list | Type="disc, square or circle" | +| dl | defination list | | +| li | list item | | +| dt | defination term | | +| dd | defination description | | +| img | image | align, alt, border, height, width, hspace, vspace | +| strike | text strikethrough | | +| span | Used to group inline elements | style="color:blue" | +| table | creating a table | align, bgcolor, border, cellpadding, cellspacing, width | +| tr | table row | align, valign, bgcolor | +| td | table data | align, vlign, rowspan, colspan, width, height | +| th | table header | align, vlign, rowspan, colspan, width, height | +| a | anchor | href | +| form | html form | | +| input | form textbox | | +| textarea | form textarea | | + +```markup +
    +
  1. Coffee
  2. +
  3. Tea
  4. +
  5. Milk
  6. +
+ +
    +
  • Coffee
  • +
  • Tea
  • +
  • Milk
  • +
+ +
+
Coffee
+
Black hot drink
+
Milk
+
White cold drink
+
+ + + + + + + + + + +
MonthSavings
January$100
+ +
+ First name:
+ Last name:
+ +
+``` + +### CSS \(Cascading Style Sheet\) + +Advantages- + +* Efficiency in design: Create rules and apply them on many +* Consistency: Style consisten on every page +* Greater control over layout and appearance +* Faster page downloads +* Low maintenance + +Disadvantages- + +* Fragmentation: CSS renders differently on different browser so tested perfectly before going live +* Lack of security + +**Inline Style sheet** + +```markup +

Yo

+``` + +**Internal Style sheet** Within head enclosed with < style > < /style > +**External Style sheet** + +```markup + + + +``` + +```css +body { + background-color: #DCDCDC; + max-width: 800px; + margin: auto; + font-size: 18; +} +table{ + background-color: #CCCCCC; + width: 100%; + padding: 10; +} +.notice{ + float: right; + padding:10px; + padding-left: 30px; + border: 2px solid black; + margin: 10 10 10 10; + width: 250px; +} + +usage of css class .notice +

Notice

+``` + +### JavaScript + +* An interpolated language +* Embedded within html +* Minimal syntax, easy to learn +* Supports quick development & easy to learn +* Designed for programming user events +* Platform independent +* Improves the user interface of a website +* Validates user input before sending to server +* It doesn't have any design, multithreading or networking capabilities + +```javascript +

+ +``` + +#### Bootstrap + +* Easy to use +* Responsive features +* Consistent design +* Compatible with browsers +* Open source + +## Sever-Side + +Technologies Server-side scripting refers to the dynamic generation of web pages served up by the web server, as opposed to static web pages in the server storage that are served up to the web browser. + +* Read data submitted by the user +* Generate HTML dynamically based on user input +* Determine information about the client browser +* Access database systems +* Exploit the HTTP protocol Perl, ASP, PHP, Node.js + +### PHP \(Personal Home Page\) + +Server side scriptting language used to make HTML dynamic. Considering the Model-View-Controller for web application development. A server is needed to be run since it's a server-side language. XAMPP or other which supports PHP + +```markup + + + My First PHP page + + + Hello World!"; + ?> + + +``` + +We asked the server to type Hello World + + +> echo date\("r"\); + +PHP is similar to C/C++ when it comes to basic syntax, though it has its own variations. The PHP interpreter provides the functionality to "preprocess hypertext," which means executing PHP commands and producing the desired HTML. + +* Semicolon termination +* Space insensitive +* Keywords - if, else, while, echo... +* Variable names case sensitive +* // for comment \(or \#\) or /\* \*/ +* Variable start with $ followed by it's name + +```php +$txt = "Hello World!"; +$num = 12; +$arr = array("val1", "val2", "val3"); +$multiArr = array( + array( + "name" => "Ankit Priyarup", + "email" => "ankitpriyarup@gmail.com", + ), + array( + "name" => "Anukriti", + "email" => "anu1999kriti@gmail.com", + ), +); +echo $txt . "\n"; +if ($num > 50) + echo $num . "\n"; +else + echo "LOSER" . "\n"; +echo $arr[0] . "\n"; +echo $multiArr[1]["name"] . "\n"; +``` + +* constants declared with define\("KEY", VAL\); doesn't require $ prefix to access + +```php +define("SITE_URL", "http://www.dtu.ac.in/"); +echo "Thanks for visiting homepage - " . SITE_URL; +``` + +strlen\(string\), strev\(string\), str\_word\_count\(string\) + +```php +function getSum($num1, $num2) +{ + $sum = $num1 + $num2; + echo "sum is: " . $sum; +} +getSum(10, 20); +``` + +```php +$odd_numbers = [1,3,5,7,9]; +for ($i = 0; $i < count($odd_numbers); $i=$i+1) +{ + $odd_number = $odd_numbers[$i]; + echo $odd_number . "\n"; +} +``` + +```php +class Student +{ + public function __construct($first_name, $last_name) { + $this->first_name = $first_name; + $this->last_name = $last_name; + } + + public function say_name() + { + echo "My name is " . $this->first_name . " " . $this->last_name . ".\n"; + } +} + +$anu = new Student("Anukriti", "Kumar"); +$anu->say_name(); +``` + +Advantages: + +* PHP is very flexible you can add it anywhere in HTML by just using the tag +* No jar, preprocessor, no compiler, and deployment dependency exists +* It's very simple to test & deploy + +Disdvantages: + +* Relatively slower than other advanced server-side languages like Node.js +* PHP is not suitable for making larger applications +* PHP is open source, meaning anyone can access it. If there are bugs in the source code, it can be used by people to explore the weakness of PHP + +```php + + + +
+ Name: + +
+ + + + + +``` + +### Node.js - Server Side JavaScript + +* Node.js is suitable for complex applications that need powerful processing +* Node.js uses JavaScript as the front-end and back-end language +* Node.js applications are much faster than PHP + +## Web Frameworks + +### Django + +Django is a full stack high-level Python web framework. It follows the MVT Architecture + +1. URLs: A URL mapper is used to redirect HTTP requests to the appropriate view based on the request URL. The URL mapper can also match particular patterns of strings or digits that appear in an URL. +2. M stands for Model: The data access layer contains anything and everything about the data—how to access it, how to validate it, which behaviors it has, and the relationships between the data. +3. T stands for Template: The presentation layer contains presentation-related decisions—how something should be displayed on a web page or other type of document. +4. V stands for view: The business logic layer contains the logic that accesses the model and defers to the appropriate templates. This works as the bridge between models and templates. + +![](../.gitbook/assets/image%20%28246%29.png) + +### Ruby On Rails + +Ruby on Rails \(RoR\) is an open-source, full-stack framework written in Ruby for developing database-backed web applications. MVC based design. A model in a Ruby on Rails framework maps to a table in a database. A controller is the component of Rails that responds to external requests from the web server to the application and responds to the external request by determining which view file to render. A view in the default configuration of Rails is an .erb file. It is typically converted to output HTML at runtime + +## Web Databases + +A web database is a database that can be queried and/or updated through the World Wide Web. It is a system for storing information that can then be accessed via a web site. For example, an online community may have a database that stores the usernames, passwords, and other details of all its members. Database technology concerns about adopting the right database model and breaking the "one model fits all" approach to handle data. + +SQL \(Structured Query Language\) Popular SQL databases - MySQL, Oracle NOSQL - Non Relatational, Distributive data - MongoDB, Neo4j + +In MySQL data is in table format, In MongoDB it's in JSON object oriented format in Neo4j it's graph based JSON object. + diff --git a/sorting.md b/sorting.md new file mode 100644 index 0000000..2fe4394 --- /dev/null +++ b/sorting.md @@ -0,0 +1,742 @@ +# Sorting + +## Sorting + +> **Selection Sort:** Unstable \(Can be turned stable\), Ω\(N²\) - θ\(N²\) - O\(N²\) : O\(1\) +> **Bubble Sort:** Stable**,** Ω\(N\) - θ\(N²\) - O\(N²\) : O\(1\) +> **Insertion Sort:** Stable, Ω\(N\) - θ\(N²\) - O\(N²\) : O\(1\) +> **Merge Sort:** Stable, Ω\(NlogN\) - θ\(NlogN\) - O\(NlogN\) : O\(N\) +> **Quick Sort:** Unstable \(Can be turned stable\), Ω\(NlogN\) - θ\(NlogN\) - O\(N²\) : O\(1\) + +**Insertion sort** is **faster** for **small** n because Quick **Sort** has extra overhead from the recursive function calls. Due to recursion constant factor is higher. **Insertion sort** requires less memory then quick sort \(stack memory\). + +```cpp +void insertionSort(vector &arr, int n) +{ + for (int i = 1; i < n; ++i) + { + int key = arr[i]; + int j = i - 1; + while (j >= 0 && arr[j] > key) + arr[j + 1] = arr[j], j--; + arr[j + 1] = key; + } +} + +// In-place merge sort makes time complexity O(N²) +void inplaceMerge(vector &arr, int l, int m, int r) +{ + for (int i = r; i > m; --i) + { + if (arr[m] > arr[i]) + { + swap(arr[m], arr[i]); + int tmp = arr[m]; + int j = m-1; + while (j >= 0 && tmp < arr[j]) + arr[j+1] = arr[j], j--; + arr[j+1] = tmp; + } + } +} +void merge(vector &arr, int l, int m, int r) +{ + vector temp = arr; + int i = l, j = m + 1, k = l; + while (i <= m && j <= r) + { + if (temp[i] > temp[j]) + arr[k++] = temp[j++]; + else + arr[k++] = temp[i++]; + } + while (i <= m) + arr[k++] = temp[i++]; + while (j <= r) + arr[k++] = temp[j++]; +} +void mergeSort(vector &arr, int l, int r) +{ + if (l < r) + { + m = (l + r) / 2; + mergeSort(arr, 0, m); + mergeSort(arr, m + 1, r); + merge(arr, 0, m, r); + } +} +/* Randomized quick sort (picking random pivot index instead of r) gives +NlogN in worst aswell */ +// Quick sort is worst when - already sorted (asc or desc) or all elems are same +int partition(vector &arr, int l, int r) +{ + int pivot = arr[r]; + int j = l; + for (int i = l; i < r; ++i) + { + if (arr[i] < pivot) + swap(arr[j++], arr[i]); + } + swap(arr[r], arr[j]); + return j; +} +void sort(vector &arr, int l, int r) +{ + if (l < r) + { + int partitionIndex = partition(arr, l, r); + sort(arr, l, partitionIndex - 1); + sort(arr, partitionIndex + 1, r); + } +} +stable_partition(vec.begin(), vec.end()); +``` + +> **Heap Sort:** Unstable, Ω\(NlogN\) - θ\(NlogN\) - O\(NlogN\) : O\(1\) +> **Counting Sort:** Unstable, O\(N\) : O\(A\[i\]\) + +```cpp +/* Heap is in array form, for all leaves i.e. from i = 0 to n/2 +in reverse order heapify is called, child then root otherwise +child will cause unnecessary changes. After getting proper heap, +it's 0th element gives max (or min in min heap) take that and +put it at the end now ignore thatlast value because it's sorted +and again apply heapify on theremaining.*/ +void heapify(int arr[], int n, int i) // max heap here +{ + int parent = i, left = 2 * i + 1, right = 2 * i + 2; + if (left < n && arr[parent] < arr[left]) + { + swap(arr[left], arr[parent]); + heapify(arr, n, left); + } + else if (right < n && arr[parent] < arr[right]) + { + swap(arr[right], arr[parent]); + heapify(arr, n, right); + } +} +void heapSort(int arr[], int n) +{ + // Building heap part is O(N) + // https://www.geeksforgeeks.org/time-complexity-of-building-a-heap/ + for (int i = n / 2 - 1; i >= 0; --i) + heapify(arr, n, i); + // ascending order sort + for (int i = n - 1; i >= 0; --i) + { + swap(arr[0], arr[i]); + heapify(arr, i, 0); + } +} +``` + +### Radix Sort + +[https://www.youtube.com/watch?v=JMlYkE8hGJM](https://www.youtube.com/watch?v=JMlYkE8hGJM) + +O\(d \* \(n + b\)\) - b is base in number it is 10, for strings it's 26 + +* Most optimal, only drawback is due to not being comparison based sorting in nature only limited to int, float or strings. + +```cpp +void radixSort(vector &arr) +{ + int d = log10(*max_element(arr.begin(), arr.end())) + 1; + vector bucket[10]; + /* Move from LSB to MSB (digit), get that dig from each + element in arr and put it on buckets of 0-9. + In the end iterate over buckets and preserve that order */ + for (int i = 0, pos = 10; i < d; ++i, pos *= 10) + { + for (auto &x : bucket) x.clear(); + for (auto &x : arr) + { + int val = ((x % pos) / (pos/10)); + bucket[val].push_back(x); + } + arr.clear(); + for (auto &x : bucket) + for (auto &y : x) arr.push_back(y); + } +} + +// optimized space usage implementation +void radixSort(vector &arr) +{ + vector bucket(10), aux(arr.size()); + int d = log10(*max_element(arr.begin(), arr.end())) + 1; + for (int i = 0, pos = 10; i < d; ++i, pos *= 10) + { + fill(bucket.begin(), bucket.end(), 0); + for (int i = 0; i < arr.size(); ++i) bucket[(arr[i] % pos) / (pos/10)]++; + for (int i = 1; i < 10; ++i) bucket[i] += bucket[i-1]; + for (int i = arr.size()-1; i >= 0; --i) + { + int x = (arr[i] % pos) / (pos/10); + aux[--bucket[x]] = arr[i]; + } + for (int i = 0; i < arr.size(); ++i) arr[i] = aux[i]; + } +} +``` + +## Partial Sorting + +Time complexity: O\(n + klogk\) + +```cpp +// 10, 45, 60, 78, 23, 21, 3 +partial_sort(vec.begin(), vec.begin() + 3, vec.end()); +// gives 3 10 21 78 60 45 23 +/* If say problem was add k elements from array in sorted order then doing it +with a priority queue is same as sorting all at once O(nlogn) using partial +sort is better */ + +// stl uses heap sort internally +``` + +### Kth Smallest/Largest Number + +```cpp +// Quick Sort extension +using namespace std; +int partition(int arr[], int l, int r) +{ + int pivot = arr[r]; + int j = l - 1; + for (int i = l; i <= r - 1; ++i) + if (arr[i] <= pivot) swap(arr[++j], arr[i]); + swap(arr[++j], arr[r]); + return j; +} +int k_th_smallest(int arr[], int l, int r, int k) +{ + if (k > 0 && k <= r - l + 1) + { + int pos = partition(arr, l, r); + if (pos - l == k - 1) return arr[pos]; + if (pos - l > k - 1) return k_th_smallest(arr, l, pos - 1, k); + return k_th_smallest(arr, pos + 1, r, k - pos + l - 1); + } + return INT_MAX; +} +``` + +### Count Inversions + +```cpp +// BruteFoce O(N²) +int invCount(vector &arr) +{ + int inv_count = 0; + for (int i = 0; i < arr.size(); ++i) + { + for (int j = i + 1; j < arr.size(); ++j) + if (arr[i] > arr[j]) inv_count++; + } + return inv_count; +} + +/* Merge Sort extension O(nlogn) +Whenever there's a swap while merging, there will be m-i+1 inversions */ +int merge(vector &arr, int l, int m, int r) +{ + vector temp = arr; + int i = l, j = m + 1, k = l, inv_count = 0; + while (i <= m && j <= r) + { + if (temp[i] > temp[j]) arr[k++] = temp[j++], inv_count += m - i + 1; + else arr[k++] = temp[i++]; + } + while (i <= m) arr[k++] = temp[i++]; + while (j <= r) arr[k++] = temp[j++]; + return inv_count; +} +int mergeSort(vector &arr, int l, int r) +{ + int inv_count = 0, m = (l + r) / 2; + if (l < r) + { + inv_count += mergeSort(arr, 0, m); + inv_count += mergeSort(arr, m + 1, r); + inv_count += merge(arr, 0, m, r); + } + return inv_count; +} + +/* Using Fenwick tree O(nlogn) +For an element x inside array we need to find how many elements are smaller +that it and appeared before. Initialize a BIT with all zero once element x +is visited update it's count +1 in BIT. Find query for element >= x +thats inv count */ +int invCount(vector &arr) +{ + int inv_count = 0; + for (auto &x : arr) + { + inv_count += query(MAXN) - query(x); + update(x, 1); + } +} +``` + +### Minimum Number of Swaps required to Sort array + +```cpp +/* Way #1 - Use selection Sort if there's a swap, count it +O(N^2) however it can be optimized through heap giving +O(NlogN) */ +int solve(int &n, vector &arr) +{ + int count = 0; + priority_queue< pair, vector< pair >, greater< pair > > pq; + for (int i = 1; i < n; ++i) pq.push({arr[i], i}); + for (int i = 0; i < n-1; ++i) + { + int idx = pq.top().second; + pq.pop(); + if (arr[idx] != arr[i]) + { + int temp = arr[idx]; + arr[idx] = arr[i]; + arr[i] = temp; + count++; + } + } + return count; +} +/* But the code only works for distinct elements + 5 1 2 2 2 2 2 => should give 2 but gives 6 + We can do one thing instead of having idx to the leftmost + we should get the rightmost one */ +int solve(int &n, vector &arr) +{ + int count = 0; + unordered_map keyToIndex; + for (int i = 0; i < n; ++i) keyToIndex[arr[i]] = i; + priority_queue, greater > pq; + for (int i : arr) pq.push(i); + for (int i = 0; i < n-1; ++i) + { + int smallest = pq.top(); + pq.pop(); + if (smallest != arr[i]) + { + int temp1 = arr[i]; + arr[i] = arr[keyToIndex[smallest]]; + arr[keyToIndex[smallest]] = temp1; + + int temp2 = keyToIndex[smallest]; + keyToIndex[smallest] = keyToIndex[temp1]; + keyToIndex[temp1] = temp2; + count++; + } + } + return count; +} +/* +The idea is that if a occupies b's position, b occupies c's +position and so on, then there will be some integer x which +will occupy a's position. So, this forms a cycle. +So, if any element arr[i] is not at its correct position, we +shift it to its correct position j, then shift arr[j] to its +correct position k and so on. So, if len is the length of the +cycle (number of elements in the cycle), then it will require +a minimum of len-1 swaps to rearrange the elements of the cycle +to their correct positions. +We find all such cycles and compute our answer. +*/ +int DFS(vector adj[], vector &visited, int cur) +{ + visited[cur] = true; + int val = 1; + for (auto x : adj[cur]) + { + if (!visited[x]) + val += DFS(adj, visited, x); + } + return val; +} +int solve(int &n, vector &arr) +{ + vector adj[n]; + vector visited(n, false); + for (int i = 0; i < n; ++i) adj[i].push_back(arr[i] - 1), adj[arr[i]-1].push_back(i); + int count = 0; + for (int i = 0; i < n; ++i) + { + if (!visited[i]) + count += DFS(adj, visited, i) - 1; + } + return count; +} +``` + +### [Merge Intervals](https://leetcode.com/problems/merge-intervals) + +```cpp +class Solution { +public: + vector> merge(vector>& intervals) + { + vector> res; + if (intervals.size() == 0) + return res; + sort(intervals.begin(), intervals.end(), [](auto &x, auto &y) + { + return (x[0] == y[0]) ? (x[1] < y[1]) : (x[0] < y[0]); + }); + res.push_back(intervals[0]); + for (int i = 1; i < intervals.size(); ++i) + { + if (intervals[i][0] <= res.back()[1]) + res[res.size()-1][1] = max(res[res.size()-1][1], intervals[i][1]); + else + res.push_back(intervals[i]); + } + return res; + } +}; + +// O(1) space solution, N^2 time +class Solution { +public: + vector> merge(vector>& intervals) + { + if (intervals.size() == 0) return intervals; + sort(intervals.begin(), intervals.end(), [](auto &x, auto &y) + { + return (x[0] == y[0]) ? (x[1] < y[1]) : (x[0] < y[0]); + }); + + vector>::iterator back = intervals.begin(); + for (auto it = ++intervals.begin(); it != intervals.end();) + { + if ((*it)[0] <= (*back)[1]) + { + (*back)[1] = max((*back)[1], (*it)[1]); + intervals.erase(it); // this increases complexity + } + else back = it++; + } + return intervals; + } +}; +``` + +### [Insert Interval In a Sorted List](https://leetcode.com/problems/insert-interval/) + +In 2 pass found start and end bound. Start is max index with intervals\[start\]\[1\] <= newInterval\[0\] and end is min index with intervals\[end\]\[0\] <= newInterval\[1\] + +```cpp +class Solution { +public: + vector> insert(vector>& intervals, vector& newInterval) + { + if (intervals.empty()) return {newInterval}; + int l = 0, r = intervals.size()-1; + while (l <= r) + { + int mid = (l+r)/2; + if (intervals[mid][1] == newInterval[0]) { l = mid; break; } + if (intervals[mid][1] < newInterval[0]) l = mid+1; + else r = mid-1; + } + int start = l; r = intervals.size()-1; + while (l <= r) + { + int mid = (l+r)/2; + if (intervals[mid][0] == newInterval[1]) { r = mid; break; } + if (intervals[mid][0] < newInterval[1]) l = mid+1; + else r = mid-1; + } + int end = r; + if (start < intervals.size()) + newInterval[0] = min(newInterval[0], intervals[start][0]); + if (end >= 0) + newInterval[1] = max(newInterval[1], intervals[end][1]); + intervals.erase(intervals.begin()+start, intervals.begin()+end+1); + intervals.insert(intervals.begin()+start, newInterval); + return intervals; + } +}; +``` + +### [Interval List Intersections](https://leetcode.com/problems/interval-list-intersections/) + +```cpp +vector> intervalIntersection(vector>& A, vector>& B) +{ + vector> res; + for (int i = 0, j = 0; i < A.size() && j < B.size();) + { + int p = max(A[i][0], B[j][0]); + int q = min(A[i][1], B[j][1]); + if (p <= q) + { + res.push_back({p, q}); + if (q == A[i][1]) ++i; + else ++j; + } + else + { + if (A[i][0] > B[j][1]) ++j; + else ++i; + } + } + return res; +} +``` + +### [Hotel Booking Problem](https://www.interviewbit.com/problems/hotel-bookings-possible/) + +```cpp +/* Consider it like a timeline +1 means arrival -1 means departure then sort it +and add to find rooms required at an instance. */ +bool Solution::hotel(vector &arrive, vector &depart, int K) +{ + vector> v; + int n = arrive.size(); + for (int i = 0; i < n; ++i) + { + v.push_back({arrive[i], 1}); + v.push_back({depart[i], -1}); + } + sort(v.begin(), v.end()); + int count = 0; + for (auto &x : v) + { + count += x.second; + if (count > k) return false; + } + return true; +} +``` + +### [Largest Number](https://www.interviewbit.com/problems/largest-number/) + +```cpp +string Solution::largestNumber(const vector &A) +{ + vector b; + for (auto &x : A) b.push_back(to_string(x)); + sort(b.begin(), b.end(), [](string x, string y) + { + string xy = x.append(y); + string yx = y.append(x); + return xy.compare(yx) > 0 ? true : false; + }); + string ans = ""; + for (int i = 0; i < b.size(); i++) ans += b[i]; + bool allzero = true; + for (char i : ans) + if (i != '0') { allzero = false; break; } + if (allzero) return "0"; + return ans; +} +``` + +### [Max Distance](https://www.interviewbit.com/problems/max-distance/) + +```cpp +int Solution::maximumGap(const vector &A) +{ + int n = A.size(); + if (n == 0) return -1; + vector> arr; + for (int i = 0; i < n; ++i) arr.push_back({A[i], i}); + sort(arr.begin(), arr.end()); + int ans = 0, rmax = arr[n - 1].second; + for (int i = n - 2; i >= 0; --i) + { + ans = max(ans, rmax - arr[i].second); + rmax = max(rmax, arr[i].second); + } + return ans; +} +``` + +### Missing Integer in an array + +```cpp +/* If the array contains all numbers from 1 to N except one of them is missing +(n*(n+1))/2 - sum_of_array is answer */ + +/* First missing integer +Mark every element visited as negative within array only */ +for (auto it = A.begin(); it != A.end();) // first remove negative numbers +{ + if (*it <= 0) A.erase(it); + else ++it; +} +for (auto &x : A) +{ + int cur = abs(x)-1; + if (cur >= 0 && cur < A.size()) A[cur] = -A[cur]; +} +for (int i = 0; i < A.size(); i++) + if (A[i] > 0) return i + 1; +return A.size()+1; +``` + +### Maximum Consecutive Gap + +```cpp +/* Basically if we could have sort then it's simple how about counting sort? +It would have worked if number range was low. +We have to reduce comparisons in sorting, we can use idea of bucket sort. +Considering uniform gap: +min, min + gap, min + 2*gap, ... min + (n-1)*gap +min + (n-1)*gap = max +gap = (max - min) / (n-1) +Now we place every number in these n-1 buckets: +bucket = (num - min)/gap, we prepare max and min for each bucket and subtract +to find our answer */ +int Solution::maximumGap(const vector &A) +{ + int n = A.size(); + if (n < 2) return 0; + vector forMin(n, INT_MAX), forMax(n, INT_MIN); + int mn = *min_element(A.begin(), A.end()); + int mx = *max_element(A.begin(), A.end()); + int gap = (mx-mn) / (n-1); + if (gap == 0) return (mx-mn); + for (auto &x : A) + { + int bucket = (x - mn) / gap; + forMin[bucket] = min(x, forMin[bucket]); + forMax[bucket] = max(x, forMax[bucket]); + } + int maxDiff = 0; + for (int i = 0, j = 0; i < forMin.size(); ++i) + { + if (forMin[i] >= 0) + { + maxDiff = max(maxDiff, forMin[i] - forMax[j]); + j = i; + } + } + return maxDiff; +} +``` + +### Min/Max XOR Pair + +```cpp +/* If we sort and then check xor of consecutive pair it will give min +no need to check pair which are not consecutive. */ +int Solution::findMinXor(vector &A) +{ + sort(A.begin(), A.end()); + int mn = INT_MAX; + for (int i = 0; i < A.size()-1; ++i) + mn = min(ans, A[i]^A[i+1]); + return mn; +} +// Only work for min XOR +``` + +Can be solved using trie along with Max XOR Pair problem + +```cpp +/* No need to check for isTerminal since we have same length +(i.e. 32) for all */ +vector> trieArr; +int nxt; +void insert(int num) +{ + int pos = 0; + for (int i = 31; i >= 0; --i) + { + bool cur = !!(num & (1<= 0; --i) + { + bool cur = !!(num & (1<& nums) +{ + trieArr.assign((nums.size()+1)*32, vector(2, 0)); + nxt = 1; + + for (auto &x : nums) insert(x); + int res = 0; + for (auto &x : nums) res = max(res, x^findOptimal(x)); + return res; +} +``` + +### [The Skyline Problem](https://leetcode.com/problems/the-skyline-problem/) + +![\[ \[2 9 10\], \[3 7 15\], \[5 12 12\], \[15 20 10\], \[19 24 8\] \] -&gt; \[ \[2 10\], \[3 15\]...](.gitbook/assets/image%20%28264%29.png) + +Can also be solved using segment tree + +```cpp +class Solution { +public: + vector> getSkyline(vector>& buildings) + { + vector> edges; + for (auto &x : buildings) + { + edges.push_back({x[1], x[2]}); + edges.push_back({x[0], -x[2]}); + } + sort(edges.begin(), edges.end()); + + /* + [9, 10] [2, -10] + [2, -10] [3, -15] + [7, 15] [5, -12] + [3, -15] [7, 15] + [12, 12] -> [9, 10] + [5, -12] [12, 12] + [20, 10] [15, -10] + [15, -10] [19, -8] + [24, 8] [20, 10] + [19, -8] [24, 8] + */ + + multiset st; + st.insert(0); + int cur = 0; + vector> res; + for (auto &x : edges) + { + if (x.second < 0) st.insert(-x.second); // -ve is starting + else st.erase(st.find(x.second)); + if (cur != *st.rbegin()) + { + res.push_back({x.first, *st.rbegin()}); + cur = *st.rbegin(); + } + } + return res; + } +}; +``` + diff --git a/square-root-algorithms.md b/square-root-algorithms.md new file mode 100644 index 0000000..4df4baf --- /dev/null +++ b/square-root-algorithms.md @@ -0,0 +1,44 @@ +# Square Root Algorithms + +### Simple Range Query-Update Problem \(Sum/Max/Min\) + +If we divide our regular array of size n to blocks each having size √n \(last block may have lesser elements\) then we can update in O\(1\) and query in O\(**√n\)** + +```cpp +// build +int len = (int) sqrt(n + .0) + 1; +vec<1, int> blocks(len, 0); +for (int i = 0; i < n; ++i) blocks[i/len] += arr[i]; + +// update +int oldVal = arr[x] +arr[x] = val; +blocks[x/len] += val - oldVal; + +// query: sum [l, r] +int l = 2, r = 5, res = 0; +int _l = l/len, _r = r/len; +if (_l == _r) + for (int i = l; i <= r; ++i) res += arr[i]; +else +{ + for (int i = l, end = ((_l+1)*len - 1); i <= end; ++i) res += arr[i]; + for (int i = _l+1; i <= _r-1; ++i) res += blocks[i]; + for (int i = _r*len; i <= r; ++i) res += arr[i]; +} +``` + +Simmilarly we can find minimum and maximum using this. + +### Case Processing + +Given a 2D n x n grid, each cell is assigned a letter. Find two cells with same letter whose manhattan distance is minimum. In below case its 'E'. + +![](.gitbook/assets/image%20%2861%29.png) + +**Algorithm 1**: Go through all all pairs of cells with letter c \(let's say there are k blocks with c letter\) it will be K^2 + +**Algorithm 2**: Perform a breadth-first search that simultaneously starts at each cell with letter c. The minimum distance between two cells with letter c will be calculated in O\(n\) time. + + + diff --git a/string-algorithms.md b/string-algorithms.md new file mode 100644 index 0000000..c50ffa6 --- /dev/null +++ b/string-algorithms.md @@ -0,0 +1,1050 @@ +# String Algorithms + +## String Stream + +Strings are not mutable. StringStream is mutable. + +Improves string concatenation, if say there's an empty string and we do str += "a" in a loop till n times. It's time complexity will be O\(N^2\) and not O\(N\) it's because inside the loop every time a new string will be created while copying previous one so it will be O\(1 + 2 + 3 + ... + n\) = O\(n \* \(n + 1\) / 2\) + +```cpp +stringstream ss("initialise with some str"); +ss << "append"; +cout << ss.str() << endl; + +// Split using string stream +stringstream ss("abc def ghi"); +string temp; +while (getline(ss, temp, ' ')) cout << temp << endl; +/* + Output: + abc + def + ghi +*/ +``` + +### [Validate IP Address](https://leetcode.com/problems/validate-ip-address/) + +```cpp +class Solution { +public: + string validIPAddress(string IP) + { + stringstream ss(IP); + string tmp; + int cnt = 0; + if (count(IP.begin(), IP.end(), ':') == 7) // IPv6 + { + while (getline(ss, tmp, ':')) + { + cnt++; + if (tmp.size() == 0 || tmp.size() > 4 || tmp.find_first_not_of("0123456789abcdefABCDEF") != string::npos) + return "Neither"; + } + return (cnt == 8 ? "IPv6" : "Neither"); + } + else if (count(IP.begin(), IP.end(), '.') == 3) // IPv4 + { + while (getline(ss, tmp, '.')) + { + cnt++; + if (tmp.size() == 0 || tmp.size() > 3 || (tmp[0] == '0' && tmp.size() > 1) || (tmp.find_first_not_of("0123456789") != string::npos) or (stoi(tmp) > 255)) + return "Neither"; + } + return (cnt == 4 ? "IPv4" : "Neither"); + } + else return "Neither"; + } +}; +``` + +### [Remove Comments](https://leetcode.com/problems/remove-comments/) + +```cpp +vector removeComments(vector& source) +{ + string file = "", parsedFile = ""; + for (const string line : source) file += (line + '\n'); + for (int i = 0; i < file.size();) + { + if (i < file.size()-1 && file[i] == '/' && file[i+1] == '*') + { + int j = i+2; + for(; j < file.size(); j++) + if(file[j] == '*' && file[j+1] =='/') break; + i = j+2; + } + else if (i < file.size()-1 && file[i] =='/' && file[i+1] =='/') + { + int j = i+2; + for(; j < file.size(); j++) if(file[j] == '\n') break; + i = j; + } + else parsedFile += file[i++]; + } + stringstream ss(parsedFile); string line; + vector res; + while(getline(ss, line)) if(!line.empty()) res.push_back(line); + return res; +} +``` + +### [Substring with Concatenation of All Words](https://leetcode.com/problems/substring-with-concatenation-of-all-words/) + +```cpp +class Solution { +public: + /* + - one word can occur multiple time in words? (here yes) + - sliding window technique for each word + edge case: "aaaaaaaa" ["aa","aa","aa"] + output should be: [0, 1, 2] + */ + vector findSubstring(string s, vector &words) + { + vector ans; + int n = s.size(), m = words.size(); + if (n == 0 || m == 0 || n < m*words[0].size()) return ans; + int k = words[0].size(); + + unordered_map cnt; + for (const string x : words) cnt[x]++; + /* for s = "barfoothefoobarman" + str will give: bar foo the foo bar man [NEXT LINE] arf oot ... */ + for (int offset = 0; offset < k; ++offset) + { + unordered_map curCnt; + int found = 0; + for (int l = offset, r = offset; r <= n-k; r += k) + { + string str = s.substr(r, k); + if (cnt.find(str) != cnt.end()) + { + curCnt[str]++, found++; + while (curCnt[str] > cnt[str]) + { + curCnt[s.substr(l, k)]--; + found--, l += k; + } + if (found == m) + { + ans.push_back(l); + curCnt[s.substr(l, k)]--; + found--, l += k; + } + } + else + { + curCnt.clear(); + found = 0, l = r+k; + } + } + } + return ans; + } +}; +``` + +### Minimum Window Problem + +Given string S and T, find minimum substring window in S that contains all character of T +[https://leetcode.com/problems/minimum-window-substring/](https://leetcode.com/problems/minimum-window-substring/) + +```cpp +string minWindow(string s, string t) +{ + if (s.size() < t.size()) return ""; + unordered_map cnt, curCnt; + for (const char ch : t) cnt[ch]++; + + int counter = 0, foundMin = INT_MAX, pos; + for (int l = 0, r = 0; r < s.size(); ++r) + { + if (curCnt[s[r]] < cnt[s[r]]) counter++; + curCnt[s[r]]++; + while (curCnt[s[l]] > cnt[s[l]]) { curCnt[s[l]]--; l++; } + if (counter == t.size()) + { + int newLen = r-l+1; + if (newLen < foundMin) foundMin = newLen, pos = l; + } + } + return (foundMin == INT_MAX) ? "" : s.substr(pos, foundMin); +} +``` + +That contains all characters of T in the same order \(basically subsequence of it is T\) + +```cpp +/* dp can be represented with 2 states - i (current pos we are at in s) and j +(current pos we are at in t) dp[i][j] means minimum length required if we +start at pos i and j. + +transitioning is very easy. INF (1<<30) is uesd instead of INT_MAX to avoid +overflow due to addition operation. + +This is still O(NK * N) which will fail for larger test cases. we can optimize +transition part */ + +vector> dp; +#define INF (1<<30) +int solve(string &s, string &t, int i = 0, int j = 0) +{ + if (j == t.size()) return 0; + if (i == s.size()) return INF; + if (dp[i][j] != -1) return dp[i][j]; + + int res = INF; + for (int x = i; x < s.size(); ++x) + { + if (s[x] == t[j]) + res = min(res, (x - i + 1) + solve(s, t, x+1, j+1)); + } + return dp[i][j] = res; +} +string minWindow(string &s, string &t) +{ + dp = vector>(s.size(), vector(t.size(), -1)); + int res = INF, pos; + for (int i = 0; i < s.size(); ++i) + { + int cur = solve(s, t, i); + if (cur < res) res = cur, pos = i; + } + + return (res == INF) ? "" : s.substr(pos, res); +} + +/* transition optimisation - we want to find next position from i which has +a specific character, using set lower bound stuff */ +vector> dp; +unordered_map> pos; +#define INF (1<<30) +int solve(string &s, string &t, int i = 0, int j = 0) +{ + if (j == t.size()) return 0; + if (i == s.size()) return INF; + if (dp[i][j] != -1) return dp[i][j]; + + int res = INF; + auto it = pos[t[j]].lower_bound(i); + if (it != pos[t[j]].end()) + res = min(res, (*it - i + 1) + solve(s, t, *it+1, j+1)); + return dp[i][j] = res; +} +string minWindow(string &s, string &t) +{ + dp = vector>(s.size(), vector(t.size(), -1)); + pos.clear(); + for (int i = 0; i < s.size(); ++i) pos[s[i]].insert(i); + + int res = INF, pos; + for (int i = 0; i < s.size(); ++i) + { + int cur = solve(s, t, i); + if (cur < res) res = cur, pos = i; + } + + return (res == INF) ? "" : s.substr(pos, res); +} +// O(NK logN) +``` + +## Rope + +* Insert into a string so APAP add XYZ so APXYZAP +* Delete from string +* Move pieces around + +All these in O\(logN\) + +'binary' string is inorder traversal of our tree + +![](.gitbook/assets/image%20%28103%29%20%281%29.png) + +Next important concept, is say we have to insert at pos 10, count subtree sizes so \(in right\) we will go to the right of x because 10 > 8 + +![](.gitbook/assets/image%20%2838%29.png) + +![](.gitbook/assets/image%20%2883%29%20%281%29.png) + +```cpp +struct Rope +{ + Rope *left, *right, *parent; + string str; + int lCount; +}; + +// Maximum number of characters to be put in leaves +const int LEAF_LEN = 2; +void initRope(Rope *&node, Rope *par, string a, int l, int r) +{ + Rope *temp = new Rope(); + temp->left = temp->right = NULL; + temp->parent = par; + if ((r-l) > LEAF_LEN) + { + temp->str = ""; + temp->lCount = (r - l) / 2; + node = temp; + int m = l + (r - l)/2; + initRope(node->left, node, a, l, m); + initRope(node->right, node, a, m+1, r); + } + else + { + node = temp; + temp->lCount = (r - l); + stringstream ss; + for (int i = l; i <= r; ++i) ss << a[i]; + temp->str = ss.str(); + } +} +void printString(Rope *rope) +{ + if (rope == NULL) return; + if (rope->left == NULL && rope->right == NULL) cout << rope->str; + printString(rope->left); + printString(rope->right); +} +Rope* concatenate(Rope *&root1, Rope *root2, int n1) +{ + Rope *temp = new Rope(); + temp->parent = NULL; + temp->left = root1, temp->right = root2; + root1->parent = root2->parent = temp; + temp->lCount = n1; + temp->str = ""; + return temp; +} + +int main() +{ + Rope *root1 = NULL; + string s1 = "YO YO YO"; + initRope(root1, NULL, s1, 0, s1.size() - 1); + Rope *root2 = NULL; + string s2 = "NO NO"; + initRope(root2, NULL, s2, 0, s2.size() - 1); + auto res = concatenate(root2, root1, 5); + printString(res); + return 0; +} +``` + +## String Hashing + +We want to compare strings efficiently. The brute force way of doing so is just to compare the letters of both strings, which has a time complexity of O\(min\(n1,n2\)\) if n1 and n2 are the sizes of the two strings. + +we convert each string into an integer, and compare those instead of the strings. Comparing two strings is then an O\(1\) operation. For comparison we use a hash function. The following condition has to hold: if two strings s and t are equal \(s=t\), then also their hashes have to be equal \(hash\(s\)=hash\(t\)\). Otherwise we will not be able to compare strings. Notice, the opposite direction doesn't have to hold. The reason why the opposite direction doesn't have to hold, if because there are exponential many strings. If we only want this hash function to distinguish between all strings consisting of lowercase characters of length smaller than 15, then already the hash wouldn't fit into a 64 bit integer. + +So usually we want the hash function to map strings onto numbers of a fixed range \[0,m\), then comparing strings. + +![Widely used here p \(prime\) and m are chosen, it's called polynomial hash](.gitbook/assets/image%20%2829%29.png) + +For example, if the input is composed of only lowercase letters of English alphabet, p=31 is a good choice. Obviously m should be a large number, since the probability of two random strings colliding is about ≈1/m. + +```cpp +long long compute_hash(string const& s) +{ + const int p = 31; + const int m = 1e9 + 9; + long long hash_value = 0; + long long p_pow = 1; + for (char c : s) + { + hash_value = (hash_value + (c - 'a' + 1) * p_pow) % m; + p_pow = (p_pow * p) % m; + } + return hash_value; +} +``` + +### Search for duplicate strings in an array of strings + +We calculate the hash for each string, sort the hashes together with the indices, and then group the indices by identical hashes. + +```cpp +vector> group_identical_strings(vector const& s) +{ + int n = s.size(); + vector> hashes(n); + for (int i = 0; i < n; i++) + hashes[i] = {compute_hash(s[i]), i}; + + sort(hashes.begin(), hashes.end()); + + vector> groups; + for (int i = 0; i < n; i++) + { + if (i == 0 || hashes[i].first != hashes[i-1].first) + groups.emplace_back(); + groups.back().push_back(hashes[i].second); + } + return groups; +} +``` + +### Fast hash calculation of substring of given string + +![](.gitbook/assets/image%20%2863%29%20%281%29.png) + +### Number of different substrings in a string \(N^2 log N\) + +```cpp +int count_unique_substrings(string const& s) +{ + int n = s.size(); + const int p = 31; + const int m = 1e9 + 9; + vector p_pow(n); + p_pow[0] = 1; + for (int i = 1; i < n; i++) + p_pow[i] = (p_pow[i-1] * p) % m; + + vector h(n + 1, 0); + for (int i = 0; i < n; i++) + h[i+1] = (h[i] + (s[i] - 'a' + 1) * p_pow[i]) % m; + + int cnt = 0; + for (int l = 1; l <= n; l++) + { + set hs; + for (int i = 0; i <= n - l; i++) + { + long long cur_h = (h[i + l] + m - h[i]) % m; + cur_h = (cur_h * p_pow[n-i-1]) % m; + hs.insert(cur_h); + } + cnt += hs.size(); + } + return cnt; +} +``` + +## Rolling Hashes and Bloom Filters + +If we want to encode a string: + +Say "abcad" => 0.26^4 + 1.26^4 + 2.26^4 + ... +But there are problems in this way say for "aaa" "aa" it is same +**Fixes**: encode length in hash \(messy\), don't use 0 + +At the end we can take modulo of it to avoid very big number + +![](.gitbook/assets/image%20%28135%29.png) + +![](.gitbook/assets/image%20%2868%29.png) + +![](.gitbook/assets/image%20%28125%29.png) + +![](.gitbook/assets/image%20%2845%29.png) + +![](.gitbook/assets/image%20%28183%29.png) + +### Estimating Collision: + +Pick prime number for modulus \(Cycle length if we just take any number greater then 1 and just multiply it repeatedly the cycle length before you get back the number mod p is exactly p-1. It's through fermat's little theorem so it is more uniformly distributed i.e. a ^ p-1 mod p = 1\) + +Assuming that strings are uniform our probability of collision will be n/p + +$$ +P_{collision} = \prod_{i=1}^{n}(1 - (i-1)/p) +$$ + +Tip: Use multiple primes -> 1e9 + 7, 1e9 + 9, 1e9 + 23 + +Why we can getaway with calculating only handful of different hashes comes from Chinese remainder theorem. X = 1 \(mod p1\) X = 2 \(mod p2\) +If gcd\(p1, p2\) = 1 X is unique mod LCM\(p1, p2\) = p1.p2 +So we can now use multiple primes will now become n/p1.p2... So collision chances will reduce + +### Tsukuba Regional Problem - Anagram + +{% embed url="http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1370" %} + +Basically given two strings say - "anagram" and "grandmother" find longest substring which is anagram to both so 'nagr' 'gran' is the answer. + +If we take all \(s1 size\)^2 substring compute it's hash and then do a sliding window test thing on s2 for all we can find the answer. However hashset are pretty slow that's the problem so it will give TLE thats where bloom filter comes. + +> In bloom filters say we are using 3 hash functions and we use 1 string "cat" it's hash a, b, c from those 3 functions will set ath bth and cth bit of bloom filter bitset. Later we search say "mat" and we get hashes c d e now we can check if the bit was previously set say it was 1 0 0. We take and of all to find result. +> Bloom filter gives sure that if it's no then string was not searched but if yes it may be wrong result as well chances are less though. +> +> To avoid failures in bloom filter +> - Make bitset hude i.e. 1e9 +> - Add more hash functions +> - One bitset per hash function + +Hashset are expensive at times bloom filters are better to use in this case. + +TODO: + +{% embed url="https://www.acmicpc.net/problem/14214" %} + +## Suffix Array + +It is a lexicographical sorted array of all suffix of given string. To save space instead of actually storing string we can store index. +s = "abaab" +suffices = \["abaab", "baab", "aab", "ab", "b"\] +after sorting = \["aab", "ab", "abaab", "b", "baab"\] +Therefore suffix array will be = \[2, 3, 0, 4, 1\] + +## Suffix Tree / Trie + +```cpp +// Pointer based implementation +struct node +{ + char data; + unordered_map next; + bool isTerminal; + node(char d) { data = d, isTerminal = false; } +}; +class Trie +{ + node* root; +public: + Trie() { root = new node('\0'); } + void addWord(string word) + { + node* temp = root; + for (int i = 0; word[i] != '\0'; ++i) + { + char ch = word[i]; + if (temp -> next.count(ch) == 0) + { + node* child = new node(ch); + temp -> next[ch] = child; + temp = child; + } + else temp = temp -> next[ch]; + } + temp->isTerminal = true; + } + bool search(string word) + { + node* temp = root; + for (int i = 0; word[i] != '\0'; ++i) + { + char ch = word[i]; + if (temp -> next.count(ch)) temp = temp -> next[ch]; + else return false; + } + return temp -> isTerminal; + } +}; + +// Array based implementation, faster because no dynamic allocation +const int MAXN = 1e5; +int trieArr[MAXN+1][26], nxt = 1; +bool isTerminal[MAXN+1]; +void insert(const string &str) +{ + int node = 0; + for (auto &ch : str) + { + if (trieArr[node][ch-'a'] == 0) + { + trieArr[node][ch-'a'] = nxt; + node = nxt; + nxt++; + } + else node = trieArr[node][ch-'a']; + } + isTerminal[node] = true; +} +bool find(const string &str) +{ + int ind = 0; + for (auto &ch : str) + { + if (trieArr[ind][ch-'a'] == 0) return false; + else ind = trieArr[ind][ch-'a']; + } + return isTerminal[ind]; +} +``` + +### [Longest Common Prefix using Tries](https://leetcode.com/problems/longest-common-prefix) + +```cpp +class Solution { + struct node + { + char data; + int cnt; + unordered_map next; + node(char d) { data = d, cnt = 0; } + }; + class Trie + { + node* root; + public: + Trie() { root = new node('\0'); } + void addWord(string word) + { + node* temp = root; + temp->cnt++; + for (int i = 0; word[i] != '\0'; ++i) + { + char ch = word[i]; + if (temp -> next.count(ch) == 0) + { + node* child = new node(ch); + temp -> next[ch] = child; + temp = child; + } + else temp = temp -> next[ch]; + temp->cnt++; + } + } + string lcp() + { + string res = ""; + if (!root) return res; + node *temp = root; + while (temp) + { + if (temp->next.size() == 1) + { + char val = temp->next.begin()->first; + temp = temp->next.begin()->second; + if (temp && temp->cnt == root->cnt) + res += val; + } + else break; + } + return res; + } + }; + +public: + string longestCommonPrefix(vector& strs) + { + Trie trie; + for (auto &x : strs) trie.addWord(x); + return trie.lcp(); + } +}; +``` + +## Pattern Matching + +```cpp +// Brute force O(MN) +class Solution { +public: + int strStr(string haystack, string needle) { + for (int i = 0; ; ++i) + { + for (int j = 0; ; ++j) + { + if (j == needle.size()) return i; + if (i + j == haystack.size()) return -1; + if (needle[j] != haystack[i+j]) break; + } + } + } +}; + +// KMP +int strStr(string haystack, string needle) +{ + int nSize = needle.size(), hSize = haystack.size(); + if (nSize == 0) return 0; + vector table(nSize); + + // building table + for (int i = 1, j = 0; i < nSize-1;) + { + if (needle[i] != needle[j]) + { + if (j > 0) j = table[j-1]; + else ++i; + } + else table[i] = j+1, ++i, ++j; + } + + // matching + for (int i = 0, matchPos = 0; i < hSize;) + { + if (haystack[i] == needle[matchPos]) + { + if (matchPos == nSize-1) return (i - (nSize - 1)); + else ++i, ++matchPos; + } + else + { + if (matchPos == 0) ++i; + else matchPos = table[matchPos - 1]; + } + } + return -1; +} +``` + +### Rabin Karp implementation using rolling hash + +![](.gitbook/assets/image%20%2811%29.png) + +Window is taken, at each iteration push last and pull first is called in rolling hash generated. +Once hash matches with pattern window we can also check to be fully sure. + +## Aho-Corasick Algorithm for Pattern Matching + +Given an input text of length n and an array of k words, arr\[\], find all occurrences of all words in the input text. m is count of letters in all arr\[\] words. It is used in Unix fgrep command. + +If we iterate over words and perform pattern matching complexity will be O\(nk + m\) with this algo it will be O\(n + m + z\) where z is total number of occurrences of word in the text. + +## Z Algorithm + +```cpp +// N^2 version +vector z_func_trivial(string s) +{ + int n = s.size(); + vector z(n, 0); + for (int i = 1; i < n; ++i) + while (i + z[i] < n && s[z[i]] == s[i + z[i]]) ++z[i]; + return z; +} + +vector z_func(string s) +{ + int n = s.size(); + vector z(n, 0); + for (int i = 1, l = 0, r = 0; i < z; ++i) + { + if (i <= r) z[i] = min(r-i+1, z[i-l]); + while (i + z[i] < n && s[z[i]] == s[i + z[i]]) ++z[i]; + if (i + z[i] - 1 > r) l = i, r = i + z[i] - 1; + } + return z; +} +``` + +{% embed url="https://codeforces.com/contest/126/problem/B" %} + +```cpp +/* Problem: given string find a longest substring such that +it appears at the front, end & inside. +eg: "fixprefixsuffix" -> "fix" + +using hashmap with binary search takes O(nLogn) Z algorithm +takes O(N) + +As we iterate over the letters in the string (index i from 1 to +n - 1), we maintain an interval [L, R] which is the interval with +maximum R such that 1 ≤ L ≤ i ≤ R and S[L...R] is a prefix-substring +(if no such interval exists, just let L = R =  - 1) */ + +string s; +cin >> s; +vector z(s.size()); +int n = s.size(); +int L = 0, R = 0; +/* Z algorithm produces an array z such that z[i] is length +of largest substring which is also the prefix and starting +from i */ +for (int i = 1; i < n; ++i) +{ + // If i > R, then there does not exist a prefix-substring + // of S that starts before i and ends at or after i. + if (i > R) + { + L = R = i; + while (R < n && s[R - L] == s[R]) R++; + z[i] = R - L; + R--; + } + else + { + int k = i - L; + if (z[k] < R - i + 1) z[i] = z[k]; + else + { + L = i; + while (R < n && s[R - L] == s[R]) R++; + z[i] = R - L; + R--; + } + } +} +/* example: + 0 0 0 0 0 0 3 0 0 0 0 1 3 0 0 + f i x p r e f i x s u f f i x */ +int maxz = 0, res = 0; +for (int i = 1; i < n; i++) +{ + if (z[i] == n-i && maxz >= n-i) { res = n-i; break; } + maxz = max(maxz, z[i]); +} +/* example (for if condition): + 0 0 0 0 0 0 12 0 0 0 0 0 6 0 0 0 0 0 + q w e r t y q w e r t y q w e r t y + without if condition ans will get qwertyqwerty */ +if (res == 0) cout << "Just a legend\n"; +else cout << s.substr(0, res) << "\n"; +``` + +Z Algorithm as pattern matching + +{% embed url="https://youtu.be/CpZh4eF8QBw" %} + +```text +Text = xabcabzabc +Pattern = abc +Patter$Text ($ or any char that's not present in strings) + abc$xabcabzabc +z 00000300200300 + * * +take the index with z value = pattern size subtract index +by (pattern size + 1) that's the answer +O(M + N) Time +``` + +Other Problems: +[https://www.codechef.com/problems/CHSTR](https://www.codechef.com/problems/CHSTR) +[http://www.spoj.com/problems/SUFEQPRE/](http://www.spoj.com/problems/SUFEQPRE/) +[https://codeforces.com/contest/119/problem/D](https://codeforces.com/contest/119/problem/D) + +## Suffix Automata + +![The above picture shows an automaton for the string "abcbc"](.gitbook/assets/image%20%2852%29.png) + +![Longest & Shortest string in equivalence class and suffix link \(in blue\)](.gitbook/assets/image%20%28158%29.png) + +```cpp +// O(N) +struct SuffixAutomaton +{ + vector> edges; + vector link, length; + unordered_map terminals; + int last; + SuffixAutomaton(string s) + { + edges.push_back(map()); + link.push_back(-1); + length.push_back(0); + last = 0; + for (int i = 0; i < s.size(); i++) + { + edges.push_back(map()); + length.push_back(i + 1); + link.push_back(0); + int r = edges.size() - 1; + int p = last; + while (p >= 0 && edges[p].find(s[i]) == edges[p].end()) edges[p][s[i]] = r, p = link[p]; + if (p != -1) + { + int q = edges[p][s[i]]; + if (length[p] + 1 == length[q]) link[r] = q; + else + { + edges.push_back(edges[q]); + length.push_back(length[p] + 1); + link.push_back(link[q]); + int qq = edges.size() - 1; + link[q] = qq; + link[r] = qq; + while (p >= 0 && edges[p][s[i]] == q) edges[p][s[i]] = qq, p = link[p]; + } + } + last = r; + } + int p = last; + while (p) terminals[p] = 1, p = link[p]; + } +}; +/* +edges: 0 1 2 3 4 5 6 7 + a=1 b=2 c=3 b=4 c=6 c=7 - b=4 + b=5 + c=7 +last: 6 +length: 0 1 2 3 4 1 5 2 +link: -1 0 5 7 5 0 7 0 +terminals: 6 7 +*/ +``` + +![](.gitbook/assets/image%20%28163%29.png) + +Applications: + +```cpp +// Pattern Matching +SuffixAutomaton sa(str); +bool res = true; +int n = 0; +for (char ch : str) +{ + if (sa.edges[n].find(ch) == sa.edges[n].end()) + { + res = false; + break; + } + n = a.edges[n][ch]; +} +return res; + +// Count Unique Substrings +int countUniqueSubstrings(SuffixAutomaton &sa, int cur = 0) +{ + int val = 0; + for (auto x : sa.edges[cur]) val += countUniqueSubstrings(sa, x.second); + return (cur == 0) ? val : val + 1; +} + +// Lexiographically Kth Substring +// Given string find all substring and sort them then find kth +// Problem: https://codeforces.com/problemset/problem/128/B +void DFS(SuffixAutomaton &sa, vector &occurences, vector &words, int cur = 0) +{ + int occ = 0, wrd = 0; + if (occurences[cur] != 0) return; + if (sa.terminals[cur]) occ++, wrd++; + for (auto x : sa.edges[cur]) + { + DFS(sa, occurences, words, x.second); + occ += occurences[x.second], wrd += words[x.second] + occurences[x.second]; + } + occurences[cur] = occ, words[cur] = wrd; +} + +string KthLexiographicalSubstring(SuffixAutomaton &sa, int k) +{ + vector words(sa.edges.size()), occurences(sa.edges.size()); + DFS(sa, occurences, words); + + int node = 0; + string res; + while (k > 0) + { + int acc = 0; + for (auto x : sa.edges[node]) + { + int tmp = acc; + acc += words[x.second]; + if (acc >= k) + { + node = x.second; + k -= tmp + occurences[x.second]; + res += x.first; + break; + } + } + } + return res; +} +``` + + + +## Palindromic Tree + +Palindromic Tree is based on Manacher's Algorithm, but it's easier to understand and can be extended to other applications as well. This data structure is infact very new. + +Every node is a palindrome, edge u->v represents we can get v by adding that character both end to u. Next there are suffix link \(dotted\) u->v because \(like here\) a is largest suffix palindrome of aba. + +![](.gitbook/assets/image%20%28152%29.png) + +```cpp +struct PalindromicTree +{ + int MAXN, len, num, suff; + struct node { int len, sufflink, num, next[26]; }; + node *tree; + long long ans; + char *s; + + PalindromicTree(string &str) + { + MAXN = str.size() + 5; + tree = new node[MAXN]; + s = new char[MAXN]; + strcpy(s, str.c_str()); + num = 2, suff = 2; + tree[1].len = -1, tree[1].sufflink = 1, tree[2].len = 0, tree[2].sufflink = 1; + } + ~PalindromicTree() { delete[] tree, delete[] s; } + bool addLetter(int pos) + { + int cur = suff, curlen = 0, let = s[pos] - 'a'; + while (true) + { + curlen = tree[cur].len; + if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) break; + cur = tree[cur].sufflink; + } + if (tree[cur].next[let]) { suff = tree[cur].next[let]; return false; } + num++, suff = num, tree[num].len = tree[cur].len + 2, tree[cur].next[let] = num; + if (tree[num].len == 1) + { + tree[num].sufflink = 2, tree[num].num = 1; + return true; + } + while (true) + { + cur = tree[cur].sufflink, curlen = tree[cur].len; + if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) + { + tree[num].sufflink = tree[cur].next[let]; + break; + } + } + tree[num].num = 1 + tree[tree[num].sufflink].num; + return true; + } +}; +``` + +Applications: + +```cpp +// 1) Count number of palindromic substrings in O(N) +// https://informatics.mccme.ru/moodle/mod/statements/view.php?chapterid=1750 +string str; +cin >> str; +PalindromicTree pt(str); +int ans = 0; +for (int i = 0; i < str.size(); ++i) +{ + pt.addLetter(i); + ans += pt.tree[pt.suff].num; +} +cout << ans << endl; + +/* 2) Shady String (Last question of CodeAgon 2019 + A shady string is a palindromic string of odd length. + Em has a string s and he is looking for such a pair of + shady strings that are non-overlapping and exists in + string S. he also wants to find such a shady string + pair whose product of lengths give the maximum possible + value. + + Input: + 3 + 5 5 + 82 79 38 49 9 + 5 9 + 47 37 75 93 89 + 5 2 + 120 160 176 172 192 + + Output: + 44 + 56 + 18 + + Explanation: + - For the first testcase, it s impossible to divide any + number by 5, and the most optimal solution would be to + multiply last number by 5 to get: [82, 79, 38, 49, 45] + - For the second testcase, not changing the array gives the + optimal answer. + - The most optimal array after performing a sequence of + operations would be: [30, 40, 44, 43, 48] */ +``` + diff --git a/system-design.md b/system-design.md new file mode 100644 index 0000000..59d4a66 --- /dev/null +++ b/system-design.md @@ -0,0 +1,55 @@ +# System Design + +## Design Patterns + +### Singleton Class + +```cpp +class Restaurant +{ +private: + static Restaurant _instance = NULL; +public: + static Restaurant getInstance() + { + if (!_instance) _instance = Restaurant(); + return _instance; + } +}; +``` + +> Can interfere unit testing - provide a well-known point of access to some service in your application so that you don’t have to pass around a reference to that service. How is that different from a global variable? \(remember, globals are bad, right???\) What ends up happening is that the dependencies in your design are hidden inside the code, and not visible by examining the interfaces of your classes and methods. You have to inspect the code to understand exactly what other objects your class uses. + +### Factory Method + +```cpp +class CardGame +{ +public: + static CardGame createCardGame(GameType type) + { + if (type == GameType::POKER) return new PokerGame(); + else if (type == GameType::BLACKJACK) return new Blackjack(); + return NULL; + } +}; +``` + +## Common Questions + +### Deck of Cards + +Design the data structure for a generic deck of cards. Explain how would you subclass the data structures to implement blackjack. + +```cpp + +``` + +## Grokking The System Design Interviews + +Part 1: [https://coursehunters.online/t/educative-io-design-gurus-grokking-the-system-design-interview-part-1/579](https://coursehunters.online/t/educative-io-design-gurus-grokking-the-system-design-interview-part-1/579) +Part 2: [https://coursehunters.online/t/educative-io-design-gurus-grokking-the-system-design-interview-part-2/580](https://coursehunters.online/t/educative-io-design-gurus-grokking-the-system-design-interview-part-2/580) +Part 3: [https://coursehunters.online/t/educative-io-design-gurus-grokking-the-system-design-interview-part-3/581](https://coursehunters.online/t/educative-io-design-gurus-grokking-the-system-design-interview-part-3/581) +Part 4: [https://coursehunters.online/t/educative-io-design-gurus-grokking-the-system-design-interview-part-4/583](https://coursehunters.online/t/educative-io-design-gurus-grokking-the-system-design-interview-part-4/583) +Part 5: [https://coursehunters.online/t/educative-io-design-gurus-grokking-the-system-design-interview-part-5/584](https://coursehunters.online/t/educative-io-design-gurus-grokking-the-system-design-interview-part-5/584) +