0% found this document useful (0 votes)
15 views59 pages

Imp Ac II Answer

Uploaded by

joshi kumar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views59 pages

Imp Ac II Answer

Uploaded by

joshi kumar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 59

1. Explain about the fractional knapsack problem?

You are given the list of weight and prices of certain items and a bag/knapsack of
certain capacity say W. Your task is to fill this bag in such a manner that the total price
of all the items that you take in this bag is maximum for all the configurations. And you
can either collect any object as a whole or a fraction of it.
Given the weights and profits of N items, in the form of {profit, weight} put these
items in a knapsack of capacity W to get the maximum total profit in the knapsack.
In Fractional Knapsack, we can break items for maximizing the total value of the
knapsack..
Input: arr[] = {{60, 10}, {100, 20}, {120, 30}}, W = 50
Output: 240
Explanation: By taking items of weight 10 and 20 kg and 2/3 fraction of 30 kg.
Hence total price will be 60+100+(2/3)(120) = 240

Input: arr[] = {{500, 30}}, W = 10


Output: 166.667

Illustration:

Check the below illustration for a better understanding: Consider the example: arr[] =
{{100, 20}, {60, 10}, {120, 30}}, W = 50. Sorting: Initially sort the array based on the
profit/weight ratio. The sorted array will be {{60, 10}, {100, 20}, {120, 30}}.

Iteration:

 For i = 0, weight = 10 which is less than W. So add this element in the


knapsack. profit = 60 and remaining W = 50 – 10 = 40.
 For i = 1, weight = 20 which is less than W. So add this element too.
profit = 60 + 100 = 160 and remaining W = 40 – 20 = 20.
 For i = 2, weight = 30 is greater than W. So add 20/30 fraction = 2/3
fraction of the element. Therefore profit = 2/3 * 120 + 160 = 80 + 160
= 240 and remaining W becomes 0.
So the final profit becomes 240 for W = 50.

Follow the given steps to solve the problem using the above approach:
 Calculate the ratio (profit/weight) for each item.
 Sort all the items in decreasing order of the ratio.
 Initialize res = 0, curr_cap = given_cap.
 Do the following for every item i in the sorted order:
o If the weight of the current item is less than or equal to the remaining
capacity then add the value of that item into the result
o Else add the current item as much as we can and break out of the loop.
 Return res.
#include <bits/stdc++.h>
using namespace std;
struct Item
{
int profit, weight;
Item(int profit, int weight)
{
this->profit = profit;
this->weight = weight;
}
};
static bool cmp(struct Item a, struct Item b)
{
double r1 = (double)a.profit / (double)a.weight;
double r2 = (double)b.profit / (double)b.weight;
return r1 > r2;
}
double fractionalKnapsack(int W, struct Item arr[], int N)
{
sort(arr, arr + N, cmp);
double finalvalue = 0.0;
for (int i = 0; i < N; i++)
{
if (arr[i].weight <= W)
{
W -= arr[i].weight;
finalvalue += arr[i].profit;
}
else
{
finalvalue += arr[i].profit * ((double)W / (double)arr[i].weight);
break;
}
}
return finalvalue;
}
int main()
{
int W = 50;
Item arr[] = { { 60, 10 }, { 100, 20 }, { 120, 30 } };
int N = sizeof(arr) / sizeof(arr[0]);
cout << fractionalKnapsack(W, arr, N);
return 0;
}
Complexity:
Time complexity: O(2N)
Space complexity: O(N)

2. Explain about the job scheduling problem?

Scheduling of processes/work is done to finish the work on time.CPU Scheduling is


a process that allows one process to use the CPU while another process is delayed (in
standby) due to unavailability of any resources such as I / O etc, thus making full use
of the CPU. The purpose of CPU Scheduling is to make the system more efficient,
faster, and fairer.
Problem statement: Given N events with their starting and ending times, find a
schedule that includes as many events as possible. It is not possible to select an event
partially. Consider the below events:-

In this case, the maximum number of events is two. As selected events B and D are as
follows:-

It is possible to invent several greedy algorithms for the problem.

Problem Statement on Job scheduling algorithm:-


You are given a set of n jobs where each has a deadline and profit associated with it.
Each job takes one unit of time to complete, and only one job can be scheduled at a
time. We earn the profit associated with the job if and only if the job is completed by
its deadline. Find the job scheduling of the given jobs that ensure maximum profit.
Input:

Job id 1 2 3 4 5
deadline 2 1 2 1 3
profit 100 19 27 25 15

Output:
Order of job ids : 3, 1, 5
Explanation:
First, select the job with the highest profit(100) i.e., job 1 with deadline=2.
Job 3 has 2nd highest profit= 27 with deadline= 2;
So, we can schedule jobs 1 and 3 for the first two time slots. No other job can be
assigned these time slots.
Next, we need to find a job having the deadline >2 i.e job 5; as there is no other job
with higher profit we will allot the 3rd time slot to job 5.
So, the order of job ids after scheduling is 3, 1, 5 or 1, 3, 5. This ordering ensures the
maximum profit.
Approach:
Here we will take a greedy approach to implement the job scheduling problem. We will
follow the following steps to schedule the job in the desired ways.
 First, sort the jobs in the decreasing order of their profits.
 Then find the highest deadline among all deadlines.
 Next, we need to assign time slots to individual job ids.
 First, check if the maximum possible time slot for the job, i.e., its deadline, is
assigned to another job or not. If it is not filled yet, assign the slot to the current job
id.
 Otherwise, search for any empty time slot less than the deadline of the current job.
If such a slot is found, assign it to the current job id and move to the next job id.
#include <bits/stdc++.h>
using namespace std;
struct Job
{
int id;
int dead;
int profit;
};
bool compare(Job a, Job b)
{
return a.profit>b.profit;
}
vector<int> JobScheduling(Job arr[], int n)
{
sort(arr,arr+n,compare);
int maxline=0,j=0;
for(int i=0;i<n;i++)
{
if(arr[i].dead>maxline)
{
maxline=arr[i].dead;
}
}
int i=0;
int a[maxline];
memset(a,-1,sizeof(a));
while(j!=maxline && i<n )
{
if(a[arr[i].dead-1]==-1)
{
a[arr[i].dead-1]=arr[i].id;
j++;
}
else
{
for(int k=arr[i].dead-1;k>=0;k--)
{
if(a[k]==-1)
{
a[k]=arr[i].id;
j++;
break;
}
}
}
i++;
}
vector<int> schedule;
for(i=0;i<maxline;i++)
{
if(a[i]==-1)
{
continue;
}
else{
schedule.push_back(a[i]);
}
}
return schedule;
}

int main()
{
Job arr[] = { {1, 2, 100}, {2, 1, 19}, {3, 2, 27},{4, 1, 25}, {5, 3, 15}};
vector<int> schedule=JobScheduling( arr, 5);
cout<<"order of scheduled jobs for maximum profit: ";
for(int i=0;i<schedule.size();i++)
{
cout<<schedule[i]<<" ";
}
return 0;
}
Complexity:
Time complexity: O(n)
Space complexity: O(1)

3. Explain about Dijkstra’s Algorithm with help of pseudo code?


Dijkstra’s algorithm finds a shortest path tree from a single source node, by building a
set of nodes that have minimum distance from the source. The algorithm creates a tree
of shortest paths from the starting vertex, the source, to all other points in the graph.

Algorithm:

1. Create a set sptSet (shortest path tree set) that keeps track of vertices included
in the shortest path tree, i.e., whose minimum distance from the source is calculated
and finalized. Initially, this set is empty.
2. Assign a distance value to all vertices in the input graph. Initialize all distance
values as INFINITE. Assign the distance value as 0 for the source vertex so that it
is picked first.
3. While sptSet doesn’t include all vertices
1. Pick a vertex u which is not there in sptSet and has minimum distance
value.
2. Include u to sptSet.
3. Update the distance value of all adjacent vertices of u. To update the
distance values, iterate through all adjacent vertices. For every adjacent vertex v, if the
sum of the distance value of u (from source) and weight of edge u-v, is less than the
distance value of v, then update the distance value of v.
Example:
Let us consider the following graph as Dijkstra’s Algorithm example in this case. Here,
we will be finding the shortest paths from the starting vertex A to all the other points.

