`prices`

where `prices[i]`

is the price of a given stock on the `i<sup>th</sup>`

day.You want to maximize your profit by choosing a **single day** to buy one stock and choosing a **different day in the future** to sell that stock.

Return *the maximum profit you can achieve from this transaction*. If you cannot achieve any profit, return `0`

.

Solution:

In this problem, we are given an array **prices** and we need to buy the stock at some point of time and we need to sell that stock at another time , and the answer will be the difference between the selling price and buying prize.

so to solve this problem, we need to find the difference between the selling and buying prize of the given stock

All we have to do is to find the maximum difference which is possible and that will be my answer.

`#include<bits/stdc++.h>using namespace std;int main(){ int prices[] = {2,3,5,4,6,7}; int n = sizeof(prices)/sizeof(prices[0]); int ans = 0; int mini = prices[0]; int maxi = prices[0]; for(int i=0;i<prices.size(); i++){ if(prices[i] < mini){ maxi = max(maxi, prices[i]); ans = max(ans, maxi-mini); } } return ans;}`

That's all for this video

I will see you in the next blog.

]]>Each gondola may have one, or two children in addition, the total weight of a gondola may not exceed **x**. You know the weight of every child.

What is the minimum number of gondolas needed for the children?

**Input**

The first input line contains two integers **N** and **x**: the number of children and the maximum allowed weight.

The next line contains **N** integers p1,p2,,pn,pn: the weight of each child.

Print one integer: the minimum number of gondolas.

1n21051

1x1091

1pix1

Input:

`4 107 2 3 9`

Output:

`3`

Let's understand the problem, the total weight of the gondola cannot exceed **x,** so to solve this problem, we need to count the maximum number of pairs in the array having a sum less than equal to **x**.

We need to count the actual number of pairs which has a sum less than or equal to **x** and we need to actually count the number of pairs which has a sum equal to or less than **x**.

Let's see how we can do so.

All we have to do is to use the 2-pointer approach in which we have one pointer at the start and another pointer at the end of the given array.

So, we need to just take the sum of these two numbers such that the sum of these two numbers does not exceed **x.**

Let's jump to the code implementation part.

`#include<bits/stdc++.h>using namespace std;int main(){ int n,x; cin >> n >> x; vector<int>v(n); for(int i=0; i < n; i++)cin >> v[i]; int ans = 0; int i = 0, j = n-1; while(i <= j){ if(i == j){ if(v[i] <= x){ ans++; i++; j++; } }else if(v[i] + v[j] > x){ ans++; j--; }else if(v[i] + v[j] <= x){ ans++; i++; j--; } } cout << ans;}`

Let's understand the code above, we have an array **v** for which we have to find the number of pairs having a sum not exceeding **x.**

To solve this problem, we are using **2** pointers **i** and **j** where the first points to the first value of the integer and the second to the last value of the integer.

We need

]]>Each gondola may have one or two children in it, and in addition, the total weight in a gondola may not exceed **x**. You know the weight of every child.

What is the minimum number of gondolas needed for the children?

Input

The first input line contains two integers N and x: the number of children and the maximum allowed weight.

The next line contains **n** integers p1,p2,,pnp_1,p_2,p_np1,p2,,pn: the weight of each child.

Print one integer: the minimum number of gondolas.

1n21051

1x1091

1pix1

Input:

`4 107 2 3 9`

Output:

`3`

To solve this problem, we need to find the maximum number of pairs having a sum less than equal to **x** and that will give us our answer.

Let's see how we can do this

`#include<bits/stdc++.h>using namespace std;int main(){ int n,x; cin >> n >> x; vector<int>p(n); for(int i=0;i<n;i++)cin >> p[i]; sort(p.begin(), p.end()); int i = 0, j = n-1; while(i <= j){ if(i == j){ if(v[i] <= x){ ans++; i++; j--; }else if(v[i] + v[j] > x)ans++, j--; else if(v[i] + v[j] <= x)ans++, j--, i++; } }cout << ans;}`

So, in this fashion we can solve this problem and that's all for this blog ,will seee you in the next one.

]]>Each applicant has a desired apartment size, and they will accept any apartment whose size is close enough to the desired size.

The first input line has three integers n, m, and k: the number of applicants, the number of apartments, and the maximum allowed difference.

The next line contains nnn integers a1,a2,,ana_1, a_2, \ldots, a_na1,a2,,an: the desired apartment size of each applicant. If the desired size of an applicant is xxx, he or she will accept any apartment whose size is between xkx-kxk and x+kx+kx+k.

The last line contains mmm integers b1,b2,,bmb_1, b_2, \ldots, b_mb1,b2,,bm: the size of each apartment.

Print one integer: the number of applicants who will get an apartment.

1n,m21051 \le n, m \le 2 \cdot 10^51n,m2105

0k1090 \le k \le 10^90k109

1ai,bi1091 \le a_i, b_i \le 10^91ai,bi109

Input:

`4 3 560 45 80 6030 60 75`

Output:

`2`

In this problem, we have **n** applicants and **m** free appartments, the task is to distribute the apratments so that as many applicants as gets an apartment.

We can see from above that the number of applicants who will get an apartment are **2** as given from the numbers.

There are multiple approaches to solve this problem, first one is to user binary search for any x, we can binary search if we have the apartment between the range **x-k** to **x + k.**

Another aproach is to use two pointers ,

Sort both the arrays and then look for those pairs which have the difference greater than equal to **k** and simply count them.

Let's jump to the code implementation part of the second one.

`#include<bits/stdc++.h>using namespace std;int main(){ int n,m,k; cin >> n >> m >> k; vector<int>v(n), vv(m); for(int i=0;i<n;i++)cin >> v[i]; for(int i=0;i<m;i++)cin >> b[i]; sort(v.begin(), v.end()); sort(v.begin(), v.end()); int ans = 0; int i = 0, j = 0; while(i < n and j < m){ if(v[i]-b[i] <= k){ ans++; i++; j++; }else if(v[i] > b[j]){ j++; }else{i++;} }}`

]]>The first input line has an integer n: the number of values.

The second line has the integers x1,x2,,xn.

Print one integer: the number of distinct values.

1n2

1xi1091

Input:

`52 3 2 2 3`

Output:

`2`

To solve this problem, all we have to do is to just count distinct values which can be done using a set data structure.

A set can be used to solve this problem, which stores the distinct values.

`#include<bits/stdc++.h>using namespace std;int main(){ int n; cin >> n; vector<int>v(n); for(int i=0;i<n;i++)cin >> v[i]; set<int>st; for(auto it: v)st.insert(it); cout << st.size();}`

That was the first approach, let's see another approach to solve this problem.

The second approach is to use a hashmap to count the number of distinct values.

`#include<bits/stdc++.h>using namespace std;int main(){ int n; cin >> n; map<int,int>mp; for(int i=0;i<n;i++){ int x; cin >> x; mp[x]++; } cout << mp.size();}`

That's all for this blog, will see you in the next one soon.

]]>for example, **20! = 2432902008176640000**

The only input line has an integer **n**.

Print the number of trailing zeros in **n**!

**1 <= n <= 10^9**

`20`

Output:

`4`

To solve this problem, we just need to count the number of **5's** and number of **2s** in the pr**i**me factorization of the number **n.**

We can see that the ending digit of the given number is **0** which is obtained only by multiplying the given number **5** with **2.**

Hence, for the number of factors given number **n**, we can add them up and that will be our answer

