Engineering Reference

Data Structures & Algorithms

Core concepts, Big-O complexity analysis, and fundamental problem-solving techniques for software engineers.

Brute Force Technique

Brute force technique is a strategy in which we try all the possible solutions to get the correct answer.

It is a straightforward approach that tries all possible solutions or uses the most basic logic to solve a problem

Example: If you want to find the factor of a number, then in the brute force technique you will check all the numbers from 1 till that number to see if they are part of that number or not.

var n = 15;
for (var i = 1; i <= n; i++) {
    if (n % i == 0) {
        console.log('Factor is ' + i);
    }
}

Advantages of Brute Force

TitleDescription
Simple to ImplementEasy to write and understand; good for beginners and quick prototyping.
Guaranteed to WorkIt covers all cases because it doesn't rely on optimization tricks.
Good for Small InputsIf the data size is small, brute force works just fine.
Helps Understand the ProblemBrute force often helps you see patterns for optimizing later.
No Extra Knowledge RequiredDoesn’t require understanding of advanced algorithms or data structures.

Disadvantages of Brute Force

TitleDescription
Inefficient for Large InputsTime complexity is often high (e.g., O(n^2), O(2^n)), making it slow.
Doesn’t ScaleNot suitable for real-time systems or large datasets.
High Memory UsageMay use unnecessary space or re-compute the same things multiple times.
Not Suitable for InterviewsMost interviewers expect you to optimize beyond brute-force solutions.
Misses PatternsIt might solve the problem but doesn't reveal deeper insights or optimal techniques.

Time Complexity

Time complexity tells how much time your program will take (in steps or operations) as the input size increases.

let str = 'hello';
for (let i = 0; i < str.length; i++) {
  console.log(str[i]);
}
  • This loop is printing each character once. If there are 5 characters in the string, it will run 5 times.
  • It means, If the input is 100, then the loop will run 100 times
  • So Time Complexity = O(n)

Space Complexity

Space Complexity tells how much extra memory (RAM) your program is using based on the input.

let str = 'hello';
let rev = '';
// Extra memory = n characters
// Space Complexity = O(n)
  • We are created a new string (rev) that is as large as the input.
  • Therefore: Extra memory = 'n' characters
  • So, Space Complexity = O(n)

What is O(n) notation

This notation is called Big-O Notation

It shows how the performance of an algorithm changes as the input size n increases.

TitleDescriptionExample
O(1)Constant Time (very fast, no matter the input size)console.log("Hi")
O(n)Linear Time (as the input increases, so does the time)Loop from 0 to n
O(n²)Quadratic Time (time increases rapidly as the input size increases) (Quadratic Time (input size बढ़ने पर समय बहुत तेज़ बढ़ता है))Nested loops
O(log n)Logarithmic Time (very fast algorithm) (Logarithmic Time (बहुत तेज़ algorithm))Binary Search
O(n log n)Efficient Sorting AlgorithmsMerge Sort, Quick Sort

Examples

Example 1: O(1) – Constant Time

function printFirstElement(arr) {
 console.log(arr[0]);
}

Example 2: O(n) – Linear Time

function printAllElements(arr) {
 for (let i = 0; i < arr.length; i++) {
  console.log(arr[i]);
 }
}

Example 3: O(n^2) – Quadratic Time

function printPairs(arr) {
  for (let i = 0; i < arr.length; i++) { 
   for (let j = 0; j < arr.length; j++) { 
   console.log(arr[i], arr[j]); 
  } 
 } 
}

Two Pointer Technique

Two-pointer is a common DSA pattern where two indices move towards each other to solve array or string problems efficiently.

  • Convert string to array (if allowed).
  • Use 2 pointers — one at start, one at end.
  • Swap while left < right.
let str = 'hello';
let arr = str.split('');
let left = 0, right = arr.length - 1;
while (left < right) {
  [arr[left], arr[right]] = [arr[right], arr[left]];
  left++;
  right--;
}
console.log(arr.join(''));

Sliding Window Technique

The Sliding Window technique is a powerful DSA pattern used when you need to analyze a subset (window) of elements in a contiguous array or string.

It uses two pointers that move in the same direction (mostly left → right) to expand and shrink a window dynamically.

This helps reduce time complexity compared to using nested loops.

  • Define the window size or condition (for example, subarray length = K).
  • Iterate through the array while adding the current element to the window.
  • When the window reaches the required size, calculate or compare the result (like sum or max).
  • Before sliding forward, remove the element that’s leaving the window from the sum/count.
  • Continue sliding the window until the end of the array is reached.
const arr = [2, 1, 5, 1, 3, 2];
const k = 3;
let maxSum = 0, windowSum = 0;

for (let i = 0; i < arr.length; i++) {
  windowSum += arr[i]; // add current element

  if (i >= k - 1) {
    maxSum = Math.max(maxSum, windowSum);
    windowSum -= arr[i - (k - 1)]; // remove left element
  }
}

console.log(maxSum); // 9 (5 + 1 + 3)