Merge branch 'main' of https://github.com/MakeContributions/DSA into added-new-algorithm

pull/969/head
Pranav-Rustagi 2022-10-10 19:31:02 +05:30
commit 3fe14144fb
10 changed files with 510 additions and 1 deletions

View File

@ -0,0 +1,97 @@
/*
Algorithm:
(i) Traverse the list and push all of its nodes onto a stack.
(ii) Traverse the list from the head node again and pop a value
from the stack top and connect them in reverse order.
TIME COMPLEXITY: O(n), as we are traversing over the linked list of size N using a while loop.
SPACE COMPLEXITY: o(n), as we are using stack of size N in worst case which is extra space.
*/
#include <iostream>
#include <stack>
using namespace std;
class Node {
public:
int data;
Node *next;
};
Node *head;
void Print(Node* n);
void RevList();
int main() {
head = NULL;
Node *first = new Node;
Node *second = new Node;
Node *third = new Node;
Node *fourth = new Node;
Node *fifth = new Node;
Node *sixth = new Node;
Node *seventh = new Node;
head = first;
first->data = 10;
first->next = second;
second->data = 20;
second->next = third;
third->data = 30;
third->next = fourth;
fourth->data = 40;
fourth->next = fifth;
fifth->data = 50;
fifth->next = sixth;
sixth->data = 60;
sixth->next = seventh;
seventh->data = 70;
seventh->next = NULL;
Print(head);
RevList();
cout<<endl;
Print(head);
return 0;
}
void Print(Node* n){
if(n==NULL){
return;
}
cout<<n->data<<" ";
Print(n->next);
}
void RevList() {
if(head == NULL) return;
stack<Node *> st;
Node * temp = head;
while(temp!= NULL){
st.push(temp);
temp = temp->next;
}
temp = st.top();
head = temp;
st.pop();
while(!st.empty()) {
temp->next = st.top();
temp = temp->next;
st.pop();
}
temp->next = NULL;
}

View File

@ -78,7 +78,7 @@
- [Find Merge Point of two singly linked list](Linked-Lists/Find-Merge-Point.cpp)
- [Segregate Even Odd Nodes of linked list](Linked-Lists/segregate-even-odd-nodes-of-linked-list.cpp)
- [Remove Duplicate in Sorted linked list](Linked-Lists/remove-duplicates-in-sorted-linked-list.cpp)
- [Reverse the linked list using stack](Linked-Lists/reverse-the-list-using-stack.cpp)
## Searching
- [Linear Search](Searching/linear-search.cpp)
@ -99,6 +99,7 @@
- [Infix to postfix expression conversion](Stacks/infix-to-postfix.cpp)
- [Stock Span Problem using Stacks](Stacks/stock-span-problem.cpp)
- [Prefix to Postfix expression conversion](Stacks/prefix_to_postfix.cpp)
- [Redundant Parenthesis](Stacks/redundant-parenthesis.cpp)
## Sorting

View File

