๐ From Brute Force to Optimal: Solving LeetCode Problems Step-by-Step (with JavaScript Examples)


When tackling coding problems, the smartest approach isnโt always the fastestโitโs knowing how to evolve your solution over time. Whether you're a beginner or brushing up for interviews, this post will walk you through 8 techniques, each one solving an example problem in progressively smarter ways.
๐งฑ Step 1: Brute Force with Loops
๐ Problem: Two Sum
Given an array nums
and a target value, return the indices of two numbers such that they add up to the target.
๐ง Brute Force Solution
function twoSum(nums, target) {
for (let i = 0; i < nums.length; i++) {
for (let j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] === target) {
return [i, j];
}
}
}
}
๐ Analysis
โ Easy to understand
โ Time:
O(nยฒ)
โ slow for large arrays
๐งฎ Step 2: Hash Map Optimization
๐ก Use hashing to store previously seen elements
function twoSum(nums, target) {
const map = new Map();
for (let i = 0; i < nums.length; i++) {
const diff = target - nums[i];
if (map.has(diff)) return [map.get(diff), i];
map.set(nums[i], i);
}
}
๐ Analysis
โ Time reduced to
O(n)
โ More scalable
๐ Step 3: Sliding Window
๐ Problem: Longest Substring Without Repeating Characters
๐ง Brute Force (Nested Loops)
function lengthOfLongestSubstring(s) {
let max = 0;
for (let i = 0; i < s.length; i++) {
let set = new Set();
for (let j = i; j < s.length; j++) {
if (set.has(s[j])) break;
set.add(s[j]);
}
max = Math.max(max, set.size);
}
return max;
}
๐ง Optimized with Sliding Window
function lengthOfLongestSubstring(s) {
let set = new Set();
let left = 0, maxLen = 0;
for (let right = 0; right < s.length; right++) {
while (set.has(s[right])) {
set.delete(s[left]);
left++;
}
set.add(s[right]);
maxLen = Math.max(maxLen, right - left + 1);
}
return maxLen;
}
๐ Analysis
โ Brute force:
O(nยฒ)
โ Sliding window:
O(n)
๐ฆ Step 4: Prefix Sum
๐ Problem: Subarray Sum Equals K
๐ง Optimized with Prefix Sum + Map
function subarraySum(nums, k) {
const map = new Map();
map.set(0, 1);
let count = 0, sum = 0;
for (const num of nums) {
sum += num;
if (map.has(sum - k)) count += map.get(sum - k);
map.set(sum, (map.get(sum) || 0) + 1);
}
return count;
}
๐ Analysis
โ Handles multiple subarrays
โ Time:
O(n)
โ Space:
O(n)
๐ Step 5: Sorting + Binary Search
๐ Problem: Find Insert Position
๐ง Binary Search
function searchInsert(nums, target) {
let left = 0, right = nums.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (nums[mid] === target) return mid;
else if (nums[mid] < target) left = mid + 1;
else right = mid - 1;
}
return left;
}
๐ Analysis
โ Efficient for sorted arrays
โ Time:
O(log n)
๐งญ Step 6: Heap / Greedy
๐ Problem: Top K Frequent Elements
๐ง Using Map + Sort (Greedy-style)
function topKFrequent(nums, k) {
const count = new Map();
for (const num of nums) {
count.set(num, (count.get(num) || 0) + 1);
}
const sorted = [...count.entries()].sort((a, b) => b[1] - a[1]);
return sorted.slice(0, k).map(([num]) => num);
}
๐ Analysis
โ Time:
O(n log n)
๐ ๏ธ Can optimize with heap for
O(n log k)
๐งต Step 7: Backtracking
๐ Problem: Subsets
๐ง Recursive Backtracking
function subsets(nums) {
const res = [];
function backtrack(start, path) {
res.push([...path]);
for (let i = start; i < nums.length; i++) {
path.push(nums[i]);
backtrack(i + 1, path);
path.pop();
}
}
backtrack(0, []);
return res;
}
๐ Analysis
โ Generates all combinations
โ Time:
O(2โฟ)
๐๏ธ Step 8: Dynamic Programming
๐ Problem: Climbing Stairs
๐ง Bottom-Up DP
function climbStairs(n) {
if (n <= 2) return n;
let dp = [1, 1];
for (let i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
๐ Analysis
โ Time:
O(n)
โ Space:
O(n)
(can optimize toO(1)
)
๐ Final Recap Table
Step | Technique | Example Problem | Time Complexity |
1 | Brute Force | Two Sum | O(nยฒ) |
2 | Hash Map / Set | Two Sum (Optimized) | O(n) |
3 | Sliding Window | Longest Substring Without Repeat | O(n) |
4 | Prefix Sum | Subarray Sum Equals K | O(n) |
5 | Binary Search | Search Insert Position | O(log n) |
6 | Greedy / Sort / Heap | Top K Frequent Elements | O(n log k) |
7 | Backtracking | Subsets | O(2โฟ) |
8 | Dynamic Programming | Climbing Stairs | O(n) |
๐ง Conclusion
When approaching a problem:
Start with brute force to understand the core logic.
Climb the ladderโoptimize with hash maps, two pointers, prefix sums, and beyond.
Always analyze complexity and think: Can I do better?
Whether you're prepping for interviews or improving daily, this technique ladder gives you a structured way to level up. ๐
Subscribe to my newsletter
Read articles from Aakib Shah Sayed directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
