Skip to main content

Linked List, Stack, Queue & Hashing


Linked List

Node Structure

// C++
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(nullptr) {}
};

Reverse Linked List

Pattern trigger: "Reverse list", "palindrome linked list"

// C++: Iterative — O(n) time, O(1) space
ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr) {
ListNode* next = curr->next; // save next
curr->next = prev; // reverse pointer
prev = curr; // move prev
curr = next; // move curr
}
return prev;
}

Detect Cycle — Floyd's Algorithm

Two pointers: slow moves 1 step, fast moves 2 steps. If they meet → cycle exists.

Pattern trigger: "Detect cycle", "find loop", "linked list loop start"

// C++
bool hasCycle(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) return true;
}
return false;
}

// Find cycle start
ListNode* detectCycle(ListNode* head) {
ListNode* slow = head, *fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
slow = head; // reset slow to head
while (slow != fast) {
slow = slow->next;
fast = fast->next;
}
return slow; // cycle start
}
}
return nullptr;
}

Find Middle Node

// C++: Fast & Slow pointer
ListNode* middleNode(ListNode* head) {
ListNode* slow = head, *fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
// [1,2,3,4,5] → returns node 3

Merge Two Sorted Lists

// C++
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode dummy(0);
ListNode* curr = &dummy;
while (l1 && l2) {
if (l1->val <= l2->val) { curr->next = l1; l1 = l1->next; }
else { curr->next = l2; l2 = l2->next; }
curr = curr->next;
}
curr->next = l1 ? l1 : l2;
return dummy.next;
}

Stack

LIFO — Last In First Out

// C++
#include <stack>
stack<int> st;
st.push(10); // push
st.push(20);
cout << st.top(); // 20 — peek
st.pop(); // remove top
cout << st.empty(); // false

Valid Parentheses

Pattern trigger: "Balanced brackets", "matching pairs", "valid expression"

// C++
bool isValid(string s) {
stack<char> st;
for (char c : s) {
if (c == '(' || c == '{' || c == '[') {
st.push(c);
} else {
if (st.empty()) return false;
char top = st.top(); st.pop();
if (c == ')' && top != '(') return false;
if (c == '}' && top != '{') return false;
if (c == ']' && top != '[') return false;
}
}
return st.empty();
}
// Input: "()[]{}" → true
// Input: "([)]" → false

Monotonic Stack — Next Greater Element

Pattern trigger: "Next greater/smaller element", "daily temperatures", "stock span"

// C++: Next Greater Element
vector<int> nextGreater(vector<int>& nums) {
int n = nums.size();
vector<int> result(n, -1);
stack<int> st; // stores indices

for (int i = 0; i < n; i++) {
while (!st.empty() && nums[st.top()] < nums[i]) {
result[st.top()] = nums[i];
st.pop();
}
st.push(i);
}
return result;
}
// Input: [2,1,2,4,3] → [4,2,4,-1,-1]

Queue

FIFO — First In First Out

// C++
#include <queue>
queue<int> q;
q.push(10);
q.push(20);
cout << q.front(); // 10 — peek front
q.pop(); // remove front
cout << q.back(); // 20 — peek back

Priority Queue (Heap-based)

Pattern trigger: "Top K elements", "K largest/smallest", "median", "task scheduling"

// C++: Min heap
priority_queue<int, vector<int>, greater<int>> minHeap;
minHeap.push(5);
minHeap.push(1);
minHeap.push(3);
cout << minHeap.top(); // 1 — smallest

// Max heap (default)
priority_queue<int> maxHeap;
maxHeap.push(5); maxHeap.push(1); maxHeap.push(3);
cout << maxHeap.top(); // 5 — largest

Deque — Sliding Window Maximum

// C++: Max in each window of size k — O(n)
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> dq; // stores indices, front = max
vector<int> result;

for (int i = 0; i < nums.size(); i++) {
// remove elements out of window
if (!dq.empty() && dq.front() <= i - k) dq.pop_front();
// remove smaller elements from back
while (!dq.empty() && nums[dq.back()] < nums[i]) dq.pop_back();
dq.push_back(i);
if (i >= k - 1) result.push_back(nums[dq.front()]);
}
return result;
}
// Input: [1,3,-1,-3,5,3,6,7], k=3
// Output: [3,3,5,5,6,7]

Hashing

HashMap / HashSet

O(1) average for insert, delete, lookup.

// C++
#include <unordered_map>
#include <unordered_set>

unordered_map<string, int> freq;
freq["apple"]++;
freq["banana"] = 5;
if (freq.count("apple")) cout << freq["apple"]; // 1

unordered_set<int> seen;
seen.insert(3);
if (seen.count(3)) cout << "found"; // found

Two Sum — Classic Hash Map Problem

// C++: O(n) time, O(n) space
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> map; // value → index
for (int i = 0; i < nums.size(); i++) {
int complement = target - nums[i];
if (map.count(complement))
return {map[complement], i};
map[nums[i]] = i;
}
return {};
}
// Input: [2,7,11,15], target=9 → [0,1]

Frequency Counter Pattern

// C++: Anagram check
bool isAnagram(string s, string t) {
if (s.size() != t.size()) return false;
unordered_map<char, int> freq;
for (char c : s) freq[c]++;
for (char c : t) {
freq[c]--;
if (freq[c] < 0) return false;
}
return true;
}
// "anagram" and "nagaram" → true

Pattern Recognition

ProblemStructureWhy
Balanced parenthesesStackLIFO matches pairs
Next greater elementMonotonic StackMaintain decreasing order
BFS traversalQueueLevel-by-level processing
Sliding window maxDequeO(1) front/back access
Fast lookup, dedupHashMap/HashSetO(1) average ops
Top K frequent elementsHeap + HashCount then rank

Classic Problems

ProblemTechnique
Reverse Linked ListPointer manipulation
Linked List CycleFast & Slow pointer
Valid ParenthesesStack
Daily TemperaturesMonotonic Stack
Sliding Window MaximumDeque
Two SumHashMap
Group AnagramsHashMap
Top K Frequent ElementsHeap + HashMap
LRU CacheHashMap + Doubly Linked List