Let's code the solution up.

`#include<bits/stdc++.h>using namespace std;int getFactors(int n){ int cnt = 0; while(n % 5 == 0) { n /= 5; cnt++; } return cnt;}int primeFactrization(int n){ int ret = 0; for(int i = 5; i <= n; i += 5) { ret += getFactors(i); } return ret;}int main(){ int n; cin >> n; cout << primeFactorization(n);}`

That's all we have to do in this problem, I shall see you soon in the next blog.

]]>For example, if **n=3**, the correct answer is **888**, because the possible bit strings are **000**, **001**, **010**, **011**, **100**, **101**, **110**, and **111**.

The only input line has an integer **n**.

Print the result modulo **10^9 + 7**.

**1 <= n <= 10^6**

Input:

`3`

Output:

`8`

In this problem, we need to count the bit strings having a length of **n** and Let's say **n** is **3**, the possible bit strings are 000, 001, 010, 011, 100, 101, 110, and 111.

Let's understand what is expected in this problem, we need to just count the possible strings which are possible using the length n.

for the place we have the string as **000**, and we know that at any bit we can change the bit in two ways either it is **1** or **0**.

So, to solve this problem, we just have to find the total number of ways to find the bit strings.

That is just **2^n** where **n** represents the length of the given string.

Let's think of using binary exponentiation.

Let's code the solution up.

`#include<bits/stdc++.h>using namespace std;#define MOD 1000000007int Bexp(int a, int b){ long long ret=1; for (;b;a=a*a%MOD,b>>=1) if (b&1) ret=ret*a%MOD; return ret;}int main(){ int n; cin >> n; cout << Bexp(2,n);}`

The second thing is to calculate the binary exponentiation.

Let's see what is binary exponentiation.

The term refers to the exponentiation of **a** raised to the power **b** and we know that **a^b** can be calculated using binary exponentiation which refers to the process of multiplying **a**, **b** times.

Let's understand the process of binary exponentiation.

`#define MOD 100000009int binaryExponentiation(int a, int b){ long long ans = 1; while(a){ ans = (ans*a)%MOD; b = (b*b)%MOD; b >>= 1; }}`

That's all for this blog and I shall see you in the next one.

]]>The only input line contain**s** an integer n.

The only input line contains an integer n.

Print **"YES"**, if the division is possible, and **"NO"** otherwise.

After this, if the division is possible, print an example of how to create the sets. First, print the number of elements in the first set followed by the elements themselves in a separate line, and then, print the second set in a similar way.

- 1n106

Input:

`7`

Output:

`YES41 2 4 733 5 6`

Input:

`6`

Output:

`NO`

To solve this problem, we need to just divide the given set into two parts such that the sum of numbers in both parts is the same .

To solve this problem, we have to just brute force the problem i.e. just start putting up the values such that you just push values from the last till you do not exceed the (sum/2) , Let's understand this with an example.

Let's say we have **N = 7**, Now, we know that we cannot exceed value **(7*(8))/2 = 28**.

Let's start adding values from the end i.e. **(7 + 6 + 5 + 4 + .. )** till we do not exceed **28** say we have **k** and we also have **t**.

So, to solve this problem, we need to keep adding till the values exceed **28**,

So we add till the sum exceed **28** and we also mark the given numbers using a boolean array.

Let's say the sum desired is s , then we push (s - k) into the array.

Let's code the solution

`#include<bits/stdc++.h>using namespace std;int main(){ int n; cin >> n; int sum = n*(n+1)/2; if(sum % 2 == 0) { cout << "YES\n"; int s = sum/2; vi a , b; int k = 0; int t = n; vector<bool>bul(n+1,false); while(k+t < s) { a.push_back(t); bul[t] = true; k += t; t--; } if(k < s) { a.push_back(s-k); bul[s-k] = true; } for(int i = 1; i <= n; i++) { if(!bul[i]) b.push_back(i); } cout << a.size() << endl; for(int i=0;i<a.size(); i++) cout << a[i]; cout << endl; cout << b.size() << endl; for(int i=0;i< out(b[i]); } else { cout << "NO\n"; }}`

]]>Your task is to find out the number in row y and column x.

The first input line contains an integer T: the number of tests.

After this, there are the lines, each containing integers by and xxx.

For each test, print the number in row Y and column x

1 <= t <= 10^5

1 <= y,x <= 10^9

Input:

`32 31 14 2`

Output:

`8115`

To solve this problem, we need to observe that the numbers are in either increasing or decreasing order, so we can solve this problem using that solution observe the pattern in the above image ,

We can see that any cell (x,y) we are searching for lies at the border of the square formed by the k = max(x,y).

Take this example, (x,y) = (2,4)

So for every (x, y) its value is located on the border of the square created by max (x,y).

The Value is located vertically when x > y and horizontally when x <= y, the solution might be obvious to you now we need to sum up the maximum value of the inner square of the square thats contains the solution with either x or y of the value we are searching for.

`#include<bits/stdc++.h>using namespace std;int main(){ int x,y; cin >> x >> y; int z= max(x,y); int k = z*z; if(k%2) cout << z - ((x-1) + (k-y)); else cout << z - ((x-1) + (k-y)); }`

That's all for this blog , will see you in the next one.

]]>Given nnn, construct a beautiful permutation if such a permutation exists.

The only input line contains an integer on n.

Print a beautiful permutation of integers 1,2,,n. If there are several solutions, you may print any of them. If there are no solutions, print "NO SOLUTION".

- 1 <= n <= 10^6

Input:

`5`

Output:

`4 2 5 3 1`

Let's analyze the first example, we can see that we have the sequence (4,2,5,3,1), and the difference between the two consecutive numbers is 2, and hence, we can see that this is a valid sequence while other sequences like (1,2,3,4,5) or (5,4,3,2,1) are not valid and hence is the answer.

To solve this problem we just need to make sure that consecutive integers do not have a difference of more than 1 and hence we can simply think of printing 1,3,2,5,4 as a valid sequence.

So, to solve this problem, we need to print alternate odd-even numbers, and we have to handle the edge cases such as when N = 2,3 we can see that in these cases we do not have a valid sequence so we print "NO SOLUTION".

Also for N = 1, we do not have any valid sequence so we print 1.

Also for N = 4, the sequence, we do not have a valid sequence so we print "2 4 1 3"

Hence, we print **NO SOLUTION** for this sequence.

Let's code the solution up.

`#include<bits/stdc++.h>using namespace std;int main(){ int n; cin >> n; if(n == 1){ cout << 1; } else if(n <= 3){ cout << "NO SOLUTION"; }else{ for(int i=1;i<=n;i+=2) cout << i << " "; for(int i=2;i<=n;i+=2) cout << i << " "; }}`

So, in this fashion, we need to work to cover the test cases.

That's all for this, will see you soon.

]]>The only input line contains a string of n characters.

Print one integer: the length of the longest repetition.

- 1n10^6

Input:

`ATTCGGGA`

Output:

`3`

Here, we can see that in this problem all we have to do is to find the longest substring containing the same characters.

So, to solve this problem we need to compare adjacent characters to get the longest string containing the same characters.

So, to solve this problem, we need to compare the adjacent characters find the characters that are similar, and keep counting the similar characters in a **count** variable, finally, we need to update our **answer** variable and print it.

