· 9 min read
LeetCode for Travel-Booking Platforms: Easy & Medium Patterns (JS)
A pragmatic, domain-mapped LeetCode guide for Easy/Medium problems you’ll see in travel-booking style systems: intervals/availability, sliding windows, heaps, hashing, prefix sums, and binary search—with clean JavaScript templates.
This is a focused set of Easy/Medium LeetCode problems that map cleanly to travel-booking platform needs: availability/rooms, inventory windows, pricing, ranking, capacity, and caching. Each topic has a one-sentence mapping plus a JS template you can re-use.
Quick Map (Problem → Scenario → Technique)
- Can Attend Meetings → back-to-back booking validation → sort + scan
- Min Rooms (meeting/hotel rooms) → concurrent bookings → two pointers on starts/ends
- Merge/Insert Intervals → consolidate booking ranges → sort by start + greedy merge
- Corporate Flight Bookings → batched updates on routes/dates → difference array + prefix sum
- Car Pooling → capacity feasibility per corridor/time → event sweep (diff array)
- Top K Frequent Elements → top searched cities/hotels → hashmap + bucket/heap
- Min Size Subarray Sum → minimum window hitting a target demand → sliding window
- Max Average Subarray I → rolling KPI (occupancy/price) → fixed window
- Search Insert Position → price bucket insertion / sorted ids → lower_bound binary search
- Two Sum → bundle pricing / complementary offers → hashmap lookup
- Merge Sorted Array → merge paginated, sorted search results → in-place from back
- LRU Cache → cache hot searches/results → ordered Map
Availability & Intervals
Can Attend All Meetings (No Overlap) — Easy
Problem. Given intervals[i] = [start, end) determine if any overlap exists.
- Input/Output:
number[][] → boolean - Mapping: Validate that back-to-back bookings are allowed but overlaps are rejected.
- Approach: Sort by start; if
start_i < end_{i-1}anywhere, there’s an overlap. - Complexity: Time
O(n log n), SpaceO(1)(in-place sort). - Edge cases: Empty or single interval; equal end-start is allowed with half-open
[start, end). - Example:
[[10,20],[20,30]] → true,[[10,20],[19,25]] → false.
function canAttendMeetings(intervals) {
intervals.sort((a, b) => a[0] - b[0]);
for (let i = 1; i < intervals.length; i++) {
if (intervals[i][0] < intervals[i - 1][1]) return false;
}
return true;
}
Minimum Number of Rooms (Concurrent Bookings) — Medium
Problem. Minimum parallel rooms to host all intervals without overlap.
- Input/Output:
number[][] → number - Mapping: Peak concurrent bookings = number of rooms/capacity needed.
- Approach: Sort
startsandendsseparately; sweep with two pointers; increment when a meeting starts before the earliest end, else decrement. - Complexity: Time
O(n log n), SpaceO(n)for starts/ends. - Edge cases: Same-time start/end; treat end before start at same timestamp to free capacity.
- Example:
[[0,30],[5,10],[15,20]] → 2.
function minMeetingRooms(intervals) {
if (intervals.length === 0) return 0;
const starts = intervals.map((i) => i[0]).sort((a, b) => a - b);
const ends = intervals.map((i) => i[1]).sort((a, b) => a - b);
let i = 0,
j = 0,
used = 0,
best = 0;
while (i < starts.length) {
if (starts[i] < ends[j]) {
used++;
if (used > best) best = used;
i++;
} else {
used--;
j++;
}
}
return best;
}
Merge Intervals — Medium
Problem. Merge all overlapping intervals.
- Input/Output:
number[][] → number[][] - Mapping: Combine adjacent availability windows into compact blocks.
- Approach: Sort by start; push or merge with last interval greedily.
- Complexity: Time
O(n log n), SpaceO(n). - Edge cases: Fully contained intervals; identical starts; back-to-back
[a,b)and[b,c)remain separate under half-open semantics. - Example:
[[1,3],[2,6],[8,10],[15,18]] → [[1,6],[8,10],[15,18]].
function mergeIntervals(intervals) {
if (intervals.length <= 1) return intervals;
intervals.sort((a, b) => a[0] - b[0]);
const res = [intervals[0].slice()];
for (let i = 1; i < intervals.length; i++) {
const [s, e] = intervals[i];
const last = res[res.length - 1];
if (s <= last[1]) last[1] = Math.max(last[1], e);
else res.push([s, e]);
}
return res;
}
Insert Interval — Medium
Problem. Insert a new interval into non-overlapping sorted intervals and merge as needed.
- Input/Output:
(number[][], [number, number]) → number[][] - Mapping: Add a new availability/blackout and normalize the calendar.
- Approach: Append all intervals ending before new; merge overlaps; append the rest.
- Complexity: Time
O(n), SpaceO(1)extra if reusing output buffer. - Edge cases: New interval before all; after all; fully covering many.
- Example:
[[1,3],[6,9]], [2,5] → [[1,5],[6,9]].
function insertInterval(intervals, newInterval) {
const res = [];
let [ns, ne] = newInterval;
let i = 0;
while (i < intervals.length && intervals[i][1] < ns) res.push(intervals[i++]);
while (i < intervals.length && intervals[i][0] <= ne) {
ns = Math.min(ns, intervals[i][0]);
ne = Math.max(ne, intervals[i][1]);
i++;
}
res.push([ns, ne]);
while (i < intervals.length) res.push(intervals[i++]);
return res;
}
Batched Updates & Capacity
Corporate Flight Bookings — Medium
Problem. Apply batch additions over date ranges efficiently.
- Input/Output:
bookings: [start,end,seats][], n: number → number[] - Mapping: Promotions/load updates over date windows per route; compute resulting demand per day.
- Approach: Difference array; add at start, subtract after end; one prefix pass to realize totals.
- Complexity: Time
O(n + q), SpaceO(n). - Edge cases: 1-indexed ranges; very large q; overlapping updates canceling.
- Example:
[[1,2,10],[2,3,20]], n=3 → [10,30,20].
// bookings: number[][] where [start, end, seats] (1-indexed days)
// n: number of days
function corpFlightBookings(bookings, n) {
const diff = new Array(n + 1).fill(0);
for (const [start, end, seats] of bookings) {
diff[start - 1] += seats;
diff[end] -= seats;
}
const res = new Array(n).fill(0);
let cur = 0;
for (let i = 0; i < n; i++) {
cur += diff[i];
res[i] = cur;
}
return res;
}
Car Pooling — Medium
Problem. Determine if trips fit into capacity with pickups/dropoffs along a line.
- Input/Output:
trips: [passengers, start, end][], capacity: number → boolean - Mapping: Shuttle capacity across segments/time windows with loads and unloads.
- Approach: Event sweep: +p at start, -p at end; sort by time, apply cumulative sum; ensure never exceeds capacity.
- Complexity: Time
O(n log n), SpaceO(n). - Edge cases: Equal times (process drop before pick); large passenger counts; zero-capacity sanity.
- Example:
[[2,1,5],[3,3,7]], cap=4 → false.
// trips: [passengers, start, end]
function carPooling(trips, capacity) {
const events = [];
for (const [p, s, e] of trips) {
events.push([s, p]);
events.push([e, -p]);
}
events.sort((a, b) => (a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]));
let cur = 0;
for (const [, d] of events) {
cur += d;
if (cur > capacity) return false;
}
return true;
}
Ranking & Frequency
Top K Frequent Elements — Medium
Problem. Return the k most frequent items.
- Input/Output:
(number[]|string[], k: number) → same-type[] - Mapping: Top searched cities/hotels/filters.
- Approach: Count with hashmap; bucket by frequency; collect from highest bucket down. Alt: min-heap of size k.
- Complexity: Bucket: Time
O(n), SpaceO(n); Heap: TimeO(n log k). - Edge cases: Ties; k equals distinct count; large domain values.
- Example:
nums=[1,1,1,2,2,3], k=2 → [1,2].
function topKFrequent(nums, k) {
const count = new Map();
for (const x of nums) count.set(x, (count.get(x) || 0) + 1);
const buckets = Array(nums.length + 1)
.fill(0)
.map(() => []);
for (const [val, freq] of count) buckets[freq].push(val);
const res = [];
for (let f = buckets.length - 1; f >= 0 && res.length < k; f--) {
for (const v of buckets[f]) {
res.push(v);
if (res.length === k) break;
}
}
return res;
}
Sliding Windows (Demand, KPIs)
Minimum Size Subarray Sum — Medium
Problem. Smallest contiguous window whose sum ≥ target.
- Input/Output:
(target: number, nums: number[]) → number - Mapping: Minimal number of days to hit a sales/demand threshold.
- Approach: Expand right; while sum ≥ target, shrink left and update best.
- Complexity: Time
O(n), SpaceO(1). - Edge cases: No solution (return 0); large numbers; single element ≥ target.
- Example:
target=7, nums=[2,3,1,2,4,3] → 2([4,3]).
function minSubArrayLen(target, nums) {
let left = 0,
sum = 0,
best = Infinity;
for (let right = 0; right < nums.length; right++) {
sum += nums[right];
while (sum >= target) {
best = Math.min(best, right - left + 1);
sum -= nums[left++];
}
}
return best === Infinity ? 0 : best;
}
Maximum Average Subarray I — Easy
Problem. Maximize average over any length-k window.
- Input/Output:
(nums: number[], k: number) → number - Mapping: Highest average KPI (e.g., occupancy) over fixed horizon.
- Approach: Sum first k; slide by add-right, remove-left while tracking best.
- Complexity: Time
O(n), SpaceO(1). - Edge cases: k equals n; negatives; decimals.
- Example:
nums=[1,12,-5,-6,50,3], k=4 → 12.75.
function findMaxAverage(nums, k) {
let sum = 0;
for (let i = 0; i < k; i++) sum += nums[i];
let best = sum;
for (let i = k; i < nums.length; i++) {
sum += nums[i] - nums[i - k];
if (sum > best) best = sum;
}
return best / k;
}
Binary Search (Sorted Data/Prices)
Search Insert Position — Easy
Problem. Position to insert target in sorted array.
- Input/Output:
(nums: number[], target: number) → number - Mapping: Insert price tier or id into sorted catalog.
- Approach: Lower-bound binary search: first index where
nums[i] ≥ target. - Complexity: Time
O(log n), SpaceO(1). - Edge cases: Insert at start/end; duplicates (return first occurrence).
- Example:
nums=[1,3,5,6], target=5 → 2,target=2 → 1,target=7 → 4.
function searchInsert(nums, target) {
let lo = 0,
hi = nums.length;
while (lo < hi) {
const mid = lo + ((hi - lo) >> 1);
if (nums[mid] < target) lo = mid + 1;
else hi = mid;
}
return lo;
}
Hashing & Merging (Catalogs)
Two Sum — Easy
Problem. Find two indices whose values sum to target.
- Input/Output:
(nums: number[], target: number) → [number, number] - Mapping: Complementary bundle pricing or promo targets.
- Approach: Hashmap of value → index; for each value check if complement seen.
- Complexity: Time
O(n), SpaceO(n). - Edge cases: Duplicates; negative targets; exactly one solution per constraints.
- Example:
nums=[2,7,11,15], target=9 → [0,1].
function twoSum(nums, target) {
const seen = new Map();
for (let i = 0; i < nums.length; i++) {
const need = target - nums[i];
if (seen.has(need)) return [seen.get(need), i];
seen.set(nums[i], i);
}
return [];
}
Merge Sorted Array — Easy
Problem. Merge two sorted arrays where the first has trailing buffer.
- Input/Output:
(nums1: number[], m: number, nums2: number[], n: number) → void - Mapping: Merge two sorted result pages into one stream in-place.
- Approach: Fill from the back comparing tails to avoid overwriting.
- Complexity: Time
O(m+n), SpaceO(1). - Edge cases: One empty; all from nums2 smaller/larger.
- Example:
nums1=[1,2,3,0,0,0], m=3, nums2=[2,5,6], n=3 → [1,2,2,3,5,6].
// nums1 has length m + n with trailing space; merge nums2 into nums1
function merge(nums1, m, nums2, n) {
let i = m - 1,
j = n - 1,
k = m + n - 1;
while (j >= 0) {
if (i >= 0 && nums1[i] > nums2[j]) nums1[k--] = nums1[i--];
else nums1[k--] = nums2[j--];
}
}
Caching Hot Results
LRU Cache — Medium
Problem. Design a cache that evicts least-recently-used on capacity.
- Input/Output:
get(key): number,put(key, value): void - Mapping: Cache hot destination/hotel search results with bounded memory.
- Approach: Ordered Map: reinsert on get/put to mark recent; evict oldest key when size exceeds capacity.
- Complexity: Amortized
O(1)for get/put. - Edge cases: Update existing keys; capacity = 1; non-existent keys.
- Example:
put(1,1); put(2,2); get(1) → 1; put(3,3) evicts 2.
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.map = new Map();
}
get(key) {
if (!this.map.has(key)) return -1;
const value = this.map.get(key);
this.map.delete(key);
this.map.set(key, value);
return value;
}
put(key, value) {
if (this.map.has(key)) this.map.delete(key);
this.map.set(key, value);
if (this.map.size > this.capacity) {
const oldestKey = this.map.keys().next().value;
this.map.delete(oldestKey);
}
}
}
Notes & Pitfalls
- Prefer half-open intervals [start, end) to allow back-to-back bookings; adjust only if the problem states inclusive end.
- For concurrency (rooms), sorting starts/ends separately with two pointers is often simpler and faster than heap-based solutions.
- For bulk updates on ranges (routes/dates), difference arrays with one prefix pass turn O(n·q) into O(n + q).
- For ranking (top K), bucket sort avoids log factors and is easy to code in JS.
- Sliding windows: grow right, shrink left while constraint holds; track best window length/score.
- Binary search for positions uses lower_bound (first index with nums[i] ≥ target); template above is safe for duplicates.