#include<iostream>
#include <limits.h>
using namespace std;
int minDistance(int dist[], bool Tset[])
{
int min = INT_MAX, min_index;
for (int i = 0; i < 6; i++)
if (Tset[i] == false && dist[i] <= min)
min = dist[i], min_index = i;
return min_index;
}
void output(int dist[])
{
cout << "Vertex \t Distance from the Source\n";
for (int i = 0; i < 6; i++){
char ver = 65+i;
cout << ver << " \t\t " << dist[i] << endl;
}
}
void dijkstraAlgorithm(int graph[6][6], int src)
{
int dist[6];
bool Tset[6];
for (int i = 0; i < 6; i++)
dist[i] = INT_MAX, Tset[i] = false;

dist[src] = 0;
for (int count = 0; count < 6 - 1; count++)
{
int u = minDistance(dist, Tset);
Tset[u] = true;
for (int v = 0; v < 6; v++)
if (!Tset[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v]
< dist[v])
dist[v] = dist[u] + graph[u][v];
}
output(dist);
}
int main()
{
int graph[6][6] = { { 0, 1, 2, 0, 0, 0},
{ 1, 0, 1, 0, 3, 0},
{ 2, 1, 0, 2, 2, 0},
{ 0, 0, 2, 0, 1, 1},
{ 0, 3, 2, 1, 0, 2},
{ 0, 0, 0, 1, 2, 0},
};
dijkstraAlgorithm(graph, 0);
return 0;
}

Output:-

Vertex Distance from the Source

A 0

B 1

C 2

D 4

E 4

F 5

Complexity:
Time complexity: O((V + E) log V)
Space complexity: O(V)
4. Explain about the Robin-Karp algorithm?

The Rabin-Karp algorithm is a string-searching algorithm that uses hashing to find


patterns within a text efficiently.
Overview of Rabin-Karp Algorithm
Purpose: The Rabin-Karp algorithm searches for occurrences of a pattern within a text
by using a hash function to compare the hash values of the pattern and the text’s
substrings.
Hash Function: A hash function converts a string into a numeric value (hash value).
The algorithm uses this to quickly filter out positions in the text that cannot match the
pattern.

Algorithm Steps:
Compute the hash value of the pattern.
Compute the hash value of the first substring of the text with the same length as the
pattern.
Compare the hash values. If they match, perform a character-by-character comparison
to confirm.
Slide the window one position to the right and update the hash value of the new
substring using a rolling hash technique.
Repeat the comparison and sliding steps until the end of the text.

Time Complexity:
Average Case: (O(n + m)), where (n) is the length of the text and (m) is the length of
the pattern.
Worst Case: (O(n * m)), which occurs when there are many hash collisions.
Advantages: The Rabin-Karp algorithm is particularly useful for multiple pattern
searches and can be very efficient with a good hash function that minimizes collisions.

Here’s how the hash value is typically calculated in Rabin-Karp:


Step 1: Choose a suitable base and a modulus:
Select a prime number ‘p‘ as the modulus. This choice helps avoid overflow issues and
ensures a good distribution of hash values. Choose a base ‘b‘ (usually a prime number
as well), which is often the size of the character set (e.g., 256 for ASCII characters).
Step 2: Initialize the hash value:
Set an initial hash value ‘hash‘ to 0.
Step 3: Calculate the initial hash value for the pattern:
Iterate over each character in the pattern from left to right. For each character ‘c’ at
position ‘i’, calculate its contribution to the hash value as ‘c * (bpattern_length – i –
1) % p’ and add it to ‘hash‘. This gives you the hash value for the entire pattern.
Step 4: Slide the pattern over the text:
Start by calculating the hash value for the first substring of the text that is the same
length as the pattern.
Step 5: Update the hash value for each subsequent substring:
To slide the pattern one position to the right, you remove the contribution of the
leftmost character and add the contribution of the new character on the right.
The formula for updating the hash value when moving from position ‘i’ to ‘i+1’ is:
hash = (hash - (text[i - pattern_length] * (bpattern_length - 1)) % p) * b + text[i]
Step 6: Compare hash values:
When the hash value of a substring in the text matches the hash value of the pattern,
it’s a potential match. If the hash values match, we should perform a character-by-
character comparison to confirm the match, as hash collisions can occur.

#include <bits/stdc++.h>
using namespace std;
// d is the number of characters in the input alphabet
#define d 256
//pat -> pattern; txt -> text q -> A prime number
void search(char pat[], char txt[], int q)
{
int M = strlen(pat);
int N = strlen(txt);
int i, j;
int p = 0; // hash value for pattern
int t = 0; // hash value for txt
int h = 1;
// The value of h would be "pow(d, M-1)%q"
for (i = 0; i < M - 1; i++)
h = (h * d) % q;

// Calculate the hash value of pattern and first window of text


for (i = 0; i < M; i++) {
p = (d * p + pat[i]) % q;
t = (d * t + txt[i]) % q;
}

// Slide the pattern over text one by one


for (i = 0; i <= N - M; i++) {
// Check the hash values of current window of text and pattern. If the hash values
match then only check for characters one by one
if (p == t) {
/* Check for characters one by one */
for (j = 0; j < M; j++) {
if (txt[i + j] != pat[j]) {
break;
}
}
// if p == t and pat[0...M-1] = txt[i, i+1...i+M-1]
if (j == M)
cout << "Pattern found at index " << i
<< endl;
}
// Calculate hash value for next window of text: Remove leading digit, add trailing
digit
if (i < N - M) {
t = (d * (t - txt[i] * h) + txt[i + M]) % q;

// We might get negative value of t, converting it to positive


if (t < 0)
t = (t + q);
}
}
}
/* Driver code */
int main()
{
char txt[] = "PATTERN TO SEARCH";
char pat[] = "SEARCH";
// we mod to avoid overflowing of value but we should take as big q as possible to
avoid the collison
int q = INT_MAX;
// Function Call
search(pat, txt, q);
return 0;
}
Input
txt[] = "PATTERN TO SEARCH";
pat[] = "SEARCH";
Output
Pattern found at index 11

5. Explain about KMP algorithm?

KMP is the fastest string-matching algorithm. Its full form is Knuth Morris Pratt
Algorithm. The KMP algorithm got this name from the name of its inventors. In 1970,
James H Morris, Vaughan Pratt, and Donald Knuth invented this linear string-matching
algorithm.

The KMP is the only string-matching algorithm with a time complexity of O(n+m),
where n is the string length and m is the pattern length.

In string-matching algorithms, there are two terminologies: sting or text and pattern.

 String or text is the original string that is used for matching.

 The pattern is the sample text which is to be matched.

Overview of KMP Algorithm


Purpose: The KMP algorithm searches for occurrences of a pattern within a text by
preprocessing the pattern to create an array called the LPS (Longest Prefix which is
also Suffix) array. This helps in skipping unnecessary comparisons.
LPS Array: The LPS array is used to store the length of the longest proper prefix which
is also a suffix for each sub-pattern. This array helps in determining the next positions
to match after a mismatch.

Algorithm Steps:
Preprocessing: Compute the LPS array for the pattern.
Searching: Use the LPS array to skip characters while matching the pattern with the
text.

Preprocessing Overview:
KMP algorithm preprocesses pat[] and constructs an auxiliary lps[] of size m (same as
the size of the pattern) which is used to skip characters while matching.A proper prefix
is a prefix with a whole string not allowed. For example, prefixes of “ABC” are “”,
“A”, “AB” and “ABC”. Proper prefixes are “”, “A” and “AB”. Suffixes of the string
are “”, “C”, “BC”, and “ABC”.We search for lps in subpatterns. More clearly we focus
on sub-strings of patterns that are both prefix and suffix. For each sub-pattern pat[0..i]
where i = 0 to m-1, lps[i] stores the length of the maximum matching proper prefix
which is also a suffix of the sub-pattern pat[0..i].

