A binary search tree (BST) is a data structure that is commonly used in computer science to store and retrieve data efficiently. It is called a "binary" search tree because each node has at most two children, and it is called a "search" tree because it allows for efficient search and retrieval of data.

All elements on left are less than the root and all elements on right are greater than the root!

**Time Complexity**:

Access -> O(n).

Deletion -> O(n).

Searching -> O(n)

Insertion -> O(n)

Inorder traversal is sorted!

https://leetcode.com/problems/search-in-a-binary-search-tree/

```
public class BinarySearchTree {
// Node class represents a node in the binary tree
static class Node {
int value;
Node left;
Node right;
// Constructor to create a new node
Node(int value) {
this.value = value;
left = null;
right = null;
}
}
// Root of the binary tree
Node root;
// Constructor to create a binary search tree
BinarySearchTree() {
root = null;
}
// Method to search a value in the binary tree
boolean search(int value) {
return search(root, value);
}
// Helper method to search a value in the binary tree
boolean search(Node node, int value) {
// If the tree is empty, return false
if (node == null) {
return false;
}
// If the value is found at the root, return true
if (node.value == value) {
return true;
}
// Recursively search in the left or right subtree
if (value < node.value) {
return search(node.left, value);
} else {
return search(node.right, value);
}
}
}
```

Kth largest node

So this is it for this article. I hope it helped you somewhere. Don't forget to support us and share with other geekians.

Thank you, Have a nice day !!

]]>Preorder (DFS)

- Operations order: root -> left -> right

Inorder (DFS)

- Operations order: left -> node -> right

Postorder (DFS)

Operations order: reft -> right -> root

Operations order: right -> left -> root [Reverse post order]

In all above we traverse a complete branch first!

Time complexity is O(N). Why? Recursion says time complexity should be 2^N

- There is only one choice go to its children

Prefer post-order traversal if not specified. The structure is similar to DP.

Calculate answers for children and from that answer for parents.

Level order (BFS)

We are going level by level!

Get these traversals right! Very important!

You can construct a binary tree from any two traversals!

eg: https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/

When the sum is only from top to bottom

When the sum passes through a node

eg: https://www.geeksforgeeks.org/find-largest-subtree-sum-tree/

Longest distance between two nodes of a binary tree !

https://www.geeksforgeeks.org/find-maximum-path-sum-two-leaves-binary-tree/

https://www.geeksforgeeks.org/lowest-common-ancestor-binary-tree-set-1/

https://www.geeksforgeeks.org/lowest-common-ancestor-in-a-binary-search-tree/

So this is it for this article. I hope it helped you somewhere. Don't forget to support us and share with other geekians.

Thank you, Have a nice day !!

]]>A tree is a data structure that is commonly used in computer science to store and organize data in a hierarchical manner. At the top of the tree is a root node, which branches out into multiple child nodes. Each child node can then have its own child nodes, creating a tree-like structure.

Special directed/undirected graph with N nodes and N-1 edges.

Each node is can be reached from other nodes by some path.

No cycles.

Directed when you can only go from parent to child.

```
public class TreeNode {
private int value;
List<TreeNode> children;
}
```

- Usually tree problems are asked for binary tree.

- It is a hierarchical structure consisting of nodes, where each node has at most two children. The children of a node are referred to as the left child and the right child.

```
public class BinaryTreeNode {
private int data;
private BinaryTreeNode left;
private BinaryTreeNode right;
public BinaryTreeNode(int data) {
this.data = data;
this.left = null;
this.right = null;
}
public int getData() {
return this.data;
}
public void setData(int data) {
this.data = data;
}
public BinaryTreeNode getLeft() {
return this.left;
}
public void setLeft(BinaryTreeNode left) {
this.left = left;
}
public BinaryTreeNode getRight() {
return this.right;
}
public void setRight(BinaryTreeNode right) {
this.right = right;
}
}
```

Special binary trees

Complete binary tree.

Full binary tree.

No of nodes in a full binary tree

Height of full binary tree - log (number of nodes)

2^H - 1 = total nodes

H = log (total nodes)

Binary search tree (Explained in another blog)

Balanced binary tree (AVL , Red black)

Operations on Binary Tree or detailed explanation of Binary and Binary Search Tree will be in next blog. Keep in touch.

So this is it for this article. I hope it helped you somewhere. Don't forget to support us and share with other geekians.

Thank you, Have a nice day !!

]]>Dynamic programming is a powerful technique for solving complex problems by breaking them down into smaller subproblems. This approach allows for the optimization of computational resources by avoiding redundant calculations and ensuring that each subproblem is only solved once.

DP = recursion + memoization.

It is an optimization over recursion.

