DSA Math Notes
Posted by Sajid Khan | Last updated on
Faulhaber’s formula
\[ 1+2+3+…+n\ \ \ =\ \ \ \frac{n\left(n+1\right)}{2} \]
\[ 1^2+2^2+3^2+…+n^2\ \ \ =\ \ \ \frac{n\left(n+1\right)\left(2n+1\right)}{6} \]
\[ 1^3+2^3+3^3+…+n^3\ \ \ =\ \ \ \left[\frac{n\left(n+1\right)}{2}\right]^2 \]
Sum of AP, GP and Harmonic series
For an AP series, \[ a_1+a_2+a_3+…..+b\ \ =\ \ \frac{1}{2}\left(a+b\right) \]
For a GP series, \[ a+ak+ak^2+ak^3+…..+b\ \ =\ \ \frac{bk-a}{k-1} \]
For a Harmonic Series \[ \sum_{k=1}^n\frac{1}{k} \], the sum is always less than or equal to \( 1+\log_2n \)
\[ \Rightarrow 1+\frac{1}{2}+\frac{1}{3}+\frac{1}{4}+\frac{1}{5}+\frac{1}{6}+\frac{1}{7}+\frac{1}{8}+…. \]
\[ \le1+\underline{\frac{1}{2}+\frac{1}{2}}+\underline{\frac{1}{4}+\frac{1}{4}+\frac{1}{4}+\frac{1}{4}}+\underline{\frac{1}{8}+……..} \]
Sieve of Eratosthenes (Linear Sieve) Algorithm
Used to find all prime numbers from 1 to N with the help of a boolean array.
Following is an in-efficient \( O\left(n^2\right) \) way to prepare the array:
int maxN = 100; boolean isPrime[] = new boolean[maxN + 1]; isPrime[1] = false; for (int i = 2; i <= maxN; i++) for (int j = i * 2; j <= maxN; j += i) { isPrime[j] = false;
Following is an optimised \( O\left(n\log\left(\log n\right)\right) \) version of above approach:
int maxN = 100; boolean isPrime[] = new boolean[maxN + 1]; isPrime[1] = false; for (int i = 2; i * i <= maxN; i++) if (isPrime[i]) for (int j = i * i; j <= maxN; j += i) { isPrime[j] = false;
GCD (Greatest Common Devisor)
GCD of two numbers \( a \) and \( b \) is the greatest integer number which is a divisor of both \( a \) and \( b \). As an example, GCD of 6 and 10 is 2 because 2 is the greatest integer which can equally devide both 6 and 10. and GCD of 6 and 12 is 6 because 6 can equally devide both 6 as well as 12.
GCD is also called HCF (Highest common factor) or GCM (Greatest common measure)
Properties of GCD
- \( \gcd\left(a,b\right)=\gcd\left(b,a\right) \) i.e. GCD is a cumutative function.
- \( \gcd\left(a,\gcd\left(b,c\right)\right)=\gcd\left(\gcd\left(a,b\right),c\right) \). i.e. GCD is assosiative function. Therefore, the GCD of multiple values can be simply denoted as \( \gcd\left(a,b,c,…\right) \).
- \( \gcd\left(a,0\right)=a \). Because any number \( a \) can equally devide both \( a \) as well as \( 0 \)
- If \( c \) is any constant integer, then \( \gcd\left(a,c\times a+r\right)=\gcd\left(a,r\right) \)
- Euclidean algorithm for GCD: Euclidean algorithm is based on the previous property ( \( \gcd\left(a,c\times a+r\right)=\gcd\left(a,r\right) \)). According to Euclidean algo, if \( a\ge b \) and \( r \) is remainder of \[ \frac{a}{b} \] then \( \gcd\left(a,b\right)=\gcd\left(r,b\right) \). Euclidean algo can be used to efficiently calculate GCD’s of two integers using recursive function calls.
public int gcd(int a, int b) { if (b == 0) return a; //notice that the position of a % b, b are swapped, this is to ensure //that the right argument is always smaller than left argument //if not swapped, seperate condition checks have to be implemented which //will check the larger and smaller numbers to calculate the remainder return gcd(b, a % b); }
- If \( g \) is gcd of \( a \) and \( b \) then \( g \) is also a divisor of \( a+b \). In other words, \( \gcd\left(a,b\right)=\gcd\left(a,b,a+b\right) \).
Let, \( g \) is GCD of \( a \) and \( b \)
\( \Rightarrow a=g\cdot k_1 \) and \( b=g.k_2 \)
\( \Rightarrow\left(a+b\right)=g\left(k_1+k_2\right) \)
Which prooves that \( g \) is divisor of \( \left(a+b\right) \)
- \( \gcd\left(a,b\right)=\gcd\left(a,a+b\right) \). Similarly, \( \gcd\left(a,b,c,…\right)=\gcd\left(a,a+b,a+b+c,…\right) \)
- \( \gcd\left(a,b\right)=\gcd\left(-a,b\right)=\gcd\left(a,-b\right)=\gcd\left(-a,-b\right) \)
- \( \gcd\left(…,a_i,….,a_j…\right)=\gcd\left(…,a_i,….,a_j+n\cdot a_i…\right) \).
- If \( a_1\text{ and }a_2 \) are co-prime, then \( \gcd\left(an,b\right)=\gcd\left(n,b\right) \)
- If \( \gcd\left(a,b\right)=d \), \( \Rightarrow a=P\cdot d \) and \( \Rightarrow b=Q\cdot d \) where \( P \) and \( Q \) are some constants, then \( P \) and \( Q \) are co-prime.
- \( \gcd\left(P,Q\right)=1 \)
From wikipedia
https://en.wikipedia.org/wiki/Greatest_common_divisor#Properties
- If a divides the product b⋅c, and gcd(a, b) = d, then a/d divides c.
- If m is a positive integer, then gcd(m⋅a, m⋅b) = m⋅gcd(a, b).
- If m is a positive common divisor of a and b, then gcd(a/m, b/m) = gcd(a, b)/m. This can further be deduced into following:
- \[ \gcd\left(\frac{a_1}{\gcd\left(a_1,…,a_i\right)},…,\frac{a_i}{\gcd\left(a_1,…,a_i\right)}\right)=\frac{\gcd\left(a_1,…,a_i\right)}{\gcd\left(a_1,…,a_i\right)}=1 \]
- \[ \gcd\left(a_1,…,a_i\right)=m\cdot\gcd\left(\frac{a_1}{m},…,\frac{a_i}{m}\right) \]
- If m is any integer, then gcd(a + m⋅b, b) = gcd(a, b)
- If a1 and a2 are relatively prime, then gcd(a1⋅a2, b) = gcd(a1, b)⋅gcd(a2, b)
- gcd(na − 1, nb − 1) = ngcd(a,b) − 1
Extended Euclidean algorithm
In addition to calculating just the GCD using euclidean algo as explained above in properties of GCD, the Extended Euclidean algorithm also helps in finding the coefficients of Bézout’s identity \( x \) and \( y \). i.e., if \( \gcd\left(a,b\right)=d \), then the extended euclidean helps in finding coefficients \( x \) and \( y \), such that \( xa+yb=d \).
The above equation is called Bézout’s identity. This equation is particularly usefull when \( a \) and \( b \) are co-primes, in that case, \( xa+yb=1 \) which implies that \( x \) is modular multiplicative inverse of \( a \) and \( y \) is modular multiplicative inverse of \( b \). Modular multiplicative inverse, for instance, has application in cryptography.
- Nice video explaining the Extended Euclidean algorithm for calculating cofficients of Bézout’s identity.
As we know that based on euclidean algorithm \( \gcd\left(a,b\right)=\gcd\left(b,a\%b\right) \).
Because of this recursive behaviour, the coefficients \( x \) and \( y \) of integers \( a \) and \( b \) ( such that \( ax+by=\gcd\left(a,b\right) \) ) can be obtained with the help of the coefficients \( x_0 \) and \( y_0 \) of integers \( b \) and \( a\%b \) (such that \( bx_0+\left(a\%b\right)y_0=\gcd\left(b,a\%b\right) \) )
Derivation of relation between \( x,y\text{ and }x_0,y_0 \) (as explained on GFG):
\[ \begin{aligned} &\gcd\left(a,b\right)=\gcd\left(b,a\%b\right) \\ \text{but, }&\gcd\left(a,b\right)=x\cdot a+y\cdot b \\ \text{similarly, }&\gcd\left(b,a\%b\right)=x_0\cdot b+y_0\cdot a\%b \end{aligned} \]
based on above 3 equations,
\[ \begin{aligned} x\cdot a+y\cdot b &=x_0\cdot b+y_0\cdot a\%b \\ x\cdot a+y\cdot b &=x_0\cdot b+y_0\cdot (a-\frac{a}{b}*b) \ \ \ \ \ -\text{ ( note that here }\frac{a}{b}\text{ represents integer devision of } a \text{ by } b \text{)}\\x\cdot a+y\cdot b &=x_0\cdot b+y_0\cdot a-y_0\frac{a}{b}b \\ &=y_0\cdot a+\left(x_0-y_0\frac{a}{b}\right)\cdot b \end{aligned} \]
Comparing LHS with RHS, we get
\[ x=y_0\text{ and }y=x_0-y_0\cdot\frac{a}{b} \]
Implementation based on above relation between \( x,y,x_0\text{ and }y_0 \)
class Solution{ private int x, y, g; private void gcd(int a, int b) { //keep in mind the default value of x and y for base condition if (b == 0) { x = 1; y = 0; g = a; return; } //notice how x and y become x0 and y0 due to the recursive call gcd(b, a % b); int x0 = x, y0 = y; //following is performed based on the derived relations between x, y, x0 and y0 x = y0; y = x0 - y0 * (a/b); } public void printGCD(int a,int b){ x = 0; y = 0; g = 0; gcd(a, b); System.out.println("GCD of "+a+" and "+b+" : " + g); System.out.println("bezout's identity (a*x + b*y = GCD) : "+a+"*"+x+" + "+b+"*"+y+" = "+g); } } //Driver class class Test { public static void main(String args[]) { new Solution().printGCD(12, 42); } }
LCM (Least common Multiple)
LCM of two numbers \( a \) and \( b \) is the smallest number which is divisible by both \( a \) as well as \( b \). As an example, LCM of 6 and 10 is 30 because 30 is divisible by both 6 as well as 10. Similarly, LCM of 6 and 12 is 12 because 12 is devisible by both 12 as well as 6. LCM and GCD are closely related. By definition, LCM is opposite of GCD
For two numbers \( a \) and \( b \),
\( \operatorname{lcm}\left(a,b\right)\cdot\gcd\left(a,b\right)=\left|ab\right| \) \( \Rightarrow \) \[ \operatorname{lcm}\left(a,b\right)=\frac{\left|ab\right|}{\gcd\left(a,b\right)} \]
It is important to note that \[ \operatorname{lcm}\left(a,b,c\right)\ne\frac{\left|abc\right|}{\gcd\left(a,b,c\right)} \]
\[ \operatorname{lcm}\left(a,b,c\right)=\frac{abc}{\gcd\left(ab,bc,ca\right)} \]
Similarly, \[ \operatorname{lcm}\left(a,b,c,d\right)=\frac{abcd}{\gcd\left(abc,bcd,cda,dab\right)} \]
Also, following relations between GCD and LCM holds true:
- \( \gcd\left(a,\operatorname{lcm}\left(b,c,d…\right)\right)=\operatorname{lcm}\left(\gcd\left(a,b\right),\gcd\left(a,c\right),\gcd\left(a,d\right),…\right) \)
- \( \operatorname{lcm}\left(a,\gcd\left(b,c,d…\right)\right)=\gcd\left(\operatorname{lcm}\left(a,b\right),\operatorname{lcm}\left(a,c\right),\operatorname{lcm}\left(a,d\right),…\right) \)
Properties of LCM
Properties are mostly similar to (but opposite of) GCD. By replacing \[ \gcd\left(a,b\right)\text{ with }\frac{\left|a\cdot b\right|}{\operatorname{lcm}\left(a,b\right)} \] in the properties of GCD, following properties of LCM can be obtained.
- If \( a \) and \( b \) both equally devide \( n \), i.e. \( a\mid n\text{ and }b\mid n \), then \( \operatorname{lcm}\left(a,b\right) \) also equally devides \( n \), i.e. \( \operatorname{lcm}\left(a,b\right)\mid n \)
- \( \operatorname{lcm}\left(an,bn\right)=n\operatorname{lcm}\left(a,b\right) \)
- If \( a \) and \( b \) are co-prime, then \[ \operatorname{lcm}\left(ab,n\right)=\frac{\operatorname{lcm}\left(a,n\right)\cdot\operatorname{lcm}\left(b,n\right)}{m} \]
Modular Arithmatic
Modulo vs Remainder
Modulo and Remainder are same when performed on positive operands, but can produce different result when operands are negative. in Java and C++, the % operator always produces the remainder of given operands. The result of % operator can be different when Modulo of operands is expected.
Remainder: The part that remains after integer devision of two operands.
- 7 % 3 = 1 because \[ \frac{7}{3}=2 \] which gives 7 = 3 * 2 + 1
- 7 % -3 = 1 because \[ \frac{7}{-3}=-2 \] which gives 7 = -3 * -2 + 1
- -7 % 3 = -1 because \[ \frac{-7}{3}=-2 \] which gives -7 = 3 * -2 -1
- -7 % -3 = -1 because \[ \frac{-7}{-3}=2 \] which gives -7 = -3 * 2 -1
In short, if the first operand of % operator (remainder operator) is negative, the result will be \( -1\times \) remainder of same operands when first operand was positive. The sign of second operand doesn’t have effect on the result
Modulo (Euclidean division): Modulo is based on the division theorem according to which, if \( a \) and \( b \) are two integers, than there exist two integers \( q \) and \( r \), such that
\( a=q\cdot b+r \)
Where \( 0\le r\le\left|b\right| \)
Therefore, modulo of two operands is always positive regardless of the sign of any of the operand.
- 7 mod 3 = 1 because 7 = 3 * 2 + 1
- 7 mod -3 = 1 because 7 = -3 * -2 + 1
- -7 mod 3 = 2 because -7 = 3 * -3 + 2
- -7 mod -3 = 2 because -7 = -3 * 3 + 2
See this problem which is based on modulo (not remainder).
Implimentation of Modulo in Java
Modulo can be simply derived with the help of remainder of two operands. If the remainder is positive, the modulo remains same as remainder, however if remainder is negative, the modulo is simply \( \left|\text{second operand}\right|+\text{remainder} \)
int aMODb(int a, int b) { int mod = a % b; if (mod < 0) mod = Math.abs(b) + mod; return mod; }
Congruence
- If a % m = b, then it can be said that “a is congruent to b with respect to modulo m” denoted \( a\equiv b\left(\text{mod}\ m\right) \)
- In other words, two integers a and b are said to be congruent module m if m is a divisor of their difference.
\( \Rightarrow \) If \( a\equiv b\left(\text{mod}\ m\right) \) then \( a-b=k\cdot m \) (where \( k \) is some constant)
Modular multiplicative inverse
\( x \) is a modular multiplicative inverse of integer \( a \) (with respect to modulo \( m \)) if \( ax\ \text{mod}\ m=1 \) or \( ax\equiv1\left(\text{mod}\ m\right) \). Furthermore, modular multiplicative inverse \( x \) will exist only if \( a \) and \( m \) are co-prime, i.e. GCD of \( a \) and \( m \) is 1
Modular multiplicative inverse can be obtained:
- using Extended euclidean algorithm: Extended euclidean algorithm can be used to find the coefficient \( x \) and \( y \) in equation \( xa+yb=\gcd\left(a,b\right) \). If a and b are coprime, that is, if \( xa+yb=1 \), then x is the modular multiplicative inverse of a modulo b, and y is the modular multiplicative inverse of b modulo a.
- Note: while using extended euclidean algorithm to find Modular multiplicative inverse (MMI), the MMI can sometimes come out to be negative. Simply add \( m \) to it to make it positive
- using Fermat’s little theorm (if \( m \) is prime)
Fermat’s little theorm
According to Fermat’s little theorm, if \( p \) is a prime number, then for any integer \( a \), \( a^p\equiv a\left(\ \text{mod}\ p\right) \) (or \( a^p\ mod\ p=a\ mod\ p \))
Deviding both sides in above equation by \( a \), \[ \frac{a^p}{a}\equiv\frac{a}{a}\left(\text{mod}\ \frac{p}{\gcd\left(a,p\right)}\right) \]
If \( a \) and \( p \) are coprime to each other, we get \[ a^{p-1}\equiv1\left(\text{mod}\ p\right) \]
Multiply above equation by \[ \frac{a}{a} \], we get \[ a\times a^{p-2}\equiv1\left(\text{mod}\ p\right) \]
Above equation implies that, for any integer \( a \), \[ a^{p-2} \] will be it’s inverse with respect to modulo \( p \) if \( p \) is a prime number and both \( a \) and \( p \) are co-prime to each other.
Properties of Modulos
- Distributive: \( \left(a+b\right)\ \text{mod}\ m\ =\ \left(a\ \text{mod}\ m\ +b\ \text{mod}\ m\right)\text{mod}\ m \)
- \( \left(a\times b\right)\ \text{mod}\ m\ =\ \left(a\ \text{mod}\ m\ \times b\ \text{mod}\ m\right)\text{mod}\ m \)
- However, same is not always true when it comes to division, i.e: \[ \left(\frac{a}{b}\right)\ \text{mod}\ m\ \ne\left(\frac{a\ \text{mod}\ m}{b\ \text{mod}\ m}\right) \]
- But, If \( a\equiv b\left(\ \text{mod}\ m\ \right) \), then \[ \frac{a}{d}\equiv\frac{b}{d}\left(\ \text{mod}\ \frac{m}{\gcd\left(m,d\right)}\right) \]
- \( \Rightarrow \) If \( a\equiv b\left(\text{mod}\ m\right) \) and if an integer \( d \) is coprime with \( m \) ,then \[ \frac{a}{d}\equiv\frac{b}{d}\left(\text{mod}\ m\right) \]
How to find \[ \left(\frac{a}{b}\right)\ \text{mod}\ m \] without directly dividing a by b (in case a and b are unknowingly huge)?
- \[ \left(\frac{a}{b}\right)\ \text{mod}\ m \] is equivalant to \[ \left(a\times b^{-1}\right)\ \text{mode}\ m \] where \[ b^{-1} \] is modular multiplicative inverse of \( b \)
Example: Find \[ \left(\frac{888888888}{98765432}\right)\text{mod}\ 1000000007 \] without directly divinding 888888888 by 98765432
Solution: Since 98765432 and 1000000007 are coprime to each other, Find modulo multiplicative inverse of 98765432 with respect to modulo 1000000007, that is \[ 98765432^{\left(1000000007-2\right)}\text{mod}\ 1000000007 \]. Using a custom modPower()
function to solve above equation, 609375003 is obtained as inverse of 98765432 with respect to modulo 1000000007. therefore:
\[ \therefore\frac{888888888}{98765432}\text{mod}\ 1000000007=888888888\times609375003\ \text{mod}\ 1000000007=9 \]
The result \( 9 \) is indeed correct and can be confirmed by dividing 888888888 by 98765432 directly
Bit Manipulation
XOR operator properties
- \( a \oplus a = 0 \)
- \( a \oplus b = b \oplus a \)
- \( (a \oplus b) \oplus c = a \oplus (b\oplus c) \)
- If \( a \oplus b = c \) then \( a \oplus c = b \) and \( b \oplus c = a \) (Tricky problem based on this)
- Distribution of XOR over OR : \( a\oplus\left(b\mid c\right)=\left(a\oplus b\right)\mid\left(a\oplus c\right) \)
- Distribution of XOR over AND : \( \left(x\&a\right)\oplus\left(y\&a\right)=\left(x\oplus y\right)\&a \)
- For an array \( A \) of length \( n \),
- if \[ A_0\ \oplus A_1\oplus A_2\oplus…….\oplus A_{n-1}\ \ =0 \], then for each \( i\in\left[0,n\right] \),
- \[ A_0\oplus A_1\oplus…..\oplus A_i\ \ \ =\ \ A_{i+1}\oplus A_{i+2}\oplus……\oplus A_{n-1} \]
Problems
- Count number of times ith bit is set in integers when counting from integer 0 to n
- Observe the 1st, 2nd bits when counting from 0 to 7
000
001
010
011
100
101
110
111 - The 1st bit (right most) is set after every one unset bit, whereas the two 2nd bit is set after every two unset bits. Similarly for the 3rd bit, four bits are set after every four unset bits. This pattern can be used to easily calculated number times bit at any position is set when counting from 0 to n.
- See problem Find Products of Elements of Big Array which is based on above observation
Combinatorics
Crazy combinatorics problem with good explanation of bucket arrangement.
Matrix
TODO
Matrix Exponentiation
Leetcode problem: 1220. Count Vowels Permutation with O(logN) solution using Matrix Exponentiation.
Power of adjacency Matrix
Leetcode problem : Knight Dialer with \( O\left(\log n\right) \) solution using power of adjacency matrix