Examples of lps[] construction:


For the pattern “AAAA”, lps[] is [0, 1, 2, 3]
For the pattern “ABCDE”, lps[] is [0, 0, 0, 0, 0]
For the pattern “AAABAAA”, lps[] is [0, 1, 2, 0, 1, 2, 3]

Preprocessing Algorithm:
In the preprocessing part, we calculate values in lps[]. To do that, we keep track of the
length of the longest prefix suffix value (we use len variable for this purpose) for the
previous index
We initialize lps[0] and len as 0.
If pat[len] and pat[i] match, we increment len by 1 and assign the incremented value to
lps[i].
If pat[i] and pat[len] do not match and len is not 0, we update len to lps[len-1]

Matching Overview
txt = “AAAAABAAABA”
pat = “AAAA”
We compare first window of txt with pat
txt = “AAAAABAAABA”
pat = “AAAA” [Initial position]
We find a match. This is same as Naive String Matching.
In the next step, we compare next window of txt with pat.
txt = “AAAAABAAABA”
pat = “AAAA” [Pattern shifted one position]

This is where KMP does optimization over Naive. In this second window, we only
compare fourth A of pattern with fourth character of current window of text to decide
whether current window matches or not. Since we know first three characters will
anyway match, we skipped matching first three characters.

Implementation of KMP algorithm:

How to use lps[] to decide the next positions (or to know the number of characters to be
skipped)?
We start the comparison of pat[j] with j = 0 with characters of the current window of
text.We keep matching characters txt[i] and pat[j] and keep incrementing i and j while
pat[j] and txt[i] keep matching. When we see a mismatch: We know that characters
pat[0..j-1] match with txt[i-j…i-1] (Note that j starts with 0 and increments it only
when there is a match).We also know (from the above definition) that lps[j-1] is the
count of characters of pat[0…j-1] that are both proper prefix and suffix.
From the above two points, we can conclude that we do not need to match these lps[j-
1] characters with txt[i-j…i-1] because we know that these characters will anyway
match.
#include <bits/stdc++.h>
using namespace std;

// Fills lps[] for given pattern pat


void computeLPSArray(string& pat, int M, vector<int>& lps)
{
// Length of the previous longest prefix suffix
int len = 0;
// lps[0] is always 0
lps[0] = 0;
// loop calculates lps[i] for i = 1 to M-1
int i = 1;
while (i < M) {
if (pat[i] == pat[len]) {
len++;
lps[i] = len;
i++;
}
else // (pat[i] != pat[len])
{
if (len != 0) {
len = lps[len - 1];
}
else // if (len == 0)
{
lps[i] = 0;
i++;
}
}
}
}

// Prints occurrences of pat in txt


vector<int> KMPSearch(string& pat, string& txt)
{
int M = pat.length();
int N = txt.length();
// Create lps[] that will hold the longest prefix suffix values for pattern
vector<int> lps(M);
vector<int> result;

// Preprocess the pattern (calculate lps[] array)


computeLPSArray(pat, M, lps);

int i = 0; // index for txt


int j = 0; // index for pat
while ((N - i) >= (M - j)) {
if (pat[j] == txt[i]) {
j++;
i++;
}

if (j == M) {
result.push_back(i - j + 1);
j = lps[j - 1];
}

// Mismatch after j matches


else if (i < N && pat[j] != txt[i]) {

// Do not match lps[0..lps[j-1]] characters, they will match anyway


if (j != 0)
j = lps[j - 1];
else
i = i + 1;
}
}
return result;
}

int main()
{
string txt = "AABAACAADAABAABA";
string pat = "AABA";
vector<int> result = KMPSearch(pat, txt);
// Print all the occurance (1-based indices)
for (int i = 0; i < result.size(); i++) {
cout << result[i] << " ";
}
return 0;
}

Input: txt = "AABAACAADAABAABA"; pat = "AABA";


Output: 1 10 13

Time Complexity: The KMP algorithm has a time complexity of (O(n + m)) for the
searching phase, where (n) is the length of the text and (m) is the length of the pattern.
The preprocessing phase also takes (O(m)) time.
Auxiliary Space: O(M)
Advantages: The main advantage of the KMP algorithm is its efficiency in handling
large texts and patterns, making it faster than the naive approach in the worst-case
scenario.

6. What is Dynamic Programming? and when to use Dynamic Programming?

Dynamic Programming is a technique in computer programming that helps to


efficiently solve a class of problems that have overlapping subproblems and optimal
substructure property. If any problem can be divided into subproblems, which in turn
are divided into smaller subproblems, and if there are overlapping among these
subproblems, then the solutions to these subproblems can be saved for future reference.
In this way, efficiency of the CPU can be enhanced. This method of solving a solution
is referred to as dynamic programming. Such problems involve repeatedly calculating
the value of the same subproblems to find the optimum solution.

Key Concepts of Dynamic Programming


Optimal Substructure: A problem has an optimal substructure if an optimal solution to
the problem contains optimal solutions to its subproblems.
Overlapping Subproblems: A problem has overlapping subproblems if the same
subproblems are solved multiple times.
When to Use Dynamic Programming
Dynamic Programming is particularly useful in the following scenarios:-
Problems with Overlapping Subproblems: If a problem can be broken down into
subproblems that are reused multiple times, DP can save computation time by storing
the results of these subproblems.
Example: Calculating Fibonacci numbers, where each number is the sum of the two
preceding ones.
Problems with Optimal Substructure: If the optimal solution to a problem can be
constructed from the optimal solutions of its subproblems, DP is a suitable approach.
Example: Shortest path problems, like finding the shortest path in a graph using
algorithms like Dijkstra’s or Bellman-Ford.
Steps to solve a Dynamic programming problem:
Identify if it is a Dynamic programming problem.
Decide a state expression with the Least parameters.
Formulate state and transition relationship.
Do tabulation (or memoization).

Identify if it is a Dynamic Programming problem:-


Check for overlapping subproblems and optimal substructure properties.
Problems involving maximizing/minimizing quantities or counting arrangements often
fit this category.
Decide a state expression with the least parameters:-
Define a state that uniquely identifies a subproblem with minimal parameters.
Example: In the Knapsack problem, the state can be defined by index and weight.
Formulate state and transition relationship:
Establish a relation between the current state and previous states.
Example: For forming a number using sums, derive a relation like state(n) = state(n-1)
+ state(n-3) + state(n-5).
Do tabulation (or memoization):
Store the results of subproblems to avoid redundant calculations.
Use either memoization (top-down) or tabulation (bottom-up) techniques to optimize
the solution.
Examples of Dynamic Programming Problem Fibonacci Sequence:-
Top-Down Approach (Memoization):
#include <iostream>
#include <vector>
using namespace std;

vector<int> memo;
int fib(int n) {
if (n <= 1) return n;
if (memo[n] != -1) return memo[n];
memo[n] = fib(n - 1) + fib(n - 2);
return memo[n];
}
int main() {
int n = 10;
memo.resize(n + 1, -1);
cout << "Fibonacci of " << n << " is " << fib(n) << endl;
return 0;
}
Output:
Fibonacci of 10 is 55

7. Explain top down and bottom up approaches of DP?

Top-down dynamic programming, also known as memoization, involves solving the