**Memoization:**It involves storing the results of previously computed subproblems in a table or other data structure, to avoid having to recompute them in the future.

```
public static int fibonacci(int n) {
// Declare an array to store the fibonacci numbers
int[] fib = new int[n + 1];
// Initialize the first two numbers in the sequence
fib[0] = 0;
fib[1] = 1;
// Calculate the remaining fibonacci numbers
for (int i = 2; i <= n; i++) {
fib[i] = fib[i - 1] + fib[i - 2];
}
// Return the nth fibonacci number
return fib[n];
}
```

**Overlapping Subproblems**: When the solutions to the same subproblems are needed repetitively for solving the actual problem. The problem is said to have overlapping subproblems property.**Optimal Substructure Property**: If the optimal solution of the given problem can be obtained by using optimal solutions of its subproblems then the problem is said to have Optimal Substructure Property.

**Bottom-Up Approach (Tabulation):**In this approach, the problem is solved by starting from the smallest subproblems and gradually building up to larger and more complex solutions. This method is often used when the subproblems have overlapping solutions, as it allows for the efficient reuse of previously computed results.`// Tabulated version to find factorial x. int dp[MAXN]; // base case int dp[0] = 1; for (int i = 1; i< =n; i++) { dp[i] = dp[i-1] * i; }`

**Top-Down Approach (Memoization):**In this approach, the problem is solved by starting from the largest, most complex subproblem and working downwards to smaller subproblems. This method is often used when the subproblems have distinct solutions and do not overlap, as it allows for a more efficient and concise solution.`// initialized to -1 int dp[MAXN] // return fact x! int solve(int x) { if (x==0) return 1; if (dp[x]!=-1) return dp[x]; return (dp[x] = x * solve(x-1)); }`

Thank you, Have a nice day !!

Backtracking is a common technique used in computer programming to solve problems by exploring all possible solutions to a given problem and then choosing the best one. It is often used in situations where a problem has multiple solutions and it is not clear which one is the best.

General backtracking algorithm

if the current point is a feasible solution, return success.

else if all paths are exhausted (i.e current point is an endpoint), return failure, since we have no feasible solution.

else if the current point is not an endpoint, backtrack and explore other points and repeat the above steps.

One common example of backtracking is the use of the depth-first search algorithm in the tree traversal. In this algorithm, the algorithm starts at the root of the tree and explores as far as possible along each branch before backtracking and trying a different path. This allows the algorithm to quickly find a solution to the problem by quickly exploring all possibilities.

For example, suppose we are trying to solve a maze by finding the shortest path from the start to the finish. We could use a backtracking approach to this problem by breaking it down into smaller subproblems, such as finding the shortest path from the current position to the next intersection, and then to the next intersection after that, and so on. However, if we reach a dead end, we must backtrack and try a different path. This would look something like this:

```
function solveMaze(maze, currentPosition, destination):
if (currentPosition == destination):
return true
mark currentPosition as visited
for each possible move from currentPosition:
if move is valid:
if (solveMaze(maze, newPosition, destination) == true):
return true
unmark currentPosition
return false
```

Program Explanation:

Create a function that takes in the maze, the current position, and the destination as parameters.

Check if the current position is equal to the destination. If it is, return true to indicate that a path has been found.

Mark the current position as visited.

Check all possible moves from the current position (up, down, left, and right). If the move is valid (i.e. within the bounds of the maze and not a wall), then recursively call the function with the new position as the current position. If the recursive call returns true, then return true to indicate that a path has been found.

If none of the moves is successful, unmark the current position and return false to indicate that no path has been found.

Backtracking uses recursion to solve the problem i.e All backtracking are recursion but not all recursions are backtracking.

Backtracking essentially means try out all possible combinations.

Factorial is technically not backtracking because there is only one path.

Rat maze is backtracking:

https://www.geeksforgeeks.org/rat-in-a-maze-backtracking-2/Backtracking is given as the first brute-force solution for many problems.

**Note:** Most important thing in backtracking is to be able to identify the state and think about the choices eg: Take, do not take etc.

Thank you, Have a nice day !!

]]>Recursion is a method of solving a problem by breaking it down into smaller, simpler subproblems. In other words, it is a way of defining a problem in terms of itself.

When a function calls itself.

Recursion is often used in data structures, such as linked lists and trees, to traverse and manipulate the data in those structures.

To solve a recursion problem identify the following things:

What are the subproblems i.e choices?

What is the recursion state?

What is the base case?

```
public static int fibo(int n) { //state
if (n <= 1) { // Base case or terminating condition
return n;
}
return fibo(n-1) + fibo(n-2);
}
```

Problems can be broken down into smaller problems.

There is a terminating condition/base case.

