Skip to Content


Find First and Last Position of Element in Sorted Array

  • Use binary search technique to find the first & last position of the target element
  • Modify the conditional logic accordingly to find the first & last position of the target
/** * @param {number[]} nums * @param {number} target * @return {number[]} */ var searchRange = function (nums, target) { // if target is beyond the limits of nums if (target > nums.at(-1) || target < nums[0]) { return [-1, -1]; } const firstPos = getFirstPos(nums, target); if (firstPos === -1) { // if start position is not present, it means the number itself is not present return [-1, -1]; } const lastPos = getLastPos(nums, target, firstPos); return [firstPos, lastPos]; }; function getFirstPos(nums, target) { let left = 0, right = nums.length - 1; let firstPos = -1; while (left <= right) { const mid = Math.floor((left + right) / 2); if (nums[mid] === target) { firstPos = mid; right = mid - 1; } else if (nums[mid] > target) { right = mid - 1; } else { left = mid + 1; } } return firstPos; } function getLastPos(nums, target, firstPos) { let left = firstPos, right = nums.length - 1; let lastPos = -1; while (left <= right) { const mid = Math.floor((left + right) / 2); if (nums[mid] === target) { lastPos = mid; left = mid + 1; } else if (nums[mid] > target) { right = mid - 1; } else { left = mid + 1; } } return lastPos; }
Complexity
  • Time: O(log(n))
  • Space: O(1)


Search in Rotated Sorted Array

  • Find which half is sorted and check if the target is within the sorted half
  • If the target is within the sorted half, update the search range accordingly
/** * @param {number[]} nums * @param {number} target * @return {number} */ var search = function (nums, target) { let left = 0, right = nums.length - 1; while (left <= right) { const mid = left + Math.floor((right - left) / 2); if (nums[mid] === target) { return mid; } if (nums[left] <= nums[mid]) { if (nums[left] <= target && target < nums[mid]) { right = mid - 1; } else { left = mid + 1; } } else { if (nums[mid] < target && target <= nums[right]) { left = mid + 1; } else { right = mid - 1; } } } return -1; };
Complexity
  • Time: O(log(n))
  • Space: O(1)


Find Minimum in Rotated Sorted Array

  • Find which half is sorted and store the minimum value
  • Explore the unsorted half till completion
/** * @param {number[]} nums * @return {number} */ var findMin = function (nums) { let left = 0, right = nums.length - 1, min = Infinity; while (left <= right) { const mid = left + Math.floor((right - left) / 2); if (nums[left] <= nums[mid]) { min = Math.min(min, nums[left]); left = mid + 1; } else { min = Math.min(min, nums[mid]); right = mid - 1; } } return min; };
Complexity
  • Time: O(log(n))
  • Space: O(1)


Search in Rotated Sorted Array II

  • Find which half is sorted and check if the target is within the sorted half
  • If the target is within the sorted half, update the search range accordingly
  • If left, mid, and right are the same, move the left and right pointers
/** * @param {number[]} nums * @param {number} target * @return {boolean} */ var search = function (nums, target) { let left = 0, right = nums.length - 1; while (left <= right) { const mid = left + Math.floor((right - left) / 2); if (nums[mid] === target) { return true; } if (nums[left] === nums[mid] && nums[mid] === nums[right]) { left += 1; right -= 1; } else if (nums[left] <= nums[mid]) { if (nums[left] <= target && target < nums[mid]) { right = mid - 1; } else { left = mid + 1; } } else { if (nums[mid] < target && target <= nums[right]) { left = mid + 1; } else { right = mid - 1; } } } return false; };
Complexity
  • Time: O(n)
  • Space: O(1)


Reverse Words in a String

  • Convert the string into an array of words and push the array of words (except empty space)
  • Reverse the resultant array and covert the array into string with space between words
/** * @param {string} s * @return {string} */ var reverseWords = function (s) { let words = s.split(' '); let result = []; for (const word of words) { if (word.length) { result.push(word); } } return result.reverse().join(' '); };
Complexity
  • Time: O(n)
  • Space: O(n)


Find Minimum in Rotated Sorted Array II

  • Find which half is sorted and store the minimum value
  • Explore the unsorted half till completion
  • If left, mid, and right are the same, move the left and right pointers
/** * @param {number[]} nums * @return {number} */ var findMin = function (nums) { let left = 0, right = nums.length - 1; let min = Infinity; while (left <= right) { const mid = left + Math.floor((right - left) / 2); if (nums[left] === nums[mid] && nums[mid] === nums[right]) { min = Math.min(min, nums[mid]); left += 1; right -= 1; } else if (nums[left] <= nums[mid]) { min = Math.min(min, nums[left]); left = mid + 1; } else { min = Math.min(min, nums[mid]); right = mid - 1; } } return min; };
Complexity
  • Time: O(n)
  • Space: O(1)


Find Peak Element

  • Use binary search to find if mid is a peak. If mid is not a peak, move towards the direction of the greater element
  • If mid ends at the first or last element, consider it as a peak
/** * @param {number[]} nums * @return {number} */ var findPeakElement = function (nums) { let left = 0, right = nums.length - 1, mid; while (left <= right) { mid = left + Math.floor((right - left) / 2); if (nums[mid - 1] < nums[mid] && nums[mid] > nums[mid + 1]) { return mid; } if (nums[mid - 1] > nums[mid]) { right = mid - 1; } else if (nums[mid] < nums[mid + 1]) { left = mid + 1; } else { // edge case where mid is the first/last element return mid; } } return mid; };
Complexity
  • Time: O(log(n))
  • Space: O(1)


Delete Node in a Linked List

  • Copy the data from the successor node into the current node to be deleted.
  • Update the next pointer of the current node to reference the next pointer of the successor node.
/** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */ /** * @param {ListNode} node * @return {void} Do not return anything, modify node in-place instead. */ var deleteNode = function(node) { node.val=node.next.val; node.next=node.next.next; };
Complexity
  • Time: O(1)
  • Space: O(1)


Find All Anagrams in a String

  • Use Sliding window technique and check the every window is Anagram or not
  • if any window is Anagram, add its index to “res” array
/** * @param {string} s * @param {string} p * @return {number[]} */ var findAnagrams = function(s, p) { let res = []; let pCount = {}; let sCount = {}; let pLen = p.length; let sLen = s.length; // Populate the frequency count for the pattern p for (let char of p) { pCount[char] = (pCount[char] || 0) + 1; } // Initialize the frequency count for the first window of size p in s for (let i = 0; i < pLen; i++) { sCount[s[i]] = (sCount[s[i]] || 0) + 1; } // Compare the frequency count of the first window if (isSameCount(pCount, sCount)) { res.push(0); } // Slide the window over string s for (let i = pLen; i < sLen; i++) { // Add the new character to the current window count sCount[s[i]] = (sCount[s[i]] || 0) + 1; // Remove the character that is no longer in the window let startChar = s[i - pLen]; if (sCount[startChar] > 1) { sCount[startChar]--; } else { delete sCount[startChar]; } // Compare the frequency count of the current window if (isSameCount(pCount, sCount)) { res.push(i - pLen + 1); } } return res; }; // Helper function to compare two frequency count objects const isSameCount = function(count1, count2) { if (Object.keys(count1).length !== Object.keys(count2).length) { return false; } for (let key in count1) { if (count1[key] !== count2[key]) { return false; } } return true; };
Complexity
  • Time: O(n)
    • The sliding window ensures that each character in s is processed only once.
    • The comparison of frequency counts is efficient and does not depend on the length of s.
  • Space: O(1)
    • The space used by the frequency count objects is limited to the number of distinct characters in p and s, which is constant (26 letters for lowercase English letters).


Kth Missing Positive Number

  • Find the index of the lower bound of the missing number using binary search
  • Return the missing number by adding the k to the index
/** * @param {number[]} arr * @param {number} k * @return {number} */ var findKthPositive = function (arr, k) { let left = 0, right = arr.length - 1; let ans = arr.length; while (left <= right) { const mid = left + Math.floor((right - left) / 2); const missingCount = arr[mid] - (mid + 1); // find smallest index of missing number greater than k if (k <= missingCount) { ans = mid; right = mid - 1; } else { left = mid + 1; } } return ans + k; // arr[ans] + k - (arr[ans] - (ans + 1)) = kth missing number };
Complexity
  • Time: O(log(n))
  • Space: O(1)


Two Sum II - Input Array Is Sorted

  • As the array is sorted, we can use two pointers approach to find the sum of two numbers
  • If the sum of the two numbers is equal to the target, return the indices
  • If the sum is less than the target, move the left pointer to the right else move the right pointer to the left
/** * @param {number[]} numbers * @param {number} target * @return {number[]} */ var twoSum = function (numbers, target) { let i = 0, j = numbers.length - 1; while (i < j) { const sum = numbers[i] + numbers[j]; if (sum === target) { return [i + 1, j + 1]; } else if (target < sum) { j--; } else if (target > sum) { i++; } } };
Complexity
  • Time: O(n)
  • Space: O(1)


Koko Eating Bananas

  • Use binary search to find the if mid is the minimum eating time
  • If time is less than or equal to h, update the answer and move towards the left
  • If time is greater than h, move towards the right
/** * @param {number[]} piles * @param {number} h * @return {number} */ var minEatingSpeed = function (piles, h) { let max = Math.max(...piles); // max possible count of bananas eaten per hour let left = 0, right = max, ans; while (left <= right) { const mid = left + Math.floor((right - left) / 2); const time = piles.reduce((acc, bananas) => acc + Math.ceil(bananas / mid), 0); if (time <= h) { ans = mid; right = mid - 1; } else { left = mid + 1; } } return ans; };
Complexity
  • Time: O(n log(Max(piles)))
  • Space: O(1)


Validate Stack Sequences

  • Create a stack and loop through the pushed elements
  • If the element popped is encountered loop through the array popped and find the point where it is not equal
/** * @param {int[] , int[]} pushed, popped * @return {boolean} */ public boolean validateStackSequences(int[] pushed, int[] popped) { // start from pushed and check if it is in popped // just follow the instructions, if not encpuntered just return false int pop =0; Stack<Integer> stack = new Stack<>(); for(int i=0; i<pushed.length ; i++) { stack.add(pushed[i]); if(pushed[i]==popped[pop]) { for(int j=pop ; j<popped.length; j++) { if(!stack.isEmpty() && stack.peek()==popped[j]){ pop++; stack.pop(); } else { break; } } } } return stack.isEmpty(); }
Complexity
  • Time: O(n)
  • Space: O(n)


Kth Largest Element in an Array

  • Use PriorityQueue to save all the values in as a max heap
  • Dequeue k times to get the kth largest element
/** * @param {number[]} nums * @param {number} k * @return {number} */ var findKthLargest = function (nums, k) { const maxPQ = new MaxPriorityQueue(); for (const num of nums) { maxPQ.enqueue(num, num); } while (k > 1) { maxPQ.dequeue(); k--; } return maxPQ.front(); };
Complexity
  • Time: O(n * log(n))
  • Space: O(n)


Minimum Number of Days to Make m Bouquets

  • Use binary search to find the if mid is the days to make m bouquets
  • If bouquets are greater than or equal to m, update the answer and move towards the left
  • If bouquets are less than m, move towards the right
/** * @param {number[]} bloomDay * @param {number} m * @param {number} k * @return {number} */ var minDays = function (bloomDay, m, k) { if (m * k > bloomDay.length) { return -1; } let max = Math.max(...bloomDay); // max possible days let left = 0, right = max, ans; while (left <= right) { const mid = left + Math.floor((right - left) / 2); const bouquets = getBouquets(bloomDay, mid, m, k); if (bouquets >= m) { ans = mid; right = mid - 1; } else { left = mid + 1; } } return ans; }; function getBouquets(bloomDay, mid, m, k) { let bouquets = 0, flowers = 0; for (let i = 0; i < bloomDay.length; i++) { // add flowers to bouquet if bloomed or reset flowers = bloomDay[i] <= mid ? flowers + 1 : 0 // if enough flowers in a bouquet if (flowers === k) { bouquets += 1; flowers = 0; } // if enough bouquets if (bouquets === m) { break; } } return bouquets; }
Complexity
  • Time: O(n log(Max(days)))
  • Space: O(1)


Find the Smallest Divisor Given a Threshold

  • Use binary search to find the divisor if it satisfies the threshold
  • If sum is mo than threshold, move towards the right else move towards the left
/** * @param {number[]} nums * @param {number} threshold * @return {number} */ var smallestDivisor = function (nums, threshold) { const max = Math.max(...nums); let left = 1, right = max, ans; while (left <= right) { const mid = left + Math.floor((right - left) / 2); const sum = divisorSum(nums, mid); if (sum <= threshold) { ans = mid; right = mid - 1; } else { left = mid + 1; } } return ans; }; function divisorSum(nums, div) { let sum = 0; for (const val of nums) { sum += Math.ceil(val / div); } return sum; }
Complexity
  • Time: O(n log(Max(nums)))
  • Space: O(1)


Capacity To Ship Packages Within D Days

  • Use binary search to find the capacity with min & max as the max weight & total weight respectively
  • If the days to ship is less than or equal to the given days, move towards the left else move towards the right
/** * @param {number[]} weights * @param {number} days * @return {number} */ var shipWithinDays = function (weights, days) { const [totalWeight, maxWeight] = getTotalAndMax(weights); let left = maxWeight, right = totalWeight; let ans = totalWeight; while (left <= right) { const mid = left + Math.floor((right - left) / 2); const daysToShip = getDaysToShip(weights, mid); if (daysToShip <= days) { ans = mid; right = mid - 1; } else { left = mid + 1; } } return ans; }; function getTotalAndMax(arr) { let sum = 0, max = 0; for (const item of arr) { sum += item; if (max < item) { max = item; } } return [sum, max]; } function getDaysToShip(weights, shipCapacity) { let days = 1, capacity = 0; for (const weight of weights) { if (capacity + weight > shipCapacity) { days += 1; capacity = 0; } capacity += weight; } return days; }
Complexity
  • Time: O(n log(Sum(weights)))
  • Space: O(1)


Magnetic Force Between Two Balls

  • Using binary search, set the left as 1 and right as the maximum distance between the balls
  • Check if the placements are possible with the given distance and continue till you find the maximum distance
  • Popularly known as the Aggressive Cows problem
/** * @param {number[]} position * @param {number} m * @return {number} */ var maxDistance = function (positions, m) { positions.sort((a, b) => a - b); let left = 1, right = positions.at(-1) - positions.at(0); // placed in the 2 extreme end of the array if (m === 2) { return right; } let ans; while (left <= right) { const mid = Math.floor((left + right) / 2); const isPossible = checkPlacements(positions, m, mid); if (isPossible) { ans = mid; left = mid + 1; } else { right = mid - 1; } } return ans; }; function checkPlacements(arr, m, distance) { let prev = arr[0], count = 1; for (let i = 1; i < arr.length; i++) { // if the gap is maintained if (arr[i] - prev >= distance) { count += 1; prev = arr[i]; } // if placements are complete if (count === m) { return true; } } return false; }
Complexity
  • Time: O(n log(n))
  • Space: O(1)


Asteroid Collision

  • Start from left of the array, if the asteroid is positive, push it to the stack
  • If the asteroid is negative, keep popping from the stack until the stack is empty or the top of the stack is positive
/** * @param {number[]} asteroids * @return {number[]} */ var asteroidCollision = function (asteroids) { const left = [], right = []; for (const asteroid of asteroids) { // when a right moving asteroid comes if (asteroid > 0) { left.push(asteroid); continue; } // when left moving asteroid destroys the possible right moving asteroids while (left.length && left.at(-1) < -asteroid) { left.pop(); } // for the remaining right moving asteroid (may be equal or greater than the left moving destroyer) if (left.length) { if (left.at(-1) === -asteroid) { left.pop(); } continue; } // if left moving asteroid wins right.push(asteroid); } return right.concat(left); };
Complexity
  • Time: O(n)
  • Space: O(n)


Making File Names Unique

  • Save all the file names in a map with their frequency & if a file name is already present, append a number to it
  • Continue until a unique file name is found and update the map with the new file name as well and its frequency
/** * @param {string[]} names * @return {string[]} */ var getFolderNames = function (names) { const freq = new Map(); for (let i = 0; i < names.length; i++) { let key = names[i]; let count = freq.get(key) ?? 0; while (freq.has(key)) { key = names[i] + `(${++count})`; } freq.set(key, 0); freq.set(names[i], count); names[i] = key; } return names; };
Complexity
  • Time: O(n)
  • Space: O(n)


Score After Flipping Matrix

  • Flip each row if it has more 0 in the first column (MSB will give the maximum value)
  • For each column, maximize the number of 1s by flipping the column if it has more 0s than 1s
/** * @param {number[][]} grid * @return {number} */ var matrixScore = function (grid) { const m = grid.length, n = grid[0].length; let sum = (1 << (n - 1)) * m; // Set the MSB to 1 for each row for (let j = 1; j < n; j++) { // Count the number of 1s in the column let count = 0; for (let i = 0; i < m; i++) { // Flip the column if that row MSB was flipped count += grid[i][0] ? grid[i][j] : 1 - grid[i][j]; } // Flip the column if it has more 0s than 1s sum += (1 << (n - 1 - j)) * Math.max(count, m - count); } return sum; };
Complexity
  • Time: O(m * n)
  • Space: O(1)
Last updated on