`#include<bits/stdc++.h>using namespace std;int main(){ string s; cin >> s; int count = 1, answer = 1; int n = s.length(); for(int i=1;i<n-1;i++){ if(s[i] == s[i-1]){ count++; } else{ answer = max(answer, count); count = 1; } } answer = max(answer, count); cout << answer;}`

That's all for this blog, I will see you soon in the next blog.

]]>**Input:**

The first input line contains an integer **n**.

The second line contains **n1** numbers. Each number is distinct and between **1** and **n** (inclusive).

**Output:**

Print the missing number.

**Constraints:**

- 2 <= n <= 2.10^5

Input:

`52 3 1 5`

Output:

`4`

**Solution:**

It is easy to solve this problem, as only one number is missing then we focus on the difference, the difference is only of one number, all we have to do is just sum up all the numbers from the given series and then subtract this number from **(n*(n+1))/2**;

because **(n*(n+1))/2** represents the sum of all numbers from **1** to **n.**

That's all we have to do for this.

Let's code the solution

`#include<bits/stdc++.h>using namespace std;int main(){ int n; vector<int>v(n-1); int sum = 0; for(int i=0;i<n-1;i++)cin >> v[i], sum += v[i]; cout << ((n*(n+1))/2) - sum; }`

See you in the next blog article :)

]]>Consider an algorithm that takes as input a positive integer. If it is even, the algorithm divides it by two, and if it is odd, the algorithm multiplies it by three and adds one. The algorithm repeats this until it is one.

For example, the sequence for **n=3** is as follows:

**3105168421**

Your task is to simulate the execution of the algorithm for a given value of **n**.

**Solution:**

Let's see how we can solve this problem, All we have to do is just simulate as it is given in the problem statement i.e just do as given in the problem statement

print the element n

If

**n**is even, then divide it by**2**.If

**n**is odd, then multiply it by**3**and add 1

`#include<bits/stdc++.h>using namespace std;int main(){ int n; cin >> n; while(n != 1){ cout << n << " "; if(n % 2 == 0){ n /= 2; }else{ n = n *3 + 1; } } cout << n << " "; }`

In this fashion, we can finally print the number n at the end.

]]>So, Let's define the problem statement, we are given a tree consisting of **N** nodes and the task is to process **Q** queries of the form what is the distance between nodes **a** and **b.**

Let's understand how this problem can be solved using the LCA concept learned in the last video (I will attach the link to the video in the description).

Let's take a test case example to understand the problem statement better

In this tree, we want to find the distance between nodes **2** and **5,** so think about how we can do this !!

One of the ways is to start the **BFS** from one of the nodes say **a** and simply keep track of the count of nodes visited till you reach the other node say **b.**

This strategy might seem easy but the time complexity for the **BFS** is **O(N+E)** and to process **Q** queries we need to perform **BFS** for **Q** times and it will cost **O(Q*(N+E))** time complexity and we can see that to process queries **Q** of the order of **10^5** and **N** as the number of nodes of order **10^5,** we require **10^5 * 10^5 = 10^10** operations and we know that the number of operations in **1** sec are **10^8** and hence the total number of seconds will be **10^10/10^8 = 100s**.

Hence, we require **100s** to execute the approach for the extreme cases.

So, to solve this problem efficiently, you need to have a better approach that works under the given constraints.

So, observe that there is exactly one path between any two nodes **a** and **b** and we need to find the length of that path.

Here, the path length is of **4** nodes consisting of nodes **2,1,3** and **5.**

Observe that any path goes through the LCA of the two nodes

So, if we know the distance of each node from their LCA, we can easily calculate the distance between two nodes, right?

Let's calculate the depth of all nodes of the tree

The code to calculate the depth is:

`void dfs(int node, int par, vector<int>&level, int depth, vector<int>adj[]){ level[node] = depth; for(auto child: adj[node]){ if(node != par){ dfs(child, node,level,depth+1,adj); } }}`

Here, we shall have the depth of each node in the level array.

Now, observe that we need to find the distance between **4** and **5** which is **2** and it can be observed that adding the depth of nodes **4** and **5** gives me the sum of distances of both of these nodes from the root node, and in this way, I am adding the depth of the **LCA** of **4** and **5** twice and to calculate the distance between **4** and **5**, I need to subtract the depth from the addition twice.

So, the answer to the distance between two nodes is **level[4] + level[5] - 2 level[LCA(4,5)] = 2 + 2 - 2 * 1 = 2.**

Hence, the general formula to solve the problem is **level[a] + level[b] - 2 * level[LCA(a,b)].**

So, we need to calculate the LCA of the two nodes which we have already learned to do and the code is :

`const int MAXN = 200111;const int N = 20;vector<int>adj[MAXN];int up[MAXN][N],level[MAXN];int q;//Function to calculate the level void dfs(int node, int par, vector<int>&level, int depth, vector<int>adj[]){ level[node] = depth; up[node][0] = par; for(auto child: adj[node]){ if(child != par){ dfs(child, node, level, depth+1, adj); } }}//preprocessing the up arrayvoid preprocess(){ for(int i=1;i<MAXN;i++){ for(int j=1;j<N;j++){ if(up[i][j-1] != -1){ int par = up[i][j-1]; up[i][j] = up[par][j-1]; } } }}int LCA(int a, int b){ if(b < a)swap(a,b); int d = level[b] - level[a]; while(d){ int i = log2(d); b = up[b][i]; d -= (1 << i); } if(a == b)return a; for(int i=N-1;i>=0;i--){ if(up[a][i] != -1 && (up[a][i] != up[b][i]){ a = up[a][i]; b = up[b][i]; } } return up[a][0];}`

and to process the **Q** queries we just need to use the equation **level[a] + level[b] - 2 * level[LCA(a,b)].**

`cin >> q;while(q--){ int a,b; cin >> a >> b; cout << level[a] + level[b] - 2 * level[LCA(a,b)] << "\n";}`

The solution code for the problem is

`#include<bits/stdc++.h>using namespace std;const int MAXN = 200111;const int N = 20;vector<int>adj[MAXN];int up[MAXN][N],level[MAXN];void dfs(int node, int par, int lvl){ level[node]=lvl; up[node][0]=par; for(auto child: adj[node]){ if(child != par){ dfs(child,node,lvl+1); } }}void preprocess(){ dfs(1,-1,0); for(int i=1;i<MAXN;i++){ for(int j=1;j<N;j++){ if(up[i][j-1] != -1){ int par = up[i][j-1]; up[i][j] = up[par][j-1]; } } }}int LCA(int a, int b){ if(level[b] < level[a])swap(a,b); int d = level[b]-level[a]; while(d){ int i = log2(d); b = up[b][i]; d -= (1 << i); } if(a == b)return a; for(int i=N-1;i>=0;i--){ if(up[a][i] != -1 && (up[a][i] != up[b][i])){ a = up[a][i]; b = up[b][i]; } } return up[a][0];}int main(){ int n,q; cin >> n >> q; for(int i=2;i<=n;i++){ int a,b; cin >> a >> b; adj[a].push_back(b); adj[b].push_back(a); } up[0][0] = -1; level[0] = 0; preprocess(); while(q--){ int a,b; cin >> a >> b; cout << level[a] + level[b] - 2 * level[LCA(a,b)] << "\n"; }}`

The time complexity for the given code is **O(Q * log(N))**.

That's all I have got for today, will see you soon with yet another problem :)

Link to the binary Search Video:

]]>So let's delve into the process.

You may have encountered a category of problems like

Given a pair

**(K, V)**, find the**Kth**ancestor of some node**V**in a tree.Given a pair of nodes

**(a,b)**, find the lowest common ancestor of these nodes.

The naive approach to solving this problem is to build the edge to the parent node for each node, in this way we can always move up and store the parent for each node of the tree in a parent array like **parent[node]** stores the parent of the node **"node".**

Using the strategy explained above, let's say we have **Q** queries and we need to traverse **N** edges in the worst case when we have a skewed tree giving me an overall complexity of **O(Q*N).**

Let's say we have queries and the number of nodes of the order **10^5** that will give me the overall complexity of **10^5 * 10^5** i.e. **10^10,** and the number of operations that a computer performs in **1s** are **10^8,** which will give me the time as **10^10/10^8 = 100s** to execute on the extreme cases which is beyond the time limit of the online judge which is **1s.**

Hence, we need to use a better technique to solve these types of problems, and here comes the binary lifting as a rescue.

So, let's see what binary lifting is.

To solve the first type of problem, we need to move **K** nodes up so instead of moving up one by one we move up in the powers of **2,** but how? The answer is that the number **K** can be represented as a sum of powers of **2.**

Let's say **K** is **7 = 0111** which is **2^2 + 2^1 + 2^0 = 4 + 2 + 1**, hence, make jumps of size 4,2 and 1 to reach the **Kth** node starting from node **V** which reduces the number of jumps down to **3** from **7** and hence, the time complexity for a single query is **ceil(log2(K))** which reduces the time complexity to **O(Q*logN)** which is far better than the previous one and it will work for the given constraints of the problem.

To implement the above strategy we use a 2d array of dimensions **N * ceil(logN)** called **up[N][ceil(logN)]** where **up[i][j]** represents the **2^j**th ancestor of the node **i.**

`int M = ceil(log2(N));int up[N][M];`

Let's see the next step to fill this array, first of all, fill the array for the direct parent nodes of all the nodes of the tree.

Now, the next step is to fill the array for the remaining ancestors which are easy to calculate now, it's like if you want to find the **2^2 = 4th** parent for the current node then we find the **2^1** parent for the current node say **par** then find the successive **2^1** parent for the node **par**.

`for(int i=1;i<N;i++){ for(int j=1;j<M;j++){ if(up[i][j-1] != -1){ int par = up[i][j-1]; up[i][j] = up[par][j-1]; } }}`

In this way, we prepare the **up** array,

Now, Let's answer the queries using this array prepared i.e. given a pair **(K,** **V),** find the **Kth** ancestor of the node **V,** so we just need to start with the largest jump we can take from node **V** which is equal to the largest number which is a power of **2** and less than **K** which is equal to **i =** **log2(K)** and move to the node present at **V =** **up[V][i],** Now, subtract from the **K** the term **(1 << i) i.e. 2^i**, now repeat the process i.e. again find the largest power of **2** in the remaining number and keep doing until we exhaust the number.

For example: let's take **K** to be **7**, the largest power here is **2^2 = 4** i.e. make a jump of size 4 first i.e. move from **V to V = up[V][2],** now subtract **4** from **7** to give **3** as the remaining number, and again find the largest power of **2** which is **2^1** and move to the node **V =** **up[V][1]** and then subtract **2** from **3** to give **1** and Now, the largest power is **2^0,** and finally move to **V = up[V][0]** which is my answer as well.

Finally, print the answer node as **V.**

Let's implement the above strategy in code:

`while(K){ //Find the largest power of 2 int i = log2(K); //make a corresponding jump node = up[node][i]; //Substract the power of 2 from K K -= (1 << i);}//Print the ancestoral node cout << node;`

So, that's how we move up the tree using binary lifting :)

We need to handle an edge case here i.e. when the **Kth** ancestor does not exist i.e. depth of the starting node is lesser than the ancestor that we require, in that case, we shall print **-1**, so to handle that we need to use another array let's say **level** which stores the **depth** for each node of the tree taking root as the node at depth **0.**

We know, the depth can be calculated using **dfs** traversal of the tree.

Let's put it all together to solve the first type of problem.

`int N;int M = ceil(log2(N));int up[N][M];int level[N];vector<int>adj[N+1];void dfs(int node, int par, int depth){ level[node] = depth; for(auto child: adj[node]){ if(child != par){ dfs(child, node,depth+1); } } }void preprocess(){ dfs(1,0,0); for(int i=1;i<N;i++){ for(int j=1;j<M;j++){ if(up[i][j-1] != -1){ int par = up[i][j-1]; up[i][j] = up[par][j-1]; } } }}`

As we have already discussed the time complexity is **O(Q*logN)** for the **Q** queries and hence for the **Q** and **N** of the order **10^5** the time will be **10^5 * log(10^5) = 10^5** which will work fine.

That's all I have got for today and I hope you learned something new from this, make sure to practice the problems given in the end to get in shape so that you can "tweak" the algorithm as per the problem's requirement.

Will see you soon with something "new" :)

]]>First of all, let's revise the definition of trees, the tree is a special graph having **N** nodes and **N-1** edges.

Implementing trees is the same as implementing graphs, so learn to implement trees you will learn to implement graphs as well.

Let's implement trees using an adjacency list:

The adjacency list which stores **5** nodes numbered from **0** to **4** can be declared as follows:

`vector<int>tree[5];`

Then, the next question is how can we store the nodes in it, Let's see how can we do so.

Let's see how can we make edges

`//Here, I am making a bidirectional edgetree[0].push_back(1);tree[1].push_back(0);//Here, again a bidirectional edge between 1 and 3tree[1].push_back(3);tree[3].push_back(1);//Bidirectional edge between 2 and 0tree[0].push_back(2);tree[2].push_back(0);//Bidirectional edge between 1 and 4tree[1].push_back(4);tree[4].push_back(1);`

The edges above are bidirectional i.e. both ways and hence, we need to make edges both ways:)

So that's all I have got for this, will see you in my next blog :D

]]>While thinking about trees, the first thing that comes to our mind is the actual tree having roots, leaves, and so on but in programming, the terms are the same for the tree data structure but things change a little.

The tree in programming is inverted

yeah, it is very similar to this, the root is at the top and the leaves are at the bottom :)

Let's define the tree in data structures

Unlike other data structures, the tree is a hierarchical data structure where we have a root node which is at the top of the hierarchy, and leaf nodes at the bottom of the hierarchy.

The structure is very similar to the college system we have a director at the top level, then we have a **principal/dean**, followed by **HODs**, **teachers**, and finally students.

In the above image, I have shown how the college system resembles the tree rooted at node number **0**, here, node **0** represents the **director**, and other nodes are called child nodes.

Let's define some terms related to trees:

A tree is a special type of graph having **N** nodes and **N-1** edges.

There is exactly one path between any pair of nodes in the tree.

**Degree:**It represents the number of edges connecting any node in the tree for example the root node**0**in the above tree has a degree of**1**.**Root**: The node at the top of the tree with degree 1 is called the root node.**Leaf:**The node at the bottom of the tree is called the leaf node.**Parent:**The very first node in the path from any node**n**to the root node is the parent of the node**n.****Ancestor:**All of the nodes that are parent nodes of a node and parent of parent are ancestors.**Subtree:**A subtree of a node n is the set of nodes that have n as an ancestor.**Depth:**The distance of a node from the root is called depth.

That's all I have got for today, Do like it and follow for further updates :D

]]>Let's understand this with the example