N is very small (N <= 24).

Mathematical description of a recursion

fibo(n) = fibo(n-1) + fibo(n-2), n >= 2

`1, n < 2`

Recursion creates a DFS tree when executing.

Visualisation: https://visualgo.net/bn/recursion

For every recursion, you should be able to visualise the recursion tree.

No of nodes in the recursion tree * No of operations per node. Try drawing a small recursion tree to estimate.

For fibo: 2^N * 1

https://www.interviewbit.com/problems/reccmpl2/ [Draw recursion tree]

Generally, it is of the form: (X^Y)*P where X = no of choices, Y = total states, P = No of operations per state

Recursion uses a stack to come back to the calling function i.e it stores meta information like memory address, state etc. So we use at least O(Size of stack memory).

Example: fact(n) = n*fact(n-1)

Visualization: https://www.educative.io/courses/recursion-for-coding-interviews-in-java/xl7GjENLLvE

If we define extra variables at states then that memory is added up.

Thank you, Have a nice day !!

]]>A stack is a linear data structure that stores items in a

**Last-In/First-Out (LIFO)**manner.A stack is typically implemented using an array or a linked list.

The basic operations that can be performed on a stack are:

`Push`

: Adds an item to the top of the stack`Pop`

: Removes an item from the top of the stack`Peek`

: Returns the item at the top of the stack without removing it

**Time Complexity**:Access -> at O(n).

Deletion at O(1).

Searching -> O(n)

Insertion -> O(1)

Push back, pop front i.e process the last element again

eg: https://www.interviewbit.com/problems/simplify-directory-path/

https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string/

Next smaller / larger element

eg: https://www.interviewbit.com/problems/nearest-smaller-element/

Valid parentheses as a use case

eg: https://www.geeksforgeeks.org/check-for-balanced-parentheses-in-an-expression/

- By maintaining scores:

eg: https://leetcode.com/problems/minimum-add-to-make-parentheses-valid/

- By maintaining scores:
Direct operations over stack

For recursion

eg: DFS https://leetcode.com/problems/binary-tree-preorder-traversal/

Stacks are widely used in many applications. Some of the common examples are:

The undo/redo functionality in text editors

Balancing symbols in programming languages

Backtracking in algorithms such as depth-first search

Function calls in programming languages

Thank you, Have a nice day !!

]]>Linear data structure where operations are performed in First In First Out

**(FIFO)**order.**FIFO:**push_back, pop_front.**Time Complexity**:Access -> at O(n).

Deletion at O(1).

Searching -> O(n)

Insertion -> O(1)

For all implementation purposes:

**queue = list**- It gives four operations: push_back, pop_back, pop_front, push_front

**Note**that since**queue = DLL**as we can access both ends. All DLL questions are basically queue questions.

eg: LRUAlso Linear Queue is generally used to implement other algorithms, majorly

**Sliding window**https://www.geeksforgeeks.org/sliding-window-maximum-maximum-of-all-subarrays-of-size-k/

**Note**that we may also use unordered_set/map to implement the same . In Fact this is the preferred method.

**Level order traversal****BFS**

**To do things in order of arrival**https://www.interviewbit.com/problems/first-non-repeating-character-in-a-stream-of-characters/

LRU is also a similar example

Maintain elements in a sorted tree.

**Push**: O(log n)**Top/Pop**: O(1)**Construction**: O(N)Two variants:

Min heap

Max heap

Can be implemented using

Priority queue data structure: https://www.geeksforgeeks.org/priority-queue-in-cpp-stl/

Using a set since the definition ~= Set

begin() -> Priority queue top

erase() -> Priority queue pop

Use multiset if duplicate elements are allowed

Custom comparator if reverse ordering is required

```
bool lex_compare(const int64_t &a, const int64_t &b)
{
stringstream s1,s2;
s1 << a;
s2 << b;
return s1.str() < s2.str();
}
set<int64_t, lex_compare> s;
```

```
class MyNameComp implements Comparator<Empl>{
@Override
public int compare(Empl e1, Empl e2) {
return e1.getName().compareTo(e2.getName());
}
}
TreeSet<Empl> nameComp = new TreeSet<Empl>(new MyNameComp());
```

When to use?

Maintain elements in sorted fashion while iterating (Similar to a Set).

Difference is that you are only maintaining top K elements OR Reduce space complexity to O(k) OR Reduce time complexity to N log K.

**Note**that: All priority queue questions are basically set questions. Even the O(K) questions can be done using a set of size K.

Thank you, Have a nice day !!

]]>Linear data structure with dynamic memory allocation.

**Time Complexity**:Access -> at O(n).

Deletion at O(1).

Searching -> O(n)

Insertion -> O(1)

