Playground Component
Remove Node
from End in Linked List Visualizer
An interactive linked list visualization that removes the nth node from the end using fast and slow pointers in one pass.

Remove Nth Node From End
List: [1, 2, 3, 4, 5]
Fast
—
Slow
—
Target
—
Step
0
Action
-
Status
Ready
Linked List
HeadNULL
dummy
1
2
3
4
5
Algorithm
1dummy.next = head; fast = slow = dummy2for (i = 0; i <= n; i++) fast = fast.next3while (fast != null) {4 fast = fast.next; slow = slow.next5}6slow.next = slow.next.next
Copy Code
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
<title>Remove Nth Node From End</title>
<style>
:root{--bg:#090909;--panel:#111;--gold:#f4c430;--gold-dark:#b88700;--text:#f5f5f5;--border:#2f2f2f;--blue:#4ea8ff;--red:#ff6b6b;--green:#25c05a}*{box-sizing:border-box}body{margin:0}.rmn-ll{min-height:100vh;padding:40px;background:radial-gradient(circle at top,#1a1505 0%,#090909 40%);color:var(--text);font-family:Poppins,Arial,sans-serif}.rmn-ll h2{text-align:center;font-size:3rem;color:var(--gold);margin:0 0 8px}.rmn-ll-subtitle{text-align:center;color:#999;margin-bottom:30px;font-size:.95rem}.rmn-ll-controls{display:flex;justify-content:center;align-items:center;gap:15px;flex-wrap:wrap;margin-bottom:16px}.rmn-ll-n-field{display:flex;align-items:center;gap:10px;background:#151515;border:1px solid #2b2b2b;border-radius:12px;padding:8px 16px}.rmn-ll-n-field label{color:#999;font-size:.85rem;font-weight:600}.rmn-ll-n-field input{width:60px;background:#0c0c0c;border:1px solid #333;border-radius:8px;color:var(--gold);font-size:1.1rem;font-weight:700;text-align:center;padding:6px 4px}.rmn-ll-button{padding:14px 22px;border:0;border-radius:12px;cursor:pointer;font-weight:600;font-size:15px;background:linear-gradient(180deg,#ffd54d,#d9a900);color:#111;display:inline-flex;align-items:center;gap:10px;transition:.25s}.rmn-ll-button:hover{transform:translateY(-2px)}.rmn-ll-button:disabled{cursor:not-allowed;opacity:.55;transform:none}.rmn-ll-button.secondary{background:#1c1c1c;color:var(--text);border:1px solid #333}.rmn-ll-error{text-align:center;color:var(--red);font-size:.85rem;min-height:20px;margin-bottom:20px}.rmn-ll-stats{width:100%;max-width:900px;margin:auto;margin-bottom:40px;display:grid;grid-template-columns:1fr 1fr 1fr 1fr 2fr 1fr;gap:18px}.rmn-ll-stat-box{background:#151515;border:1px solid #2b2b2b;border-radius:14px;padding:18px;text-align:center}.rmn-ll-stat-box h4{margin:0;color:#999;font-size:.9rem}.rmn-ll-stat-box p{margin:8px 0 0;color:var(--gold);font-size:1.4rem;font-weight:bold}.rmn-ll-result{width:100%;max-width:900px;margin:0 auto 30px;padding:16px 22px;border-radius:14px;display:flex;align-items:center;justify-content:center;gap:12px;font-size:1.2rem;font-weight:700;border:1px solid var(--green);background:rgba(37,192,90,.1);color:var(--green);animation:pop .35s ease}@keyframes pop{from{transform:scale(.94);opacity:0}}.rmn-ll-code,.rmn-ll-stage{width:100%;max-width:1400px;margin:0 auto 30px;padding:24px 26px 20px;border:1px solid var(--border);border-radius:18px;background:#111}.rmn-ll-code h3,.rmn-ll-stage h3{margin:0 0 16px;text-align:center;color:var(--gold);font-size:1.6rem}.rmn-ll-code-block{margin:0;font-family:"Fira Code","Courier New",monospace;font-size:1rem;line-height:1.9;background:#0c0c0c;border:1px solid #222;border-radius:12px;padding:16px 10px}.rmn-ll-code-line{display:flex;gap:16px;padding:2px 14px;border-left:3px solid transparent;border-radius:6px;color:#8a8a8a;white-space:pre;transition:.3s}.rmn-ll-code-linenum{color:#4a4a4a;font-size:.85rem;min-width:16px;text-align:right}.rmn-ll-code-line.active{color:var(--gold);background:rgba(244,196,48,.1);border-left-color:var(--gold);transform:translateX(4px);animation:glow 1.1s ease-in-out infinite}.rmn-ll-code-line.active .rmn-ll-code-linenum{color:var(--gold)}@keyframes glow{50%{box-shadow:0 0 18px rgba(244,196,48,.32) inset,0 0 20px rgba(244,196,48,.28)}}.rmn-ll-stage{padding:28px 30px 34px}.rmn-ll-stage h3{margin-bottom:28px}.rmn-ll-chain{display:flex;align-items:center;justify-content:center;gap:10px;min-height:132px;overflow-x:auto;padding:8px 4px 22px}.rmn-ll-label,.rmn-ll-null{color:var(--gold);font-weight:700;white-space:nowrap}.rmn-ll-node-wrap{display:flex;flex-direction:column;align-items:center;gap:8px;min-width:82px;max-width:82px;overflow:visible;opacity:1;transition:max-width .5s cubic-bezier(.4,0,.2,1),min-width .5s cubic-bezier(.4,0,.2,1),margin .5s cubic-bezier(.4,0,.2,1),opacity .35s ease .1s}.rmn-ll-node-wrap.collapsing{min-width:0;max-width:0;margin-left:-5px;margin-right:-5px;opacity:0;overflow:hidden}.rmn-ll-pointer-stack{width:100%;height:44px;display:flex;align-items:flex-end;justify-content:center;flex-wrap:wrap;gap:4px}.rmn-ll-pointer-badge{position:relative;z-index:2;min-width:34px;min-height:18px;padding:2px 5px;border:1px solid #343434;border-radius:5px;background:#111;color:#999;display:inline-flex;align-items:center;justify-content:center;font-size:.68rem;font-weight:700;text-transform:uppercase;animation:badge .3s cubic-bezier(.4,0,.2,1)}@keyframes badge{from{transform:translateY(6px) scale(.8);opacity:0}}.fast-pointer{border-color:var(--red);color:#ffaaa8}.slow-pointer{border-color:var(--blue);color:#91c8ff}.rmn-ll-node{width:72px;height:72px;border-radius:16px;background:linear-gradient(180deg,#1c1c1c,#151515);border:2.5px solid #454545;color:var(--text);display:flex;align-items:center;justify-content:center;font-size:1.3rem;font-weight:700;box-shadow:0 4px 12px rgba(0,0,0,.5),inset 0 1px 0 rgba(255,255,255,.04);transition:.4s}.rmn-ll-node.dummy{width:56px;height:56px;border-style:dashed;border-color:#5a5a5a;background:#141414;color:#888;font-size:.7rem;text-transform:uppercase}.rmn-ll-node.fast-on{border-color:var(--red)}.rmn-ll-node.slow-on,.rmn-ll-node.prev{border-color:var(--blue)}.rmn-ll-node.target-on,.rmn-ll-node.target{background:#ffb000;color:#000;border-color:#ffd54d;transform:translateY(-8px) scale(1.05);box-shadow:0 0 20px rgba(255,193,7,.45)}.rmn-ll-node.removing{opacity:0;transform:scale(.4) translateY(10px);box-shadow:none}.rmn-ll-node.done{background:#25c05a;color:#fff;border-color:#43e97b;box-shadow:0 0 22px rgba(37,192,90,.35)}.rmn-ll-arrow{position:relative;width:78px;height:22px;flex:0 0 78px;opacity:1;transition:.5s}.rmn-ll-arrow.collapsing{flex-basis:0;width:0;margin:0 -5px;opacity:0}.rmn-ll-arrow:before{content:"";position:absolute;left:0;right:13px;top:50%;height:4px;border-radius:999px;background:var(--gold);transform:translateY(-50%)}.rmn-ll-arrow:after{content:"";position:absolute;right:0;top:50%;border-top:11px solid transparent;border-bottom:11px solid transparent;border-left:17px solid var(--gold);transform:translateY(-50%)}.rmn-ll-arrow.reconnected{animation:arrowglow .9s ease-in-out 2}@keyframes arrowglow{50%{filter:drop-shadow(0 0 8px rgba(244,196,48,.8))}}.rmn-ll-dot{width:20px;height:20px;border-radius:50%;background:var(--gold-dark);box-shadow:0 0 18px rgba(244,196,48,.3)}@media(max-width:768px){.rmn-ll{padding:20px}.rmn-ll h2{font-size:2rem}.rmn-ll-stats{grid-template-columns:repeat(2,1fr)}.rmn-ll-code,.rmn-ll-stage{padding:18px 14px 14px}.rmn-ll-code-block{font-size:.85rem}.rmn-ll-chain{justify-content:flex-start}.rmn-ll-node{width:58px;height:58px;font-size:1rem}.rmn-ll-node-wrap{min-width:58px}.rmn-ll-arrow{width:56px;flex-basis:56px}}
</style>
</head>
<body><main class="rmn-ll"><h2>Remove Nth Node From End</h2><p id="subtitle" class="rmn-ll-subtitle"></p><div class="rmn-ll-controls"><div class="rmn-ll-n-field"><label for="nInput">n =</label><input id="nInput" type="number" min="1"></div><button id="runBtn" class="rmn-ll-button">Remove Nth From End</button><button id="pauseBtn" class="rmn-ll-button">Pause</button><button id="speedBtn" class="rmn-ll-button"></button><button id="newBtn" class="rmn-ll-button secondary">New List</button><button id="resetBtn" class="rmn-ll-button secondary">Reset</button></div><p id="error" class="rmn-ll-error"></p><div id="stats" class="rmn-ll-stats"></div><div id="result"></div><section class="rmn-ll-stage"><h3>Linked List</h3><div id="chain" class="rmn-ll-chain"></div></section><section class="rmn-ll-code"><h3>Algorithm</h3><pre id="code" class="rmn-ll-code-block"></pre></section></main>
<script>
const speedLevels=[["Very Slow",900],["Slow",650],["Normal",450],["Fast",260],["Very Fast",120]],codeLines=["dummy.next = head; fast = slow = dummy","for (i = 0; i <= n; i++) fast = fast.next","while (fast != null) {"," fast = fast.next; slow = slow.next","}","slow.next = slow.next.next"],lineMap={"Init fast & slow at dummy":0,"Advance fast":1,"Check fast != null":2,"Move fast & slow":3,"Found predecessor":5,"Remove target node":5,"Relink list":5};
let values=[1,2,3,4,5],nodes,links,speedIndex=2,nInput="2",nError="",fastIndex=null,slowIndex=null,targetIndex=null,reconnectedLink=null,collapsing={node:null,arrow:null},step=0,action="-",status="Ready",removedValue=null,running=false,paused=false;
const sleep=ms=>new Promise(async r=>setTimeout(async()=>{while(paused)await new Promise(x=>setTimeout(x,120));r()},ms));const build=vals=>vals.map(value=>({value,state:"default"}));function randomList(){let len=5+Math.floor(Math.random()*3),used=new Set(),a=[];while(a.length<len){let v=1+Math.floor(Math.random()*90);if(!used.has(v)){used.add(v);a.push(v)}}return a}
function reset(force=false,nextValues=values){if(running&&!force)return;paused=false;nodes=build(nextValues);links=Array(nextValues.length).fill("forward");fastIndex=null;slowIndex=null;targetIndex=null;reconnectedLink=null;collapsing={node:null,arrow:null};step=0;action="-";status="Ready";removedValue=null;nError="";running=false;render()}
function pointerLabel(i){if(i===null||i===undefined)return "-";if(i===-1)return"dummy";if(i>=values.length)return"NULL";return values[i]}function mark(i,s){nodes=nodes.map((n,idx)=>idx===i?{...n,state:s}:n)}
function badges(i){let b="";if(i===fastIndex)b+=`<span class="rmn-ll-pointer-badge fast-pointer">Fast</span>`;if(i===slowIndex)b+=`<span class="rmn-ll-pointer-badge slow-pointer">Slow</span>`;return b}function nodeClass(i){let c=["rmn-ll-node",nodes[i].state];if(i===fastIndex)c.push("fast-on");if(i===slowIndex)c.push("slow-on");if(i===targetIndex)c.push("target-on");return c.join(" ")}
function render(){subtitle.textContent="List: ["+values.join(", ")+"]";nInputEl.value=nInput;nInputEl.max=values.length;error.textContent=nError;runBtn.disabled=running||status==="Completed";pauseBtn.disabled=!running;pauseBtn.textContent=paused?"Play":"Pause";speedBtn.textContent="Speed: "+speedLevels[speedIndex][0];newBtn.disabled=running;nInputEl.disabled=running;stats.innerHTML=[["Fast",pointerLabel(fastIndex)],["Slow",pointerLabel(slowIndex)],["Target",targetIndex!==null?values[targetIndex]:"-"],["Step",step],["Action",action],["Status",status]].map(x=>`<div class="rmn-ll-stat-box"><h4>${x[0]}</h4><p>${x[1]}</p></div>`).join("");result.innerHTML=removedValue!==null?`<div class="rmn-ll-result">Removed node with value ${removedValue}</div>`:"";let dummyBadges=badges(-1),html=`<span class="rmn-ll-label">Head</span><span class="rmn-ll-arrow"></span><div class="rmn-ll-node-wrap"><div class="rmn-ll-pointer-stack">${dummyBadges}</div><div class="rmn-ll-node dummy">dummy</div></div><span class="rmn-ll-arrow ${reconnectedLink===-1?"reconnected":""} ${collapsing.arrow&&collapsing.arrow.type==="dummy"?"collapsing":""}"></span>`;values.forEach((_,i)=>{html+=`<div class="rmn-ll-node-wrap ${collapsing.node===i?"collapsing":""}"><div class="rmn-ll-pointer-stack">${badges(i)}</div><div class="${nodeClass(i)}">${nodes[i].value}</div></div>`;if(i<values.length-1)html+=`<span class="rmn-ll-arrow ${reconnectedLink===i?"reconnected":""} ${collapsing.arrow&&collapsing.arrow.type==="link"&&collapsing.arrow.index===i?"collapsing":""}"></span>`});html+=`<span class="rmn-ll-arrow"></span><span class="rmn-ll-dot"></span><span class="rmn-ll-null">NULL</span>`;chain.innerHTML=html;let active=running||status==="Completed"?lineMap[action]:null;code.innerHTML=codeLines.map((l,i)=>`<div class="rmn-ll-code-line ${active===i?"active":""}"><span class="rmn-ll-code-linenum">${i+1}</span><span>${l}</span></div>`).join("")}
async function runRemoval(){if(running)return;let n=parseInt(nInput,10);if(!Number.isInteger(n)||n<1||n>values.length){nError=`n must be between 1 and ${values.length}`;render();return}reset(true,values);running=true;status="Running";let len=values.length,currentStep=0,fast=-1,slow=-1;fastIndex=fast;slowIndex=slow;action="Init fast & slow at dummy";step=++currentStep;render();await sleep(speedLevels[speedIndex][1]);for(let i=0;i<=n;i++){action="Advance fast";fast++;fastIndex=fast;if(fast>=0&&fast<len)mark(fast,"fast");step=++currentStep;render();await sleep(speedLevels[speedIndex][1])}while(fast<len){action="Check fast != null";step=++currentStep;render();await sleep(speedLevels[speedIndex][1]);if(fast>=0&&fast<len)mark(fast,"default");if(slow>=0&&slow<len)mark(slow,"default");fast++;slow++;fastIndex=fast;slowIndex=slow;if(fast>=0&&fast<len)mark(fast,"fast");if(slow>=0&&slow<len)mark(slow,"prev");action="Move fast & slow";step=++currentStep;render();await sleep(speedLevels[speedIndex][1])}let target=slow+1;targetIndex=target;mark(target,"target");action="Found predecessor";step=++currentStep;render();await sleep(speedLevels[speedIndex][1]);action="Remove target node";mark(target,"removing");step=++currentStep;render();await sleep(speedLevels[speedIndex][1]);let removed=values[target],arrowAfter=target<len-1,arrowToCollapse=arrowAfter?{type:"link",index:target}:target>0?{type:"link",index:target-1}:{type:"dummy"};action="Relink list";collapsing={node:target,arrow:arrowToCollapse};step=++currentStep;render();await sleep(600);values=values.slice(0,target).concat(values.slice(target+1));nodes=build(values);links=Array(Math.max(values.length,1)).fill("forward");fastIndex=null;slowIndex=null;targetIndex=null;collapsing={node:null,arrow:null};removedValue=removed;reconnectedLink=arrowAfter?(target>0?target-1:-1):null;render();await sleep(speedLevels[speedIndex][1]);nodes=nodes.map(n=>({...n,state:"done"}));reconnectedLink=null;status="Completed";running=false;paused=false;render()}
const nInputEl=document.getElementById("nInput");nInputEl.oninput=e=>{nInput=e.target.value;nError="";render()};runBtn.onclick=runRemoval;pauseBtn.onclick=()=>{paused=!paused;status=paused?"Paused":"Running";render()};speedBtn.onclick=()=>{speedIndex=(speedIndex+1)%speedLevels.length;render()};newBtn.onclick=()=>{if(running)return;values=randomList();nInput=String(1+Math.floor(Math.random()*values.length));reset(true,values)};resetBtn.onclick=()=>reset();reset(true,values);
</script></body></html>
About this Component
Removing the nth node from the end of a linked list is commonly solved with two pointers separated by n nodes. This visualizer shows the fast pointer advancing first, then fast and slow moving together until fast reaches the end. The slow pointer then identifies the node before the one that must be removed. The two-pointer method runs in O(n) time and uses O(1) extra space because it completes the removal in a single traversal.
Explore More Components
Discover more components from the Playground.



