-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
123 changed files
with
9,758 additions
and
45 deletions.
There are no files selected for viewing
126 changes: 126 additions & 0 deletions
126
C_CPP/Algorithmic Approaches/Backtracking/backtracking.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
# Backtracking Algorithms | ||
|
||
### What is meant by "Backtracking" ? | ||
- Backtracking means to retrace one's steps. | ||
- Backtracking Algorithm is an algorithm implemented using recursion for solving problems. | ||
- Backtracking technique is simply based upon the idea that you take a step and then if that step is not fulfilling the constraints | ||
then you take that step back and choose another step,Means you backtrack. | ||
|
||
**For Example** | ||
You encountered with four gates with different paths ,and you don't know which gate will take you to the correct position, | ||
So what you will do is open the gates one by one if you get the right one then you will go ahead and if not then you will move back and choose another gate, | ||
Means you just backtrack from using that step and then choose another step. | ||
|
||
|
||
### Question on ***Backtracking*** | ||
|
||
**1 Rat in a Maze** | ||
A square matrix named maze is given to you.The blocks which can be used are denoted by 1 and rest by 0 | ||
**Brute force Approach** | ||
In backtracking we used to try each and every **possible solution** to reach our destination and at the end we find the correct solution. | ||
In the same manner for this question we have two directions in which the rat can move,**forward** and **downward**. | ||
Here to reach from the source to destination the rat will first try to move in the forward direction if the block ahead will be 1 then that solution will be | ||
added to the solution,else the rat will backtrack from that block to its initial position and try another option i.e. move downwards. | ||
### Algorithm | ||
- Take the matrix maze as input | ||
- Make a solutions array an initialize with 0 | ||
- traverse through the maze and check whether the block is safe or not | ||
- Mark 1 for those blocks which are in your solution | ||
- If any block takes you to wrong position then set that block to 0 again | ||
|
||
### Code | ||
```c++ | ||
|
||
#include <iostream> | ||
#include<vector> | ||
using namespace std; | ||
|
||
|
||
bool issafe (vector < vector < int >>maze, int x, int y, int m, int n) | ||
{ // the boolean function issafe is checking whether the block at x,y index is safe or not { //check whether the index lie inside the maze and is it 1 or not | ||
if (x >= 0 && x < m && y >= 0 && y < n && maze[x][y] == 1) | ||
return true; | ||
return false; | ||
} | ||
|
||
bool solution (vector < vector < int >>maze, int x, int y, vector < vector < int >>&ans, int m, int n) //here x and y are storing the current position of rat | ||
{ | ||
if (x == m - 1 && y == n - 1 && maze[x][y] == 1) | ||
{ | ||
ans[x][y] = 1; | ||
return true; | ||
} | ||
if (issafe (maze, x, y, m, n) == true) | ||
{ | ||
if (ans[x][y] == 1) | ||
return false; | ||
ans[x][y] = 1; | ||
|
||
if (solution (maze, x + 1, y, ans, m, n) == true) //if the solution for moving one block forward is true then return true | ||
return true; | ||
if (solution (maze, x, y + 1, ans, m, n) == true) //if the solution for moving one block downward is true then return true | ||
return true; | ||
ans[x][y] = 0; //if either of them is not true means the current block is not the correct solution so backtrack from it by marking it 0 | ||
return false; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
int main () | ||
{ | ||
|
||
int m, n; | ||
cout << "Enter number of rows\n"; | ||
cin >> m; | ||
cout << "Enter number of columns\n"; | ||
cin >> n; | ||
vector < vector < int >>maze (n, vector < int >(m)); | ||
for (int i = 0; i < m; i++) | ||
{ | ||
for (int j = 0; j < n; j++) | ||
{ | ||
int element; | ||
cin >> element; | ||
maze[i][j] = element; | ||
} | ||
} | ||
vector < vector < int >>sol (n, vector < int >(m)); | ||
for (int row = 0; row < m; row++) | ||
{ | ||
for (int col = 0; col < n; col++) | ||
{ | ||
sol[row][col] = 0; // initialized each element of solution to 0 initially | ||
} | ||
} | ||
bool answer = solution (maze, 0, 0, sol, m, n); //solution is taking the maze and solution array | ||
// and starting and ending positions in the maze i.e. 0,0 | ||
if (answer == false) // if false is returned by solution it means no path to destination exists | ||
cout << "Solution does not exists"; | ||
else | ||
{ | ||
for (int i = 0; i < sol.size (); i++) | ||
{ | ||
for (int j = 0; j < sol[i].size (); j++) | ||
cout << sol[i][j]; | ||
cout << "\n"; | ||
} | ||
} | ||
return 0; | ||
} | ||
``` | ||
**Input** | ||
>Enter number of rows | ||
>2 | ||
>Enter number of columns | ||
>2 | ||
>1 1 0 1 | ||
**Output:** | ||
>1 1 | ||
>0 1 | ||
### Complexity Analysis: | ||
**Time Complexity: O(2<sup>(n<sup>2</sup>)</sup>).** | ||
**Space Complexity: O(n<sup>2</sup>).** |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[Backtracking Algorithm](./Algorithmic%20Approaches/Backtracking/backtracking.md) |
98 changes: 98 additions & 0 deletions
98
C_CPP/Algorithmic Approaches/Brute Force/Longest_Palindromic_Substring.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
# Longest Palindromic Substring Using Brute Force Approach | ||
# Brute Force | ||
- A Brute Force Algorithm is a straight-forward approach to a problem i.e the first method or algorithm which come in our mind to solve a particular problem. In this we try every possibility rather than going for advance techniques to improve efficiency. | ||
# Longest Palindromic Substring | ||
Task: Given a string, find the longest substring which is palindrome. | ||
|
||
Approach: The simple/brute force approach will be to check for each substring whether the substring is a palindrome or not. To do this, we will run three loops, the outer two loops will pick up each substring one by one by modifying its start and end index (here i and j), the inner loop will check whether the selected substring is a palindrome or not. If yes and also the length of that substring is greater than the previous then we will update the values of start_index and length. | ||
|
||
After coming out of all loops we will print the longest substring via using start index and length and then we will return length of the longest substring. | ||
|
||
# Code of Longest Palindromic Substring in C++ | ||
```cpp | ||
/* | ||
Given a string, find the longest substring which is palindrome. | ||
*/ | ||
#include<bits/stdc++.h> | ||
using namespace std; | ||
|
||
//Function to get length of longest palindromic substring and to print that substring | ||
int Longest_Palindromic_substr(string str) | ||
{ | ||
//This will store maximum length so far | ||
int length=0; | ||
|
||
//Starting index of substring | ||
int start_index=0; | ||
|
||
//Loops to regulate size of substring | ||
for(int i=0;i<str.length();i++) | ||
{ | ||
for(int j=i;j<str.length();j++) | ||
{ | ||
int flag=1; | ||
|
||
//To check if it is a palindrome or not | ||
for(int k=0;k<(j-i+1)/2;k++) | ||
if(str[i+k]!=str[j-k]) | ||
flag=0; | ||
//If it is a palindrome and its length is greater than the current length then update the values | ||
if(flag && (j-i+1)>length) | ||
{ | ||
start_index=i; | ||
length=j-i+1; | ||
} | ||
} | ||
} | ||
//Print the substring | ||
cout << "Longest palindromic substring is: "; | ||
for(int i=start_index;i<=start_index+length-1;i++) | ||
cout << str[i]; | ||
|
||
return length; | ||
} | ||
|
||
//Main Function | ||
int main() | ||
{ | ||
string str; | ||
|
||
//Take string from the user | ||
cout << "Enter string: "; | ||
cin >> str; | ||
|
||
cout << "\nLength of longest palindromic substring is: " << Longest_Palindromic(str); | ||
|
||
return 0; | ||
} | ||
``` | ||
# Input/Output Example | ||
<b>Example 1-</b> | ||
<b>Input:</b> | ||
Enter string: babad | ||
<b>Output:</b> | ||
Longest palindromic substring is: bab | ||
Length of longest palindromic substring is: 3 | ||
<b>Example 2-</b> | ||
<b>Input:</b> | ||
Enter string: cbbd | ||
<b>Output:</b> | ||
Longest palindromic substring is: bb | ||
Length of longest palindromic substring is: 2 | ||
# Time And Space Complexity | ||
Time Complexity: O(n<sup>3</sup>) | ||
Space Complexity: O(1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
- [Longest Palindromic Substring](Longest_Palindromic_Substring.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
# Divide and Conquer Algorithm | ||
As its name suggest in this algorithmic approach we divide the given problem in to sub problem and then we solve each sub problem recursively and then we combine the result of each sub problem to get the solution.<br> | ||
there are many algorith which are based on this technique but from those some of the important algorithm are:-<br> | ||
1. Binary search | ||
2. Merge sort | ||
3. Find max and min | ||
4. Quick sort | ||
## Binary seearch using DAC | ||
```cpp | ||
//binary search using DAC techinque | ||
#include<bits/stdc++.h> | ||
using namespace std; | ||
int binary_DAC(int arr[],int i , int j,int key) | ||
{ if(i==j){ | ||
if(key==arr[i]) | ||
return i; | ||
else | ||
return -1; | ||
} | ||
int mid=(i+j)/2; //Divide step | ||
if(key==arr[mid]) | ||
return mid; | ||
if(key<arr[mid]) | ||
return binary_DAC(arr,i,mid-1,key); // solving each sub problem recursively | ||
else | ||
return binary_DAC(arr,mid+1,j,key); | ||
} | ||
int main() | ||
{ int arr[]={10,20}; | ||
int size=sizeof(arr)/sizeof(int),key=10; | ||
int index=binary_DAC(arr,0,size-1,key); | ||
if(index==-1) | ||
cout<<"element not found"; | ||
else | ||
cout<<"element is found at the index "<<index; | ||
return 0; | ||
} | ||
``` | ||
**Note** :- The combine step is not mandatory in DAC approach as u can see there is no combine step in this problem. | ||
## Merge sort using DAC | ||
```cpp | ||
#include<bits/stdc++.h> | ||
using namespace std; | ||
void merge(int arr[],int beg,int mid,int end) | ||
{ int l1=mid-beg+1,l2=end-mid; | ||
int left[l1],right[l2]; | ||
for(int m=0 ; m<l1 ; m++) left[m]=arr[beg+m]; | ||
for(int m=0 ; m<l2 ; m++) right[m]=arr[mid+m+1]; | ||
int m=0,n=0,k=beg; | ||
while(m<l1 && n<l2) | ||
{ if(left[m]<right[n]) | ||
arr[k++]=left[m++]; | ||
else | ||
arr[k++]=right[n++]; | ||
} | ||
while(m<l1) {arr[k++]=left[m++];} | ||
while(n<l2) {arr[k++]=right[n++];} | ||
} | ||
void mergesort(int arr[],int i,int j) | ||
{ if(i<j){ | ||
int mid=(i+j)/2; // divide step | ||
mergesort(arr,i,mid); // solving each sub problem | ||
mergesort(arr,mid+1,j); // solving each sub problem | ||
merge(arr,i,mid,j); // combine step | ||
} | ||
else | ||
return; | ||
} | ||
int main() | ||
{ int arr[]={21,3,10,11,50,14,23}; | ||
int size=sizeof(arr)/sizeof(int); | ||
mergesort(arr,0,size-1); | ||
for(auto it:arr) | ||
cout<<it<<" "; | ||
return 0; | ||
} | ||
``` | ||
This algorithmic approach has a time complixity of O(n log n) and space complixity of O(n). Majority portion of its time complixity is in **combine step** and this is one of the difference in the merge sort and quick sort as in quick sort major portion of its time complixity is in **divide step**. | ||
## Find max and min in an array using DAC | ||
```cpp | ||
//use divide and conqure technique to find the maximum and minimum element in an array | ||
#include<bits/stdc++.h> | ||
using namespace std; | ||
struct node{ | ||
int max,min; | ||
}; | ||
node dac_max_min(int arr[],int i,int j) | ||
{ struct node s1,s2,s3; | ||
if(i==j){ | ||
s1.max=s1.min=arr[i]; | ||
return s1; | ||
} | ||
else if(j-i==1) | ||
{ s1.max=arr[i]>arr[j]?arr[i]:arr[j]; | ||
s1.min=arr[i]<arr[j]?arr[i]:arr[j]; | ||
return s1; | ||
} | ||
else | ||
{ int mid=(i+j)/2; // divide step | ||
s2=dac_max_min(arr,i,mid); // solving each sub problem recursively | ||
s3=dac_max_min(arr,mid+1,j); // solving each sub problem recursively | ||
s1.max=s2.max>s3.max?s2.max:s3.max; // combine step | ||
s1.min=s2.min<s3.min?s2.min:s3.min; // combine step | ||
return s1; | ||
} | ||
} | ||
int main() | ||
{ int arr[20]={-2,5,1,-10,20,13,75,12,52,11}; | ||
int i=0,size=sizeof(arr)/sizeof(int); | ||
struct node result=dac_max_min(arr,i,size-1); | ||
cout<<"maximun element is: "<<result.max<<endl; | ||
cout<<"minimun element is: "<<result.min; | ||
return 0; | ||
} | ||
``` | ||
## Quick sort using DAC | ||
```cpp | ||
// use quick sort (DAC) to sort an array | ||
#include<bits/stdc++.h> | ||
using namespace std; | ||
void swap( int *a , int *b) | ||
{ int temp; | ||
temp=*a; | ||
*a=(*b); | ||
*b=temp; | ||
} | ||
int partition(int arr[],int beg,int end) | ||
{ int i=beg-1,j=beg,pivot; | ||
pivot=arr[end]; | ||
while(j<end) | ||
{ if(arr[j]<pivot) | ||
{ i++; | ||
swap(&arr[i],&arr[j]); | ||
} | ||
j++; | ||
} | ||
swap(&arr[i+1],&arr[end]); | ||
return (i+1); | ||
} | ||
void quicksort(int arr[],int beg,int end) | ||
{ if(beg<end) | ||
{ int q=partition(arr,beg,end); // divide step | ||
quicksort(arr,beg,q-1); // solving each sub problem recursively | ||
quicksort(arr,q+1,end); //solving each sub problem recursively | ||
} | ||
} | ||
int main() | ||
{ int arr[]={10,60,12,56,54,25,41}; | ||
int size=sizeof(arr)/sizeof(int); | ||
quicksort(arr,0,size-1); | ||
for(auto it:arr) | ||
cout<<it<<" "; | ||
return 0; | ||
} | ||
``` | ||
In this approach <br> | ||
best time complexity is O(n log n)<br> | ||
average case O(n log n)<br> | ||
worst case O(n^2) |
Oops, something went wrong.