Interview Setbook · Part 2 of 6 · Q036–Q070
C++ Mastery Series · Interview Prep

The Interview
Problem Setbook

Part 2 of 6. Stacks, Queues, Linked Lists, and Hashing — the four data structures that appear in every interview. Master these and 40% of all interview problems become straightforward pattern recognition.

Part 2 · Q036–Q070 Stacks & Monotonic Patterns Queues & Deques Linked Lists Hashing Patterns
Chapter 04 · Q036–Q050 · Stacks
Stacks — Monotonic Patterns, Classic Designs & The LIFO Mindset
The Stack Mental Model — When to Think "Stack"

Pattern 1 — Matching/Nesting: Opening brackets, tags, function calls. Push opens, pop-and-check closes. Valid Parentheses is the archetype.
Pattern 2 — "Next Greater/Smaller" problems: Monotonic stack. Maintain a stack in increasing or decreasing order. When a new element breaks the monotone property, the elements it pops have found their answer.
Pattern 3 — Undo/History: Browser back button, undo in text editors, DFS traversal without recursion.
Pattern 4 — Expression evaluation: Infix to postfix, calculator problems. Two stacks for operators and operands.

Q036 · EASY Valid Parentheses
StringStack
LeetCode #20
Must KnowAsked 9,000+Stack Pattern 1

Given a string with only ( ) { } [ ], determine if the brackets are valid. Opening brackets must be closed in correct order.

Input"()[]{}"
Outputtrue
Input 2"([)]"
Output 2false
Input 3"{[]}"
Output 3true
Decode — Push Opens, Pop-and-Match Closes

For every opening bracket, push it. For every closing bracket, the top of the stack must be the matching opener. If it's not (or the stack is empty), the string is invalid. At the end, the stack must be empty (all openers got matched).