Here, in this list, the last node points to the second node so, we have a cycle here, to detect it, the simplest approach is to keep track of the visited nodes in a hashmap i.e. use a **map<ListNode*, int>** type where for each node we store **1** if it is visited else **0**.

Now, while traversing we come across a node that is already visited, then there is a cycle like in the above example 2 will be revisited.

`// using MAPclass Solution {public: bool hasCycle(ListNode *head) { if(head==NULL) return false; unordered_map<ListNode*,int> map; while(head!=NULL){ if(map.count(head)>0) return true; else map[head]=1; head=head->next; } return false;}};`

The time complexity for this approach is **O(N)** as we are traversing the list exactly once while space complexity is **O(N)** as we are using a hashmap container.

**Optimal Approach: Floyd Algorithm:**

Now, I want to optimize the space complexity for the given linked list. To do so we shall be using **Floyd Cycle Detection Algorithm.**

In this algorithm, we use two pointers, fast and slow both initialized to the first node of the linked list.

Now, move the fast pointer by 2 steps and the slow pointer by one step parallely till they meet at a certain point, if they meet then we return true otherwise we don't have a cycle in the list so return false.

Let's see the implementation.

`//Floyd Algorithmclass Solution {public: bool hasCycle(ListNode *head) { if(head==NULL || head->next==NULL) return false; ListNode* slow=head; ListNode* fast=head; while(fast!=NULL && fast->next!=NULL){ slow=slow->next; fast=fast->next->next; if(fast==slow) return true; } return false;}};`

The Proof for this algorithm is given here (Optional) https://cs.stackexchange.com/questions/10360/floyds-cycle-detection-algorithm-determining-the-starting-point-of-cycle

Let's discuss the time and space complexity for the given implementation.

We can see that we are traversing the linked list in a linear fashion exactly once hence, **O(N)** time complexity, while the space complexity is **O(1)** as we are not using any extra auxiliary space here.

that's all I have got for this problem, feel free to ask your doubts :)

Hope to see you in the next problem.

]]>`Symbol ValueI 1V 5X 10L 50C 100D 500M 1000`

For example, 27 can be written as XXVII, which is XX + V + II i.e. 10 + 10 + 5 + 1 + 1 = 27.

To create the number 9, we write it as IX i.e. IntegerValue(X) - IntegerValue(I) = 10 - 1 = 9.

So, this is the case, when we have a Roman number lesser than the next number, then we simply subtract the value of this current number from the value of the next number.

**Solution:**

The solution to the problem is simple

we simply prepare a hashmap for <roman, integer> pair.

Initialize an

**answer**to**0**, and iterate over the given string**s**, and for each character, if the corresponding value for that is lesser than the value of the next Roman number then subtract the values of this current Roman character from the**answer**.Otherwise, add the value of the current Roman character.

Finally, return the answer.

`int romanToInt(string s) { int ans = 0; unordered_map<int,int>mp; mp['I'] = 1; mp['V'] = 5; mp['X'] = 10; mp['L'] = 50; mp['C'] = 100; mp['D'] = 500; mp['M'] = 1000; int n = s.length(); for(int i=0;i<n;i++){ if(mp[s[i]] < mp[s[i+1]]){ ans -= mp[s[i]]; }else{ ans += mp[s[i]]; } } return ans; }`

Let's discuss the time and space complexity.

The time complexity for this solution is **O(N)** where **N** is the length of the string s.

The space complexity is **O(N)** because we are using the unordered map.

Hey there! Welcome back If you are preparing for tech interviews you must have come across the problems like 2-sum, 3-sum, 4-sum etc, if not then you will be learning the same here.

Not only that in this blog I will be discussing a generic strategy to solve these kinds of problems. Let's put them in a single category called **k-sum** problems.

After you learn this strategy, you will be able to come up with the solution to any problem in this category be it 2-sum, 3-sum or 4-sum as far as the solution runs under the constraints of time and space.

Let's delve into the process

In this problem, we are given an array of **N** integers let's call it **nums** and we want to find the number of unique pairs of integers **(nums[i], nums[j])** such that **(i != j)** they have a **sum** equal to the **target,** there can be duplicate integers in the given array.

Let's understand this with an example

**nums = [2, 7, 11, 15]**, **target = 9**

Here, the answer pair is the integer number one and two i.e. **(2,7).**

Let's discuss the solution to this problem.

The most straightforward solution to the problem would be to use nested loops where we select each possible pair of integers for the array and there would be n^2 pairs.

`int n = nums.size()//Outer loop which selects each element of the arrayfor(int i=0;i<n;i++){ //Inner nested loop which selects second element of pair for(int j=i+1; j < n; j++){ if(nums[i] + nums[j] == target){ answer.push({nums[i],nums[j]}) } }}`

The time complexity for this solution is O(N^2) because we are using a nested loop to find the pair of elements while the space complexity is O(1) because we are not using any extra space to solve the problem.

Observe that we are given an integer **target** and if we sort the array and start selecting integers one by one say **nums[i]** then in the rest of the array i.e. **[i+1, n-1]** we need to search for the **target - nums[i]** and if we find it then we have **(nums[i], target - nums[i])** as a valid pair.

`//Sort the given nums arraysort(nums.begin(), nums.end());//Find the size of the nums arrayn = nums.size();//Iterate over the elements of nums and binary search for // the rest of the arrayfor(int i=0;i<n;i++){ //Find the second element of the pair if(binary_search(nums.begin(), nums.end(), target - nums[i]) == NULL){ answer.push_back({nums[i], target - nums[i]}); }}`

The time complexity for this approach is **O(NlogN)** as we are performing a binary search for **N-1** times and the time complexity for the binary search is **O(logN).** While the space complexity for the given binary search is **O(1)**

We can observe that in a sorted array of size **n** the first element is the smallest and the last element is the largest, if we add them we get some value say **X =** **nums[0] + nums[n-1],** Now if **X** is larger than the **target** then that means we should not use the largest element to evaluate our target sum, then which one to choose just smaller than the largest so we pick second largest element **nums[n-2]** and compare the new sum **X =** **nums[0] + nums[n-2]** again and so on until we get the sum larger than the target.

On the other hand, if **X = nums[0] + nums[n-1]** is smaller than the **target** that means we must include a larger number in our **X**, which one is the best choice the next greater number which is second hence giving the new sum as **X = nums[1] + nums[n-1]** and compare it again with **target** and so on.

In this way, I will eventually arrive at my target pair if it exists.

`#include<bits/stdc++.h>using namespace std;vector<int>twoSum(vector<int>&nums, int target){ //Calculate the size of the nums array int n = nums.size(); //Initialize two pointers left and right int left = 0, right = n-1; //Vector to store the two sum pairs vector<int>result; //Iterate till these pointers do not match while(left < right){ //check if the sum of two integers // is less than target if(nums[left] + nums[right] == target){ result.push_back({nums[left], nums[right]}); // Now handle the duplicate integers while(left + 1 < n and nums[left] == nums[left+1])left++; left++; right--; } else if(nums[left] + nums[right] < target) left++; else right--; } return result;}`

