Use two pointers when the input is sorted or can be sorted and you need a linear scan to compare elements from different positions. Use a sliding window when you need the best/first/minimal subarray fulfilling a constraint, usually with a monotone property as the window grows/shrinks.
// Two-sum in sorted array: return any pair (i, j) with a[i] + a[j] == target
function twoSumSorted(a, target) {
let i = 0, j = a.length - 1;
while (i < j) {
const s = a[i] + a[j];
if (s === target) return [i, j];
if (s < target) i++; else j--;
}
return [-1, -1];
}
// Intersection of two sorted arrays (unique elements)
function intersectSorted(a, b) {
let i = 0, j = 0, out = [];
while (i < a.length && j < b.length) {
if (a[i] === b[j]) { out.push(a[i]); i++; j++; }
else if (a[i] < b[j]) i++; else j++;
}
return out;
}
// Max sum of any subarray of length k
function maxSumFixedWindow(a, k) {
let sum = 0; for (let i = 0; i < k; i++) sum += a[i];
let best = sum;
for (let i = k; i < a.length; i++) {
sum += a[i] - a[i - k];
if (sum > best) best = sum;
}
return best;
}
// Longest substring with at most K distinct characters
function lengthOfLongestSubstringKDistinct(s, K) {
let freq = new Map();
let l = 0, best = 0;
for (let r = 0; r < s.length; r++) {
freq.set(s[r], (freq.get(s[r]) || 0) + 1);
while (freq.size > K) {
const c = s[l++];
freq.set(c, freq.get(c) - 1);
if (freq.get(c) === 0) freq.delete(c);
}
best = Math.max(best, r - l + 1);
}
return best;
}
// Sliding window maximum in O(n)
function maxSlidingWindow(nums, k) {
const dq = []; // stores indices, decreasing by value
const out = [];
for (let i = 0; i < nums.length; i++) {
while (dq.length && dq[0] <= i - k) dq.shift();
while (dq.length && nums[dq[dq.length - 1]] <= nums[i]) dq.pop();
dq.push(i);
if (i + 1 >= k) out.push(nums[dq[0]]);
}
return out;
}