s = "{[()]}" c='{': opening → push. stack=[{] c='[': opening → push. stack=[{,[] c='(': opening → push. stack=[{,[,(] c=')': closing → top='(' matches ')' → pop. stack=[{,[] c=']': closing → top='[' matches ']' → pop. stack=[{] c='}': closing → top='{' matches '}' → pop. stack=[] Stack empty → VALID ✓ s = "([)]" c='(': push → stack=[(] c='[': push → stack=[(,[] c=')': top='[' does NOT match ')' → INVALID ✗
C++ Solution — O(n) time · O(n) space bool isValid(string s) { stack<char> st; unordered_map<char,char> close = {{'(',')'},{'{','}'},{'[',']'}}; for (char c : s) { if (close.count(c)) // Opening bracket st.push(c); else { // Closing bracket if (st.empty() || close[st.top()] != c) return false; st.pop(); } } return st.empty(); // All openers matched }
TimeO(n)
SpaceO(n)
SimilarMinimum Remove to Make Valid · Score of Parentheses
Q037 · MEDIUM Min Stack
StackDesign
LeetCode #155
Must KnowDesign ClassicParallel Min Stack

Design a stack that supports push, pop, top, and getMin() — all in O(1). getMin() returns the minimum element in the stack.

Decode — Track the Minimum at Every Level with a Second Stack

A plain stack loses the minimum when you pop. The trick: maintain a second stack (minSt) that always stores the current minimum at each level. When pushing x, push min(x, minSt.top()) to minSt. When popping, pop both stacks together. getMin() = minSt.top().

Operations: push(5), push(3), push(7), push(2), getMin, pop, getMin push(5): st=[5] minSt=[5] push(3): st=[5,3] minSt=[5,3] (min(3,5)=3) push(7): st=[5,3,7] minSt=[5,3,3] (min(7,3)=3) push(2): st=[5,3,7,2]minSt=[5,3,3,2] (min(2,3)=2) getMin() → minSt.top()=2 pop(): st=[5,3,7] minSt=[5,3,3] getMin() → minSt.top()=3
C++ Solution — All operations O(1) class MinStack { stack<int> st, minSt; public: void push(int val) { st.push(val); // Track min at this level minSt.push(minSt.empty() ? val : min(val, minSt.top())); } void pop() { st.pop(); minSt.pop(); } int top() { return st.top(); } int getMin() { return minSt.top(); } };
All opsO(1)
SpaceO(n)
VariantMax Stack · Stack with increment operation
Q038 · MEDIUM Daily Temperatures
ArrayMonotonic Stack
LeetCode #739
Must KnowMonotonic Stack TemplateStack Pattern 2

Given daily temperatures, return an array where each element is the number of days to wait for a warmer temperature. 0 if no warmer day exists.

Input[73,74,75,71,69,72,76,73]
Output[1,1,4,2,1,1,0,0]
Decode — Monotonic Decreasing Stack Finds "Next Greater"

Maintain a stack of indices in decreasing temperature order. When a new temperature is higher than the top, we've found the "next warmer day" for the top element — pop it and record the answer (current index − popped index). All remaining elements in the stack at the end get answer 0.

T = [73,74,75,71,69,72,76,73] (stack stores indices) i=0: T=73, push 0. stack=[0] i=1: T=74>T[0]=73 → pop 0, ans[0]=1-0=1. push 1. stack=[1] i=2: T=75>T[1]=74 → pop 1, ans[1]=2-1=1. push 2. stack=[2] i=3: T=71<75. push 3. stack=[2,3] i=4: T=69<71. push 4. stack=[2,3,4] i=5: T=72>T[4]=69 → pop 4, ans[4]=5-4=1 72>T[3]=71 → pop 3, ans[3]=5-3=2 72<T[2]=75. push 5. stack=[2,5] i=6: T=76>T[5]=72 → pop 5, ans[5]=6-5=1 76>T[2]=75 → pop 2, ans[2]=6-2=4 push 6. stack=[6] i=7: T=73<76. push 7. stack=[6,7] Remaining in stack → ans[6]=ans[7]=0 (already initialised to 0) Answer: [1,1,4,2,1,1,0,0]
C++ Solution — O(n) time · O(n) space vector<int> dailyTemperatures(vector<int>& T) { int n = T.size(); vector<int> ans(n, 0); stack<int> st; // Monotonic decreasing (stores indices) for (int i = 0; i < n; i++) { while (!st.empty() && T[i] > T[st.top()]) { ans[st.top()] = i - st.top(); // Days to wait st.pop(); } st.push(i); } return ans; }
TimeO(n)
SpaceO(n)
Same PatternNext Greater Element · Stock Span · Largest Rectangle
Q039 · MEDIUM Next Greater Element I & II (Circular)
ArrayMonotonic Stack
LeetCode #496 & #503
Must KnowCircular = Double the Array

Part I: For each element in nums1, find the next greater element in nums2. nums1 is a subset of nums2.
Part II: Circular array — the next greater of the last element wraps around to the beginning.

I Inputnums1=[4,1,2] nums2=[1,3,4,2]
I Output[-1,3,-1]
II Input[1,2,1]
II Output[2,-1,2]
Part II Trick — Simulate Circular by Iterating 2n Times with i % n

For the circular version, iterate from i=0 to 2n-1 using a[i%n]. This simulates the wrap-around. Only push indices when i < n (first pass). Answers are filled during both passes.

C++ — Both Parts // Part I — hash map records next-greater from nums2, then answer nums1 vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) { unordered_map<int,int> nextGreater; stack<int> st; for (int x : nums2) { while(!st.empty() && x > st.top()){ nextGreater[st.top()] = x; st.pop(); } st.push(x); } while(!st.empty()){ nextGreater[st.top()]=-1; st.pop(); } vector<int> res; for(int x:nums1) res.push_back(nextGreater[x]); return res; } // Part II — circular array (iterate 2n times) vector<int> nextGreaterElements(vector<int>& a) { int n=a.size(); vector<int> res(n,-1); stack<int> st; // Stores indices for(int i=0;i<2*n;i++){ while(!st.empty()&&a[i%n]>a[st.top()]){ res[st.top()]=a[i%n]; st.pop(); } if(i<n) st.push(i); // Only push index on first pass } return res; }
TimeO(n)
SpaceO(n)
Q040 · HARD Largest Rectangle in Histogram
ArrayMonotonic Stack
LeetCode #84
Must KnowGoogle/Amazon FavouriteMonotonic Increasing Stack

Find the area of the largest rectangle that can be formed within a histogram (array of bar heights). Bars are adjacent and width = 1.

Input[2,1,5,6,2,3]
Output10
Whybars 5,6 → height=5 width=2 → area=10
Decode — For Each Bar: How Far Left and Right Can It Extend?

A bar of height h can extend left until it hits a shorter bar, and right until it hits a shorter bar. Monotonic increasing stack: when bar[i] < bar[stack.top()], the top bar's right boundary has been found. The left boundary is the new stack top after popping. Area = height × (right − left − 1). Append a sentinel 0 to flush all remaining bars.

h = [2,1,5,6,2,3,0] (0 is sentinel) i=0: push 0. stack=[0] (h[0]=2) i=1: h[1]=1<h[0]=2 → pop 0 width = 1-(-1)-1=1, area=2×1=2. best=2 stack empty now, push 1. stack=[1] i=2: h[2]=5>1, push 2. stack=[1,2] i=3: h[3]=6>5, push 3. stack=[1,2,3] i=4: h[4]=2<6 → pop 3: height=6, left=2, right=4, width=4-2-1=1, area=6. best=6 2<5 → pop 2: height=5, left=1, right=4, width=4-1-1=2, area=10. best=10 2=2, push 4. stack=[1,4] i=5: h[5]=3>2, push 5. stack=[1,4,5] i=6: sentinel 0 flushes everything... pop 5: height=3, left=4, width=6-4-1=1, area=3 pop 4: height=2, left=1, width=6-1-1=4, area=8 pop 1: height=1, left=-1, width=6-(-1)-1=6, area=6 Answer: 10
C++ Solution — O(n) time · O(n) space int largestRectangleArea(vector<int>& h) { h.push_back(0); // Sentinel flushes remaining bars stack<int> st; int best = 0; for (int i = 0; i < (int)h.size(); i++) { while (!st.empty() && h[i] < h[st.top()]) { int height = h[st.top()]; st.pop(); int left = st.empty() ? -1 : st.top(); int width = i - left - 1; best = max(best, height * width); } st.push(i); } h.pop_back(); // Restore original return best; }
TimeO(n)
SpaceO(n)
ExtensionMaximal Rectangle in Matrix (LC#85) — apply this per row
Q041 · HARD Maximal Rectangle in Binary Matrix
MatrixMonotonic Stack
LeetCode #85
Must KnowReduce Each Row to Histogram

Given a binary matrix, find the largest rectangle containing only 1s. Return its area.

Input[["1","0","1","0","0"], ["1","0","1","1","1"], ["1","1","1","1","1"], ["1","0","0","1","0"]]
Output6
Decode — Transform Each Row into a Histogram, Then Apply Q040

For each cell (i,j), compute the height = number of consecutive 1s above (including current row). This turns each row into a histogram. Apply the Largest Rectangle in Histogram algorithm to each row's histogram. The maximum across all rows is the answer.

Matrix row by row → histogram heights Row 0: [1,0,1,0,0] → heights = [1,0,1,0,0] maxRect=1 Row 1: [1,0,1,1,1] → heights = [2,0,2,1,1] maxRect=3 Row 2: [1,1,1,1,1] → heights = [3,1,3,2,2] maxRect=6 (height=2,width=3) Row 3: [1,0,0,1,0] → heights = [4,0,0,3,0] maxRect=4 Answer: 6
C++ Solution — O(R×C) time int largestHistogram(vector<int>& h) { // Q040 function h.push_back(0); stack<int> st; int best=0; for(int i=0;i<(int)h.size();i++){ while(!st.empty()&&h[i]<h[st.top()]){ int ht=h[st.top()];st.pop(); int w=i-(st.empty()?-1:st.top())-1; best=max(best,ht*w); } st.push(i); } h.pop_back(); return best; } int maximalRectangle(vector<vector<char>>& mat) { int R=mat.size(), C=mat[0].size(), best=0; vector<int> heights(C,0); for(int i=0;i<R;i++){ for(int j=0;j<C;j++) heights[j] = mat[i][j]=='1' ? heights[j]+1 : 0; // Build histogram best = max(best, largestHistogram(heights)); } return best; }
TimeO(R×C)
SpaceO(C)
Q042 · MEDIUM Evaluate Reverse Polish Notation
ArrayStack
LeetCode #150
Must KnowExpression Evaluation Pattern

Evaluate an arithmetic expression in Reverse Polish Notation (postfix). Numbers are operands, then operator consumes the top two values.

Input["2","1","+","3","*"]
Output9
Why((2+1)*3) = 9
Decode — Numbers Go On Stack, Operators Consume Two Numbers

Walk tokens left to right. If token is a number → push. If token is an operator → pop two values (b first, then a), compute (a op b), push result. Final answer is the single remaining element on the stack.

["2","1","+","3","*"] "2": push 2. stack=[2] "1": push 1. stack=[2,1] "+": pop b=1, pop a=2. push 2+1=3. stack=[3] "3": push 3. stack=[3,3] "*": pop b=3, pop a=3. push 3*3=9. stack=[9] Answer: 9
C++ Solution — O(n) int evalRPN(vector<string>& tokens) { stack<long long> st; for (auto& t : tokens) { if (t=="+"||t=="-"||t=="*"||t=="/") { long long b=st.top();st.pop(); long long a=st.top();st.pop(); if (t=="+") st.push(a+b); else if (t=="-") st.push(a-b); else if (t=="*") st.push(a*b); else st.push(a/b); // Integer division truncates toward zero } else st.push(stoll(t)); } return st.top(); }
TimeO(n)
SpaceO(n)
Q043 · HARD Basic Calculator II
StringStack
LeetCode #227
Must KnowPush with Sign, Apply * / Immediately

Implement a basic calculator to evaluate a string expression with +, -, *, / (integer division), no parentheses. Return the result.

Input"3+2*2"
Output7
Input 2" 3/2 "
Output 21
Decode — Push Signed Numbers, Apply * and / Immediately

Key insight: + and - have lower precedence so push the number (with sign) onto the stack and defer addition. * and / have higher precedence so apply them immediately to the stack top. Final answer = sum of all stack values.

"3+2*2" num=3, op='+' → push +3. stack=[3] num=2, op='*' → push +2. stack=[3,2] num=2, op=end → op was '*': pop 2, compute 2*2=4, push. stack=[3,4] (last operator '*' applied immediately) Sum = 3+4 = 7
C++ Solution — O(n) int calculate(string s) { stack<int> st; int num=0; char op='+'; for(int i=0;i<(int)s.size();i++){ char c=s[i]; if(isdigit(c)) num=num*10+(c-'0'); if((!isdigit(c)&&c!=' ')||i==(int)s.size()-1){ if (op=='+') st.push( num); else if(op=='-') st.push(-num); else if(op=='*'){ int top=st.top();st.pop();st.push(top*num); } else if(op=='/'){ int top=st.top();st.pop();st.push(top/num); } op=c; num=0; } } int res=0; while(!st.empty()){ res+=st.top(); st.pop(); } return res; }
TimeO(n)
SpaceO(n)
ExtensionLC#224 with parentheses — recursive or stack of stacks
Q044 · MEDIUM Decode String
StringStack
LeetCode #394
Must KnowStack of (Count, String) Pairs

Decode an encoded string where k[encoded_string] means repeat encoded_string k times. Encoding can be nested.

Input"3[a]2[bc]"
Output"aaabcbc"
Input 2"2[abc]3[cd]ef"
Output 2"abcabccdcdcdef"
Decode — Stack Saves State Before Each Nested Bracket

Two stacks: one for counts, one for strings built so far. On [: push current string and current count, reset both. On ]: pop count and previous string, repeat current string count times, prepend previous. On digit: build count. On letter: append to current string.

"3[a2[c]]" '3': k=3 '[': push (k=3,""). reset curr="", k=0 'a': curr="a" '2': k=2 '[': push (k=2,"a"). reset curr="", k=0 'c': curr="c" ']': pop → k=2, prev="a". curr = "a" + "c"*2 = "acc" ']': pop → k=3, prev="". curr = "" + "acc"*3 = "accaccacc" Answer: "accaccacc"
C++ Solution — O(output length) string decodeString(string s) { stack<int> countSt; stack<string> strSt; string curr = ""; int k = 0; for (char c : s) { if (isdigit(c)) k = k*10 + (c-'0'); else if (c == '[') { countSt.push(k); strSt.push(curr); curr=""; k=0; } else if (c == ']') { int n = countSt.top(); countSt.pop(); string prev = strSt.top(); strSt.pop(); string rep = ""; while(n--) rep += curr; curr = prev + rep; } else curr += c; } return curr; }
TimeO(output size)
SpaceO(depth × length)
Q045 · MEDIUM Asteroid Collision
ArrayStack
LeetCode #735
Simulate with Stack — Collision Rules

Array of asteroids. Positive = moving right, negative = moving left. Same direction: no collision. Opposite: smaller explodes (both if equal). Return the state after all collisions.

Input[5,10,-5]
Output[5,10]
Input 2[8,-8]
Output 2[]
Decode — Collision Only Happens When Stack Top is Positive and Current is Negative

Use a stack. For each asteroid: if stack is empty, or current is positive, or stack top is negative → push (no collision). Otherwise: compare sizes. If current |size| wins → pop and re-check. If equal → pop both. If stack top wins → current is destroyed.

C++ Solution — O(n) vector<int> asteroidCollision(vector<int>& a) { stack<int> st; for(int x : a){ bool alive = true; while(alive && x<0 && !st.empty() && st.top()>0){ if(st.top() < -x) st.pop(); // Stack top explodes else if(st.top() == -x){ st.pop(); alive=false; } // Both explode else alive=false; // Current explodes } if(alive) st.push(x); } vector<int> res; while(!st.empty()){ res.push_back(st.top()); st.pop(); } reverse(res.begin(), res.end()); return res; }
TimeO(n)
SpaceO(n)
Q046 · MEDIUM Car Fleet
ArrayStackSorting
LeetCode #853
Sort by Position, Compare Arrival Times

Cars on a single-lane road. Each car has position and speed. Cars in front can't be passed. Cars that meet form a fleet and travel at the slower car's speed. Return number of fleets reaching the target.

Inputtarget=12 pos=[10,8,0,5,3] speed=[2,4,1,1,3]
Output3
Decode — Sort by Position, Stack Tracks Fleet Leaders by Arrival Time

Sort cars by position (descending). Compute each car's time to reach target = (target - pos) / speed. A car forms a new fleet if its time > the fleet in front's time (it's slower, so it catches up). Use a stack: if current car's time ≤ stack top's time, it merges into the fleet ahead (don't push). If greater, it forms a new fleet (push). Stack size = number of fleets.

C++ Solution — O(n log n) int carFleet(int target, vector<int>& pos, vector<int>& speed) { int n=pos.size(); vector<pair<int,double>> cars(n); for(int i=0;i<n;i++) cars[i]={pos[i],(double)(target-pos[i])/speed[i]}; sort(cars.rbegin(), cars.rend()); // Sort by position descending stack<double> st; for(auto& [p,t]:cars){ if(st.empty()||t>st.top()) st.push(t); // New fleet // else: car catches the fleet ahead, merges (don't push) } return st.size(); }
TimeO(n log n)
SpaceO(n)
Q047 · MEDIUM Remove K Digits
StringMonotonic Stack
LeetCode #402
Must KnowGreedy: Remove Digits That Create Decreasing Sequence

Remove k digits from number string to make it the smallest possible number. Return the result as a string (no leading zeros).

Input"1432219", k=3
Output"1219"
Input 2"10200", k=1
Output 2"200"
Decode — Remove a Digit When It's Larger Than the Next Digit

Greedily remove digits from the left when they're larger than the next digit (a "peak"). Use a monotonic increasing stack. Pop when stack.top() > current digit AND k > 0. The resulting stack forms the answer.

C++ Solution — O(n) string removeKdigits(string num, int k) { string st; // Use string as stack (efficient) for(char c : num){ while(k>0 && !st.empty() && st.back()>c){ st.pop_back(); k--; } st.push_back(c); } while(k--) st.pop_back(); // If k remains, remove from end // Remove leading zeros int start=0; while(start<(int)st.size()-1 && st[start]=='0') start++; return st.substr(start); }
TimeO(n)
SpaceO(n)
Q048 · MEDIUM Stock Span Problem
ArrayMonotonic Stack
GFG / HackerRank Classic
Must KnowMonotonic Stack Classic

For each day's stock price, compute the span — the number of consecutive days before (and including) today where the price was ≤ today's price.

Input[100,80,60,70,60,75,85]
Output[1,1,1,2,1,4,6]
Decode — "Previous Greater" = Next Smaller in Reverse

The span of day i = i − (index of the last day with price > today's price). Monotonic decreasing stack of (price, span) or indices. When popping, accumulate the spans of all popped elements (they were all ≤ current).

C++ Solution — O(n) amortised vector<int> stockSpan(vector<int>& price) { stack<pair<int,int>> st; // {price, span} vector<int> res; for(int p : price){ int span=1; while(!st.empty() && st.top().first <= p){ span += st.top().second; // Absorb span of popped day st.pop(); } st.push({p, span}); res.push_back(span); } return res; }
TimeO(n)
SpaceO(n)
Q049 · MEDIUM Score of Parentheses
StringStack
LeetCode #856
() = 1, (A) = 2×score(A)

Score a balanced parentheses string. () = 1, AB = A+B, (A) = 2×A.

Input"(()(()))"
Output6
C++ Solution — Stack of Scores int scoreOfParentheses(string s) { stack<int> st; st.push(0); // Current level's score for(char c:s){ if(c=='(') st.push(0); // New level else{ int v=st.top(); st.pop(); st.top() += max(2*v, 1); // () gives 1, (A) gives 2*A } } return st.top(); }
TimeO(n)
SpaceO(n)
Q050 · HARD Trapping Rain Water (Stack Approach)
ArrayMonotonic Stack
LeetCode #42 · Alt Approach
Horizontal Layer Accumulation

Solve Trapping Rain Water (seen in Part 1, Q007) using a monotonic stack — a completely different mental model that accumulates water in horizontal layers instead of vertical columns.

Decode — Stack Accumulates Water Horizontally When a "Basin" Is Formed

Maintain a monotonic decreasing stack of indices. When height[i] > height[stack.top()], a basin has formed: the bottom is the popped element, left wall is new stack top, right wall is current i. Compute the water for this horizontal layer. Repeat for all basins.

C++ — Stack Approach (horizontal layers) int trap(vector<int>& h) { stack<int> st; int water=0; for(int i=0;i<(int)h.size();i++){ while(!st.empty()&&h[i]>h[st.top()]){ int bottom=st.top(); st.pop(); if(st.empty()) break; int left=st.top(); int width = i - left - 1; int height = min(h[left],h[i]) - h[bottom]; water += width * height; } st.push(i); } return water; }
TimeO(n)
SpaceO(n)
NoteTwo-pointer approach (Q007) uses O(1) space — prefer that in interviews
↑ back to top
Chapter 05 · Q051–Q058 · Queues & Deques
Queues & Deques — BFS, Monotonic Deque & Classic Designs
Queue vs Deque — When to Use Each

Queue (FIFO): BFS traversal, level-order processing, task scheduling. Always prefer queue over stack when you need to process in order of arrival.
Deque (Double-ended): When you need O(1) push/pop from both ends. Sliding window maximum (see Q020) uses a monotonic deque. Also used to implement stacks and queues with additional powers.
Priority Queue (Heap): When "next to process" = "most extreme value". Dijkstra, top-K, merge K sorted, median stream. See Part 3 for heap problems.

Q051 · MEDIUM Implement Queue Using Two Stacks
StackDesign
LeetCode #232
Must KnowAmortised O(1) per op

Implement a queue (FIFO) using only two stacks. Implement push, pop, peek, empty.

Decode — Lazy Transfer: Only Move to Output Stack When It's Empty

Input stack for push. Output stack for pop/peek. Transfer from input → output only when output is empty and you need to pop/peek. This amortises to O(1) per operation — each element crosses between stacks at most once.

push(1), push(2), pop(), push(3), pop(), peek() push(1): inSt=[1] push(2): inSt=[1,2] pop(): outSt empty → transfer: outSt=[2,1], inSt=[] pop outSt.top()=1. outSt=[2] push(3): inSt=[3] pop(): outSt not empty → pop outSt.top()=2. outSt=[] peek(): outSt empty → transfer: outSt=[3], inSt=[] peek outSt.top()=3
C++ Solution — Amortised O(1) per operation class MyQueue { stack<int> inSt, outSt; void transfer() { if(outSt.empty()) while(!inSt.empty()){ outSt.push(inSt.top()); inSt.pop(); } } public: void push(int x) { inSt.push(x); } int pop() { transfer(); int v=outSt.top(); outSt.pop(); return v; } int peek() { transfer(); return outSt.top(); } bool empty() { return inSt.empty() && outSt.empty(); } };
push/emptyO(1)
pop/peekO(1) amortised
Q052 · EASY Implement Stack Using Two Queues
Design
LeetCode #225
Reverse the Queue Each Push

Implement a stack using only two queues. push, pop, top, empty.

Decode — On Each Push, Rotate the Queue to Keep Newest at Front

After pushing x to q2, move all of q1 into q2, then swap q1 and q2. Now q1.front() is always the most recently pushed element. pop/top just access q1.front(). Push is O(n), pop is O(1).

C++ Solution class MyStack { queue<int> q; public: void push(int x) { q.push(x); // Rotate so x is at the front for(int i=0;i<(int)q.size()-1;i++){ q.push(q.front()); q.pop(); } } int pop() { int v=q.front(); q.pop(); return v; } int top() { return q.front(); } bool empty() { return q.empty(); } };
pushO(n)
pop/topO(1)
Q053 · MEDIUM Design Circular Queue
Design
LeetCode #622
Array + Two Pointers (head, tail)

Design a circular queue of capacity k with enqueue, dequeue, front, rear, isEmpty, isFull — all O(1).

Decode — Fixed Array + head/tail Pointers + Count

Use a fixed-size array. head points to front, tail points to next insertion spot. Both advance circularly using % k. Track size with a count. Full when count==k, empty when count==0.

C++ Solution — All ops O(1) class MyCircularQueue { vector<int> buf; int head=0, tail=0, cnt=0, cap; public: MyCircularQueue(int k): buf(k), cap(k) {} bool enQueue(int v){ if(isFull()) return false; buf[tail]= v; tail=(tail+1)%cap; cnt++; return true; } bool deQueue(){ if(isEmpty()) return false; head=(head+1)%cap; cnt--; return true; } int Front() { return isEmpty()?-1:buf[head]; } int Rear() { return isEmpty()?-1:buf[(tail-1+cap)%cap]; } bool isEmpty() { return cnt==0; } bool isFull() { return cnt==cap; } };
All opsO(1)
SpaceO(k)
Q054 · MEDIUM Task Scheduler
ArrayGreedyMath
LeetCode #621
Must KnowFormula: (maxFreq-1)×(n+1) + maxFreqCount

Given tasks (array of characters) and cooldown n — same task must be at least n slots apart. Find minimum total slots to finish all tasks.

Inputtasks=["A","A","A","B","B","B"] n=2
Output8
WhyA B _ A B _ A B
Decode — Most Frequent Task Determines the Frame Size

The most frequent task (maxFreq) creates (maxFreq-1) "cooling slots". Each slot has (n+1) units (task + n idle). Total = (maxFreq-1)×(n+1) + (# tasks with maxFreq). But we need at least tasks.size() slots if tasks fill all the idle time. Answer = max(tasks.size(), formula).

tasks=AAABBB, n=2 freqs: A=3, B=3 maxFreq=3, maxFreqCount=2 (both A and B appear 3 times) Frame: (3-1)×(2+1) = 6 slots + 2 (tasks with maxFreq) = 8 max(8, 6) = 8 Layout: [A B _] [A B _] [A B] frame1 frame2 last
C++ Solution — O(n) int leastInterval(vector<char>& tasks, int n) { int freq[26]={}; for(char c:tasks) freq[c-'A']++; int maxF=*max_element(freq,freq+26); int maxFCount=count(freq,freq+26,maxF); return max((int)tasks.size(), (maxF-1)*(n+1)+maxFCount); }
TimeO(n)
SpaceO(26)
Q055 · HARD Design Twitter / Hit Counter
HashDesignQueue
LeetCode #355 / #362
Design: Hash Map + Queue Pattern

Hit Counter: Design a hit counter which counts hits received in the past 5 minutes (300 seconds). hit(timestamp) records a hit. getHits(timestamp) returns hits in last 300 seconds.

Decode — Queue Stores Timestamps, Evict Stale Hits

Use a queue of timestamps. On hit: push timestamp. On getHits: pop from front while front is <= timestamp - 300 (stale). Return queue size.

C++ Hit Counter Solution — O(1) amortised class HitCounter { queue<int> q; public: void hit(int ts){ q.push(ts); } int getHits(int ts){ while(!q.empty() && q.front() <= ts-300) q.pop(); return q.size(); } }; // If timestamps arrive in large batches at same second, // store (timestamp, count) pairs instead of individual timestamps. class HitCounterOpt { queue<pair<int,int>> q; // {timestamp, count} public: void hit(int ts){ if(!q.empty()&&q.back().first==ts) q.back().second++; else q.push({ts,1}); } int getHits(int ts){ while(!q.empty()&&q.front().first<=ts-300) q.pop(); int total=0; queue<pair<int,int>> tmp=q; while(!tmp.empty()){total+=tmp.front().second;tmp.pop();} return total; } };
hitO(1)
getHitsO(n) worst, O(1) amortised
Q056 · MEDIUM Dota2 Senate / Predict the Winner
GreedyQueue
LeetCode #649
Two Queues of Indices, Greedy Ban

Two factions Radiant (R) and Dire (D). Each senator can ban one senator from the other faction. Senators take turns in circular order. The faction with all surviving senators wins. Predict the winner.

Input"RDD"
Output"Dire"
Decode — Greedy: Each Senator Bans the Nearest Opponent

Maintain two queues: indices of all R senators and all D senators. At each step, the front of each queue is the next senator to act. Whichever has the smaller index goes first — it bans the other (pop that queue). The winner re-enters the queue with index += n (simulating next round).

C++ Solution — O(n) string predictPartyVictory(string senate) { int n=senate.size(); queue<int> R, D; for(int i=0;i<n;i++) senate[i]=='R' ? R.push(i) : D.push(i); while(!R.empty()&&!D.empty()){ int r=R.front(),d=D.front(); R.pop();D.pop(); r<d ? R.push(r+n) : D.push(d+n); // Winner re-enters next round } return R.empty() ? "Dire" : "Radiant"; }
TimeO(n)
SpaceO(n)
Q057 · MEDIUM Number of Recent Calls
DesignQueue
LeetCode #933
Sliding Window with Queue

Implement a class that counts recent requests within the last 3000 milliseconds. ping(t) adds a request at time t and returns the count of requests in [t-3000, t].

C++ Solution — O(1) amortised per ping class RecentCounter { queue<int> q; public: int ping(int t) { q.push(t); while(q.front() < t-3000) q.pop(); // Evict old pings return q.size(); } };
pingO(1) amortised
SpaceO(window size)
Q058 · HARD Maximum of Minimum for Every Window Size
ArrayMonotonic Stack
GFG / Codeforces Edu
Previous Smaller + Next Smaller via Stack

Given array, for each window size k (1 to n), find the maximum of all minimum values of all windows of size k. Return the result array.

Input[10,20,30,50,10,70,30]
Output[70,30,20,10,10,10,10]
Decode — Each Element Is the Minimum of Windows Where It's the Smallest

For each element a[i], find how far it spans as a window minimum: the longest window where it's the smallest. This is (nextSmaller[i] - prevSmaller[i] - 1). Use monotonic stack to find prevSmaller[] and nextSmaller[] arrays. Then fill the answer array: ans[span-1] = max(ans[span-1], a[i]). Finally fill right-to-left since ans[k-1] ≥ ans[k].

C++ Solution — O(n) vector<int> maxOfMin(vector<int>& a) { int n=a.size(); vector<int> left(n,-1), right(n,n); stack<int> st; // Previous smaller element index for(int i=0;i<n;i++){ while(!st.empty()&&a[st.top()]>=a[i]) st.pop(); left[i]=st.empty()?-1:st.top(); st.push(i); } while(!st.empty()) st.pop(); // Next smaller element index for(int i=n-1;i>=0;i--){ while(!st.empty()&&a[st.top()]>=a[i]) st.pop(); right[i]=st.empty()?n:st.top(); st.push(i); } vector<int> ans(n+1,0); for(int i=0;i<n;i++){ int span=right[i]-left[i]-1; // a[i] is min of windows of this size ans[span]=max(ans[span],a[i]); } // Fill: ans[k-1] >= ans[k] (larger windows can only have smaller minimums) for(int i=n-1;i>=1;i--) ans[i-1]=max(ans[i-1],ans[i]); return vector<int>(ans.begin()+1,ans.end()); }
TimeO(n)
SpaceO(n)
↑ back to top
Chapter 06 · Q059–Q070 · Linked Lists
Linked Lists — Pointers, Fast/Slow, Reversal & Classic Design
Linked List Mental Models — The Patterns That Repeat

Pattern 1 — Dummy Node: Prepend a dummy head node to avoid edge cases (empty list, inserting at head). Return dummy.next at the end. Appears in merge, remove, insert.
Pattern 2 — Fast/Slow Pointers: Detect cycles (Floyd's), find middle, find nth from end. Fast moves 2x, slow 1x.
Pattern 3 — Reversal: Three-pointer walk (prev, cur, next). In-place O(1) space. The base of all reversal problems.
Pattern 4 — Two Passes: First pass counts length or finds target. Second pass makes changes. Efficient when you need position from end.

Q059 · EASY Reverse a Linked List
Linked List
LeetCode #206
Must KnowAsked 8,000+Three-Pointer Template

Reverse a singly linked list iteratively and recursively.

Input1→2→3→4→5→null
Output5→4→3→2→1→null
Decode — Save Next, Flip Arrow, Advance Both

Three pointers: prev (starts null), cur (starts head), nxt (temp). At each step: save nxt = cur.next, point cur.next = prev, advance prev = cur, advance cur = nxt. When cur is null, prev is the new head.

1 → 2 → 3 → null (prev=null, cur=1) Step 1: nxt=2, 1→null, prev=1, cur=2 Step 2: nxt=3, 2→1, prev=2, cur=3 Step 3: nxt=null, 3→2, prev=3, cur=null cur is null → return prev=3→2→1→null ✓
C++ — Iterative O(n) O(1) and Recursive O(n) O(n) // Iterative — O(n) time, O(1) space (preferred) ListNode* reverseList(ListNode* head) { ListNode* prev = nullptr, *cur = head; while(cur){ ListNode* nxt = cur->next; // Save next cur->next = prev; // Reverse arrow prev = cur; cur = nxt; // Advance both } return prev; } // Recursive — O(n) time, O(n) stack space ListNode* reverseRec(ListNode* head){ if(!head || !head->next) return head; ListNode* newHead = reverseRec(head->next); head->next->next = head; // Point tail of reversed part back to head head->next = nullptr; // Disconnect head return newHead; }
TimeO(n)
SpaceO(1) iterative
Q060 · EASY Merge Two Sorted Lists
Linked List
LeetCode #21
Must KnowDummy Node Pattern

Merge two sorted linked lists. Return the head of the merged sorted list in-place (no extra nodes).

Input1→2→4 and 1→3→4
Output1→1→2→3→4→4
Decode — Dummy Head Eliminates Edge Cases

Create a dummy node as the starting point. Walk both lists with pointer tail. At each step, pick the smaller front node, attach it to tail, advance that list. After one list exhausts, attach the rest of the other. Return dummy.next.

C++ — Iterative O(m+n) O(1) and Recursive O(m+n) O(m+n) // Iterative ListNode* mergeTwoLists(ListNode* l1, ListNode* l2){ ListNode dummy(0); ListNode* tail = &dummy; while(l1 && l2){ if(l1->val <= l2->val){ tail->next=l1; l1=l1->next; } else { tail->next=l2; l2=l2->next; } tail=tail->next; } tail->next = l1 ? l1 : l2; // Attach remaining return dummy.next; } // Recursive — elegant but O(m+n) stack ListNode* mergeRec(ListNode* l1, ListNode* l2){ if(!l1) return l2; if(!l2) return l1; if(l1->val <= l2->val){ l1->next=mergeRec(l1->next,l2); return l1; } else { l2->next=mergeRec(l1,l2->next); return l2; } }
TimeO(m+n)
SpaceO(1)
Q061 · EASY Linked List Cycle Detection (Floyd's)
Linked ListFast/Slow
LeetCode #141 & #142
Must KnowFloyd's Cycle Detection

#141: Detect if a linked list has a cycle (O(1) space).
#142: Find the node where the cycle begins.

Decode — Fast Catches Slow Inside the Cycle; Reset to Find Start

Fast (2 steps) and slow (1 step). If there's a cycle, fast laps slow inside it → they meet. For the cycle start: reset one pointer to head, advance both one step at a time → they meet at the cycle entry. This works due to a mathematical proof involving distances.

List: 3→1→2→(back to 1) (cycle starts at node 1) Floyd meet: slow: 3→1→2→1→2 ... fast: 3→2→1→2→1 ... They meet at node 2 (inside cycle) Find start: reset ptr=head=3 ptr: 3→1 slow: 2→1 They meet at node 1 ← cycle start ✓
C++ — Both Parts // #141: Detect cycle bool hasCycle(ListNode* head){ ListNode* slow=head, *fast=head; while(fast && fast->next){ slow=slow->next; fast=fast->next->next; if(slow==fast) return true; } return false; } // #142: 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){ ListNode* ptr=head; while(ptr!=slow){ ptr=ptr->next; slow=slow->next; } return ptr; // Cycle entry node } } return nullptr; }
TimeO(n)
SpaceO(1)
Q062 · MEDIUM Remove Nth Node From End
Linked ListTwo Pointer
LeetCode #19
Must KnowOne-Pass Two-Pointer

Remove the nth node from the end of the list in one pass.

Input1→2→3→4→5, n=2
Output1→2→3→5
Decode — Lead Pointer n Steps Ahead, Both Move Until Lead Hits End

Two pointers starting at dummy head. Advance fast pointer n+1 steps. Then advance both until fast is null. slow is now the node BEFORE the one to delete. Relink: slow.next = slow.next.next. The dummy head handles the edge case where we delete the head.

dummy→1→2→3→4→5→null n=2 fast = dummy, advance n+1=3 steps: fast: dummy → 1 → 2 → 3 slow: dummy Both advance until fast is null: slow: dummy → 1 → 2 → 3 (fast=null) slow.next = node 4 slow.next = slow.next.next = node5 Result: dummy→1→2→3→5→null ✓
C++ Solution — O(n) time · O(1) space ListNode* removeNthFromEnd(ListNode* head, int n) { ListNode dummy(0, head); ListNode* slow=&dummy, *fast=&dummy; for(int i=0;i<=n;i++) fast=fast->next; // Advance fast n+1 steps while(fast){ slow=slow->next; fast=fast->next; } slow->next=slow->next->next; // Skip the nth-from-end node return dummy.next; }
TimeO(n)
SpaceO(1)
Q063 · MEDIUM Reorder List
Linked ListFast/Slow
LeetCode #143
Must KnowFind Mid → Reverse Second Half → Merge

Reorder list L0→L1→...→Ln to L0→Ln→L1→Ln-1→L2→Ln-2... in-place.

Input1→2→3→4→5
Output1→5→2→4→3
Decode — Three Steps: Find Middle, Reverse Second Half, Merge

1) Find middle with fast/slow pointers. 2) Reverse the second half in-place. 3) Merge the two halves by alternating nodes. This is O(n) time and O(1) space.

C++ Solution — O(n) time · O(1) space void reorderList(ListNode* head) { if(!head||!head->next) return; // Step 1: Find middle ListNode* slow=head, *fast=head; while(fast->next&&fast->next->next){ slow=slow->next; fast=fast->next->next; } // Step 2: Reverse second half ListNode* prev=nullptr, *cur=slow->next; slow->next=nullptr; while(cur){ ListNode* nxt=cur->next; cur->next=prev; prev=cur; cur=nxt; } // Step 3: Merge two halves ListNode* l1=head, *l2=prev; while(l2){ ListNode* n1=l1->next, *n2=l2->next; l1->next=l2; l2->next=n1; l1=n1; l2=n2; } }
TimeO(n)
SpaceO(1)
Q064 · MEDIUM Find the Middle of a Linked List
Linked ListFast/Slow
LeetCode #876
Must KnowFast/Slow Foundation

Return the middle node of a linked list. If even length, return the second middle.

Input1→2→3→4→5
Output3
Input 21→2→3→4→5→6
Output 24
C++ Solution — O(n) O(1) ListNode* middleNode(ListNode* head){ ListNode* slow=head, *fast=head; while(fast && fast->next){ slow=slow->next; fast=fast->next->next; } return slow; // For even length: returns second middle } // If you need first middle of even-length list: // condition: while(fast->next && fast->next->next)
TimeO(n)
SpaceO(1)
Q065 · HARD Merge K Sorted Lists
Linked ListHeap
LeetCode #23
Must KnowFAANG FavouriteMin-Heap Extracts Global Min

Merge k sorted linked lists into one sorted linked list.

Decode — Min-Heap Always Gives the Next Smallest Across All Lists

Push the head of each non-null list into a min-heap ordered by value. Pop the smallest, append to result, push that node's next (if exists). Repeat until heap is empty. Total nodes = n, each enters/exits heap once at O(log k). Overall: O(n log k).

Naive

Collect + Sort

Collect all values, sort, rebuild list. O(n log n) but loses the sorted structure.

Time: O(n log n)
Divide

Pairwise Merge

Merge lists in pairs. Like merge sort. O(n log k) but more complex code.

Time: O(n log k)
Optimal

Min-Heap

Priority queue of (value, node*). Always extract global min cleanly.

Time: O(n log k) ✓
C++ Solution — Min-Heap O(n log k) ListNode* mergeKLists(vector<ListNode*>& lists) { using P = pair<int, ListNode*>; priority_queue<P, vector<P>, greater<P>> pq; // Min-heap by value for(auto* l : lists) if(l) pq.push({l->val, l}); ListNode dummy(0); ListNode* tail = &dummy; while(!pq.empty()){ auto [v, node] = pq.top(); pq.pop(); tail->next = node; tail = tail->next; if(node->next) pq.push({node->next->val, node->next}); } return dummy.next; }
TimeO(n log k)
SpaceO(k)
Q066 · MEDIUM Reverse Linked List II (Reverse Between)
Linked List
LeetCode #92
Must KnowOne-Pass In-Place Reversal

Reverse the nodes of the list from position left to right (1-indexed) in one pass.

Input1→2→3→4→5, left=2, right=4
Output1→4→3→2→5
Decode — Walk to Start of Reversal, Then Repeatedly Move Nodes to Front

Walk (left-1) steps to reach the node before reversal starts (call it prev). Then for (right-left) times: take the node after prev.next (call it nxt), and move it to the front of the reversed segment. This is the "insertion at front" reversal technique.

dummy→1→2→3→4→5 left=2, right=4 Walk 1 step: prev=dummy→1, cur=1→next=2 Iteration 1 (left to right-left=2 times): nxt = cur.next = 3 cur.next = nxt.next = 4 nxt.next = prev.next = 2 prev.next = nxt = 3 List: dummy→1→3→2→4→5 Iteration 2: nxt = cur.next = 4 cur.next = nxt.next = 5 nxt.next = prev.next = 3 prev.next = nxt = 4 List: dummy→1→4→3→2→5 Return: 1→4→3→2→5 ✓
C++ Solution — O(n) time · O(1) space (one pass) ListNode* reverseBetween(ListNode* head, int left, int right) { ListNode dummy(0, head); ListNode* prev = &dummy; for(int i=1;i<left;i++) prev=prev->next; // Reach node before reversal ListNode* cur = prev->next; for(int i=0;i<right-left;i++){ ListNode* nxt = cur->next; // Node to move to front cur->next = nxt->next; nxt->next = prev->next; // Insert at front of reversed segment prev->next = nxt; } return dummy.next; }
TimeO(n)
SpaceO(1)
Q067 · MEDIUM Copy List with Random Pointer
Linked ListHash
LeetCode #138
Must KnowMap Old Nodes to New Nodes

Deep copy a linked list where each node has a next and a random pointer (can point to any node or null). Return the head of the copied list.

Decode — Two Passes: Create Nodes, Then Wire Random Pointers

Pass 1: Walk original list. For each node, create a new copy node and store it in a hash map: old → new. Pass 2: Walk again. Set new.next = map[old.next] and new.random = map[old.random]. Works because the map lets you look up any new node by its old counterpart.

C++ Solution — O(n) time · O(n) space Node* copyRandomList(Node* head){ if(!head) return nullptr; unordered_map<Node*,Node*> mp; // Pass 1: create all new nodes Node* cur=head; while(cur){ mp[cur]=new Node(cur->val); cur=cur->next; } // Pass 2: wire next and random cur=head; while(cur){ mp[cur]->next = mp[cur->next]; mp[cur]->random = mp[cur->random]; cur=cur->next; } return mp[head]; }
TimeO(n)
SpaceO(n)
O(1) spaceInterleave copy nodes between original nodes (3 passes)
Q068 · HARD LRU Cache
Doubly LLHash MapDesign
LeetCode #146
Must KnowAsked 6,000+System Design Classic

Design an LRU (Least Recently Used) cache with O(1) get and put operations. Evict the least recently used item when capacity is exceeded.

Decode — Hash Map for O(1) Lookup + Doubly Linked List for O(1) Ordering

Hash map: key → node pointer. Gives O(1) lookup. Doubly linked list: maintains recency order. Head = MRU (most recently used), tail = LRU. On get/put: move node to head. On eviction: remove tail. Two dummy sentinel nodes (head and tail) eliminate all edge cases. The combination is called a LinkedHashMap.

C++ Solution — O(1) get and put class LRUCache { struct Node{ int key,val; Node *prev,*next; }; int cap; unordered_map<int,Node*> mp; Node *head, *tail; // Sentinel dummies void remove(Node* n){ n->prev->next=n->next; n->next->prev=n->prev; } void insertFront(Node* n){ n->next=head->next; n->prev=head; head->next->prev=n; head->next=n; } public: LRUCache(int capacity):cap(capacity){ head=new Node{0,0,nullptr,nullptr}; tail=new Node{0,0,nullptr,nullptr}; head->next=tail; tail->prev=head; } int get(int key){ if(!mp.count(key)) return -1; remove(mp[key]); insertFront(mp[key]); // Move to MRU position return mp[key]->val; } void put(int key, int val){ if(mp.count(key)){ mp[key]->val=val; remove(mp[key]); insertFront(mp[key]); } else { if((int)mp.size()==cap){ Node* lru=tail->prev; // Evict LRU (before tail) remove(lru); mp.erase(lru->key); delete lru; } Node* n=new Node{key,val}; insertFront(n); mp[key]=n; } } };
get/putO(1)
SpaceO(capacity)
ExtensionLFU Cache (LC#460) · use freq → doubly-linked-list map
Q069 · MEDIUM Swap Nodes in Pairs
Linked List
LeetCode #24
Draw the 4 Pointers Before Coding

Swap every two adjacent nodes and return the head. Swap node links, not values.

Input1→2→3→4
Output2→1→4→3
Decode — Dummy Node + Rewire 4 Pointers Per Pair

Use a dummy head. For each pair (first, second): prev.next = second, first.next = second.next, second.next = first, advance prev = first. Draw this on paper first — the 4 pointer assignments must happen in exactly this order.

C++ Solution — O(n) O(1) ListNode* swapPairs(ListNode* head){ ListNode dummy(0,head); ListNode* prev=&dummy; while(prev->next && prev->next->next){ ListNode* first =prev->next; ListNode* second=first->next; first->next =second->next; // first skips second second->next =first; // second points to first prev->next =second; // prev connects to new first-of-pair prev=first; // advance to end of swapped pair } return dummy.next; }
TimeO(n)
SpaceO(1)
Q070 · HARD Reverse Nodes in K-Group
Linked ListRecursion
LeetCode #25
Must KnowFAANG FavouriteRecursive: Reverse Group Then Connect

Given a linked list, reverse every k nodes in groups. If remaining nodes < k, leave them as-is. Modify links — not values.

Input1→2→3→4→5, k=2
Output2→1→4→3→5
Input 21→2→3→4→5, k=3
Output 23→2→1→4→5
Decode — Count k Nodes, Reverse Group, Recurse on Rest

Check if at least k nodes remain. If not → return head as-is. Count k nodes, keep pointer to kth node and the node after. Reverse the k-node group. The original head becomes the new tail. Connect it to the recursive result of the remaining list.

1→2→3→4→5, k=2 First call: k=2 nodes exist (1,2). tail=node2, next=node3 Reverse [1,2] → [2,1] node1.next = reverseKGroup(node3, k=2) Second call: k=2 nodes (3,4). Reverse → [4,3] node3.next = reverseKGroup(node5, k=2) Third call: only 1 node, k=2 → return node5 as-is node3.next = node5 → [4→3→5] node1.next = node4 → [2→1→4→3→5] Return: 2→1→4→3→5
C++ Solution — O(n) time · O(n/k) stack space ListNode* reverseKGroup(ListNode* head, int k) { // Check if k nodes exist ListNode* cur=head; int cnt=0; while(cur && cnt<k){ cur=cur->next; cnt++; } if(cnt<k) return head; // Less than k nodes → no reversal // Reverse k nodes ListNode* prev=nullptr, *node=head; for(int i=0;i<k;i++){ ListNode* nxt=node->next; node->next=prev; prev=node; node=nxt; } // head is now the tail of the reversed group head->next = reverseKGroup(node, k); // Connect to rest return prev; // prev is new head of this group } // Iterative version using dummy node: ListNode* reverseKGroupIter(ListNode* head, int k){ ListNode dummy(0,head); ListNode* groupPrev=&dummy; while(true){ // Check if k nodes remain ListNode* kth=groupPrev; int c=k; while(kth&&c--) kth=kth->next; if(!kth) break; ListNode* groupNext=kth->next; // Reverse the group ListNode* prev=groupNext, *cur=groupPrev->next; while(cur!=groupNext){ ListNode* t=cur->next;cur->next=prev;prev=cur;cur=t; } ListNode* tmp=groupPrev->next; groupPrev->next=kth; groupPrev=tmp; } return dummy.next; }
TimeO(n)
SpaceO(n/k) recursive · O(1) iterative
RelatedReverse Between (Q066) · Reverse List (Q059)
↑ back to top