Yeh guide aapko (means meri baby Snehu) Data Structures aur Algorithms (DSA) ke important topics interview style mein samjhayegi. Hum Hinglish (Hindi + English) ka use karenge taaki concepts aasani se samajh aayein. Har topic mein definition, use cases, real-life analogies, code snippets aur kuch interactive elements honge.
Note: Animations simple rakhe gaye hain for clarity and performance in a single file. Advanced libraries ka potential dikhane ke liye kuch examples hain.
Definition: Array ek contiguous memory locations ka collection hota hai, jahan hum same type ke items store karte hain. Iska size generally fixed hota hai creation ke time pe.
Where & Why Used (Kahan aur Kyun): Jab aapko pata ho ki kitne items store karne hain aur aapko fast access chahiye by index (position). Jaise ki students ke marks, ya ek list of names.
Real-life Analogy (Asal Zindagi ki Misaal): Ek egg tray socho. Usmein fixed number of slots (e.g., 12) hote hain, aur har slot mein ek anda (same type item) rakha jaata hai. Aap direct kisi bhi slot (index) se anda utha sakte ho. Ya fir ek kitaabon ki shelf jisme har kitaab ek specific position par rakhi hai.
Pros: Fast access (O(1)) if you know the index. Cache friendly.
Cons: Fixed size. Insertion/deletion beech mein costly (O(n)) ho sakta hai kyunki elements shift karne padte hain.
let fruits = ["Apple", "Banana", "Orange"];
console.log(fruits[0]); // Output: Apple (Accessing by index)
fruits.push("Mango"); // Adding at the end (efficient if space available)
console.log(fruits); // Output: ["Apple", "Banana", "Orange", "Mango"]
// Insert "Grapes" at index 1 (can be costly)
fruits.splice(1, 0, "Grapes");
console.log(fruits); // Output: ["Apple", "Grapes", "Banana", "Orange", "Mango"]
Definition: Linked List ek linear data structure hai jahan elements (nodes) sequence mein toh hote hain, par memory mein kahin bhi scattered ho sakte hain. Har node mein data aur next node ka pointer/reference hota hai.
Where & Why Used: Jab dynamic size chahiye (elements easily add/remove kar sakein) aur random access ki zaroorat na ho. Insertion/deletion (especially at ends) arrays se efficient ho sakta hai (O(1) if you have pointer to previous node for deletion, or pointer to tail for insertion at end).
Real-life Analogy: Ek treasure hunt socho. Har clue (node) aapko batata hai ki agla clue (next node) kahan milega. Ya fir train ke coaches, har coach (node) agle coach se juda hota hai.
Types: Singly Linked List (sirf next pointer), Doubly Linked List (next aur previous pointers), Circular Linked List (last node points to first).
Pros: Dynamic size. Efficient insertion/deletion at ends (and middle if pointer is known).
Cons: Random access nahi hota (O(n) to reach an element). Extra memory for pointers.
class Node {
constructor(data) {
this.data = data;
this.next = null;
}
}
class LinkedList {
constructor() {
this.head = null;
}
append(data) { // Add to end
const newNode = new Node(data);
if (!this.head) {
this.head = newNode;
return;
}
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = newNode;
}
printList() {
let current = this.head;
let listStr = "";
while (current) {
listStr += current.data + " -> ";
current = current.next;
}
console.log(listStr + "null");
}
}
let list = new LinkedList();
list.append(10);
list.append(20);
list.append(30);
list.printList(); // Output: 10 -> 20 -> 30 -> null
(p5.js visualization for Linked List could be complex; showing conceptual nodes below)
Definition: Recursion ek programming technique hai jahan ek function khud ko call karta hai (directly ya indirectly) ek chote version of the problem ko solve karne ke liye. Har recursive call problem ko simple banata hai jab tak woh base case tak na pahunch jaaye.
Where & Why Used: Problems jo naturally recursive structure follow karti hain, jaise tree traversals, factorial, Fibonacci series, divide and conquer algorithms (Merge Sort, Quick Sort). Code often elegant aur problem definition ke close hota hai.
Real-life Analogy: Russian nesting dolls (Matryoshka dolls). Har doll ke andar ek choti doll hoti hai, jab tak sabse choti doll na mil jaaye (base case). Ya fir ek set of mirrors facing each other, creating infinite reflections (agar base case na ho!).
Key Components: 1. Base Case: Woh condition jahan recursion ruk jaata hai. Bahut important hai infinite loop se bachne ke liye. 2. Recursive Step: Function khud ko call karta hai, problem ko chota karke.
Pros: Elegant solutions for certain problems. Complex problems ko break down karna aasan.
Cons: Can be less efficient due to function call overhead. Stack overflow ka risk agar recursion bahut deep ho. Debugging thoda tricky ho sakta hai.
function factorial(n) {
// Base Case
if (n === 0 || n === 1) {
return 1;
}
// Recursive Step
return n * factorial(n - 1);
}
console.log(factorial(5)); // Output: 120 (5 * 4 * 3 * 2 * 1)
Visualizing recursion stack can be complex. Imagine function calls piling up, then resolving one by one.
Definition: Time Complexity batata hai ki ek algorithm ko run hone mein kitna time lagega as a function of input size (n). Hum ise usually Big O Notation mein express karte hain. Yeh actual time (seconds/milliseconds) nahi batata, balki growth rate batata hai jab input size badhta hai.
Why Important: Efficient algorithms choose karne ke liye. Ek algorithm jo chhote input pe fast hai, woh bade input pe bahut slow ho sakta hai. Time complexity se hum predict kar sakte hain.
Common Functions (Growth Rates):
Notations:
// O(n) - Linear
function findElement(arr, target) {
for (let i = 0; i < arr.length; i++) { // Loop runs 'n' times
if (arr[i] === target) {
return i;
}
}
return -1;
}
// O(n^2) - Quadratic
function hasDuplicates(arr) {
for (let i = 0; i < arr.length; i++) { // Outer loop: n times
for (let j = i + 1; j < arr.length; j++) { // Inner loop: roughly n times
if (arr[i] === arr[j]) {
return true;
}
}
}
return false;
}
Definition: Stack ek linear data structure hai jo LIFO (Last-In, First-Out) principle follow karta hai. Matlab, jo item sabse aakhir mein add hua, woh sabse pehle remove hoga.
Operations:
Where & Why Used: Function calls (call stack), undo/redo operations in software, expression evaluation (infix to postfix), backtracking algorithms (like maze solving).
Real-life Analogy: Plates ka stack. Aap sabse upar wali plate hi uthate ho (pop), aur nayi plate bhi sabse upar rakhte ho (push). Ya browser ka back button history.
Implementation: Can be implemented using Arrays or Linked Lists.
class Stack {
constructor() {
this.items = [];
}
push(element) {
this.items.push(element); // Array's push adds to end (our 'top')
}
pop() {
if (this.isEmpty()) {
return "Underflow - Stack is empty";
}
return this.items.pop(); // Array's pop removes from end
}
peek() {
if (this.isEmpty()) {
return "Stack is empty";
}
return this.items[this.items.length - 1];
}
isEmpty() {
return this.items.length === 0;
}
printStack() {
console.log(this.items.join(" <- "));
}
}
let myStack = new Stack();
myStack.push(10);
myStack.push(20);
myStack.push(30);
myStack.printStack(); // Output: 10 <- 20 <- 30 (30 is top)
console.log("Popped:", myStack.pop()); // Popped: 30
console.log("Peek:", myStack.peek()); // Peek: 20
myStack.printStack(); // Output: 10 <- 20
Definition: Queue bhi ek linear data structure hai, lekin yeh FIFO (First-In, First-Out) principle follow karta hai. Matlab, jo item sabse pehle add hua, woh sabse pehle remove hoga.
Operations:
Where & Why Used: Printer queues, CPU task scheduling, Breadth-First Search (BFS) in graphs, call center phone systems, message queues in distributed systems.
Real-life Analogy: Cinema hall ki ticket line. Jo log pehle line mein lagte hain, unko ticket pehle milti hai. Log line ke peeche (rear) judte hain aur aage (front) se nikalte hain.
Implementation: Can be implemented using Arrays (circular array is efficient) or Linked Lists.
class Queue {
constructor() {
this.items = [];
}
enqueue(element) {
this.items.push(element); // Add to end (rear)
}
dequeue() {
if (this.isEmpty()) {
return "Underflow - Queue is empty";
}
return this.items.shift(); // Remove from beginning (front)
}
front() {
if (this.isEmpty()) {
return "Queue is empty";
}
return this.items[0];
}
isEmpty() {
return this.items.length === 0;
}
printQueue() {
console.log("Front -> " + this.items.join(" -> ") + " <- Rear");
}
}
let myQueue = new Queue();
myQueue.enqueue(10);
myQueue.enqueue(20);
myQueue.enqueue(30);
myQueue.printQueue(); // Output: Front -> 10 -> 20 -> 30 <- Rear
console.log("Dequeued:", myQueue.dequeue()); // Dequeued: 10
console.log("Front:", myQueue.front()); // Front: 20
myQueue.printQueue(); // Output: Front -> 20 -> 30 <- Rear
Definition: Deque (pronounced "deck"), ya Double-Ended Queue, ek generalized version hai queue ka. Ismein elements dono ends (front aur rear) se add (enqueue) aur remove (dequeue) kiye ja sakte hain.
Operations:
Where & Why Used: Palindrome checker, sliding window problems, undo/redo (more complex scenarios), task scheduling where priority tasks can be added to front.
Real-life Analogy: Ek deck of cards jahan se aap dono taraf se cards nikal sakte ho ya daal sakte ho. Ya fir ek line jahan log dono taraf se enter aur exit kar sakte hain (though less common).
Implementation: Usually implemented using Doubly Linked Lists or dynamic arrays with careful management of front/rear pointers.
class Deque {
constructor() {
this.items = [];
}
addFront(element) { this.items.unshift(element); } // Add to beginning
addRear(element) { this.items.push(element); } // Add to end
removeFront() { return this.isEmpty() ? "Empty" : this.items.shift(); } // Remove from beginning
removeRear() { return this.isEmpty() ? "Empty" : this.items.pop(); } // Remove from end
getFront() { return this.isEmpty() ? "Empty" : this.items[0]; }
getRear() { return this.isEmpty() ? "Empty" : this.items[this.items.length - 1]; }
isEmpty() { return this.items.length === 0; }
printDeque() { console.log("Front <-> " + this.items.join(" <-> ") + " <-> Rear"); }
}
let myDeque = new Deque();
myDeque.addRear(20); // [20]
myDeque.addFront(10); // [10, 20]
myDeque.addRear(30); // [10, 20, 30]
myDeque.printDeque(); // Front <-> 10 <-> 20 <-> 30 <-> Rear
console.log("Removed Rear:", myDeque.removeRear()); // 30
console.log("Removed Front:", myDeque.removeFront()); // 10
myDeque.printDeque(); // Front <-> 20 <-> Rear
(Deques animation would be similar to queue but with actions at both ends)
Definition: Tree ek non-linear, hierarchical data structure hai jo nodes se bana hota hai. Topmost node ko root kehte hain. Har node ka data aur uske children (child nodes) ke references ho sakte hain. Jin nodes ke koi children nahi hote, unhe leaf nodes kehte hain.
Terminology:
Where & Why Used: Representing hierarchical data like file systems, organization charts, XML/HTML DOM structure, decision trees in AI, routing algorithms. Binary Search Trees (BSTs) are used for efficient searching and sorting.
Real-life Analogy: Family tree, company's organizational structure, file explorer in your computer.
Types: Binary Tree (max 2 children per node), Binary Search Tree (BST), AVL Tree, Red-Black Tree, N-ary Tree (any number of children), etc.
class TreeNode {
constructor(data) {
this.data = data;
this.left = null; // For Binary Tree, left child
this.right = null; // For Binary Tree, right child
}
}
// Example: Creating a simple binary tree
let root = new TreeNode(10);
root.left = new TreeNode(5);
root.right = new TreeNode(15);
root.left.left = new TreeNode(3);
root.left.right = new TreeNode(7);
// 10
// / \
// 5 15
// / \
// 3 7
console.log("Root:", root.data); // Root: 10
console.log("Root's Left Child:", root.left.data); // Root's Left Child: 5
(A p5.js sketch will attempt to draw a simple tree here)
Definition: Binary Search Tree (BST) ek special type ka Binary Tree hai jismein har node ke liye yeh properties hold karti hain:
Where & Why Used: Efficient searching (average O(log n)), insertion (average O(log n)), deletion (average O(log n)). Sorted order traversal (In-order traversal) deta hai. Used in dictionaries, symbol tables, set implementations.
Real-life Analogy: Ek dictionary. Aap ek word search karte ho, agar current word se chota hai toh pehle ke pages mein dekhte ho (left), bada hai toh baad ke pages mein (right).
Worst Case: Agar tree skewed (ek hi taraf saare nodes, like a linked list) ho jaaye, toh operations O(n) ho jaate hain. Isiliye self-balancing BSTs (like AVL, Red-Black) use hote hain.
// TreeNode class is same as above
class BST {
constructor() {
this.root = null;
}
insert(data) {
const newNode = new TreeNode(data);
if (!this.root) {
this.root = newNode;
return;
}
this._insertNode(this.root, newNode);
}
_insertNode(node, newNode) {
if (newNode.data < node.data) {
if (!node.left) {
node.left = newNode;
} else {
this._insertNode(node.left, newNode);
}
} else {
if (!node.right) {
node.right = newNode;
} else {
this._insertNode(node.right, newNode);
}
}
}
search(data) {
return this._searchNode(this.root, data);
}
_searchNode(node, data) {
if (!node) return null; // Not found
if (data < node.data) return this._searchNode(node.left, data);
else if (data > node.data) return this._searchNode(node.right, data);
else return node; // Found
}
}
let bst = new BST();
bst.insert(50); bst.insert(30); bst.insert(70);
bst.insert(20); bst.insert(40); bst.insert(60); bst.insert(80);
// 50
// / \
// 30 70
// / \ / \
// 20 40 60 80
console.log("Search for 40:", bst.search(40) ? "Found" : "Not Found"); // Found
console.log("Search for 90:", bst.search(90) ? "Found" : "Not Found"); // Not Found
BST Search Animation (Conceptual): Highlight path from root to target.
Definition: AVL Tree ek self-balancing Binary Search Tree hai. "AVL" Adelson-Velsky aur Landis ke naam se aata hai, jinhone ise invent kiya. Har node mein ek "balance factor" store hota hai (height of right subtree - height of left subtree). Yeh factor -1, 0, ya 1 hona chahiye.
Why Self-Balancing? Normal BSTs worst-case mein O(n) performance de sakte hain (jab woh skewed ho jaate hain). AVL trees ensure karte hain ki tree hamesha balanced rahe, isliye search, insert, delete operations O(log n) time mein guarantee hote hain.
How it Works: Jab bhi koi element insert ya delete hota hai, tree check karta hai ki balance factor disturb toh nahi hua. Agar hua (value -2 ya +2 ho gayi), toh rotations perform kiye jaate hain tree ko rebalance karne ke liye.
Where & Why Used: Situations jahan frequent lookups (search) ki zaroorat ho aur O(log n) worst-case performance guarantee chahiye. Databases, dictionaries, scenarios where insertions/deletions kam hain compared to lookups (kyunki rotations thoda overhead add karte hain).
Pros: Guaranteed O(log n) for all operations. Faster lookups than Red-Black trees (generally stricter balance).
Cons: Stricter balancing leads to more frequent rotations during insertion/deletion compared to Red-Black trees, so insertions/deletions can be slightly slower. Implementation complex hai.
// TreeNode for AVL would also store height and balance factor
class AVLNode extends TreeNode { // Assuming TreeNode is defined
constructor(data) {
super(data);
this.height = 1; // Height of this node
}
}
// Key operations in AVL:
// 1. getHeight(node)
// 2. getBalanceFactor(node)
// 3. rightRotate(yNode)
// 4. leftRotate(xNode)
// 5. insertNode(node, data) - with rebalancing logic
// Example of a rotation (Conceptual):
// If a node Z becomes unbalanced due to insertion in left child (Y)
// and left-left grandchild (X) (LL case):
//
// Z (unbalanced, BF= -2)
// /
// Y (BF= -1 or 0)
// /
// X
//
// After Right Rotation on Z:
//
// Y
// / \
// X Z
function rightRotate(z) {
let y = z.left;
let T3 = y.right;
// Perform rotation
y.right = z;
z.left = T3;
// Update heights (order matters)
z.height = Math.max(getHeight(z.left), getHeight(z.right)) + 1;
y.height = Math.max(getHeight(y.left), getHeight(y.right)) + 1;
return y; // New root of this subtree
}
// getHeight and other functions would be needed.
(AVL tree rotations are best visualized with diagrams/videos. Simulating them here is complex.)
Definition: Heap ek special tree-based data structure hai jo "Heap Property" satisfy karta hai. Heaps are usually complete binary trees.
Heap Property:
Where & Why Used: Priority Queues (heap is the most common way to implement them), Heap Sort algorithm, finding kth smallest/largest element, graph algorithms like Dijkstra's and Prim's.
Real-life Analogy (for Min-Heap): A company's hierarchy where the CEO (root) has the highest authority (or lowest 'priority number' if we think of tasks). For a Max-Heap, imagine a tournament bracket where the winner (largest value) moves up.
Implementation: Often implemented using arrays for efficiency due to the complete binary tree structure. Parent-child relationships can be found using array indices:
Operations:
class MinHeap {
constructor() {
this.heap = [];
}
insert(value) {
this.heap.push(value);
this._heapifyUp(this.heap.length - 1);
}
_heapifyUp(index) {
let parentIndex = Math.floor((index - 1) / 2);
while (index > 0 && this.heap[index] < this.heap[parentIndex]) {
// Swap
[this.heap[index], this.heap[parentIndex]] = [this.heap[parentIndex], this.heap[index]];
index = parentIndex;
parentIndex = Math.floor((index - 1) / 2);
}
}
extractMin() {
if (this.heap.length === 0) return null;
if (this.heap.length === 1) return this.heap.pop();
const min = this.heap[0];
this.heap[0] = this.heap.pop(); // Move last element to root
this._heapifyDown(0);
return min;
}
_heapifyDown(index) {
let smallest = index;
const leftChildIndex = 2 * index + 1;
const rightChildIndex = 2 * index + 2;
const length = this.heap.length;
if (leftChildIndex < length && this.heap[leftChildIndex] < this.heap[smallest]) {
smallest = leftChildIndex;
}
if (rightChildIndex < length && this.heap[rightChildIndex] < this.heap[smallest]) {
smallest = rightChildIndex;
}
if (smallest !== index) {
[this.heap[index], this.heap[smallest]] = [this.heap[smallest], this.heap[index]];
this._heapifyDown(smallest);
}
}
peek() { return this.heap.length > 0 ? this.heap[0] : null; }
}
let minHeap = new MinHeap();
minHeap.insert(10); minHeap.insert(5); minHeap.insert(20); minHeap.insert(2);
console.log("Heap array:", minHeap.heap); // Example: [2, 5, 20, 10] or similar after heapify
console.log("Min element:", minHeap.peek()); // Should be 2
console.log("Extracted Min:", minHeap.extractMin()); // 2
console.log("New Min element:", minHeap.peek()); // Should be 5
Heap operations involve 'bubbling' elements up or down.
Definition: Divide and Conquer ek powerful algorithmic paradigm hai. Ismein problem ko chote-chote sub-problems mein toda jaata hai, un sub-problems ko recursively solve kiya jaata hai, aur fir unke solutions ko combine karke original problem ka solution banaya jaata hai.
Steps:
Where & Why Used: Merge Sort, Quick Sort, Binary Search, Strassen's Matrix Multiplication, Closest Pair of Points. Yeh complex problems ko manageable parts mein break karne mein madad karta hai aur often efficient solutions deta hai.
Real-life Analogy: Ek badi task (jaise "clean the house") ko chote tasks mein divide karna (clean bedroom, clean kitchen, clean bathroom). Har choti task ko individually complete karna (conquer), aur fir saari tasks complete hone par poora ghar saaf ho jaata hai (combine).
Analyzing D&C Algorithms (Recurrence Relations): Recurrence relations use hote hain D&C algorithms ki time complexity analyze karne ke liye. For example, `T(n) = aT(n/b) + f(n)` where:
Methods to Solve Recurrence Relations:
function mergeSort(arr) {
if (arr.length <= 1) { // Base case
return arr;
}
// Divide
const middle = Math.floor(arr.length / 2);
const leftHalf = arr.slice(0, middle);
const rightHalf = arr.slice(middle);
// Conquer (Recursive calls)
const sortedLeft = mergeSort(leftHalf);
const sortedRight = mergeSort(rightHalf);
// Combine (Merge sorted halves)
return merge(sortedLeft, sortedRight);
}
function merge(left, right) {
let result = [];
let leftIndex = 0;
let rightIndex = 0;
while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] < right[rightIndex]) {
result.push(left[leftIndex]);
leftIndex++;
} else {
result.push(right[rightIndex]);
rightIndex++;
}
}
return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex));
}
let unsortedArray = [38, 27, 43, 3, 9, 82, 10];
console.log("Sorted:", mergeSort(unsortedArray.slice())); // Output: Sorted: [3, 9, 10, 27, 38, 43, 82]
// Recurrence for Merge Sort: T(n) = 2T(n/2) + O(n). Master Theorem Case 2 (k=0) => T(n) = Θ(n log n)
Divide and Conquer splits problems, solves sub-problems, then combines.
Yahan kuch advanced questions hain jo multiple concepts ko link karte hain, jaise real interviews mein hota hai. Inke answers detail mein samajhne ki koshish karein.
Answer: Array mein elements contiguous memory mein hote hain. Linked List mein nodes scattered hote hain, pointers se connected.
Cache Locality: Arrays have better cache locality. Jab aap ek array element access karte ho, toh chances hain ki आसपास ke elements bhi CPU cache mein load ho jaayein (spatial locality). Isse subsequent accesses faster hote hain. Linked List nodes memory mein kahin bhi ho sakte hain, toh har node access pe cache miss ka chance zyada hota hai.
Scenario: Agar aapko data pe iterate karna hai frequently (e.g., summing all elements), array cache locality ke kaaran faster ho sakta hai, even if theoretical complexities same lagein. Lekin agar frequent insertions/deletions in the middle hain, toh Linked List shifting overhead se bacha lega.
Answer:
1. Array-based Stack/Queue:
Answer: Recursive solutions aksar elegant aur problem ke mathematical formulation ke close hote hain. Lekin, har recursive call function call stack mein ek naya frame add karta hai.
Stack Overflow: Agar recursion bahut deep chali jaaye (e.g., factorial of a very large number, or traversing a very deep, unbalanced tree), toh call stack ki memory exhaust ho sakti hai, leading to a stack overflow error.
Iterative Solution: Iterative solutions loops (for, while) use karte hain aur generally stack space ka issue nahi hota (ya kam hota hai). Woh explicit stack/queue data structure use kar sakte hain recursion ko simulate karne ke liye (e.g., DFS using explicit stack, BFS using explicit queue).
Tail Recursion: Kuch languages/compilers tail call optimization (TCO) support karte hain. Agar function tail-recursive hai, toh compiler use iterative code mein convert kar sakta hai, stack overflow se bachate hue. JavaScript engines historically had limited TCO support, but it's improving in some strict mode contexts or specific engines. Generally, JS mein deep recursion se bachna better hai.
Answer:
Min-Heap for k smallest:
Answer:
BST (Average O(log n), Worst O(n)):
Answer: Yes, a binary tree can be a heap, but not all binary trees are heaps. A heap must satisfy two properties:
1. Shape Property: It must be a complete binary tree. This means all levels are completely filled except possibly the last level, which has all its nodes as far left as possible.
2. Heap Property: For a Min-Heap, every node's value must be less than or equal to its children's values. For a Max-Heap, every node's value must be greater than or equal to its children's values.
A general binary tree (like a BST) might not be complete (e.g., a skewed tree). Even if it is complete, it might not satisfy the heap property (e.g., a complete BST is not necessarily a heap unless all elements are same or structured very specifically).
So, a heap IS a specific type of binary tree.
Answer:
Master Theorem: `T(n) = aT(n/b) + f(n)`
Here, `a=2` (two subproblems), `b=2` (size of subproblem is n/2), `f(n) = n` (cost of merging).
Calculate `nlogba = nlog22 = n1 = n`.
Compare `f(n)` with `nlogba`. Here, `f(n) = n` and `nlogba = n`.
This fits Case 2 of the Master Theorem where `f(n) = Θ(nlogba * (log n)k)` with `k=0`.
So, `T(n) = Θ(nlogba * (log n)k+1) = Θ(n * (log n)0+1) = Θ(n log n)`.
Merge Sort ki time complexity `Θ(n log n)` hoti hai.
Answer:
1. Use a Hash Set (or Hash Map):
Answer:
Graph Representation:
Answer:
BFS (Breadth-First Search):
Answer: A Binary Tree can be traversed in several ways:
Depth-First Traversals (Stack/Recursion):
function inOrder(node) { if(node) { inOrder(node.left); console.log(node.data); inOrder(node.right); } }function preOrder(node) { if(node) { console.log(node.data); preOrder(node.left); preOrder(node.right); } }function postOrder(node) { if(node) { postOrder(node.left); postOrder(node.right); console.log(node.data); } }function levelOrder(root) { if(!root) return; let queue = [root]; while(queue.length > 0) { let node = queue.shift(); console.log(node.data); if(node.left) queue.push(node.left); if(node.right) queue.push(node.right); } }Answer:
1. Sorting + Two Pointers:
Answer: Dynamic Programming (DP) aur Divide and Conquer (D&C) dono hi problems ko subproblems mein todte hain.
Key Difference: Overlapping Subproblems.
Answer:
AVL Trees:
Answer: Space complexity algorithm ke execution ke dauraan use hone wali total memory space ko measure karta hai, as a function of input size. Ismein do parts hote hain:
1. Input Space: Input data ko store karne ke liye space. Yeh usually problem definition ka part hota hai.
2. Auxiliary Space: Algorithm dwara use kiya gaya extra space (variables, data structures, recursion call stack).
Generally, "space complexity" refers to auxiliary space, ya fir total space agar explicitly mention kiya ho.
Example: Sorting an array of size 'n'.
Answer: String `s1 = "hello"` aur `s2 = new String("hello")` JavaScript (aur Java) mein alag tareeke se memory allocate karte hain.
1. `String s1 = "hello";` (String Literal)
Answer:
Greedy Approach: Har step pe locally optimal choice banata hai, is ummeed mein ki yeh globally optimal solution dega.
Answer:
Pass by Value:
function modify(x) { x = 100; } let a = 10; modify(a); console.log(a); // Output: 10function modifyObj(obj) { obj.prop = "changed"; } let myObj = {prop: "original"}; modifyObj(myObj); console.log(myObj.prop); // Output: changedfunction reassignObj(obj) { obj = {prop: "new object"}; } modifyObj(myObj); console.log(myObj.prop); // Still "changed", not "new object" because obj inside reassignObj now points to a new memory location.Answer:
Abstraction: Hiding complex implementation details and showing only essential features of an object/system. User ko "kya karta hai" pata hota hai, "kaise karta hai" nahi.
Answer: In a file system:
Answer:
Problem: Check if a given string of parentheses `(`, `)`, `{`, `}`, `[`, `]` is "valid" or "balanced".
Valid: `()`, `()[]{}`, `({[]})`
Invalid: `(]`, `([)]`, `{{`
Solution using Stack:
Answer:
Merge Sort:
Answer:
Load Factor (α) = n / m
where `n` = number of elements stored in the hash table, and `m` = number of slots/buckets in the hash table.
It represents how full the hash table is.
Impact on Performance:
Answer:
1. Iterative Approach (using a `prev` pointer):
function reverseRecursive(head) {
if (head == null || head.next == null) {
return head; // Base case: empty list or single node
}
// Recursively reverse the rest of the list
let restReversedHead = reverseRecursive(head.next);
// Make current head.next (which is now tail of reversed 'rest')
// point back to current head
head.next.next = head;
// Set current head's next to null (it becomes the new tail)
head.next = null;
return restReversedHead; // The head of the fully reversed list
}
Time: O(n), Space: O(n) due to recursion call stack.
Answer:
Scenario: You have an array where elements are sorted, but then "rotated" at some pivot point. Example: `[4, 5, 6, 7, 0, 1, 2]` (original `[0,1,2,4,5,6,7]` rotated). You need to search for an element.
Modified Binary Search:
Answer:
A substring is a contiguous part of a string. Example: "sub" is a substring of "substring".
A subsequence is derived from a string by deleting zero or more characters, maintaining relative order. Example: "sting" is a subsequence of "substring" (delete 's', 'u', 'b'). "srig" is also a subsequence.
Problem: Find the Longest Common Subsequence (LCS) of two strings X and Y.
Dynamic Programming Approach:
Let `m` be length of X, `n` be length of Y.
Create a 2D table `dp[m+1][n+1]`. `dp[i][j]` will store the length of LCS of `X[0...i-1]` and `Y[0...j-1]`.
Initialization: `dp[0][j] = 0` for all `j`, `dp[i][0] = 0` for all `i`. (LCS with empty string is 0).
Fill the table: For `i` from 1 to `m`, `j` from 1 to `n`:
Answer:
Normalization (Database): Process of organizing data in a database to reduce redundancy and improve data integrity. It involves dividing larger tables into smaller, well-structured tables and defining relationships between them.
Normal Forms (NF):
Answer:
Deadlock: A situation where two or more processes/threads are blocked forever, each waiting for a resource held by another process/thread in the same set.
Four Necessary Conditions for Deadlock (Coffman Conditions): All four must hold simultaneously for a deadlock to occur.
Answer:
Process:
Answer:
SQL (Structured Query Language):
Answer:
Indexing in databases is like an index in a book. It's a data structure (often a B-Tree or B+Tree) that improves the speed of data retrieval operations on a database table.
How it works: