测试
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=Newsreader:ital,wght@0,400;0,500;0,600;0,700;1,500&family=Noto+Serif+SC:wght@400;500;600;700;900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@5/dist/reveal.css">
<style>
/* ================= 容器与变量(全部作用域到 #lc-deck) ================= */
#lc-deck{
--r-background-color:#0b1220;--slide-w:1600px;--slide-h:900px;
--page-x:88px;--page-top:34px;--page-bottom:24px;--header-h:60px;--footer-h:48px;
--bg:#0b1220;--text:#f2f6fc;--muted:#a1b0c5;--subtle:#8295ad;--blue:#65b9ff;--orange:#ffb36b;--green:#6bd6ae;--red:#ff8585;--pink:#ff9ecd;--cyan:#7fe7ff;
--line:rgba(180,205,235,.12);--line2:rgba(180,205,235,.25);--surface:rgba(101,185,255,.055);--surface2:rgba(255,255,255,.035);
--font:"Newsreader","Noto Serif SC","Songti SC",serif;--mono:"IBM Plex Mono",monospace;--ease:cubic-bezier(.22,.7,.24,1);
position:relative;width:100%;max-width:1600px;margin:0 auto;
aspect-ratio:16/9;overflow:hidden;border-radius:12px;
background:var(--bg);color:var(--text);font-family:var(--font);-webkit-font-smoothing:antialiased;
}
#lc-deck *,#lc-deck *::before,#lc-deck *::after{box-sizing:border-box}
/* ================= reveal 容器 ================= */
#lc-deck .reveal{width:100%;height:100%;font-size:24px;color:var(--text);
background-color:var(--bg);
background-image:radial-gradient(ellipse 120% 100% at 82% 8%,rgba(101,185,255,.085),transparent 55%),
radial-gradient(ellipse 85% 85% at 8% 92%,rgba(107,214,174,.045),transparent 55%),
linear-gradient(rgba(180,205,235,.025) 1px,transparent 1px),
linear-gradient(90deg,rgba(180,205,235,.025) 1px,transparent 1px);
background-size:100% 100%,100% 100%,88px 88px,88px 88px;background-attachment:scroll}
#lc-deck .reveal .slides{text-align:left}
#lc-deck .reveal .slides section{width:var(--slide-w);height:var(--slide-h);
padding:var(--page-top) var(--page-x) var(--page-bottom);overflow:hidden;background:transparent;box-shadow:none}
#lc-deck .reveal h1,#lc-deck .reveal h2,#lc-deck .reveal h3,#lc-deck .reveal p{margin:0;color:var(--text)}
#lc-deck .reveal h1,#lc-deck .reveal h2,#lc-deck .reveal h3{font-weight:700;letter-spacing:-.025em}
#lc-deck .reveal p{line-height:1.65;color:var(--muted)}
/* ================= 版式骨架 ================= */
#lc-deck .slide-frame{width:100%;height:100%;display:grid;grid-template-rows:var(--header-h) minmax(0,1fr) var(--footer-h)}
#lc-deck .slide-header{display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid var(--line);padding-bottom:12px}
#lc-deck .header-left{display:flex;align-items:center;gap:20px}
#lc-deck .chapter-index{font:600 16px var(--mono);color:var(--blue);position:relative}
#lc-deck .chapter-index::after{content:"";position:absolute;left:0;bottom:-18px;width:100%;height:2px;background:var(--blue)}
#lc-deck .chapter-name{font-size:18px;color:var(--muted)}
#lc-deck .header-meta{font:14px var(--mono);letter-spacing:.13em;color:var(--subtle)}
#lc-deck .slide-main{position:relative;min-height:0;padding-top:16px;overflow:hidden}
#lc-deck .slide-footer{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;border-top:1px solid var(--line);padding-top:9px;color:var(--subtle);font-size:12px;gap:12px;min-width:0}
#lc-deck .footer-left{justify-self:start;font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
#lc-deck .footer-right{justify-self:end;font:11px var(--mono);white-space:nowrap}
#lc-deck .global-concepts{display:flex;gap:12px;align-items:center;justify-content:center;font:10px var(--mono);letter-spacing:.04em;color:var(--subtle);white-space:nowrap}
#lc-deck .global-concepts b{color:var(--blue);font-weight:500}
/* ================= 文字工具类 ================= */
#lc-deck .eyebrow{display:inline-block;margin-bottom:9px;font:600 12px var(--mono);letter-spacing:.14em;color:var(--blue)}
#lc-deck .section-title{font-size:37px;line-height:1.16;margin-bottom:14px!important}
#lc-deck .muted{color:var(--muted)} #lc-deck .blue{color:var(--blue)} #lc-deck .orange{color:var(--orange)}
#lc-deck .green{color:var(--green)} #lc-deck .red{color:var(--red)} #lc-deck .cyan{color:var(--cyan)}
#lc-deck .mono{font-family:var(--mono)} #lc-deck .small{font-size:14px} #lc-deck .tiny{font-size:11px}
#lc-deck .lead{font-size:19px;line-height:1.52;color:var(--muted)}
/* ================= 卡片 ================= */
#lc-deck .card{background:var(--surface);border:1px solid var(--line2);border-radius:12px;padding:18px}
#lc-deck .card.soft{background:var(--surface2);border-color:var(--line)}
#lc-deck .card h3{font-size:19px;margin-bottom:9px}
#lc-deck .card p{font-size:15px;line-height:1.52}
#lc-deck .tag{display:inline-flex;align-items:center;padding:4px 8px;border:1px solid var(--line2);border-radius:6px;font:11px var(--mono);color:var(--muted);letter-spacing:.03em}
#lc-deck .pill{display:inline-flex;align-items:center;gap:8px;padding:7px 12px;border-radius:99px;background:rgba(101,185,255,.1);border:1px solid rgba(101,185,255,.25);font:13px var(--mono);color:var(--blue)}
/* ================= 栅格 ================= */
#lc-deck .grid2{display:grid;grid-template-columns:1fr 1fr;gap:16px}
#lc-deck .grid4{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}
#lc-deck .two-col{display:grid;grid-template-columns:1.05fr .95fr;gap:44px;height:100%}
#lc-deck .stack{display:flex;flex-direction:column;gap:12px}
#lc-deck .rule{height:1px;background:var(--line);margin:12px 0}
#lc-deck .bullet-list{display:grid;gap:8px}
#lc-deck .bullet{display:flex;gap:12px;align-items:flex-start;font-size:16px;line-height:1.45;color:var(--muted)}
#lc-deck .bullet::before{content:"";width:7px;height:7px;flex:none;margin-top:10px;border-radius:50%;background:var(--blue)}
/* ================= 封面 ================= */
#lc-deck .cover-layout{display:grid;grid-template-columns:1.1fr .9fr;gap:40px;height:100%;align-items:center}
#lc-deck .cover-title{font-size:88px;line-height:1.08;font-weight:900;margin:0 0 24px}
#lc-deck .cover-sub{font-size:26px;line-height:1.55;color:var(--muted);max-width:720px;border-left:3px solid var(--blue);padding-left:22px}
#lc-deck .cover-visual{display:flex;justify-content:center;align-items:center}
#lc-deck .cover-visual svg{width:100%;max-width:540px}
/* ================= 数组 ================= */
#lc-deck .array{display:flex;gap:8px;justify-content:center;align-items:flex-start;position:relative;padding:28px 6px 10px}
#lc-deck .cell{width:68px;height:62px;border:1px solid var(--line2);border-radius:9px;background:rgba(255,255,255,.035);
display:flex;align-items:center;justify-content:center;position:relative;font:21px var(--mono);color:var(--text);transition:.25s}
#lc-deck .cell small{position:absolute;bottom:-22px;color:var(--subtle);font:10px var(--mono)}
#lc-deck .cell.keep{border-color:rgba(107,214,174,.7);background:rgba(107,214,174,.12);color:var(--green)}
#lc-deck .cell.drop{border-color:rgba(255,133,133,.6);background:rgba(255,133,133,.10);color:var(--red)}
#lc-deck .cell.scan{outline:2px solid var(--orange);outline-offset:4px}
#lc-deck .cell.write{box-shadow:0 0 0 2px rgba(101,185,255,.55) inset}
#lc-deck .array-label{font:11px var(--mono);color:var(--subtle);text-align:center;margin-top:17px}
/* ================= 流程图 ================= */
#lc-deck .flow-wrap{background:rgba(5,10,20,.36);border:1px solid var(--line);border-radius:14px;padding:12px 16px}
#lc-deck .flow-svg{width:100%;height:100%;display:block}
#lc-deck .flow-svg text{font-family:"Noto Serif SC",serif}
#lc-deck .flow-caption{display:flex;gap:16px;align-items:center;color:var(--muted);font-size:12px;margin-top:8px;flex-wrap:wrap}
#lc-deck .legend-dot{width:9px;height:9px;border-radius:50%;display:inline-block;margin-right:6px}
/* ================= 步骤卡 ================= */
#lc-deck .steps{display:grid;grid-template-columns:repeat(5,1fr);gap:9px}
#lc-deck .step-card{background:var(--surface2);border:1px solid var(--line);border-radius:11px;padding:12px;min-height:105px}
#lc-deck .step-card .num{font:14px var(--mono);color:var(--blue);margin-bottom:8px}
#lc-deck .step-card strong{display:block;font-size:16px;margin-bottom:7px}
#lc-deck .step-card p{font-size:12px;line-height:1.45}
/* ================= 交互实验室 ================= */
#lc-deck .lab-layout{display:grid;grid-template-columns:1.08fr .92fr;gap:20px;flex:1;min-height:0;height:auto}
#lc-deck .lab-left{min-height:0;display:flex;flex-direction:column;justify-content:space-between;gap:12px}
#lc-deck .lab-right{min-height:0;display:flex;flex-direction:column;gap:10px;overflow:hidden}
#lc-deck .lab-right .card{padding:14px}
#lc-deck .lab-right .card h3{font-size:17px}
#lc-deck .lab-array{margin:8px 0 20px}
#lc-deck .lab-status{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
#lc-deck .metric{padding:9px 10px;background:var(--surface2);border:1px solid var(--line);border-radius:9px}
#lc-deck .metric label{display:block;color:var(--subtle);font:10px var(--mono);margin-bottom:6px}
#lc-deck .metric strong{font:17px var(--mono);color:var(--text)}
#lc-deck .lab-log{min-height:104px;padding:14px;background:rgba(101,185,255,.06);border:1px solid rgba(101,185,255,.2);border-radius:12px}
#lc-deck .lab-log .decision{font-size:18px;color:var(--text);margin-bottom:8px}
#lc-deck .lab-log p{font-size:14px;line-height:1.45}
#lc-deck .lab-controls{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
#lc-deck .btn{border:1px solid var(--line2);background:rgba(255,255,255,.05);color:var(--text);border-radius:8px;padding:8px 12px;font:12px var(--mono);cursor:pointer;transition:.2s}
#lc-deck .btn:hover{border-color:var(--blue);color:var(--blue)}
#lc-deck .btn.primary{background:rgba(101,185,255,.14);border-color:rgba(101,185,255,.55);color:var(--blue)}
#lc-deck .btn:disabled{opacity:.35;cursor:not-allowed}
#lc-deck .state-track{display:flex;height:16px;border-radius:99px;overflow:hidden;background:rgba(255,255,255,.06);margin:8px 0}
#lc-deck .track-done{background:var(--green);transition:width .3s}
#lc-deck .track-left{background:rgba(101,185,255,.35);flex:1}
#lc-deck .code-mini{font:14px/1.8 var(--mono);white-space:pre-wrap;color:#d8e2ee;background:#060a14;border:1px solid var(--line);padding:16px;border-radius:10px}
#lc-deck .code-mini .active-line{color:var(--orange)}
/* ================= 代码窗口 ================= */
#lc-deck .code-window{display:flex;flex-direction:column;background:#060a14;border:1px solid var(--line2);border-radius:12px;overflow:hidden;flex:1;min-height:0;height:auto}
#lc-deck .code-tabs{display:flex;gap:8px;padding:0 16px;border-bottom:1px solid var(--line);background:rgba(255,255,255,.025);flex:none}
#lc-deck .code-tab{padding:10px 15px;border:0;border-bottom:2px solid transparent;background:none;color:var(--subtle);font:12px var(--mono);cursor:pointer}
#lc-deck .code-tab.active{color:var(--blue);border-bottom-color:var(--blue);background:rgba(101,185,255,.05)}
#lc-deck .code-pane{display:none;overflow:auto;padding:16px 20px;flex:1;min-height:0}
#lc-deck .code-pane.active{display:block}
#lc-deck .code-pane pre{margin:0;color:#d8e2ee;font:14px/1.65 var(--mono);white-space:pre}
#lc-deck .code-note{padding:10px 16px;border-top:1px solid var(--line);font-size:13px;line-height:1.45;color:var(--muted);flex:none}
/* ================= reveal 控件 ================= */
#lc-deck .reveal .controls{right:28px;bottom:24px}
#lc-deck .reveal .controls button{color:var(--blue)!important;opacity:.45}
#lc-deck .reveal .controls button:hover:not([disabled]){opacity:1;filter:drop-shadow(0 0 8px rgba(101,185,255,.4))}
#lc-deck .reveal .progress{height:3px;color:var(--blue)}
#lc-deck .reveal .slide-number{font:12px var(--mono);color:var(--subtle);background:transparent}
/* ================= 动效 ================= */
#lc-deck .reveal .slides section.present .rise{animation:lc-rise .55s var(--ease) both}
@keyframes lc-rise{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}
/* ================= 各页微调 ================= */
#lc-deck .reveal .slides section:nth-of-type(3) .grid2{height:auto!important;flex:1;min-height:0}
#lc-deck .reveal .slides section:nth-of-type(3) .card{padding:16px 18px}
/* ----- 第7、8页流程图通用布局 ----- */
#lc-deck .reveal .slides section:nth-of-type(7) .slide-main,
#lc-deck .reveal .slides section:nth-of-type(8) .slide-main {
display: flex;
flex-direction: column;
height: 100%;
}
#lc-deck .reveal .slides section:nth-of-type(7) .flow-wrap,
#lc-deck .reveal .slides section:nth-of-type(8) .flow-wrap {
flex: 1;
min-height: 0;
display: flex;
align-items: center;
justify-content: center;
}
#lc-deck .reveal .slides section:nth-of-type(7) .flow-svg,
#lc-deck .reveal .slides section:nth-of-type(8) .flow-svg {
width: 100%;
height: 100%;
max-height: none;
}
/* ----- 第7页:底部留白微调 ----- */
#lc-deck .reveal .slides section:nth-of-type(7) .flow-wrap {
margin-bottom: 6px;
}
/* ----- 第8页:底部双卡片微调 ----- */
#lc-deck .reveal .slides section:nth-of-type(8) .grid2 {
margin-top: 12px !important;
flex: none;
}
#lc-deck .reveal .slides section:nth-of-type(8) .card {
padding: 14px 17px;
}
/* 其余页面微调 */
#lc-deck .reveal .slides section:nth-of-type(10) .slide-main{display:flex;flex-direction:column}
#lc-deck .reveal .slides section:nth-of-type(10) .section-title{flex:none}
#lc-deck .reveal .slides section:nth-of-type(12) .card{padding:16px}
#lc-deck .reveal .slides section:nth-of-type(12) .card p{font-size:14px}
</style>
<div id="lc-deck">
<div class="reveal"><div class="slides">
<!-- 01 COVER -->
<section data-transition="fade">
<div class="slide-frame" style="grid-template-rows:1fr 62px">
<div class="cover-layout">
<div>
<div class="eyebrow">ALGORITHM ANALYSIS · LEETCODE 27</div>
<h1 class="cover-title">移除元素</h1>
<div class="cover-sub">从信息空间出发,识别信息质点与约束条件,明确熵减目标,再推导双指针处理流程。</div>
<div style="display:flex;gap:10px;margin-top:28px;flex-wrap:wrap"><span class="pill">原地修改</span><span class="pill">快慢双指针</span><span class="pill">流程驱动分析</span></div>
</div>
<div class="cover-visual">
<svg viewBox="0 0 560 430" role="img" aria-label="快慢指针扫描数组示意图">
<defs><linearGradient id="g1" x1="0" x2="1"><stop stop-color="#65b9ff" stop-opacity=".2"/><stop offset="1" stop-color="#6bd6ae" stop-opacity=".2"/></linearGradient></defs>
<circle cx="280" cy="205" r="170" fill="none" stroke="rgba(101,185,255,.16)" stroke-width="1.5" stroke-dasharray="7 10"/>
<path d="M75 205 H485" stroke="rgba(180,205,235,.16)" stroke-width="1"/>
<g transform="translate(62 155)">
<rect x="0" y="0" width="72" height="72" rx="9" fill="rgba(255,133,133,.12)" stroke="#ff8585"/><text x="36" y="46" fill="#ff8585" font-size="27" text-anchor="middle">3</text>
<rect x="82" y="0" width="72" height="72" rx="9" fill="rgba(107,214,174,.12)" stroke="#6bd6ae"/><text x="118" y="46" fill="#6bd6ae" font-size="27" text-anchor="middle">2</text>
<rect x="164" y="0" width="72" height="72" rx="9" fill="rgba(107,214,174,.12)" stroke="#6bd6ae"/><text x="200" y="46" fill="#6bd6ae" font-size="27" text-anchor="middle">2</text>
<rect x="246" y="0" width="72" height="72" rx="9" fill="rgba(255,133,133,.12)" stroke="#ff8585"/><text x="282" y="46" fill="#ff8585" font-size="27" text-anchor="middle">3</text>
<text x="36" y="105" fill="#8295ad" font-size="14" text-anchor="middle">0</text><text x="118" y="105" fill="#8295ad" font-size="14" text-anchor="middle">1</text><text x="200" y="105" fill="#8295ad" font-size="14" text-anchor="middle">2</text><text x="282" y="105" fill="#8295ad" font-size="14" text-anchor="middle">3</text>
<path d="M36 -24 V-5" stroke="#ffb36b" stroke-width="2"/><text x="36" y="-34" fill="#ffb36b" font-size="15" text-anchor="middle">fast</text>
<path d="M36 132 V113" stroke="#65b9ff" stroke-width="2"/><text x="36" y="153" fill="#65b9ff" font-size="15" text-anchor="middle">slow</text>
</g>
<text x="280" y="365" fill="#a1b0c5" font-size="17" text-anchor="middle">扫描输入 · 筛选质点 · 原地重建有效前缀</text>
</svg>
</div>
</div>
<footer class="slide-footer" style="border:0"><div class="footer-left">数据结构与算法 · 单题分析</div><div class="global-concepts"><span><b>空间</b> 定义范围</span><span><b>质点</b> 承载数据</span><span><b>约束</b> 决定规则</span><span><b>熵减</b> 驱动收敛</span></div><div class="footer-right">01 / 12</div></footer>
</div>
</section>
<!-- 02 QUESTION -->
<section data-transition="slide">
<div class="slide-frame">
<header class="slide-header"><div class="header-left"><span class="chapter-index">01</span><span class="chapter-name">题目定义</span></div><span class="header-meta">PROBLEM · LC 27</span></header>
<main class="slide-main">
<div class="two-col">
<div class="stack">
<div><div class="eyebrow">QUESTION</div><h2 class="section-title">原地移除指定元素</h2><p class="lead">给你一个数组 <span class="mono cyan">nums</span> 和一个值 <span class="mono cyan">val</span>,你需要 <strong style="color:var(--text)">原地移除</strong>所有数值等于 <span class="mono cyan">val</span> 的元素,并返回移除后数组的新长度。</p></div>
<div class="card"><h3 class="orange">题目真正要求什么?</h3><div class="bullet-list"><div class="bullet">不能依赖另一个数组保存最终结果。</div><div class="bullet">前 <span class="mono cyan">k</span> 个位置必须全部是不等于 <span class="mono cyan">val</span> 的元素。</div><div class="bullet">返回新长度 <span class="mono cyan">k</span>,尾部内容不作要求。</div></div></div>
<p class="small">注意:题目允许改变元素顺序;本讲选择保留相对顺序的快慢指针方案,便于理解和验证。</p>
</div>
<div class="stack" style="justify-content:center">
<div class="card soft"><div class="eyebrow">EXAMPLE</div><div class="mono" style="font-size:22px;line-height:2"><span class="muted">nums = </span>[3, 2, 2, 3]<br><span class="muted">val = </span>3<br><span class="muted">output = </span><span class="green">2</span></div><div class="rule"></div><div class="array" style="padding-top:12px"><div class="cell drop">3</div><div class="cell keep">2</div><div class="cell keep">2</div><div class="cell drop">3</div></div><div class="array-label">输入数组 · 红色表示需要排除的元素</div></div>
<div class="card"><div class="eyebrow">VALID PREFIX</div><div class="array" style="padding-top:12px"><div class="cell keep">2</div><div class="cell keep">2</div><div class="cell">?</div><div class="cell">?</div></div><div class="array-label">只检查前 k = 2 个位置,尾部无需清理</div></div>
</div>
</div>
</main>
<footer class="slide-footer"><div class="footer-left">先把题目要求转换为可验证的结果条件</div><div class="global-concepts"><span><b>信息空间</b> nums</span><span><b>信息质点</b> nums[i]</span></div><div class="footer-right">02 / 12</div></footer>
</div>
</section>
<!-- 03 FOUR CONCEPTS -->
<section data-transition="slide">
<div class="slide-frame">
<header class="slide-header"><div class="header-left"><span class="chapter-index">02</span><span class="chapter-name">四要素建模</span></div><span class="header-meta">ANALYSIS MODEL</span></header>
<main class="slide-main">
<div class="eyebrow">FROM PROBLEM TO MODEL</div><h2 class="section-title">先建立题目的信息模型,再设计算法</h2>
<div class="grid2" style="height:calc(100% - 95px)">
<div class="card" style="border-top:3px solid var(--blue)"><div class="eyebrow">01 · INFORMATION SPACE</div><h3 class="blue">信息空间</h3><div class="mono" style="font-size:25px;margin:15px 0">nums[0 ... n-1]</div><p>本题所有待处理数据所在的数组空间。索引域是 <span class="mono cyan">[0,n)</span>,其中每个合法索引对应一个数组位置。</p></div>
<div class="card" style="border-top:3px solid var(--orange)"><div class="eyebrow">02 · INFORMATION PARTICLE</div><h3 class="orange">信息质点</h3><div class="mono" style="font-size:25px;margin:15px 0">nums[i] = value</div><p>数组中的单个元素。算法每轮读取一个质点,依据它与 <span class="mono cyan">val</span> 的关系决定保留还是排除。</p></div>
<div class="card" style="border-top:3px solid var(--pink)"><div class="eyebrow">03 · CONSTRAINTS</div><h3 style="color:var(--pink)">约束条件</h3><div class="mono" style="font-size:21px;margin:15px 0">nums[i] != val</div><p>保留条件;原地修改;前 <span class="mono cyan">k</span> 个位置构成有效结果;返回 <span class="mono cyan">k</span>。这些条件共同限定算法可以采取的操作。</p></div>
<div class="card" style="border-top:3px solid var(--green)"><div class="eyebrow">04 · ENTROPY REDUCTION</div><h3 class="green">熵减目标</h3><div class="mono" style="font-size:21px;margin:15px 0">未处理范围 → 0</div><p>逐步消解尚未决策的元素:未处理区间不断缩小,有效前缀不断建立,直到所有元素都完成分类。</p></div>
</div>
</main>
<footer class="slide-footer"><div class="footer-left">四要素不是背景知识,而是算法设计的输入</div><div class="global-concepts"><span>空间</span><span>质点</span><span>约束</span><span>熵减目标</span></div><div class="footer-right">03 / 12</div></footer>
</div>
</section>
<!-- 04 SPACE + PARTICLE -->
<section data-transition="slide">
<div class="slide-frame">
<header class="slide-header"><div class="header-left"><span class="chapter-index">03</span><span class="chapter-name">信息空间与质点</span></div><span class="header-meta">DATA REPRESENTATION</span></header>
<main class="slide-main">
<div class="eyebrow">ARRAY AS INFORMATION SPACE</div><h2 class="section-title">数组是空间,数组元素是待处理的质点</h2>
<div class="card" style="padding:30px 34px;margin-bottom:22px">
<div class="array" style="padding-top:15px;justify-content:flex-start;gap:14px">
<div class="cell drop">3<small>i = 0</small></div><div class="cell keep">2<small>i = 1</small></div><div class="cell keep">2<small>i = 2</small></div><div class="cell drop">3<small>i = 3</small></div>
<div style="display:flex;align-items:center;margin-left:24px;color:var(--muted);font:16px var(--mono)">n = 4</div>
</div>
<div style="display:flex;justify-content:space-between;margin-top:28px;font:14px var(--mono);color:var(--subtle)"><span>索引域:[0, n)</span><span>当前信息质点:nums[fast]</span><span>目标值:val = 3</span></div>
</div>
<div class="grid2">
<div class="card soft"><h3 class="blue">空间提供什么?</h3><p>提供连续的索引位置,使算法能够用 <span class="mono cyan">fast</span> 顺序访问每个元素,也能用 <span class="mono cyan">slow</span> 指定下一个有效元素的写入位置。</p></div>
<div class="card soft"><h3 class="orange">质点提供什么?</h3><p>提供本轮决策所需的值。读取 <span class="mono cyan">nums[fast]</span> 后,与 <span class="mono cyan">val</span> 比较,决定是否将它纳入有效前缀。</p></div>
</div>
<p class="small" style="margin-top:16px">关键:fast 是读取游标,slow 是写入边界。它们是算法维护的逻辑指针,不是数组内部额外存储的字段。</p>
</main>
<footer class="slide-footer"><div class="footer-left">先明确“在哪里处理”以及“处理什么”</div><div class="global-concepts"><span><b>空间</b> 索引域</span><span><b>质点</b> 元素值</span></div><div class="footer-right">04 / 12</div></footer>
</div>
</section>
<!-- 05 CONSTRAINTS -->
<section data-transition="slide">
<div class="slide-frame">
<header class="slide-header"><div class="header-left"><span class="chapter-index">04</span><span class="chapter-name">约束条件转译</span></div><span class="header-meta">CONSTRAINTS → RULES</span></header>
<main class="slide-main">
<div class="eyebrow">WHAT MUST REMAIN TRUE?</div><h2 class="section-title">把自然语言约束转换成算法规则</h2>
<div class="grid2" style="margin-bottom:20px">
<div class="card"><div class="eyebrow">题目约束</div><h3 class="pink">原地修改</h3><p>不能另建一个数组作为最终结果。需要在原数组已有位置上完成覆盖。</p><div class="rule"></div><div class="tag">操作规则:写入 nums[slow]</div></div>
<div class="card"><div class="eyebrow">结果约束</div><h3 class="green">有效前缀</h3><p>处理结束后,前 <span class="mono cyan">k</span> 个元素都必须不等于 <span class="mono cyan">val</span>。</p><div class="rule"></div><div class="tag">结果规则:返回 slow = k</div></div>
</div>
<div class="card soft">
<h3 class="orange">由约束推导双指针职责</h3>
<div class="grid2" style="margin-top:14px">
<div style="display:flex;gap:16px;align-items:center"><div style="font:600 26px var(--mono);color:var(--orange)">fast</div><div><strong>扫描指针</strong><p>负责访问每一个尚未处理的元素,不能漏读。</p></div></div>
<div style="display:flex;gap:16px;align-items:center"><div style="font:600 26px var(--mono);color:var(--blue)">slow</div><div><strong>写入指针</strong><p>指向有效前缀之后的第一个空位,负责扩展结果。</p></div></div>
</div>
</div>
<p class="small" style="margin-top:16px">算法选择:当 nums[fast] != val 时,将它写到 nums[slow],然后 slow++;无论是否保留,fast 每轮都前进。</p>
</main>
<footer class="slide-footer"><div class="footer-left">约束不是口号,要落实为读写规则</div><div class="global-concepts"><span><b>约束</b> 决定操作</span><span><b>双指针</b> 承担操作</span></div><div class="footer-right">05 / 12</div></footer>
</div>
</section>
<!-- 06 ENTROPY -->
<section data-transition="slide">
<div class="slide-frame">
<header class="slide-header"><div class="header-left"><span class="chapter-index">05</span><span class="chapter-name">熵减目标与状态收敛</span></div><span class="header-meta">PROGRESS MEASURE</span></header>
<main class="slide-main">
<div class="eyebrow">REDUCE UNRESOLVED WORK</div><h2 class="section-title">熵减在本题中的可观察表现:未处理范围归零</h2>
<div class="grid2" style="align-items:center;margin-bottom:22px">
<div class="card">
<h3 class="green">未处理范围</h3>
<div class="mono" style="font-size:28px;margin:12px 0">[fast, n)</div>
<p>fast 每前进一步,就有一个信息质点完成分类。剩余待决策元素数量从 <span class="mono cyan">n</span> 逐步降到 <span class="mono cyan">0</span>。</p>
</div>
<div class="card">
<h3 class="blue">有效结果范围</h3>
<div class="mono" style="font-size:28px;margin:12px 0">[0, slow)</div>
<p>slow 只在遇到需要保留的元素时前进,因此有效前缀逐步增长,且始终满足保留条件。</p>
</div>
</div>
<div class="card soft">
<div style="display:flex;justify-content:space-between;align-items:center"><h3 style="margin:0">状态势能(用于教学观察)</h3><span class="tag">Φ = n - fast</span></div>
<div style="display:flex;gap:8px;margin:22px 0 12px"><div class="state-track" style="flex:1;margin:0;height:24px"><div style="width:0%;background:var(--green)" id="entropyDone"></div><div style="width:100%;background:rgba(101,185,255,.28)" id="entropyLeft"></div></div></div>
<div class="grid2"><p>每轮结束:<span class="mono cyan">fast' = fast + 1</span><br>因此 <span class="mono green">Φ' = Φ - 1</span></p><p>终止条件:<span class="mono cyan">fast = n</span><br>因此 <span class="mono green">Φ = 0</span></p></div>
</div>
<p class="tiny" style="margin-top:14px;color:var(--subtle)">说明:这里的“熵减”是算法分析中的教学性抽象,表示未决策工作量持续减少;不是在计算香农信息熵。</p>
</main>
<footer class="slide-footer"><div class="footer-left">让“熵减”对应可观察、可验证的状态量</div><div class="global-concepts"><span><b>未处理</b> 递减</span><span><b>有效前缀</b> 递增</span></div><div class="footer-right">06 / 12</div></footer>
</div>
</section>
<!-- 07 OVERALL FLOW -->
<section data-transition="slide">
<div class="slide-frame">
<header class="slide-header"><div class="header-left"><span class="chapter-index">06</span><span class="chapter-name">整体处理流程</span></div><span class="header-meta">ALGORITHM FLOW · 01</span></header>
<main class="slide-main">
<div class="eyebrow">FROM INITIALIZATION TO TERMINATION</div><h2 class="section-title">整体流程:扫描所有质点,构建有效前缀</h2>
<div class="flow-wrap">
<svg class="flow-svg" viewBox="0 0 1320 650" aria-label="移除元素整体流程图">
<defs><marker id="arr" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto"><path d="M0 0 L0 6 L9 3 z" fill="#8295ad"/></marker></defs>
<g fill="none" stroke="#8295ad" stroke-width="2.2" marker-end="url(#arr)">
<path d="M660 90 V140"/>
<path d="M660 200 V250"/>
<path d="M490 300 H270 V400"/>
<path d="M830 300 H1050 V400"/>
<path d="M1050 480 V505 H660 V530"/>
<path d="M660 580 V620 H1250 V300 H830" stroke-dasharray="6 6"/>
</g>
<rect x="520" y="30" width="280" height="60" rx="13" fill="#173149" stroke="#65b9ff" stroke-width="2"/><text x="660" y="67" fill="#f2f6fc" font-size="23" text-anchor="middle">开始</text>
<rect x="500" y="140" width="320" height="60" rx="12" fill="#172a3e" stroke="#65b9ff" stroke-width="2"/><text x="660" y="178" fill="#f2f6fc" font-size="22" text-anchor="middle">初始化:slow = 0,fast = 0</text>
<path d="M660 250 L830 300 L660 350 L490 300 Z" fill="#302b25" stroke="#ffb36b" stroke-width="2"/><text x="660" y="307" fill="#ffb36b" font-size="21" text-anchor="middle">fast < nums.length ?</text>
<text x="270" y="280" fill="#ff8585" font-size="17">否</text><text x="1050" y="280" fill="#6bd6ae" font-size="17">是</text>
<rect x="120" y="400" width="300" height="80" rx="12" fill="#17352f" stroke="#6bd6ae" stroke-width="2"/><text x="270" y="436" fill="#6bd6ae" font-size="21" text-anchor="middle">返回 slow</text><text x="270" y="462" fill="#a1b0c5" font-size="15" text-anchor="middle">得到有效长度 k</text>
<rect x="900" y="400" width="300" height="80" rx="12" fill="#172a3e" stroke="#65b9ff" stroke-width="2"/><text x="1050" y="436" fill="#f2f6fc" font-size="21" text-anchor="middle">读取 nums[fast]</text><text x="1050" y="462" fill="#a1b0c5" font-size="15" text-anchor="middle">处理当前信息质点</text>
<rect x="510" y="530" width="300" height="50" rx="10" fill="#172a3e" stroke="#65b9ff" stroke-width="2"/><text x="660" y="560" fill="#65b9ff" font-size="18" text-anchor="middle">fast++ · 未处理范围缩小</text>
<text x="1015" y="610" fill="#8295ad" font-size="15" text-anchor="middle">进入下一轮判断</text>
</svg>
</div>
<div class="flow-caption"><span><i class="legend-dot" style="background:var(--blue)"></i>状态初始化 / 数据读取</span><span><i class="legend-dot" style="background:var(--orange)"></i>循环判断</span><span><i class="legend-dot" style="background:var(--green)"></i>终止输出</span></div>
</main>
<footer class="slide-footer"><div class="footer-left">整体流程回答:算法从哪里开始、如何循环、何时结束</div><div class="global-concepts"><span><b>fast</b> 控制扫描进度</span><span><b>slow</b> 控制结果长度</span></div><div class="footer-right">07 / 12</div></footer>
</div>
</section>
<!-- 08 BRANCH FLOW -->
<section data-transition="slide">
<div class="slide-frame">
<header class="slide-header"><div class="header-left"><span class="chapter-index">07</span><span class="chapter-name">分支处理流程</span></div><span class="header-meta">ALGORITHM FLOW · 02</span></header>
<main class="slide-main">
<div class="eyebrow">ELEMENT-LEVEL DECISION</div><h2 class="section-title">分支流程:当前质点应该保留还是排除?</h2>
<div class="flow-wrap">
<svg class="flow-svg" viewBox="0 0 1320 520" aria-label="当前元素保留或跳过的分支流程图">
<defs><marker id="arr2" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto"><path d="M0 0 L0 6 L9 3 z" fill="#8295ad"/></marker></defs>
<g fill="none" stroke="#8295ad" stroke-width="2.2" marker-end="url(#arr2)">
<path d="M660 80 V120"/>
<path d="M500 170 H320 V280"/>
<path d="M820 170 H1000 V280"/>
<path d="M320 360 V390 H660 V420"/>
<path d="M1000 360 V390 H660 V420"/>
</g>
<rect x="510" y="20" width="300" height="60" rx="12" fill="#172a3e" stroke="#65b9ff" stroke-width="2"/><text x="660" y="58" fill="#f2f6fc" font-size="21" text-anchor="middle">读取 nums[fast]</text>
<path d="M660 120 L820 170 L660 220 L500 170 Z" fill="#302b25" stroke="#ffb36b" stroke-width="2"/><text x="660" y="177" fill="#ffb36b" font-size="21" text-anchor="middle">nums[fast] == val ?</text>
<text x="320" y="150" fill="#ff8585" font-size="18">是:排除</text><text x="1000" y="150" fill="#6bd6ae" font-size="18">否:保留</text>
<rect x="160" y="280" width="320" height="80" rx="12" fill="#38262c" stroke="#ff8585" stroke-width="2"/><text x="320" y="316" fill="#ff8585" font-size="21" text-anchor="middle">不写入</text><text x="320" y="342" fill="#c4a9ae" font-size="16" text-anchor="middle">slow 不变</text>
<rect x="840" y="280" width="320" height="80" rx="12" fill="#17352f" stroke="#6bd6ae" stroke-width="2"/><text x="1000" y="316" fill="#6bd6ae" font-size="21" text-anchor="middle">nums[slow] = nums[fast]</text><text x="1000" y="342" fill="#b7d8cb" font-size="16" text-anchor="middle">写入有效前缀,slow++</text>
<rect x="510" y="420" width="300" height="50" rx="10" fill="#172a3e" stroke="#65b9ff" stroke-width="2"/><text x="660" y="451" fill="#65b9ff" font-size="18" text-anchor="middle">fast++ · 下一轮</text>
</svg>
</div>
<div class="grid2" style="margin-top:18px">
<div class="card soft"><h3 class="red">命中删除条件</h3><p><span class="mono cyan">nums[fast] == val</span>:当前元素不属于结果集合,直接跳过。slow 不动。</p></div>
<div class="card soft"><h3 class="green">满足保留条件</h3><p><span class="mono cyan">nums[fast] != val</span>:覆盖到 slow 位置,然后 slow 前进一格。</p></div>
</div>
</main>
<footer class="slide-footer"><div class="footer-left">分支判断来自约束条件,而不是凭经验添加</div><div class="global-concepts"><span><b>相等</b> 排除</span><span><b>不等</b> 保留</span></div><div class="footer-right">08 / 12</div></footer>
</div>
</section>
<!-- 09 INTERACTIVE -->
<section data-transition="slide" id="walkthrough">
<div class="slide-frame">
<header class="slide-header"><div class="header-left"><span class="chapter-index">08</span><span class="chapter-name">逐步执行实验室</span></div><span class="header-meta">INTERACTIVE TRACE</span></header>
<main class="slide-main">
<div class="eyebrow">WATCH THE FOUR CONCEPTS CHANGE</div><h2 class="section-title" style="margin-bottom:12px">让 fast 扫描,让 slow 建立有效前缀</h2>
<div class="lab-layout">
<div class="lab-left">
<div>
<div style="display:flex;justify-content:space-between;align-items:center"><span class="tag">nums = [3, 2, 2, 3]</span><span class="tag">val = 3</span></div>
<div class="array lab-array" id="labArray">
<div class="cell drop">3<small>0</small></div><div class="cell">2<small>1</small></div><div class="cell">2<small>2</small></div><div class="cell">3<small>3</small></div>
</div>
<div class="lab-status">
<div class="metric"><label>fast · 读取位置</label><strong id="fastVal">0</strong></div><div class="metric"><label>slow · 写入边界</label><strong id="slowVal">0</strong></div><div class="metric"><label>有效长度</label><strong id="validVal">0</strong></div><div class="metric"><label>未处理数量 Φ</label><strong id="phiVal">4</strong></div>
</div>
</div>
<div>
<div class="lab-log"><div class="decision" id="labDecision">准备开始:读取 nums[0]</div><p id="labExplanation">初始时有效前缀为空,fast 与 slow 都从索引 0 开始。</p></div>
<div class="lab-controls"><button class="btn primary" id="stepBtn">单步执行 →</button><button class="btn" id="autoBtn">自动播放</button><button class="btn" id="resetBtn">重置</button></div>
</div>
</div>
<div class="lab-right">
<div class="card soft"><div class="eyebrow">SPACE PARTITION</div><h3>空间状态</h3><div class="state-track"><div class="track-done" id="doneTrack" style="width:0%"></div><div class="track-left" id="leftTrack"></div></div><p class="small"><span class="green">已处理</span> / <span class="blue">未处理</span></p><div class="rule"></div><p class="small">有效前缀:<span class="mono cyan">[0, slow)</span></p><p class="small">未处理区间:<span class="mono cyan">[fast, n)</span></p></div>
<div class="card soft"><div class="eyebrow">CURRENT RULE</div><h3>本轮决策规则</h3><div class="code-mini" id="ruleCode">if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
fast += 1</div></div>
<div class="card soft"><div class="eyebrow">INVARIANT</div><p class="small">每轮开始时:<br><span class="green">nums[0:slow]</span> 都是不等于 val 的元素;<br><span class="blue">nums[fast:n]</span> 尚未处理。</p></div>
</div>
</div>
</main>
<footer class="slide-footer"><div class="footer-left">逐轮观察:读取 → 判断 → 写入/跳过 → 推进</div><div class="global-concepts"><span><b>Φ</b> = n - fast</span><span><b>k</b> = slow</span></div><div class="footer-right">09 / 12</div></footer>
</div>
</section>
<!-- 10 CODE -->
<section data-transition="slide">
<div class="slide-frame">
<header class="slide-header"><div class="header-left"><span class="chapter-index">09</span><span class="chapter-name">代码实现</span></div><span class="header-meta">IMPLEMENTATION</span></header>
<main class="slide-main">
<div class="eyebrow">TRANSLATE FLOW INTO CODE</div><h2 class="section-title" style="margin-bottom:14px">代码只是流程的另一种表达</h2>
<div class="code-window">
<div class="code-tabs"><button class="code-tab active" data-code="java">Java</button><button class="code-tab" data-code="python">Python 3</button><button class="code-tab" data-code="cpp">C++</button></div>
<div class="code-pane active" id="pane-java"><pre>class Solution {
public int removeElement(int[] nums, int val) {
int slow = 0;
for (int fast = 0; fast < nums.length; fast++) {
if (nums[fast] != val) {
nums[slow] = nums[fast];
slow++;
}
}
return slow;
}
}</pre></div>
<div class="code-pane" id="pane-python"><pre>class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
slow = 0
for fast in range(len(nums)):
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
return slow</pre></div>
<div class="code-pane" id="pane-cpp"><pre>class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0;
for (int fast = 0; fast < nums.size(); fast++) {
if (nums[fast] != val) {
nums[slow] = nums[fast];
slow++;
}
}
return slow;
}
};</pre></div>
<div class="code-note">映射关系:<span class="mono cyan">fast</span> 对应扫描流程;<span class="mono cyan">if</span> 对应约束判断;赋值与 <span class="mono cyan">slow++</span> 对应有效前缀扩展;<span class="mono cyan">return slow</span> 对应终态输出。</div>
</div>
</main>
<footer class="slide-footer"><div class="footer-left">先有处理规则,再把规则翻译成代码</div><div class="global-concepts"><span><b>流程</b> 决定结构</span><span><b>代码</b> 落实结构</span></div><div class="footer-right">10 / 12</div></footer>
</div>
</section>
<!-- 11 CORRECTNESS -->
<section data-transition="slide">
<div class="slide-frame">
<header class="slide-header"><div class="header-left"><span class="chapter-index">10</span><span class="chapter-name">正确性验证</span></div><span class="header-meta">LOOP INVARIANT</span></header>
<main class="slide-main">
<div class="eyebrow">WHY DOES IT WORK?</div><h2 class="section-title">用循环不变量证明双指针没有漏保留、误保留</h2>
<div class="grid2" style="margin-bottom:20px">
<div class="card" style="border-left:3px solid var(--green)"><h3 class="green">不变量 A · 有效前缀</h3><p>每轮开始时,<span class="mono cyan">nums[0:slow]</span> 中的所有元素都不等于 <span class="mono cyan">val</span>,且保持原有相对顺序。</p></div>
<div class="card" style="border-left:3px solid var(--blue)"><h3 class="blue">不变量 B · 未处理后缀</h3><p>每轮开始时,<span class="mono cyan">nums[fast:n]</span> 中的元素尚未被本算法检查,等待逐个分类。</p></div>
</div>
<div class="card soft">
<h3>三个时刻验证</h3>
<div class="grid4" style="margin-top:18px">
<div><div class="eyebrow">INITIAL</div><strong>初始化</strong><p class="small">slow = 0,空前缀天然满足不变量。</p></div>
<div><div class="eyebrow">MAINTAIN</div><strong>维持</strong><p class="small">相等则跳过;不等则写入有效前缀末尾。</p></div>
<div><div class="eyebrow">TERMINATE</div><strong>终止</strong><p class="small">fast = n,所有元素都已分类。</p></div>
<div><div class="eyebrow">CONCLUDE</div><strong>结论</strong><p class="small">前 slow 个元素全部满足条件,返回 slow。</p></div>
</div>
</div>
<p class="small" style="margin-top:18px">为什么覆盖不会破坏未处理数据?因为始终有 <span class="mono cyan">slow ≤ fast</span>,写入位置不会跑到当前扫描位置的右侧。</p>
</main>
<footer class="slide-footer"><div class="footer-left">正确性来自不变量,而不是运行样例碰巧正确</div><div class="global-concepts"><span><b>初始化</b></span><span><b>维持</b></span><span><b>终止</b></span></div><div class="footer-right">11 / 12</div></footer>
</div>
</section>
<!-- 12 SUMMARY -->
<section data-transition="fade">
<div class="slide-frame">
<header class="slide-header"><div class="header-left"><span class="chapter-index">11</span><span class="chapter-name">分析闭环</span></div><span class="header-meta">SUMMARY</span></header>
<main class="slide-main">
<div class="eyebrow">ONE PROBLEM · ONE COMPLETE MODEL</div><h2 class="section-title">四要素最终汇聚为一条可执行流程</h2>
<div class="grid4" style="margin-bottom:24px">
<div class="card"><div class="eyebrow">SPACE</div><h3 class="blue">信息空间</h3><p>数组索引域 <span class="mono">[0,n)</span></p></div>
<div class="card"><div class="eyebrow">PARTICLE</div><h3 class="orange">信息质点</h3><p>当前元素 <span class="mono">nums[fast]</span></p></div>
<div class="card"><div class="eyebrow">CONSTRAINT</div><h3 style="color:var(--pink)">约束条件</h3><p>只保留 <span class="mono">!= val</span> 的元素</p></div>
<div class="card"><div class="eyebrow">ENTROPY</div><h3 class="green">熵减目标</h3><p>未处理数量 <span class="mono">n-fast → 0</span></p></div>
</div>
<div class="card soft" style="padding:26px 30px">
<div class="mono" style="font-size:22px;line-height:2.05;text-align:center">
<span class="blue">fast</span> 扫描每个信息质点<br>
<span class="orange">nums[fast] != val</span> 决定是否保留<br>
<span class="green">slow</span> 维护有效前缀的边界<br>
<span class="cyan">fast = n</span> 时,返回 <span class="green">slow</span>
</div>
</div>
<div style="display:flex;justify-content:space-between;align-items:center;margin-top:20px"><p class="small">时间复杂度:O(n) · 额外空间复杂度:O(1)</p><span class="pill">模型闭环:题目 → 四要素 → 流程 → 代码 → 验证</span></div>
</main>
<footer class="slide-footer"><div class="footer-left">每道题都从自己的信息结构与约束出发推导流程</div><div class="global-concepts"><span><b>建模</b> → <b>推导</b> → <b>验证</b></span></div><div class="footer-right">12 / 12</div></footer>
</div>
</section>
</div></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/reveal.js@5/dist/reveal.js"></script>
<script>
(function(){
Reveal.initialize({
width: 1600, height: 900, margin: 0,
embedded: true,
hash: false,
keyboard: false,
controls: true, progress: true, slideNumber: false,
center: false, transition: 'slide', backgroundTransition: 'fade',
overview: true, minScale: .2, maxScale: 1, disableLayout: false
});
var root = document.getElementById('lc-deck');
if (!root) return;
var $ = function(id){ return document.getElementById(id); };
var input = [3, 2, 2, 3], target = 3;
var trace = [], traceIndex = 0, timer = null;
function buildTrace(){
var a = input.slice(), slow = 0, frames = [];
frames.push({a:a.slice(),fast:0,slow:slow,done:0,phi:4,
title:'准备开始:读取 nums[0]',
desc:'初始时有效前缀为空,fast 与 slow 都从索引 0 开始。',kind:'start'});
for (var fast = 0; fast < a.length; fast++) {
var value = a[fast];
if (value !== target) {
a[slow] = a[fast];
frames.push({a:a.slice(),fast:fast,slow:slow,done:fast,phi:a.length-fast,
title:'nums['+fast+'] = '+value+',满足保留条件',
desc:'当前元素不等于 val。将 nums['+fast+'] 写入 nums['+slow+'],然后 slow 从 '+slow+' 前进到 '+(slow+1)+'。',
kind:'keep',write:slow});
slow++;
} else {
frames.push({a:a.slice(),fast:fast,slow:slow,done:fast,phi:a.length-fast,
title:'nums['+fast+'] = '+value+',命中删除条件',
desc:'当前元素等于 val,不写入结果区;slow 保持不变,等待下一个可保留元素。',
kind:'drop'});
}
frames.push({a:a.slice(),fast:fast+1,slow:slow,done:fast+1,phi:a.length-fast-1,
title: fast === a.length-1 ? '所有元素处理完毕' : '推进 fast,进入下一轮',
desc: fast === a.length-1
? 'fast 已到达数组长度 '+a.length+',未处理范围为空,返回 slow = '+slow+'。'
: '未处理区间缩小为 ['+(fast+1)+', '+a.length+'),有效前缀为 [0, '+slow+')。',
kind:'advance'});
}
frames.push({a:a.slice(),fast:a.length,slow:slow,done:a.length,phi:0,
title:'处理结束:返回 k = '+slow,
desc:'前 '+slow+' 个位置构成有效结果:['+a.slice(0,slow).join(', ')+']。尾部元素不作要求。',
kind:'end'});
return frames;
}
trace = buildTrace();
function renderTrace(){
var f = trace[traceIndex];
var array = $('labArray');
array.innerHTML = '';
f.a.forEach(function(v, i){
var d = document.createElement('div');
d.className = 'cell';
d.innerHTML = v + '<small>' + i + '</small>';
if (i < f.slow) d.classList.add('keep');
if (i === f.fast && f.fast < input.length) d.classList.add('scan');
if (f.kind === 'drop' && i === f.fast) d.classList.add('drop');
if (f.kind === 'keep' && i === f.write) d.classList.add('write');
array.appendChild(d);
});
$('fastVal').textContent = f.fast > input.length ? input.length : f.fast;
$('slowVal').textContent = f.slow;
$('validVal').textContent = f.slow;
$('phiVal').textContent = f.phi;
$('labDecision').textContent = f.title;
$('labExplanation').textContent = f.desc;
$('doneTrack').style.width = (f.done / input.length * 100) + '%';
$('leftTrack').style.width = ((input.length - f.done) / input.length * 100) + '%';
$('stepBtn').disabled = traceIndex >= trace.length - 1;
var ed = $('entropyDone'), el = $('entropyLeft');
if (ed) ed.style.width = (f.done / input.length * 100) + '%';
if (el) el.style.width = ((input.length - f.done) / input.length * 100) + '%';
}
function stopAuto(){
if (timer) { clearInterval(timer); timer = null; }
$('autoBtn').textContent = '自动播放';
}
$('stepBtn').addEventListener('click', function(){
stopAuto();
if (traceIndex < trace.length - 1) { traceIndex++; renderTrace(); }
});
$('resetBtn').addEventListener('click', function(){
stopAuto(); traceIndex = 0; renderTrace();
});
$('autoBtn').addEventListener('click', function(){
if (timer) { stopAuto(); return; }
if (traceIndex >= trace.length - 1) traceIndex = 0;
$('autoBtn').textContent = '暂停播放';
renderTrace();
timer = setInterval(function(){
if (traceIndex < trace.length - 1) { traceIndex++; renderTrace(); }
else stopAuto();
}, 1150);
});
renderTrace();
document.querySelectorAll('#lc-deck .code-tab[data-code]').forEach(function(btn){
btn.addEventListener('click', function(){
document.querySelectorAll('#lc-deck .code-tab[data-code]').forEach(function(b){
b.classList.toggle('active', b === btn);
});
document.querySelectorAll('#lc-deck .code-pane').forEach(function(p){
p.classList.remove('active');
});
var pane = document.getElementById('pane-' + btn.dataset.code);
if (pane) pane.classList.add('active');
});
});
})();
</script>

浙公网安备 33010602011771号