npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jaroslawweber/algo-utils

v1.1.0

Published

A utility library for practicing LeetCode-style problems. Focus on solving the core algorithm, not on implementing data structures.

Readme

algo-utils

A utility library for practicing LeetCode-style problems. Focus on solving the core algorithm, not on implementing data structures.

Install

npm install algo-utils

Why?

When practicing LeetCode, you often waste time implementing common data structures instead of focusing on the actual problem. This library gives you battle-tested implementations so you can concentrate on what matters.

Quick Examples

Grid traversal

// Before: repetitive bounds checking
if (r >= 0 && r < grid.length && c >= 0 && c < grid[0].length) { ... }

// After: clean and simple
for (const [dr, dc] of dirs4) {
  const nr = r + dr, nc = c + dc;
  if (inBounds(grid, nr, nc)) { ... }
}

Grid Creation & Debugging

// Create a 2D grid for DP problems - much cleaner than Array.from
const dp = createGrid(m, n, 0);           // m×n grid filled with 0
const visited = createGrid(rows, cols, false);  // boolean grid

// Get grid dimensions easily
const { rows, cols } = getGridSize(grid);

// Debug your grid with pretty printing
console.log(gridToString(grid));        // " 1  2\n 3  4"
console.log(gridToString(grid, 4));     // custom cell width: 4

Priority Queue (Min-Heap)

// Just focus on the algorithm, not heap implementation
const heap = new Heap<number>();
heap.push(5);
heap.push(1);
heap.push(3);
heap.pop(); // 1

LRU Cache

// O(1) LRU cache built-in
const cache = new LRUCache<string, number>(3);
cache.set("a", 1);
cache.get("a"); // 1

DefaultMap

// Like Python's defaultdict - auto-initialize missing keys
const map = new DefaultMap<string, number[]>(() => []);
map.get("foo").push(1); // no need to check if "foo" exists
map.get("foo").push(2);
map.get("foo"); // [1, 2]

Union Find

// O(α(n)) per operation - nearly constant time
const uf = new UnionFind(5);
uf.union(0, 1);
uf.union(1, 2);
uf.connected(0, 2); // true
uf.connected(0, 3); // false

Adjacency List

// Generic graph representation with exposed internal map for flexibility
const adj = new AdjacencyList<string>();
adj.addEdge("JFK", "LAX");
adj.addEdge("JFK", "SFO");

// Basic operations
adj.getNeighbors("JFK"); // ["LAX", "SFO"]

// Direct map access for advanced operations (e.g., Reconstruct Itinerary)
adj.map.get("JFK").sort();  // Sort neighbors
adj.map.delete("LAX");      // Remove node
for (const [node, neighbors] of adj.map.entries()) {
  console.log(`${node} -> ${neighbors}`);
}

Topological Sort

// Kahn's algorithm - returns null if cycle exists
const adj = new AdjacencyList<string>();
adj.addEdge("a", "b");
adj.addEdge("b", "c");
topologicalSort(adj); // ["a", "b", "c"] or similar

Monotonic Stack

// Next greater element - find next bigger number to the right
// Input: [2, 1, 2, 4, 3] → Output: [4, 2, 4, -1, -1]
import { rangeRight } from "algo-utils";

const nums = [2, 1, 2, 4, 3];
const result = Array(nums.length).fill(-1);
const stack = new MonotonicStack<number>();

for (const i of rangeRight(nums.length)) {
  stack.popWhile((top) => nums[i] >= top);
  result[i] = stack.peek() ?? -1;
  stack.push(nums[i]);
}
result; // [4, 2, 4, -1, -1]

Monotonic Queue

// Sliding window maximum
// Input: [1,3,-1,-3,3,3], k=3 → Output: [3,3,3,3]
import { range } from "algo-utils";

const nums = [1, 3, -1, -3, 3, 3];
const k = 3;
const result: number[] = [];
const queue = new MonotonicQueue<number>();

for (const i of range(nums.length)) {
  if (i >= k && nums[i - k] === queue.front()) queue.pop();
  queue.dequeueWhile((front) => nums[i] >= front);
  queue.push(nums[i]);
  if (i >= k - 1) result.push(queue.peek()!);
}
result; // [3, 3, 3, 3]

Counter

// Count occurrences with ease
const counter = new Counter();
counter.increase("apple");     // 1
counter.increase("apple");     // 2
counter.increase("banana", 3); // 3
counter.get("apple");          // 2
counter.decrease("banana");    // 2
counter.get("banana");         // 2

// Or initialize from an array
const counter2 = new Counter(["a", "b", "a", "c", "a"]);
counter2.get("a"); // 3
counter2.get("b"); // 1
counter2.get("c"); // 1

Bucket Sort

// O(n + k) sort for integers in a known range
const nums = [2, 0, 2, 1, 1, 0];
bucketSort(nums, 0, 2); // [0, 0, 1, 1, 2, 2]