` import java.util.ArrayList;import java.util.Arrays;import java.util.List;class Solution { public List<List<Integer>> twoSum(List<Integer> nums, int target) { // Calculate the size of the nums list int n = nums.size(); // Initialize two pointers left and right int left = 0, right = n - 1; // List to store the two sum pairs List<List<Integer>> result = new ArrayList<>(); // Iterate until these pointers do not match while (left < right) { // Check if the sum of two integers is equal to the target if (nums.get(left) + nums.get(right) == target) { result.add(Arrays.asList(nums.get(left), nums.get(right))); // Handle duplicate integers while (left + 1 < n && nums.get(left).equals(nums.get(left + 1))) { left++; } left++; right--; } else if (nums.get(left) + nums.get(right) < target) { left++; } else { right--; } } return result; }}`

` from typing import Listdef twoSum(nums: List[int], target: int) -> List[List[int]]: # Calculate the size of the nums list n = len(nums) # Initialize two pointers left and right left = 0 right = n - 1 # List to store the two sum pairs result = [] # Iterate until these pointers do not match while left < right: # Check if the sum of two integers is equal to the target if nums[left] + nums[right] == target: result.append([nums[left], nums[right]]) # Handle duplicate integers while left + 1 < n and nums[left] == nums[left + 1]: left += 1 left += 1 right -= 1 elif nums[left] + nums[right] < target: left += 1 else: right -= 1 return result`

The time complexity for the given implementation is **O(N)** as we are iterating over each element exactly once using 2 pointers while the space complexity is **O(1)** as we are not using any extra space.

Now, this was a popular 2-sum problem, let's move to the next step i.e. 3-sum problem.

In this problem, we are given an integer array of **nums,** we need to return all triplets **[nums[i], nums[j], nums[k]]** such that **i != j, i != k,** and **j!= k,** and **nums[i] + nums[j] + nums[k] == 0.**

Notice that the solution set must not contain duplicate triplets.

Let's understand the problem with an example **nums =** **[-1, 0, 1, 2, -1, -4]**, and the target sum is **0**, then the possible triplets would be **[[-1, -1, 2], [-1, 0, 1]]**.

Let's understand the solution to this problem, first of all, we sort the given array as we did for the 2-sum problem, then we can observe that we need to choose three integers that sum up to **0,** let's see how to do so, first, we iterate over the array and choose integers **nums[i]** one by one starting from the first till **3rd** last i.e. **i = 0 to i = n-2**, we are assuming it to be our first integer in the tuple.

then, we require a pair of integers in the remaining array from **i+1** to **n-1** to make the entire tuple. Then, the remaining problem is the same as a **2-sum** problem.

`//Iterate over all the elements of the array till 3rd lastfor(int i = 0; i < n-1; i++){ //Choose integers one by one int remain = target - nums[i]; //Find the pair of integers which sums up to remain twoSum(nums, remain); //If i get a pair which sums up to the remain //then i got one of my target tuples answer.push({nums[i], b, c}); //here b,c represent the two sum pair for remain}`

Is it all we need to do or have we missed something, obviously there are duplicates in the array and we don't want our final answer to contain duplicate tuples, therefore we need to skip the similar integers.

`//Iterate over all the elements of the array till 3rd lastfor(int i = 0; i < n-1; i++){ //Choose integers one by one int remain = target - nums[i]; //Find the pair of integers which sums up to remain twoSum(nums, remain); //If i get a pair which sums up to the remain //then i got one of my target tuples answer.push({nums[i], b, c}); //here b,c represent the two sum pair for remain //Here, we need to skip the similar integers while(i + 1 < n and nums[i] == nums[i+1])i++;}`

In this way, I will have my tuples pushed inside the answer array.

`#include<bits/stdc++.h>using namespace std;vector<vector<int>>threeSum(vector<int>nums, int target){ //Find the size of the nums array int n = nums.size(); //Sort the given array sort(nums.begin(), nums.end()); //Declare a vector to store the tuples which sums up to target vector<vector<int>>result; //Iterate over each element of the nums array //till n-2th element for(int i=0;i<n-1;i++){ //Initialize two pointers to find the two sum pair int left = i+1, right = n-1; while(left < right){ //find the sum of the three integers int sum = nums[i] + nums[left] + nums[right]; //If the sum is equal to the target if(sum == target){ result.push_back({nums[i], nums[left], nums[right]}); while(left + 1 < n and nums[left] == nums[left + 1])left++; left++; right--; } else if(sum < target){ left++; }else{ right--; } } while(i + 1 < n and nums[i] == nums[i+1])i++; } return result;}`

`import java.util.ArrayList;import java.util.Arrays;import java.util.List;public class ThreeSum { public static List<List<Integer>> threeSum(List<Integer> nums, int target) { // Find the size of the nums array int n = nums.size(); // Sort the given array nums.sort(null); // Declare a list to store the tuples which sums up to target List<List<Integer>> result = new ArrayList<>(); // Iterate over each element of the nums array // till n-2th element for (int i = 0; i < n - 1; i++) { // Initialize two pointers to find the two sum pair int left = i + 1, right = n - 1; while (left < right) { // Find the sum of the three integers int sum = nums.get(i) + nums.get(left) + nums.get(right); // If the sum is equal to the target if (sum == target) { result.add(Arrays.asList(nums.get(i), nums.get(left), nums.get(right))); while (left + 1 < n && nums.get(left).equals(nums.get(left + 1))) left++; left++; right--; } else if (sum < target) { left++; } else { right--; } } while (i + 1 < n && nums.get(i).equals(nums.get(i + 1))) i++; } return result; } public static void main(String[] args) { List<Integer> nums = Arrays.asList(-1, 0, 1, 2, -1, -4); int target = 0; List<List<Integer>> result = threeSum(nums, target); for (List<Integer> tuple : result) { System.out.println(tuple); } }}`

`def threeSum(nums, target): # Sort the given array nums.sort() # Declare a list to store the tuples which sum up to target result = [] # Iterate over each element of the nums array # till n-2th element n = len(nums) for i in range(n - 2): # Initialize two pointers to find the two sum pair left = i + 1 right = n - 1 while left < right: # Find the sum of the three integers sum = nums[i] + nums[left] + nums[right] # If the sum is equal to the target if sum == target: result.append([nums[i], nums[left], nums[right]]) while left + 1 < n and nums[left] == nums[left + 1]: left += 1 left += 1 right -= 1 elif sum < target: left += 1 else: right -= 1 while i + 1 < n and nums[i] == nums[i + 1]: i += 1 return result# Example usagenums = [-1, 0, 1, 2, -1, -4]target = 0result = threeSum(nums, target)print(result)`

First of all, we are sorting the array which has a time complexity of **O(NlogN)**, then we are iterating over **N-3** integers in the outer loop, and inside we are calling the **twoSum** function which has a time complexity of **O(N),** Hence, the overall time complexity becomes **O(N^2 + NlogN) i.e. O(N^2).** While the space complexity is **O(1).**

Now, let's ask ourselves, how can a **4-Sum** problem be solved using the same strategy in which we need to return the set of all quadruples having a sum equal to the **target**, now you can easily guess, the solution would be to sort the array first then use two nested loops which select the first two integers of the quadruple and then find the rest pair using **twoSum.** In this way, in any K-sum problem, we can use K-2 nested loops to select the first **K-2** integers and then the base case of two integers is handled by **twoSum** function.

In the K-sum problem, we have the same idea for larger dimensions or k- dimensions i.e. given an array of integers **nums** and an integer **K** we need to find the array of all unique sets of **K** integers [nums[a], nums[b], nums[c], nums[d], ..., K elements] such that:

a,b,c,d,...K elements are less than 'n' and greater than 0.

a, b, c, d up to K different indices are Unique.