@ -0,0 +1,74 @@
// RedundantParenthesis
// Given a string of balanced expression, find if it contains a redundant parenthesis or not. A set of parenthesis are redundant if the same sub-expression is surrounded by unnecessary or multiple brackets. Print True if redundant, else False.
// Algorithm
// 1. We iterate through the given expression and for each character in the expression, if the character is an open parenthesis ( or any operators, we push it to the stack.
// 2. If the character is close parenthesis ), then pop characters from the stack till matching open parenthesis ( is found.
// For any sub-expression of expression, if we are able to pick any sub-expression of expression surrounded by (), then we again left with () as part of string, we have redundant braces.
// We iterate through the given expression and for each character in the expression, if the character is an open parenthesis ( or any of the operators or operands, we push it to the stack. If the character is close parenthesis ), then pop characters from the stack till matching open parenthesis ( is found.
// Now for redundancy two condition will arise while popping-
// 1. If immediate pop hits an open parenthesis (, then we have found a duplicate parenthesis. For example, (((a+b))+c) has duplicate brackets around a+b. When we reach the second “)” after a+b, we have “((” in the stack. Since the top of stack is an opening bracket, we conclude that there are duplicate brackets.
// 2. If immediate pop doesnt hit any operand(*, +, /, -) then it indicates the presence of unwanted brackets surrounded by expression. For instance, (a)+b contain unwanted () around a thus it is redundant.
// solution
#include <bits/stdc++.h>
using namespace std;
int main()
{
cout << "Enter the string:" << endl;
string s;
cin >> s;
// create a stack of characters
stack<char> st;
bool ans = false;
// Iterate through the given expression
for (int i = 0; i < s.size(); i++)
{
if (s[i] == '+' or s[i] == '-' or s[i] == '*' or s[i] == '/')
{
st.push(s[i]);
}
else if (s[i] == '(')
{
// if current character is close parenthesis '('
st.push(s[i]);
}
else if (s[i] == ')')
{
// if current character is close parenthesis ')'
if (st.top() == '(')
{
ans = true;
}
while (st.top() == '+' or st.top() == '-' or st.top() == '*' or st.top() == '/')
{
st.pop();
}
st.pop();
}
}
if (ans)
{
cout << "True";
}
else
{
cout << "False";
}
}
// Input :
// For example:
// 1. ((a+b))
// 2. (a+b*(c-d))
// Output:
// 1. True, ((a+b)) can reduced to (a+b), this is Redundant
// 2. False, (a+b*(c-d)) doesn't have any redundant or multiple
// brackets

View File

