Simplify Path
Ramayana — Hanuman's Shortcut — Finding the True Path Through the Forest
भ्रामक पथात् सत्यपथं ज्ञातव्यम्। व्यर्थं त्यजेत् — सरलं मार्गं स्वीकुर्यात्॥
*From the confusing path, find the true path. Abandon the meaningless — accept the direct route.*
The Story
Given a Unix-style absolute path string, simplify it to the canonical form.
Rules: - `.` refers to the current directory → ignore - `..` moves up one directory → pop from stack - Empty parts (from `//`) → ignore - Multiple slashes → treated as one - Return path must start with `/`
Examples: - `/home//foo/` → `/home/foo` - `/home/../../bin` → `/bin` (go up from home, then up from root = stay at root, then bin) - `/../` → `/` (can't go above root) - `/a/./b/../../c/` → `/c`
Hanuman was navigating through a dense forest with many false paths (`..` leads back) and standing-still signs (`.`). He needed the simplest direct route.
**Stack approach:** 1. Split the path by `/` 2. For each component: - Empty string or `.`: skip - `..`: pop from stack (go up), if stack is not empty - Anything else: push onto stack 3. Join stack contents with `/`, prepend `/`
Trace `"/a/./b/../../c/"`: Split: ["","a",".","b","..","..","c",""] - "": skip - "a": push → [a] - ".": skip - "b": push → [a,b] - "..": pop → [a] - "..": pop → [] - "c": push → [c] - "": skip
Join: "/c" ✓
"The stack naturally models directory navigation," Hanuman noted. "Pushing = entering a directory. Popping = going up one level. `.` and empty = no movement."
The Step-by-Step Navigator
Build the path component by component, handling `..` by trimming the last component. Equivalent to the optimal — just with less clean implementation.
public String simplifyPathBruteForce(String path) {
String[] parts = path.split("/");
List<String> stack = new ArrayList<>();
for (String p : parts) {
if (p.equals("..")) { if (!stack.isEmpty()) stack.remove(stack.size()-1); }
else if (!p.isEmpty() && !p.equals(".")) stack.add(p);
}
return "/" + String.join("/", stack);
}Hanuman's Split-and-Stack Wisdom
public String simplifyPath(String path) {
Deque<String> stack = new LinkedList<>();
for (String component : path.split("/")) {
if (component.equals("..")) {
if (!stack.isEmpty()) stack.removeLast();
} else if (!component.isEmpty() && !component.equals(".")) {
stack.addLast(component);
}
}
return "/" + String.join("/", stack);
}Step-by-Step Walkthrough
path="/..hidden" Split: ["","..hidden"] "": skip. "..hidden": not empty, not ".", not ".." → push [..hidden]! Result: "/..hidden" ✅ (Filenames starting with '..' like '..hidden' are VALID — only the exact ".." token means parent)
Deep Insight
**Edge cases:** - `/../` → stack goes empty on `..` from root (no pop on empty stack). Result: `/` ✓ - `//home` → empty string from double slash is skipped ✓ - `/a/...b` → `"...b"` is a valid filename (exactly 3 dots), not parent → push ✓
**Deque vs Stack:** Using LinkedList as a Deque allows `addLast`/`removeLast` for stack behavior AND easy iteration for `String.join` — more convenient than Java's Stack class.
**String.join on Deque:** Works because Deque implements Iterable, so `String.join("/", stack)` iterates from head to tail (front to back) = correct order.
Complexity Analysis
| Approach | Time | Space | Note |
|---|---|---|---|
| Brute Force | O(n) | O(n) | Same as optimal — split + process |
| Optimal | O(n) | O(n) | O(n) split, O(n) stack, O(n) join |
Pattern Recognition
✅ Unix path canonicalization ✅ Split by '/', process each component ✅ '..': pop; '.'/empty: skip; else: push ✅ Join with '/', prepend '/' **LeetCode Trigger Phrases:** → "simplify path" → "canonical Unix path" → "resolve '.' and '..' in file path"
Bhagavad Gita 3.19
असक्तो ह्याचरन्कर्म परमाप्नोति पूरुषः। लोकसंग्रहमेवापि सम्पश्यन्कर्तुमर्हसि॥
By performing action without attachment, one attains the Supreme. You should act also for the welfare of the world.
Connection: The simplify-path algorithm moves through the path without attachment — when it encounters '..', it releases what was gained without regret. When it meets '.', it passes without action. Only meaningful forward movement (a real directory name) is preserved. This is dharmic action: purposeful, unencumbered by false steps or repetitions, always moving toward the canonical truth of where one truly stands.