Difficulty
Medium


Find First and Last Position of Element in Sorted Array (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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().element;
};
Complexity
  • Time: O(n * log(n))
  • Space: O(n)


Minimum Number of Days to Make m Bouquets (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab) 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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 (opens in a new tab)

  • 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)