**Types**:**Singly Linked List**: Can only be iterated from beginning**Doubly linked list**: Can be iterated from both beginning and end

eg: https://www.geeksforgeeks.org/count-triplets-sorted-doubly-linked-list-whose-sum-equal-given-value-x/**Circular linked list:**

eg: https://leetcode.com/problems/design-circular-queue/

**Delete a node**Delete by value is O(N)

Delete by address O(1):

https://www.geeksforgeeks.org/delete-a-node-from-linked-list-without-head-pointer/

**Find kth node from beginning / end O(K)**https://leetcode.com/problems/remove-nth-node-from-end-of-list/

**Find cycle in a linked list****Reverse****Swap nodes****Copy linked list**https://www.geeksforgeeks.org/a-linked-list-with-next-and-arbit-pointer/

Doubly linked list is used as a queue

Linked list with other data structures

**Linked list & Map**

**Linked list & Priority queue**

https://leetcode.com/problems/merge-k-sorted-lists/

Thank you, Have a nice day !!

]]>Binary Search is a searching algorithm which can be used on the sorted array to reduce the time complexity from O(n) to O(log n) where n is the number of elements in an array.

It works by repeatedly dividing the search space in half until the target element is found or it is clear that the element is not present in the array.

It can be used to find the lower bound and upper bound in search space.

```
public static int findLowerBound(int[] array, int target) {
int low = 0;
int high = array.length - 1;
while (low < high) {
int mid = (low + high) / 2;
if (array[mid] < target) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
```

```
public static int findUpperBound(int[] array, int target) {
int low = 0;
int high = array.length - 1;
while (low < high) {
int mid = (low + high + 1) / 2;
if (array[mid] > target) {
high = mid - 1;
} else {
low = mid;
}
}
return low;
}
```

Binary Search can have two search spaces:

On Problem

https://leetcode.com/problems/find-smallest-letter-greater-than-target/On Answer

https://www.interviewbit.com/problems/square-root-of-integer/

Thank you, Have a nice day !!

]]>Same or similar data type at contiguous memory locations.

**Time Complexity**:Access -> at O(1).

Deletion at O(n).

Searching -> O(n)

Insertion -> O(n)

**Types**:1-dimensional

Multi-dimesional

For an array problem, these are the only approaches through which we can solve it.

**Iteration:**In this approach, we can solve the problem by just iterating over the array or storing some information while iterating using some extra space like map, set etc and comes to a solution.

eg: https://leetcode.com/problems/best-time-to-buy-and-sell-stock/

**Iteration after Sorting:**In this technique, first we sort the array then iterate over it.

eg: https://leetcode.com/problems/merge-intervals/

**Two Pointer**: Here, we use 2 pointers I and j or Start and end. When we are using two pointers or how to decide whether these pointers from same side or opposite side, we have to make sure the behavior of both pointers must be opposite.### Two Pointers from Opposite side

```
eg: [https://www.interviewbit.com/problems/diffk/](https://www.interviewbit.com/problems/diffk/)
![Untitled (2).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1668341138646/pTp1Fmqoe.png align="left")
```

**Prefix Sum**: It is a technique which is used to solve many queries in constant time instead of linear time. And we can say its a form of Dynamic Programming.

eg: https://www.geeksforgeeks.org/find-if-there-is-a-subarray-with-0-sum/

Thank you, Have a nice day !!

]]>The computation time taken by a piece of code or an algorithm.

**Big-O Notation**: Upper Bound**Theta Notation**: In between upper and lower bound**Omega Notation:**Lower Bound

But generally we used the ** Big-O Notation** to express the time complexity in programming world.

- Constant Time Complexity: O(1)
- Linear Time Complexity: O(n)
- Logarithmic Time Complexity: O(log n)
- Quadratic Time Complexity: O(n)
- Exponential Time Complexity: O(2^n)

So, to calculate time complexity, you should count the number of operations in a program. And, No of operations that can be performed in one second by a machine = 10^7

For example,

Array size = 4*10^7 -> This means you can iterate the array only once. O(N)

solution is needed.

Array size = 10^3. O(N^2) at max.

Array size = 10^5. O(N) or O(N log N)

Array size = 10 O(2^N)

Matrix N = 1000, M = 1000. Complexity O(N*M).

This is how you can look at the constraint and tell what time complexity will be needed.

So this is it for this article. I hope it helped you somewhere. Don't forget to support us and share with other geekians.Thank you, Have a nice day !!

]]>Welcome to this domain. I have started this to share my knowledge with all of you guys. I will share the blogs related to the Data Structures and Algorithms, Interview preparation, Java, Microservices etc.

It would be grateful if i can help you in anyways.

Geeky Girl

]]>