nums[a] + nums[b] + nums[c] + nums[d] + ... + nums[K distinct indices] == target.

You can return the answer in any order.

Keeping in mind the ideas that we have learned so far in this article, If we carefully observe the pattern in these problems 2-sum, 3-sum, 4-sum .. and so on we can see a recursive relationship where 2-sum is the base case as shown below:

Since this is just recursion, we can solve this for an integer **K** as follows

Imagine a function **Ksum(nums, k, target)** which has three parameters **array nums, integer k** and **target**, It returns the array of K- sum sets in the nums array, this is a recursive function. This function will select the first integer say **val1,** and recursively call itself for the **k-1** size set with target sum as **target - val1**, i.e. **Ksum(nums, k-1, target - val1)** which will eventually select another value **val2** and call itself for **k-2** size and **target - val1 - val2** target value as **Ksum(nums, k-2, target-val1-val2)** and so on till we reach the base case i.e. **k == 2** where we call the **twoSum** function to get the target pair.

`#include<bits/stdc++.h>using namespace std;//answer array to store the sets vector<vector<int>>ans;//Two sum functionvoid twoSum(vector<int>&nums, int left, int target,vector<int>&path){ int start = left, end = nums.size()-1; while(start < end){ long long sum = nums[start] + nums[end]; if(sum == target){ path.push_back(nums[start]); path.push_back(nums[end]); ans.push_back(path); path.pop_back(); path.pop_back(); //skip the duplicates while(start + 1 < end and nums[start] == nums[start+1])start++; start++; end--; }else if(sum > target)end--; else start++; }}//K sum function to return the array of K-sum setsvoid kSum(vector<int>&nums, int left, int right, int k, int target, vector<int>&path){ //Base case if(k == 2){ twoSum(nums,left,target,path); return; } while(left < right){ path.push_back(nums[left]); int rem = target - nums[left]; kSum(nums,left+1,right,k-1,rem,path); path.pop_back(); //skip the duplicates while(left+ 1 < right and nums[left] == nums[left+1])left++; left++; }}`

The time complexity for the K-sum problem is **O(N^k-2 * N)** i.e. **O(N^k-1).** This is the general case, we can derive the complexities of 2-sum as **O(N^2-1)** that is **O(N),** for three sum **O(N^3-1)** that is **O(N^2).** While the space complexity for the given implementation is **O(k)** as we are using a path array to temporarily store the k-sum set which is counted as extra space.

So that's all I have got in this blog, If you find it helpful then please share it with your friends and stay with me for updates in the future :D

]]>Binary search is a very common and widely used strategy for solving many algorithmic problems. The problems around binary search are common in tech interviews as well as programming contests. There are numerous applications of this algorithm some of them include searching for an element in a sorted arrangement, finding the frequency of an element in a sorted sequence, finding the first and last occurrence of an element in a sorted sequence, checking whether n is a square of an integer or not to name a few.

All of the above-mentioned problems have one thing in common and that is their monotonic behavior and in this article, we shall learn to identify these monotonic patterns of the problems. Let's delve into the process.

Binary search is made up of two words binary means "2" and search means to look for something. Let's take an example of searching for a word in a physical dictionary, to search for a word in the dictionary we open it in the middle and pick a random word from it then if your word starts with **R** and the picked word starts with **Q,** then it is explicit that we shall not find our target word in the first half of the dictionary and hence we move to the second half of it to search for our word. Then we again open the dictionary in the middle of the second half and repeat the process. In this way each time we look for a word we are reducing the search space by half and hence reducing the extra work of naive searching just because we have a pattern in our dictionary that the words are written in alphabetical order.

Let's ask ourselves, how many checks we need to perform to get to the desired word, suppose we had **n** pages in the dictionary, then each time the search space is reduced to half i.e.

**n** reduced to **n/2**

**n/2** reduced to **n/4**

**n/4** reduces to **n/8**

and so on

The process will stop say after **k** matches when we find our desired word then we can write it as

$$\begin{align} n/2^k = 1 \\ n = 2^k \\ log2(n) = k \\ \end{align}$$

Hence, for a dictionary of size 1000 pages, it would take us only **log2(1000)** which is approximately **10** matches which is far better than going through every page.

The very first step to solving a binary search problem is to identify if it is a binary search problem or not. The only criterion for that is to look for monotonic behavior in whatever situation we are given. we know that a monotonic function is ever increasing or decreasing function and we need to figure out the quantity which is showing this type of behavior in the problem statement.

Let's better understand the above idea using some examples

Given a sequence of integers sorted in ascending order, find the target element in it.

Let's start by identifying the monotonicity, we can observe that the integers are sorted in ascending order which means the integers are ever-increasing i.e. monotonic.

Here, we can see that we took 3 checks to find the target element in the array using binary search.

Following are the steps to perform the above procedure:

Define the search domain,

**[1, n]**in this case.Initialize two pointers

**left = 0**and**right = n-1**to mark both ends of the domain.While we have a non-zero domain i.e.

**[left, right] or till left <= right**, find the middle element as**middle = (left + right)/2**and check for the element at this middle index.If the element at the

**middle**index is equal to the**target**element, in that case, return that element.If the element at the

**middle**index is greater than the**target**element, in that case, discard the right subarray i.e.**[middle+1, n-1]**and reinitialize**right = middle.**Otherwise, discard the left subarray i.e.

**[left, middle]**and reinitialize**left = middle+1.**Finally, If I do not find the element at any position in the array then we return

**-1**as the default value.

Let's see the implementation:

`#include<bits/stdc++.h>using namespace std;//Function to perform binary searchint binarySearch(int left, int right, int arr[], int target){ //Base case if(left < right)return -1; //Repeat till we have a positive search domain. while(left < right){ //find the middle element int middle = left + (right - left)/2; //check if the middle element is // the target element if(arr[middle] == target)return arr[middle]; //if the middle element is greater than target // element if(arr[middle] > target){ right = middle; }else{ left = middle-1; } } //Otherwise return -1 return -1;}`

`import java.util.*;class Main { public static void main(String[] args) { int[] arr = {1, 2, 3, 4, 5}; int target = 4; int result = binarySearch(0, arr.length, arr, target); if (result == -1) { System.out.println("Element not found"); } else { System.out.println("Element found: " + result); } } //Function to perform binary search public static int binarySearch(int left, int right, int[] arr, int target){ //Base case if (left >= right) { return -1; } //Repeat till we have a positive search domain. while (left < right) { //find the middle element int middle = left + (right - left) / 2; //check if the middle element is // the target element if (arr[middle] == target) { return arr[middle]; } //if the middle element is greater than target // element if (arr[middle] > target) { right = middle; } else { left = middle + 1; } } //Otherwise return -1 return -1; }}`

`# Function to perform binary searchdef binarySearch(left, right, arr, target): # Base case if left >= right: return -1 # Repeat till we have a positive search domain. while left < right: # find the middle element middle = left + (right - left) // 2 # check if the middle element is # the target element if arr[middle] == target: return arr[middle] # if the middle element is greater than target # element if arr[middle] > target: right = middle else: left = middle + 1 # Otherwise return -1 return -1`

We can see that the search space is divided into half of the initial one each time we check for an integer and hence, the time complexity is **log2(N)** as we discussed earlier while the space complexity is **O(1) i.e.** constant because we are not using any extra space.

Given a sequence of integers sorted in increasing order, find the position of the first appearance of the target element in the range **[first, last)**.