@ -0,0 +1,178 @@
import java.util.*;
/*
Problem Name - Permutation Sequence
Description
The set [1, 2, 3, ..., n] contains a total of n! unique permutations.
By listing and labeling all of the permutations in order, we get the following sequence for n = 3:
1. "123"
2. "132"
3. "213"
4. "231"
5. "312"
6. "321"
Given n and k, return the kth permutation sequence.
Sample Cases:
Example 1:
Input: n = 3, k = 3
Output: "213"
Example 2:
Input: n = 4, k = 9
Output: "2314"
Example 3:
Input: n = 3, k = 1
// Output: "123"
Constraints:
1 <= n <= 9
1 <= k <= n!
You can also practice this question on LeetCode(https://leetcode.com/problems/permutation-sequence/)*/
/***Brute Force is to form an array of n size and then compute all the permutations and store it in the list and then trace it with (k-1)**
**Caution : the permutations should be in sorted order to get the answer**
*This will give TLE as we have to calculate all the permutations*
```
class Solution {
public String getPermutation(int n, int k) {
int ar[] = new int[n];
for(int x=1;x<=n;x++)
ar[x-1]=x;
List<List<Integer>> ans=new ArrayList<>();
backtrack(ans,new ArrayList<>(),ar);
String s="";
for(int x:ans.get(k-1))
s+=x;
return s;
}
public void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums){
if(tempList.size() == nums.length){
list.add(new ArrayList<>(tempList));
} else{
for(int i = 0; i < nums.length; i++){
if(tempList.contains(nums[i])) continue; // element already exists, skip
tempList.add(nums[i]);
backtrack(list, tempList, nums);
tempList.remove(tempList.size() - 1);
}
}
}
}
```
**Best Approach**
I'm sure somewhere can be simplified so it'd be nice if anyone can let me know. The pattern was that:
say n = 4, you have {1, 2, 3, 4}
If you were to list out all the permutations you have
1 + (permutations of 2, 3, 4)
2 + (permutations of 1, 3, 4)
3 + (permutations of 1, 2, 4)
4 + (permutations of 1, 2, 3)
We know how to calculate the number of permutations of n numbers... n! So each of those with permutations of 3 numbers means there are 6 possible permutations. Meaning there would be a total of 24 permutations in this particular one. So if you were to look for the (k = 14) 14th permutation, it would be in the
3 + (permutations of 1, 2, 4) subset.
To programmatically get that, you take k = 13 (subtract 1 because of things always starting at 0) and divide that by the 6 we got from the factorial, which would give you the index of the number you want. In the array {1, 2, 3, 4}, k/(n-1)! = 13/(4-1)! = 13/3! = 13/6 = 2. The array {1, 2, 3, 4} has a value of 3 at index 2. So the first number is a 3.
Then the problem repeats with less numbers.
The permutations of {1, 2, 4} would be:
1 + (permutations of 2, 4)
2 + (permutations of 1, 4)
4 + (permutations of 1, 2)
But our k is no longer the 14th, because in the previous step, we've already eliminated the 12 4-number permutations starting with 1 and 2. So you subtract 12 from k.. which gives you 1. Programmatically that would be...
k = k - (index from previous) * (n-1)! = k - 2*(n-1)! = 13 - 2*(3)! = 1
In this second step, permutations of 2 numbers has only 2 possibilities, meaning each of the three permutations listed above a has two possibilities, giving a total of 6. We're looking for the first one, so that would be in the 1 + (permutations of 2, 4) subset.
Meaning: index to get number from is k / (n - 2)! = 1 / (4-2)! = 1 / 2! = 0.. from {1, 2, 4}, index 0 is 1
so the numbers we have so far is 3, 1... and then repeating without explanations.
{2, 4}
k = k - (index from previous) * (n-2)! = k - 0 * (n - 2)! = 1 - 0 = 1;
third number's index = k / (n - 3)! = 1 / (4-3)! = 1/ 1! = 1... from {2, 4}, index 1 has 4
Third number is 4
{2}
k = k - (index from previous) * (n - 3)! = k - 1 * (4 - 3)! = 1 - 1 = 0;
third number's index = k / (n - 4)! = 0 / (4-4)! = 0/ 1 = 0... from {2}, index 0 has 2
Fourth number is 2
Giving us 3142. If you manually list out the permutations using DFS method, it would be 3142. Done! It really was all about pattern finding.
*/
public class permutation_sequence {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
System.out.println(getPermutation(n, k));
}
public static String getPermutation(int n, int k) {
List<Integer> numbers = new ArrayList<>();
StringBuilder s = new StringBuilder();
// create an array of factorial lookup
int fact[] = new int[n+1];
fact[0] = 1;
for(int x=1;x<=n;x++)
fact[x]=fact[x-1]*x;
// factorial[] = {1, 1, 2, 6, 24, ... n!}
// create a list of numbers to get indices
for(int x = 1 ;x <= n ;x++)
numbers.add(x);
k--;
// numbers = {1, 2, 3, 4}
for(int x = 1 ;x <= n ;x++ ){
int i=k/fact[n-x];
s.append(String.valueOf(numbers.get(i)));
numbers.remove(i);
k-=i*fact[n-x];
}
return s.toString();
}
}

View File

@ -36,6 +36,7 @@
- [Random Node in Linked List](Maths/algorithms_random_node.java)
- [Square Root using BinarySearch](Maths/square-root.java)
- [Roman Numerals Conversion](Maths/roman-numerals.java)
- [Permutation Sequence](Maths/permutation_sequence.java)
## Queues

View File

@ -51,6 +51,11 @@
- [Max Heap](src/heaps/max-heap.js)
- [Min Heap](src/heaps/min-heap.js)
## Graphs
- [Breadth First Search](src/graph/breadth-first-search.js)
- [Depth First Search](src/graph/depth-first-search.js)
## Trie
- [Trie Implementation](src/trie/trie-implementation.js)

View File