problem recursively and storing the results of subproblems to avoid redundant
computations.
How It Works:
Start with the original problem and break it down into smaller subproblems.
Solve each subproblem recursively. Store the results of subproblems in a table (usually
an array or a hash map). Reuse stored results whenever the same subproblem is
encountered again.
Example:
Let’s consider the Fibonacci sequence, where each number is the sum of the two
preceding ones.
#include <iostream>
#include <vector>
using namespace std;
vector<int> memo;
int fib(int n) {
if (n <= 1) return n;
if (memo[n] != -1) return memo[n];
memo[n] = fib(n - 1) + fib(n - 2);
return memo[n];
}
int main() {
int n = 10;
memo.resize(n + 1, -1);
cout << "Fibonacci of " << n << " is " << fib(n) << endl;
return 0;
}
Output: Fibonacci of 10 is 55

Bottom-up dynamic programming also known as tabulation, involves solving the


smallest subproblems first and using their solutions to build up to the solution of the
original problem. This approach avoids the overhead of recursive calls and reduces the
risk of stack overflow.
How It Works:
Determine the smallest subproblems that need to be solved. These are usually the base
cases in a recursive approach.
Decide on a state representation that captures the essence of the subproblems. This
often involves defining a table (array) where each entry represents a subproblem’s
solution.
Fill in the base cases in your table. These are the simplest subproblems that can be
solved directly.
Use a loop to fill in the table based on the relationships between subproblems. Each
entry in the table is computed using previously computed entries.
The final solution to the original problem is found in the last entry of the table.
Example: Let’s consider the Fibonacci sequence, where each number is the sum of the
two preceding ones.
#include <iostream>
#include <vector>
using namespace std;
int fib(int n) {
if (n <= 1) return n;
vector<int> fib(n + 1);
fib[0] = 0;
fib[1] = 1;
for (int i = 2; i <= n; i++) {
fib[i] = fib[i - 1] + fib[i - 2];
}
return fib[n];
}

int main() {
int n = 10;
cout << "Fibonacci of " << n << " is " << fib(n) << endl;
return 0;
}
Output:
Fibonacci of 10 is 55
Programming

1. Given a binary array nums, return the maximum number of consecutive 1's in
the array.
Example:-
Input: nums = [1,1,0,1,1,1]
Output: 3
Explanation: The first two digits or the last three digits are consecutive 1s. The
maximum number of consecutive 1s is 3.
Intuition:
The goal is to find the maximum number of consecutive 1s in a binary array. As we
traverse the array, we can keep track of how many consecutive 1s appear and reset the
count when a 0 is encountered. This way, by the end of the traversal, we can know the
largest sequence of consecutive 1s.
Approach:
Initialization: Start by initializing two variables: maxi to store the maximum number of
consecutive 1s and count to track the current sequence of 1s.
Iteration: Loop through the array:
If the current element is 1, increment the count by 1.
If the current element is 0, update maxi with the maximum of maxi and count, and reset
count to 0.
Final Check: After the loop ends, compare maxi with the current count to ensure any
final sequence of consecutive 1s is included.
Return: Return the value of maxi, which contains the maximum number of consecutive
1s.
Complexity:-
Time complexity: O(n)
Space complexity: O(n)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Solution
{
public:
int findMaxConsecutiveOnes(vector<int>& nums)
{
int maxi = 0;
int count = 0;
for (int i = 0; i < nums.size(); i++)
{
if (nums[i] == 1)
{
count++;
}
else {
maxi = max(maxi, count);
count = 0;
}
}
maxi = max(maxi, count); // Check the last sequence
return maxi;
}
};
int main()
{
int n;
cout << "Enter the number of elements: ";
cin >> n;

vector<int> nums(n);
cout << "Enter the elements (0s and 1s): ";
for (int i = 0; i < n; i++)
{
cin >> nums[i];
}
Solution sol;
int result = sol.findMaxConsecutiveOnes(nums);
cout << result << endl;
return 0;
}