// Perfect for Sort Colors (LC 75)
const colors = [2, 0, 2, 1, 1, 0];
bucketSort(colors, 0, 2); // [0, 0, 1, 1, 2, 2]

Working with Intervals

// Use first/last from lodash for readable interval access
import { first, last } from "algo-utils";

const interval: [number, number] = [1, 5];
first(interval); // 1 (start)
last(interval);  // 5 (end)

// Perfect for interval problems like Merge Intervals, Meeting Rooms
intervals.sort((a, b) => first(a) - first(b));

Swapping array elements

// Quick in-place swap without temp variable
swap(arr, i, j);

Linked List

// Standard LeetCode ListNode with utilities
const head = new ListNode(1, new ListNode(2, new ListNode(3)));

getListLength(head); // 3
getTail(head).val;   // 3
getNodeAt(head, 2);  // ListNode { val: 2, next: ... }

// Fast/slow pointer for middle node
const mid = getMid(head);  // ListNode { val: 2, ... }

// Reverse in-place, returns new head
const reversed = reverseList(head);  // 3 -> 2 -> 1

// Useful for problems like:
// - Middle of the Linked List (LC 876)
// - Reverse Linked List (LC 206)
// - Palindrome Linked List (LC 234)
// - Linked List Cycle II (LC 142)
// - Remove Nth Node From End of List (LC 19)

API

Custom Utils

| Function/Class | Description | |----------------|-------------| | swap(arr, i, j) | Swap elements at indices i and j in place | | peek(stack) | Get the top element without removing it | | inBounds(grid, r, c) | Check if coordinates are within grid bounds | | createGrid(rows, cols, val?) | Create a 2D grid filled with a value (default 0) | | gridToString(grid, width?) | Convert grid to formatted string for debugging | | getGridSize(grid) | Get grid dimensions as { rows, cols } | | getKey(r, c) | Create a string key from row and column | | charToIdx(c) | Convert 'A'-'Z' to 0-25 | | idxToChar(i) | Convert 0-25 to 'A'-'Z' | | dirs4 | 4-directional movement vectors | | dirs8 | 8-directional movement vectors | | UnionFind | Disjoint set union with path compression and union by rank | | AdjacencyList<T> | Graph adjacency list with exposed .map for direct access | | topologicalSort(adj) | Kahn's algorithm - returns sorted order or null if cycle exists | | MonotonicStack | Stack with popWhile for next greater/smaller problems | | MonotonicQueue | Queue for sliding window maximum/minimum | | Counter | Counter class with get/set/increase/decrease using DefaultMap | | bucketSort(arr, min, max) | O(n + k) counting sort for integers in range [min, max] | | ListNode | Standard LeetCode linked list node class | | getListLength(head) | Get the length of a linked list | | getTail(head) | Get the tail (last node) of a linked list | | getNodeAt(head, steps) | Get node at position (1-indexed) from head | | getMid(head) | Get middle node using fast/slow pointer | | reverseList(head) | Reverse linked list in-place, returns new head |

Lodash Re-exports

chunk, uniq, uniqBy, flatten, flattenDeep, sortBy, reverse, fill, range, cloneDeep, groupBy, countBy, keyBy, partition, pick, omit, merge, get, set, has, zip, unzip, sum, mean, min, max, random

Mnemonist Re-exports

Stack, Queue, Heap, MultiMap, DefaultMap, BitSet, BloomFilter, MultiSet, Trie, LRUCache

Full Example: Number of Islands

// LeetCode 200 - Number of Islands
import { inBounds, dirs4, getGridSize } from "algo-utils";

function numIslands(grid: string[][]): number {
  if (!grid.length) return 0;
  let count = 0;
  const { rows, cols } = getGridSize(grid);
  
  function dfs(r: number, c: number) {
    if (!inBounds(grid, r, c) || grid[r][c] !== "1") return;
    grid[r][c] = "0";
    for (const [dr, dc] of dirs4) dfs(r + dr, c + dc);
  }
  
  for (let r = 0; r < rows; r++) {
    for (let c = 0; c < cols; c++) {
      if (grid[r][c] === "1") { dfs(r, c); count++; }
    }
  }
  return count;
}

Full Example: Top K Frequent Elements

// LeetCode 347 - Top K Frequent Elements
import { uniq, sortBy, countBy } from "algo-utils";

function topKFrequent(nums: number[], k: number): number[] {
  const freq = countBy(nums);
  return uniq(nums)
    .sort((a, b) => freq[b] - freq[a])
    .slice(0, k);
}

Usage

import { 
  swap, peek, inBounds, dirs4, dirs8, getKey,
  chunk, uniq, flattenDeep, sortBy, range,
  Stack, Queue, Heap, LRUCache 
} from "algo-utils";