@ -0,0 +1,93 @@
// Program to print BFS traversal from a given source vertex s.
// breadthFirstSearch(graph, source) traverses vertices reachable from source.
// for the implementation we need the queue data structure;
// Queue class
class Queue {
// Array is used to implement a Queue
constructor() {
this.items = [];
}
// enqueue function
enqueue(element) {
// adding element to the queue
this.items.push(element);
}
// dequeue function
// removing element from the queue
// returns underflow when called
// on empty queue
dequeue() {
if (this.isEmpty()) {
return 'Underflow';
}
return this.items.shift();
}
// isEmpty function
isEmpty() {
// return true if the queue is empty.
return this.items.length == 0;
}
}
class Graph {
// defining vertex array and
// adjacent list
constructor(noOfVertices) {
this.noOfVertices = noOfVertices;
this.AdjList = new Map();
}
// add the requeired vertex in the graph
addVertex(v) {
this.AdjList.set(v, []);
}
// addition of edges in the graph as the added edge are bidirectional
addEdge(v, w) {
this.AdjList.get(v).push(w);
this.AdjList.get(w).push(v);
}
}
const breadthFirstSearch = (g, source) => {
const visited = {};
const q = new Queue();
visited[source] = true;
q.enqueue(source);
while (!q.isEmpty()) {
// Dequeue a vertex from queue and print it
const getQueueElement = q.dequeue();
console.log(getQueueElement);
const getList = g.AdjList.get(getQueueElement);
// Get all adjacent vertices of the dequeued
// vertex s. If a adjacent has not been visited,
// then mark it visited and enqueue it
for (let i = 0; i < getList.length; i++) {
const neigh = getList[i];
if (!visited[neigh]) {
visited[neigh] = true;
q.enqueue(neigh);
}
}
}
};
const g = new Graph(6);
// adding vertices
for (let i = 1; i <= 6; i++) {
g.addVertex(i);
}
g.addEdge(1, 2);
g.addEdge(2, 4);
g.addEdge(3, 1);
g.addEdge(1, 4);
g.addEdge(5, 3);
g.addEdge(6, 3);
breadthFirstSearch(g, 6);
// when we start bfs for the given graph from point 6 the output is as follow;
// output 6 3 1 5 2 4
// Time complexity: O(n), where n is the number of vertices in graph
// Space complexity: O(n), where n is the number of vertices in graph

View File

@ -0,0 +1,56 @@
class Graph {
// defining vertex array and
// adjacent list
constructor(noOfVertices) {
this.noOfVertices = noOfVertices;
this.AdjList = new Map();
}
// add the requeired vertex in the graph
addVertex(v) {
this.AdjList.set(v, []);
}
// addition of edges in the graph as the added edge are bidirectional
addEdge(v, w) {
this.AdjList.get(v).push(w);
this.AdjList.get(w).push(v);
}
}
// Recursive function which process and explore
// all the adjacent vertex of the vertex with which it is called
const depthFirstSearch = (g, currVertex, visited) => {
visited[currVertex] = true;
console.log(currVertex);
const getNeighbours = g.AdjList.get(currVertex);
// Recursive call for the non visited vertex
for (let i = 0; i < getNeighbours.length; i++) {
const getElement = getNeighbours[i];
if (!visited[getElement]) {
depthFirstSearch(g, getElement, visited);
}
}
};
const g = new Graph(6);
const visited = {};
// adding vertices
for (let i = 1; i <= 6; i++) {
g.addVertex(i);
}
g.addEdge(1, 2);
g.addEdge(2, 4);
g.addEdge(3, 1);
g.addEdge(1, 4);
g.addEdge(5, 3);
g.addEdge(6, 3);
depthFirstSearch(g, 6, visited);
// for the given graph when we explore it from vertex 6 the output is as follow;
// output 6 3 1 2 4 5
// TIME COMPLEXITY OF THE PROGRAM
// O(V+E)
// where V is number of vertices
// and E is number of edges

View File

@ -33,3 +33,7 @@ require('./stacks/two-stack');
// Queue
require('./queues/queue');
//Graphs
require('./graph/breadth-first-search');
require('./graph/depth-first-search');