Let's start by identifying the monotonicity, we can observe that the integers are sorted in ascending order and the same integers appear adjacent to each other which means the integers are ever-increasing i.e. monotonic.

In the above procedure, we performed the binary search to find the first occurrence of the element **6**

Let's see the implementation of the above procedure

`#include<bits/stdc++.h>using namespace std;//first occurence of an element int firstOccurence(int arr[], int lo, int hi, int target){ if(lo <= hi){ int mid = lo + (hi - lo)/2; if((mid == 0 || arr[mid-1] > x) and arr[mid] == x) return mid; else if(target > arr[mid]) hi = mid + 1; else lo = mid - 1; } return -1;}int main(){ int arr[] = {1, 2, 2, 2, 2, 3, 4, 7, 8, 8}; int n = sizeof arr / sizeof arr[0]; target = 8; cout << "First occurence of the " << target << " is" << firstOccurence(arr, 0, n-1, target);}`

`import java.util.*;public class Main { //first occurrence of an element static int firstOccurrence(int[] arr, int lo, int hi, int target){ if(lo <= hi){ int mid = lo + (hi - lo)/2; if((mid == 0 || arr[mid-1] < target) && arr[mid] == target) return mid; else if(target > arr[mid]) lo = mid + 1; else hi = mid - 1; } return -1; } public static void main(String[] args) { int[] arr = {1, 2, 2, 2, 2, 3, 4, 7, 8, 8}; int n = arr.length; int target = 8; System.out.println("First occurrence of " + target + " is " + firstOccurrence(arr, 0, n-1, target)); }}`

`# first occurrence of an elementdef first_occurrence(arr, lo, hi, target): if lo <= hi: mid = lo + (hi - lo) // 2 if (mid == 0 or arr[mid-1] < target) and arr[mid] == target: return mid elif target > arr[mid]: lo = mid + 1 else: hi = mid - 1 return -1arr = [1, 2, 2, 2, 2, 3, 4, 7, 8, 8]n = len(arr)target = 8print("First occurrence of", target, "is", first_occurrence(arr, 0, n-1, target))`

We can see that the search space is divided into half of the initial one each time we check for an integer and hence, the time complexity is **log2(N)** as we discussed earlier while the space complexity is **O(1) i.e.** constant because we are not using any extra space.

You are given an integer array of **heights** representing the heights of the building, some **bricks** and some **ladders.**

You start your journey from building **0** and move to the next building by possibly using bricks or ladders.

While moving from building **I** to **i+1** (0-indexed)

If the current building's height is greater than or equal to the next building's height, you do not need a ladder or bricks.

If the current building's height is less than the next building's height, you can either use

**one****ladder**or**h[i+1] - h[i]**bricks.

Return the furthest building index (0-index) you can reach if you use the given ladders and bricks optimally.

**Example**

Here, I have input array of heights as **heights[] = {4, 2, 7, 6, 9, 11, 14},** and **bricks = 5, ladders = 1.**

Let's see where we land starting from the first building i.e. building number **0,** we can simply jump to building **1** without using any bricks or ladders because building number **1** has a smaller height than building number **0** after that to jump to building number **2** which has a height of **7** units we require **5** bricks or **1** ladder which one to choose, let's choose bricks and consume all bricks to jump to building number **2**, then we jump to building number **3** without requiring bricks or ladder, then we again have a building with greater height since we are left with **0** bricks and **1** ladder we can use a ladder to jump to building number **4** and we consume all ladders and bricks here, the path taken is shown below

Let's ask ourselves can we do better or we can reach even the next buildings by changing the moves which I took here let's see

Another option would be to choose the ladder for the first jump that is from building **1** to building **2** and then use **3** bricks to move from building **3** to **4** and finally use the remaining **2** bricks to jump to building **5**. Using this approach we reach building number **5** at the end which is a better answer.

So, how do we decide which moves to make, well we can observe that in the second case what we did is simply replaced the jump till building number 3 which consumed a maximum number of bricks with a ladder hence optimizing the number of bricks which were used further to jump to next buildings.

At the end of the day we just need to optimize the number of bricks we consume i.e. try to consume bricks for smaller jumps and larger jumps and try to use a ladder, in this way, I will be going relatively far.

How all this is related to the binary search let's understand that.

To perform the binary search we require a monotonic behavior in the problem, here observe the indices

Here, the monotonicity is observed in indices, let's take an index **I** and ask ourselves if it is reachable, if it can be then all indices before **I** are also reachable till index **0.**

Let's define a predicate function **isReachable(index)** which returns **true** if the index passed can be reached or not otherwise it returns **false.**

Now, the problem reduces to returning the last index where the function **isReachable(index)** returns true which can be simply obtained by performing a binary search over the indices.

So, how do we define our predicate function, we know that we need to use the ladders for the jumps with maximum length or height difference and others we may use bricks if available.

Therefore, simply store all differences in heights of consecutive buildings and use ladders for all the larger differences till I consume all ladders and finally use bricks for the remaining jumps I can make.

Let's see the implementation of the idea explained above:

`class Solution {public: bool check(vector<int> heights, int bricks, int ladders, int mid){ vector<int> diff; for(int i = 1; i <= mid; i++){ if(heights[i] > heights[i-1]){ diff.push_back(heights[i]-heights[i-1]); } } sort(diff.begin(), diff.end(), greater<int>()); int l = diff.size(); for(int i = ladders; i < l; i++){ if(diff[i] > bricks) return false; bricks -= diff[i]; } return true; } int furthestBuilding(vector<int>& heights, int bricks, int ladders) { int n = heights.size(); int lo = 0, hi = n-1; while(lo < hi){ int mid = (lo+hi+1)/2; if(check(heights, bricks, ladders, mid)){ lo = mid; // if true, then binary search on right half } else{ hi = mid-1; // if false, then binary search on left half } } return lo; }};`

`import java.util.*;class Solution { boolean check(ArrayList<Integer> heights, int bricks, int ladders, int mid) { ArrayList<Integer> diff = new ArrayList<Integer>(); for (int i = 1; i <= mid; i++) { if (heights.get(i) > heights.get(i-1)) { diff.add(heights.get(i) - heights.get(i-1)); } } Collections.sort(diff, (a,b) -> b-a); int l = diff.size(); for (int i = ladders; i < l; i++) { if (diff.get(i) > bricks) return false; bricks -= diff.get(i); } return true; } int furthestBuilding(ArrayList<Integer> heights, int bricks, int ladders) { int n = heights.size(); int lo = 0, hi = n-1; while (lo < hi) { int mid = (lo+hi+1) / 2; if (check(heights, bricks, ladders, mid)) { lo = mid; } else { hi = mid-1; } } return lo; }}`

`from typing import Listclass Solution: def check(self, heights: List[int], bricks: int, ladders: int, mid: int) -> bool: diff = [] for i in range(1, mid+1): if heights[i] > heights[i-1]: diff.append(heights[i]-heights[i-1]) diff = sorted(diff, key=lambda x: -x) l = len(diff) for i in range(ladders, l): if diff[i] > bricks: return False bricks -= diff[i] return True def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int: n = len(heights) lo, hi = 0, n-1 while lo < hi: mid = (lo+hi+1) // 2 if self.check(heights, bricks, ladders, mid): lo = mid else: hi = mid-1 return lo`

**Check out my video for this problem:**

So that's all I have got in this blog, I appreciate your patience till now, If you liked the blog then stay tuned for more such relevant content.

I will see you soon :D

]]>