2. You are given an integer array nums. You are initially positioned at the array's
first index, and each element in the array represents your maximum jump length
at that position.
Print true if you can reach the last index, false otherwise.
Example:-
Input: nums = [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
Intuition:
The goal of this problem is to determine if you can reach the last index of the array
starting from the first index. At each position in the array, the number tells you how far
you can jump from that index. The key observation here is that you need to
continuously track the farthest index you can reach. As long as the index you're
currently processing is within the reach of your farthest jump, you can potentially reach
the last index. If at any point you are at an index that exceeds the farthest point you've
been able to jump to, you know that reaching the end of the array is impossible. If you
can reach or exceed the last index at any point, the task is complete. This leads us to a
greedy solution that tracks the farthest point you can reach as you iterate through the
array.
Approach:
Initialize a variable maxp (maximum position reachable) to store the farthest index you
can reach at any point. Initially, it's set to 0 (since you start at the first index). Iterate
through the array using a loop:
For each index i, if i is greater than maxp, it means that you're stuck at that index, i.e.,
you can't jump to or beyond this point. Therefore, you return false immediately.
Otherwise, update maxp to be the farthest position you can jump to from the current
index, i.e., max(i + nums[i], maxp).
If at any point maxp is greater than or equal to the last index (n - 1), you return true, as
this confirms that reaching the last index is possible.
Return true by default if the loop completes without returning false. This means that
you're able to jump to or beyond the last index.
Complexity:-
Time complexity: O(n)
Space complexity: O(1)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Solution
{
public:
bool canJump(vector<int>& nums)
{
int n = nums.size();
int maxp = 0;
for (int i = 0; i < n; i++)
{
if (i > maxp) return false; // If the current index is unreachable
maxp = max(i + nums[i], maxp); // Update the farthest position reachable
if (maxp >= n - 1) return true; // If the last index is reachable
}
return true; // In case it finishes the loop and last index is reachable
}
};
int main()
{
int n;
cout << "Enter the number of elements in the array: ";
cin >> n;
vector<int> nums(n);
cout << "Enter the elements of the array: ";
for (int i = 0; i < n; i++)
{
cin >> nums[i];
}
Solution sol;
bool result = sol.canJump(nums);
if (result)
{
cout << "True" << endl;
} else {
cout << "False" << endl;
}
return 0;
}

3. At a lemonade stand, each lemonade costs $5. Customers are standing in a queue to
buy from you and order one at a time (in the order specified by bills). Each customer
will only buy one lemonade and pay with either a $5, $10, or $20 bill. You must
provide the correct change to each customer so that the net transaction is that the
customer pays $5.
Note that you do not have any change in hand at first.
Given an integer array bills where bills[i] is the bill the ith customer pays, print true if
you can provide every customer with the correct change, or false otherwise.
Example :
Input: bills = [5,5,5,10,20]
Output: true
Explanation:
From the first 3 customers, we collect three $5 bills in order.
From the fourth customer, we collect a $10 bill and give back a $5.
From the fifth customer, we give a $10 bill and a $5 bill.
Since all customers got correct change, we output true.
Intuition:
The problem requires us to determine if we can give the correct change for each customer in a
line, given that we start with no money and only have bills of 5, 10, and 20 dollars. We need
to keep track of the number of 5 and 10 dollar bills to provide correct change.
Approach:
Initialize counters for the number of 5 and 10 dollar bills.
Iterate through each customer's bill:
If the bill is 5 dollars, increase the count of 5 dollar bills.
If the bill is 10 dollars, check if we have at least one 5 dollar bill for change. If we do,
decrease the count of 5 dollar bills and increase the count of 10 dollar bills. If not, return false.
If the bill is 20 dollars, first try to give one 10 dollar bill and one 5 dollar bill as change if
available. If not possible, try to give three 5 dollar bills as change. If neither option is
available, return false.
If we successfully give change to all customers, return true.
Complexity:-
Time complexity: O(n)
Space complexity: O(1)
#include <iostream>
#include <vector>
using namespace std;
class Solution
{
public:
bool lemonadeChange(vector<int>& bills)
{
int five = 0;
int ten = 0;
for (int i = 0; i < bills.size(); i++) {
if (bills[i] == 5) {
five++;
} else if (bills[i] == 10) {
if (five > 0) {
five--;
ten++;
} else {
return false;
}
} else { // when bills[i] == 20
if (ten > 0 && five > 0) {
ten--;
five--;
} else if (five >= 3) {
five -= 3;
} else {
return false;
}
}
}
return true;
}
};
int main() {
Solution solution;
vector<int> bills;
int n, bill;
cout << "Enter the number of customers: ";
cin >> n;
cout << "Enter the bills given by customers (5, 10, or 20): ";
for (int i = 0; i < n; i++) {
cin >> bill;
bills.push_back(bill); }
bool result = solution.lemonadeChange(bills);
if (result)
{
cout << "True" << endl;
} else {
cout << "False" << endl;
}
return 0;
}
4. A parentheses string is valid if and only if:
It is the empty string,
It can be written as AB (A concatenated with B), where A and B are valid strings, or
It can be written as (A), where A is a valid string.
You are given a parentheses string s. In one move, you can insert a parenthesis at any
position of the string.
For example, if s = "()))", you can insert an opening parenthesis to be "(()))" or a
closing parenthesis to be "())))".
Print the minimum number of moves required to make s valid.
Example:
Input: s = "())" Output: 1
Intuition:
The problem asks for the minimum number of parentheses that need to be added to
make a given string of parentheses valid. A string of parentheses is valid when every
open parenthesis ( has a matching close parenthesis ). The idea is to keep track of
unmatched open and close parentheses while iterating through the string.
Approach:
We can solve this problem using a linear scan of the string while maintaining two
variables:-
openBraces: Tracks how many open parentheses ( are unmatched as we go through the
string.
closedBraces: Tracks how many close parentheses ) do not have a matching open
parenthesis.
For each character in the string:
If it is an open parenthesis (, we increment openCount.
If it is a close parenthesis ), we check:
If there's an unmatched open parenthesis (openCount > 0), we decrement openCount
(since we've found a match).
Otherwise, we increment closeCount (since it's an unmatched close parenthesis).
At the end of the loop, the sum of openCount and closeCount gives us the minimum
number of parentheses we need to add to make the string valid.
Complexity:-
Time complexity: O(n)
Space complexity: O(1)
#include <iostream>
#include <string>
using namespace std;
class Solution {
public:
int minAddToMakeValid(string s)
{
int openBraces = 0;
int closedBraces = 0;

for (char c : s) {
if (c == '(') {
openBraces++;
} else {
if (openBraces > 0) {
openBraces--;
}
else {
closedBraces++;
}
}
}

return openBraces + closedBraces;


}
};

int main()
{
string s;
cout << "Enter the parentheses string: ";
cin >> s;
Solution sol;
int result = sol.minAddToMakeValid(s);
cout << result << endl;
return 0;
}

5. You are given an array of integers stones where stones[i] is the weight of the ith
stone.
We are playing a game with the stones. On each turn, we choose the heaviest two
stones and smash them together. Suppose the heaviest two stones have weights x and y
with x <= y. The result of this smash is:
If x == y, both stones are destroyed, and
If x != y, the stone of weight x is destroyed, and the stone of weight y has new
weight y - x.
At the end of the game, there is at most one stone left.
Print the weight of the last remaining stone. If there are no stones left, return 0.
Example:
Input: stones = [2,7,4,1,8,1]
Output: 1
Intuition:
We are required last two heavy weights stones from current size of the array. And an
appropriate data structure would be priority_queue or multiset.
Approach:
Suppose the array would like this [1 2 1 1 8 7]
Inserting all elements in multiset or priority_queue would be Nlog(N) operation and it
will be sorted also i.e [1 1 1 2 7 8]
Now pick last element(i.e 8) from multiset using *(--st.end()) and delete this using
iterator (i.e st.erase(st.find(lst1))) and array become [1 1 1 2 7]
Repeat above step then array become [1 1 1 2].
Now if lst1 != lst2, then insert its difference in the set again(i.e [1 1 1 1 2])
Repeat above 2,3 and 4 steps until set size is greater than 1.
When array set size is equal to 1 then it is our required answer, return it.
Complexity:
Time complexity: Nlog(N)
Space complexity: O(N)
#include <iostream>
#include <vector>
#include <set>
using namespace std;
class Solution
{
public:
int lastStoneWeight(vector<int>& s)
{
multiset<int> st;
for(int i = 0; i < s.size(); i++) {
st.insert(s[i]);
}
while(st.size() > 1) {
auto lst1 = *(--st.end());
st.erase(st.find(lst1));
auto lst2 = *(--st.end());
st.erase(st.find(lst2));
if(lst1 != lst2) {
st.insert(lst1 - lst2);
}
}
return st.empty() ? 0 : *st.begin();
}
};
int main() {
int n;
cout << "Enter the number of stones: ";
cin >> n;
vector<int> stones(n);
cout << "Enter the weights of the stones: ";
for (int i = 0; i < n; i++) {
cin >> stones[i];
}
Solution sol;
int last_stone_weight = sol.lastStoneWeight(stones);
cout << last_stone_weight << endl;
return 0;
}

6. Given an array of size n that has the following specifications: -

Each element in the array contains either a policeman or a thief.

Each policeman can catch only one thief.

A policeman cannot catch a thief who is more than K units away from the policeman.
you need to find the maximum number of thieves that can be caught.
Input : arr[] = {'P', 'T', 'T', 'P', 'T'}, k = 1.
Output : 2.
Here maximum 2 thieves can be caught, first policeman catches first thief and second
police-man can catch either second or third thief.
Intuition:
This program solves the problem of maximizing the number of thieves that can be
caught by police within a given maximum distance k. It separates the indices of thieves
('T') and police ('P') into two different vectors. Then, it uses a two-pointer approach to
match the nearest police and thieves within the allowed distance. If a match is found
(i.e., the distance is less than or equal to k), both pointers are advanced, and the count is
incremented. If no match is possible, the pointer of the thief or police is adjusted to
explore other possibilities.
Approach:
First find the left most police and thief and store the indices. There can be two cases:
CASE 1: If the distance between the police and thief <= k (given), the thief can be
caught, so increment the res counter
CASE 2: If the distance between the police and thief >= k, the current thief cannot be
caught by the current police
For CASE 2, if the police is behind the thief, we need to find the next police and
check if it can catch the current thief
if the thief is behind the police, we need to find the next thief and check if the current
police can catch the thief
Repeat the process until we find the next police and thief pair, and increment result
counter if conditions are met, i,e, CASE 1.
#include <bits/stdc++.h>
using namespace std;
int policeThief(vector<char> &arr, int n, int k)
{
int res = 0;
vector<int> thi;
vector<int> pol;

for (int i = 0; i < n; i++)


{
if (arr[i] == 'P')
pol.push_back(i);
else if (arr[i] == 'T')
thi.push_back(i);
}
int l = 0, r = 0;
while (l < thi.size() && r < pol.size())
{
if (abs(thi[l] - pol[r]) <= k)
{
l++;
r++;
res++;
}
else if (thi[l] < pol[r])
{
l++;
}
else {
r++;
}
}
return res;
}

int main()
{
int n, k;
cout << "Enter the number of positions (n): ";
cin >> n;

vector<char> arr(n);
cout << "Enter the positions (P for police, T for thief): ";
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
cout << "Enter the maximum distance (k): ";
cin >> k;

cout << policeThief(arr, n, k) << endl;

return 0;
}

7. You are given a string sentence that consist of words separated by spaces. Each word
consists of lowercase and uppercase letters only. We would like to convert the sentence
to "Goat Latin" (a made-up language similar to Pig Latin.) The rules of Goat Latin are
as follows:
If a word begins with a vowel ('a', 'e', 'i', 'o', or 'u'), append "ma" to the end of the word.
For example, the word "apple" becomes "applema".
If a word begins with a consonant (i.e., not a vowel), remove the first letter and append
it to the end, then add "ma".
For example, the word "goat" becomes "oatgma".
Add one letter 'a' to the end of each word per its word index in the sentence, starting
with 1.
For example, the first word gets "a" added to the end, the second word gets "aa" added
to the end, and so on.
Print the final sentence representing the conversion from sentence to Goat Latin.
Example:
Input: sentence = "I speak Goat Latin"
Output: "Imaa peaksmaaa oatGmaaaa atinLmaaaaa"

Intuition:

This problem is about transforming a sentence into "Goat Latin" by applying certain
rules to each word in the sentence. The transformation is based on the position of each
word in the sentence and whether the word starts with a vowel or a consonant. The goal
is to convert the sentence word-by-word according to these rules and return the
modified sentence as a single string.

Approach:

Iterate over each word in the sentence - Traverse the input string character by character
to extract individual words. Check the starting letter of each word - If the word starts
with a vowel (a, e, i, o, u), append "ma" to the end of the word. If the word starts with a
consonant, move the first letter to the end of the word and then append "ma" to it.
Append 'a' based on the word's position - For each word, append a number of 'a'
characters equal to the word's position in the sentence (i.e., for the 1st word, append "a",
for the 2nd word, append "aa", and so on). Reconstruct the final sentence - After
transforming each word according to the rules, combine them back into a single
sentence, ensuring that spaces between words are preserved.

#include <iostream>
#include <string>
using namespace std;
string toGoatLatin(string s)
{
string result; //store the final result.
string temp; //temp string to build each word.
int index = 0; //keep track of the word position.
for(int i = 0; i < s.size(); i++)
{
if(s[i] != ' ')
temp += s[i];
if(s[i] == ' ' || i == s.size() - 1)
{
index++;
char temp2 = tolower(temp[0]);
char temp3 = temp[0];
if(temp2 == 'a' || temp2 == 'e' || temp2 == 'i' || temp2 == 'o' || temp2 == 'u')
{
temp += "ma";
}
else
{
temp.erase(temp.begin());
temp.push_back(temp3);
temp += "ma";
}
for(int j = 0; j < index; j++)
temp += 'a';
if(s.size() - 1 != i)
temp += ' ';
result += temp;
temp = "";
}
}
return result;
}
int main()
{
string sentence = "I speak Goat Latin";
cout << toGoatLatin(sentence) << endl;
return 0;
}
Input: sentence = "I speak Goat Latin"
Output: Imaa peaksmaaa oatGmaaaa atinLmaaaaa

8. Regional's CS Department is writing a spell-checker system, and you have been


tasked with writing a function to determine how closely two words resemble each
other. The algorithm you are to use, albeit not a very good one, is to compare the two
words character by character, and count how many times the characters in a given
position are the same.
You are given Strings A and B and you have to print an integer K indicating the score
(as defined above) of how closely the two match.
Examples:
Input: A=” TICK” B=” TOCK ” Output: 3
Input: A=” DOG” B=” GOD” Output: 1

Intuition:

The task is to write a function that compares two strings, A and B, character by
character, and returns the number of characters that match at the same positions in both
strings. The function determines how closely two words resemble each other based on
matching characters in corresponding positions.

Approach:

Determine the shorter length: - To avoid going out of bounds while comparing the two
strings, the function compares the two strings up to the length of the shorter string. This
ensures that only valid characters are compared. Character-by-character comparison: -
Using a for loop, the program iterates over both strings, comparing the characters at
each position (index i). If the characters at the same position in both strings are the
same, it increments a count variable. Return the count:- After comparing all possible
characters up to the length of the shorter string, the program returns the count of
matching characters as the result.

#include <iostream>
using namespace std;
int check(string str,string patt)
{
int count=0;int n;

if(str.size()<patt.size())
n=str.size();
else
n=patt.size();

for(int i=0;i<n;i++)
{
if(str[i]==patt[i])
{
count++;
}
}
return count;
}

int main()
{
string str="DOG";
string patt="GOD";
int k= check(str,patt);
cout<<k;
}

9. Given an array a, we have to find the minimum product possible with the subset of
elements present in the array. The minimum product can be a single element also.
Input : a[] = { -1, -1, -2, 4, 3 }
Output : -24

Explanation : Minimum product will be ( -2 * -1 * -1 * 4 * 3 ) = -24


Intuition:
The goal of this program is to find the minimum product subset of an array. The key
idea is to handle different cases based on the presence of negative numbers, positive
numbers, and zeros in the array. The minimum product can be achieved by considering
the product of all elements while carefully handling the signs of the numbers.
Approach:
To find the minimum product of a subset of elements in an array, first handle the edge
case where the array has only one element, returning that element as the product. For
larger arrays, track key values: the largest negative number (max_neg), the smallest
positive number (min_pos), the count of negative numbers (count_neg), and the count
of zeros (count_zero). Multiply all non-zero elements to get the total product. Special
cases include handling arrays of all zeros (resulting in a product of 0), arrays without
negatives but with zeros (also resulting in 0), or arrays with only positive numbers
(where the minimum positive is the result). If there are an even number of negative
numbers, exclude the largest negative from the product to minimize it. For an odd
number of negative numbers, include all elements in the product. This ensures that the
minimum possible product is calculated.

#include <bits/stdc++.h>
using namespace std;
int minProductSubset(int a[], int n)
{
if (n == 1)
return a[0];

int max_neg = INT_MIN, min_pos = INT_MAX;


int count_neg = 0, count_zero = 0, prod = 1;
for (int i = 0; i < n; i++)
{
if (a[i] == 0) {
count_zero++;
continue;
}
if (a[i] < 0) {
count_neg++;
max_neg = max(max_neg, a[i]);
}
if (a[i] > 0)
min_pos = min(min_pos, a[i]);
prod = prod * a[i];
}
if (count_zero == n || (count_neg == 0 && count_zero > 0))
return 0;
if (count_neg == 0)
return min_pos;
if (!(count_neg & 1) && count_neg != 0)
prod = prod / max_neg;
return prod;
}
int main()
{
int a[] = { -1, -1, -2, 4, 3 };
int n = sizeof(a) / sizeof(a[0]);
cout << minProductSubset(a, n);
return 0;
}

10. Given a string paragraph and a string array of the banned words banned, print the
most frequent word that is not banned. It is guaranteed there is at least one word that
is not banned, and that the answer is unique. The words in paragraph are case-
insensitive and the answer should be returned in lowercase.
Example:
Input: paragraph = "Bob hit a ball, the hit BALL flew far after it was hit.", banned =
["hit"]
Output: "ball"
Intuition:
The problem is about finding the most frequent word in a paragraph that is not included
in the banned list. To solve this, we need to: Count the occurrences of each word in the
paragraph. Ignore words that are present in the banned list. Identify the word with the
highest count that is not banned.
Approach:
Normalize the Paragraph: Traverse through the paragraph character by character,
converting each to lowercase and collecting them into words.
Count Word Frequency: Use a map to count the frequency of each word encountered.
Whenever a non-alphabetic character is reached, finalize the current word and update
its count in the map.
Handle the Last Word: After the loop, check if there is any remaining word and update
its count.
Exclude Banned Words: Iterate through the list of banned words and set their counts to
zero in the map.
Find the Most Frequent Word: Traverse the map to find the wor d with the highest
frequency that is not banned.
#include <iostream>
#include <vector>
#include <map>
#include <sstream>
#include <algorithm>
using namespace std;
class Solution
{
public:
string mostCommonWord(string paragraph, vector<string>& banned) {
map<string, int> mp;
string s = "";
for (int i = 0; i < paragraph.size(); i++)
{
if (isalpha(paragraph[i]))
{
s.push_back(tolower(paragraph[i]));
}
else if (!s.empty())
{
mp[s]++;
s = "";
}
}
if (!s.empty())
{
mp[s]++;
}
for (auto i : banned)
{
mp[i] = 0;
}
int ans = 0;
string fans = "";
for (auto i : mp) {
if (ans < i.second) {
ans = i.second;
fans = i.first;
}
}
return fans;
}
};
int main()
{
Solution solution;
string paragraph;
int bannedSize;
cout << "Enter the paragraph: ";
getline(cin, paragraph);
cout << "Enter the number of banned words: ";
cin >> bannedSize;
vector<string> banned(bannedSize);
cout << "Enter the banned words: ";
for (int i = 0; i < bannedSize; i++)
{
cin >> banned[i];
}
string result = solution.mostCommonWord(paragraph, banned);
cout << "The most common word is: " << result << endl;
return 0;
}
Output:-
Enter the paragraph: Bob hit a ball, the hit BALL flew far after it was hit.
Enter the number of banned words: 1
Enter the banned words: hit
The most common word is: ball

11. Given a text txt and a pattern pat, write a function that finds all occurrences of p
and its permutations (or anagrams) in t. You may assume n > m where n is length of
text and m is length of pattern.
Examples:
Input: t = “BACDGABCDA”, p = “ABCD” Output: [0, 5, 6]
Explanation : “BACD” is at 0, “ABCD” at 5 and “BCDA” at 6

Intuition:

The problem focuses on finding all the starting indices where a permutation of a pattern
(pat) appears in a given text (txt). This is similar to the "Anagram Search" problem,
where the goal is to find all the anagrams of a pattern in a larger string. The core idea is
to check if the frequency of characters in a substring of the text matches the frequency
of characters in the pattern. If they match, it means the substring is a permutation
(anagram) of the pattern.

Approach:
The approach to solving this problem involves frequency counting and sliding window
techniques. We maintain two frequency arrays of size 256 (for all ASCII characters),
one for the pattern (countP) and another for the current window of text (countTW).
Initially, we populate both arrays with the frequencies of characters from the pattern
and the first window of text. As the window slides across the text, we update the
frequency array for the window by adding the new character at the end of the window
and removing the character that just exited the window. At each step, we compare the
frequency arrays; if they match, it means the current window contains a permutation of
the pattern, and we record the starting index of the window. Edge cases include
handling scenarios where the pattern is larger than the text, and we also ensure
compatibility with all ASCII characters, including any special characters.

#include <bits/stdc++.h>
using namespace std;
vector<int> search(string& pat, string& txt)
{
int m = pat.size(), n = txt.size();
vector<int> res;
vector<int> countP(256, 0), countTW(256, 0);
for (int i = 0; i < m; i++)
{
countP[pat[i]]++;
countTW[txt[i]]++;
}
for (int i = m; i < n; i++)
{
if (countP == countTW)
{
res.push_back(i - m);
}
countTW[txt[i]]++;
countTW[txt[i - m]]--;
}
if (countP == countTW)
{
res.push_back(n - m);
}
return res;
}
int main()
{
string txt = "BACDGABCDA";
string pat = "ABCD";
vector<int> res = search(pat, txt);
for (int idx : res)
{
cout << idx << " ";
}
return 0;
}

12. Given a rod of length N inches and an array of prices, price[]. price[i] denotes the
value of a piece of length i. Determine the maximum value obtainable by cutting up the
rod and selling the pieces.
Note: Consider 1-based indexing.
Example:
Input: n = 8, price[] = {1, 5, 8, 9, 10, 17, 17, 20}
Output: 22
Explanation: The maximum obtainable value is 22 by cutting in two pieces of lengths
2 and 6, i.e., 5+17=22.

Intuition:

The rod cutting problem is a classic dynamic programming problem. The goal is to
maximize the profit obtained by cutting a rod of length n into smaller pieces. Each
piece has a price associated with its length, and the problem is to find the best way to
cut the rod (if at all) to get the maximum total profit. The dynamic programming
approach helps avoid redundant calculations by solving subproblems and reusing those
results to build the solution for larger lengths of the rod.

Approach:

The approach uses dynamic programming to maximize the profit from cutting a rod of
length n. We create an array T[], where T[i] stores the maximum profit for a rod of
length i. Initially, T[0] is set to 0, representing no profit for a rod of zero length. For
each length i from 1 to n, we evaluate all possible cuts by iterating over each cut length
j. For each cut, we calculate the potential profit by adding the price of the piece of
length j (price[j - 1]) and the best profit from the remaining rod length (T[i - j]),
updating T[i] with the maximum profit. After filling the array, T[n] holds the maximum
profit obtainable for the rod of length n.

#include <iostream>

#include <string>

using namespace std;

int rodCut(int price[], int n)

int T[n + 1];

for (int i = 0; i <= n; i++)

T[i] = 0;
}

for (int i = 1; i <= n; i++)

for (int j = 1; j <= i; j++)

T[i] = max(T[i], price[j - 1] + T[i - j]);

return T[n];

int main()

int price[] = { 1, 5, 8, 9, 10, 17, 17, 20 };

int n = 8;

cout << "Profit is " << rodCut(price, n);

return 0;

13. You are given k identical eggs and you have access to a building with n floors
labeled from 1 to n. You know that there exists a floor f where 0 <= f <= n such that
any egg dropped at a floor higher than f will break, and any egg dropped at or below
floor f will not break.
Each move, you may take an unbroken egg and drop it from any floor x (where 1 <= x
<= n). If the egg breaks, you can no longer use it. However, if the egg does not break,
you may reuse it in future moves.
Print the minimum number of moves that you need to determine with certainty what
the value of f is.
Example :
Input: k = 1, n = 2
Output: 2

Explanation:
Drop the egg from floor 1. If it breaks, we know that f = 0. Otherwise, drop the egg
from floor 2. If it breaks, we know that f = 1. If it does not break, then we know f = 2.
Hence,we need at minimum 2 moves to determine with certainty what the value of f is
2.

Intuition:

The problem is about determining the minimum number of attempts required to find
the highest floor from which an egg can be dropped without breaking, given K eggs
and N floors. The goal is to minimize the worst-case number of drops required. The
challenge arises from the trade-off between eggs and floors: with fewer eggs, more
careful decisions are needed, and with more floors, the risk of losing eggs early
increases.
Approach:
By using a 2D dynamic programming table dp[m][k], where m is the number of moves
(egg drops) and k is the number of eggs. The value dp[m][k] represents the maximum
number of floors that can be tested with m moves and k eggs. Initially, dp[0][k] = 0 (0
moves can test 0 floors) and dp[m][0] = 0 (0 eggs can test 0 floors). The recurrence
relation is dp[m][k] = dp[m-1][k-1] + dp[m-1][k] + 1, where dp[m-1][k-1] handles the
case when the egg breaks (we test the remaining k-1 eggs on lower floors), and dp[m-
1][k] handles the case when the egg does not break (we test the remaining floors with k
eggs). We add +1 to account for the current floor being tested. The goal is to
incrementally compute dp[m][k] until the maximum number of testable floors meets or
exceeds the total number of floors N. The minimum number of moves m is returned at
that point. This approach has a time complexity of O(N * K) as it involves filling up the
DP table for all combinations of m moves and k eggs.

#include <iostream>
#include <vector>
using namespace std;
class Solution
{
public:
int superEggDrop(int K, int N)
{
vector<vector<int>> dp(N + 1, vector<int>(K + 1, 0));
int m = 0;
while (dp[m][K] < N)
{
m++;
for (int k = 1; k <= K; ++k)
{
dp[m][k] = dp[m - 1][k - 1] + dp[m - 1][k] + 1;
}
}
return m;
}
};
int main()
{
int K, N;
cout << "Enter the number of eggs (K): ";
cin >> K;
cout << "Enter the number of floors (N): ";
cin >> N;
Solution solution;
int result = solution.superEggDrop(K, N);
cout << result << endl;
return 0;
}
14. Given a fence with n posts and k colors, Write a program to find out the number of
ways of painting the fence so that not more than two consecutive posts have the same
colors.
Example:
Input:
n=3k=2
Output: 6
Explanation: Let the 2 colours be 'R' and 'B'. We have following possible
combinations:
1. RRB
2. RBR
3. RBB
4. BRR
5. BRB
6. BBR

Intuition:

The problem deals with calculating the number of ways to paint a fence with n posts
and k colors under the condition that no more than two adjacent posts can have the
same color. This is a variation of a dynamic programming problem, where we need to
track the possibilities of valid colouring based on constraints.

Approach:
This approach involves dynamic programming with three key variables: same, diff, and
total. The same variable tracks the number of ways the current post can be painted the
same color as the previous post, while diff tracks the number of ways it can be painted
a different color. The total variable holds the overall number of ways to paint the posts.
Initially, when n = 1, there are k ways to paint the first post, so total and diff are set to
k. For each subsequent post, the number of ways to paint it the same color as the
previous one is set to same = diff, while the number of ways to paint it a different color
is diff = total * (k - 1). The total number of valid ways to paint up to the current post is
calculated as total = (same + diff) % mod, where mod helps prevent overflow. After
processing all posts, the total variable contains the result. The time complexity of this
approach is O(n) since we only iterate through the posts once, and the space complexity
is O(1) as it uses only a constant amount of memory.

#include <bits/stdc++.h>
using namespace std;
long countWays(int n, int k)
{
long total = k;
int mod = 1000000007;
int same = 0, diff = k;
for (int i = 2; i <= n; i++)
{
same = diff;
diff = (total * (k - 1)) % 1000000007;
total = (same + diff) % mod;
}
return total;
}
int main()
{
int n,k;
cin>>n;
cin>>k;
cout << countWays(n, k) << endl;
return 0;
}

15. Given a gold mine of n*m dimensions. Each filed in this mine contains a positive
integer which is the amount of gold in tons. Initially the miner is at first column but can
be at any row. He can move only (right->, right up/,right down\) that is from a given
cell, the miner can move to the cell diagonally up towards the right or diagonally down
towards the right. Find out maximum amount of gold he can collect.
Input: mat[ ][ ] = {{1,3,3},{2,1,4},{0,6,4}}
Output: 12
Intuition: The idea is to use dynamic programming to store the maximum gold
collected up to each cell, ensuring that we only compute each subproblem once.
Approach:
Initialize a table to store the maximum gold collected up to each cell. Iterate through
each cell starting from the last column to the first column. For each cell, calculate the
maximum gold that can be collected by moving to the right, right-up, or right-down.
Update the table with the maximum gold collected for each cell. The result will be
the maximum value in the first column of the table.

#include<bits/stdc++.h>
using namespace std;
const int MAX = 100;
int getMaxGold(int gold[][MAX], int m, int n)
{
int goldTable[m][n];
memset(goldTable, 0, sizeof(goldTable));
for (int col=n-1; col>=0; col--)
{
for (int row=0; row<m; row++)
{
int right = (col==n-1)? 0: goldTable[row][col+1];
int right_up = (row==0 || col==n-1)? 0:goldTable[row-1][col+1];
int right_down = (row==m-1 || col==n-1)?0:goldTable[row+1][col+1];
goldTable[row][col] = gold[row][col] + max(right, max(right_up, right_down));
}
}
int res = goldTable[0][0];
for (int i=1; i<m; i++)
res = max(res, goldTable[i][0]);
return res;
}
int main()
{
int gold[MAX][MAX]= {{1,3,3},{2,1,4},{0,6,4}};
int m = 3, n = 3;
cout << getMaxGold(gold, m, n);
return 0;
}

16. Given an array of size N. the task is to find the sum of the contiguous subarray
within a arr[] with the largest sum.
Input: arr[] = {-2, -3, 4, -1, -2, 1, 5, -3}
Output: 7
Explanation: 4 +(-1) +(-2) +1+5 = 7

Intuition:
The program aims to find the maximum sum of contiguous subarrays within a given
integer array using a brute-force approach. The core intuition behind this solution is to
examine all possible contiguous subarrays, compute their sums, and keep track of the
maximum sum encountered.

Approach:
The approach to finding the maximum subarray sum involves initializing a variable res
with the first element of the array, which serves as the starting point for tracking the
maximum sum. It uses nested loops where the outer loop iterates through each element
of the array as a potential starting point for a subarray, while the inner loop sums the
elements from the current starting point to the end of the array, updating a temporary
sum variable currSum. After each update of currSum, the algorithm checks if it exceeds
the previously recorded maximum sum in res and updates it if necessary. Once all
possible contiguous subarrays have been explored, the maximum sum stored in res is
returned. The time complexity of this approach is O(n^2) due to the nested loops,
where n is the length of the array, while the space complexity is O(1) as it uses only a
fixed amount of additional space.

#include <bits/stdc++.h>
using namespace std;
int maxSubarraySum(vector<int> &arr)
{
int res = arr[0];
for(int i = 0; i < arr.size(); i++)
{
int currSum = 0;
for(int j = i; j < arr.size(); j++)
{
currSum = currSum + arr[j];
res = max(res, currSum);
}
}
return res;
}
int main()
{
vector<int> arr = {-2, -3, 4, -1, -2, 1, 5, -3};
cout << maxSubarraySum(arr);
return 0;
}

17. You are given an integer array coins representing coins of different denominations
and an integer amount representing a total amount of money. Print the fewest number
of coins that you need to make up that amount. If that amount of money cannot be
made up by any combination of the coins, print -1. You may assume that you have an
infinite number of each kind of coin.
Example :
Input: coins = [1,2,5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1

Intuition:
The goal of this code is to solve the "coin change" problem, which involves
determining the minimum number of coins needed to make a specific amount using a
given set of coin denominations. The approach uses dynamic programming to
efficiently calculate the minimum coins required.

Approach:
The coin change problem is addressed using a dynamic programming approach that
involves creating an array dp, where dp[i] represents the minimum number of coins
required to make the amount i. This array is initialized to INT_MAX to indicate that all
amounts are initially unreachable, except for dp[0], which is set to 0 since no coins are
needed for an amount of 0. To optimize the algorithm, the coin denominations are
sorted, allowing for early termination of the inner loop when a coin exceeds the current
amount. The outer loop iterates through all possible amounts from 1 to the target
amount, while the inner loop checks each coin denomination. If a coin can be used (i.e.,
it does not exceed the current amount), the algorithm calculates the remaining amount
(rem = i - coins[j]) and updates dp[i] to the minimum of its current value or 1 +
dp[rem], effectively counting the number of coins used. After processing all amounts, if
dp[amount] remains INT_MAX, it indicates that no combination of coins can produce
the desired amount, resulting in a return value of -1. Otherwise, the minimum number
of coins needed is given by dp[amount]. The time complexity of this approach is
O(n x m), where n is the number of coin denominations and m is the target amount,
while the space complexity is O(m) due to the dp array used to store the minimum
number of coins for each amount.
#include <iostream>
#include <vector>
#include <algorithm>
#include <limits.h>
using namespace std;
class Solution
{
public:
int coinChange(vector<int>& coins, int amount)
{
vector<long long> dp(amount + 1, INT_MAX);
dp[0] = 0;
sort(coins.begin(), coins.end());
for(int i = 1; i <= amount; i++)
{
for(int j = 0; j < coins.size(); j++)
{
if(coins[j] > i)
{
break;
}
int rem = i - coins[j];
dp[i] = min(dp[i], 1 + dp[rem]);
}
}
if(dp[amount] == INT_MAX)
{
return -1;
}
return dp[amount];
}
};
int main() {
int n, amount;
cout << "Enter the number of coin denominations: ";
cin >> n;
vector<int> coins(n);
cout << "Enter the coin denominations: ";
for(int i = 0; i < n; i++)
{
cin >> coins[i];
}
cout << "Enter the amount: ";
cin >> amount;
Solution solution;
int result = solution.coinChange(coins, amount);

if (result != -1)
{
cout << result << endl;
}
else
{
cout << "No combination possible to make the amount." << endl;
}
return 0;
}

You might also like