Skip to content

Commit d61aca9

Browse files
committed
[Feature] add for new
2 parents 08bdc91 + 960a8cc commit d61aca9

File tree

2 files changed

+253
-0
lines changed

2 files changed

+253
-0
lines changed

T160_linkedlist-two-pointer.html

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>LC160 双指针链表相交可视化</title>
6+
<style>
7+
body {
8+
font-family: "Segoe UI", sans-serif;
9+
background: #0f172a;
10+
color: #e2e8f0;
11+
padding: 40px;
12+
}
13+
h2 {
14+
text-align: center;
15+
color: #38bdf8;
16+
}
17+
input {
18+
padding: 10px;
19+
width: 300px;
20+
margin-right: 10px;
21+
border-radius: 5px;
22+
border: none;
23+
}
24+
button {
25+
padding: 10px 20px;
26+
background: #3b82f6;
27+
border: none;
28+
border-radius: 5px;
29+
color: white;
30+
font-weight: bold;
31+
cursor: pointer;
32+
margin-top: 10px;
33+
}
34+
.list-container {
35+
display: flex;
36+
align-items: center;
37+
margin: 20px 0;
38+
overflow-x: auto;
39+
}
40+
.node {
41+
padding: 10px 15px;
42+
margin-right: 10px;
43+
border-radius: 8px;
44+
background: #1e293b;
45+
border: 2px solid #334155;
46+
position: relative;
47+
min-width: 40px;
48+
text-align: center;
49+
transition: transform 0.3s ease;
50+
}
51+
.arrow::after {
52+
content: '→';
53+
position: absolute;
54+
right: -15px;
55+
top: 50%;
56+
transform: translateY(-50%);
57+
color: #94a3b8;
58+
}
59+
.highlight {
60+
background: #facc15 !important;
61+
color: #000;
62+
animation: blink 1s infinite;
63+
border-color: #facc15;
64+
}
65+
.shared {
66+
background: #10b981;
67+
border-color: #22c55e;
68+
}
69+
.overlap {
70+
background: #c084fc !important;
71+
border-color: #d946ef !important;
72+
}
73+
.both-highlight {
74+
background: #e11d48 !important;
75+
border-color: #f43f5e !important;
76+
animation: flash 1s infinite;
77+
color: white;
78+
}
79+
.log {
80+
background: #1e293b;
81+
border: 1px solid #334155;
82+
border-radius: 8px;
83+
padding: 10px;
84+
max-height: 200px;
85+
overflow-y: auto;
86+
margin-top: 20px;
87+
white-space: pre-wrap;
88+
}
89+
@keyframes blink {
90+
0% { box-shadow: 0 0 10px #facc15; }
91+
50% { box-shadow: 0 0 20px #facc15; }
92+
100% { box-shadow: 0 0 10px #facc15; }
93+
}
94+
@keyframes flash {
95+
0%, 100% { box-shadow: 0 0 10px #f43f5e; }
96+
50% { box-shadow: 0 0 20px #f43f5e; }
97+
}
98+
99+
.back-btn {
100+
position: fixed;
101+
top: 20px;
102+
left: 20px;
103+
background: #10b981;
104+
}
105+
</style>
106+
</head>
107+
<body>
108+
<button class="back-btn" onclick="location.href='index.html'">← 返回首页</button>
109+
110+
<h2>🚀 LC160 双指针链表相交可视化</h2>
111+
112+
<div style="text-align:center;">
113+
链表 A: <input id="inputA" placeholder="1,2,3,8,9" value="1,2,3,8,9" />
114+
链表 B: <input id="inputB" placeholder="4,5,8,9" value="4,5,8,9" />
115+
<br>
116+
<button onclick="startVisualization()">开始可视化</button>
117+
</div>
118+
119+
<h3>链表 A</h3>
120+
<div id="listA" class="list-container"></div>
121+
122+
<h3>链表 B</h3>
123+
<div id="listB" class="list-container"></div>
124+
125+
<h3>执行日志</h3>
126+
<div id="log" class="log"></div>
127+
128+
<script>
129+
let nodesA = [], nodesB = [];
130+
let pointerA = 0, pointerB = 0;
131+
let timer = null;
132+
let step = 1;
133+
134+
function buildLists(valA, valB) {
135+
let arrA = valA.split(',').map(s => s.trim());
136+
let arrB = valB.split(',').map(s => s.trim());
137+
138+
let i = arrA.length - 1, j = arrB.length - 1;
139+
const shared = [];
140+
while (i >= 0 && j >= 0 && arrA[i] === arrB[j]) {
141+
shared.unshift(arrA[i]);
142+
i--; j--;
143+
}
144+
145+
const build = (unique, shared) =>
146+
unique.map(v => ({ val: v, shared: false }))
147+
.concat(shared.map(v => ({ val: v, shared: true })));
148+
149+
return [
150+
build(arrA.slice(0, i + 1), shared),
151+
build(arrB.slice(0, j + 1), shared)
152+
];
153+
}
154+
155+
function renderLists() {
156+
const listA = document.getElementById("listA");
157+
const listB = document.getElementById("listB");
158+
listA.innerHTML = "";
159+
listB.innerHTML = "";
160+
161+
nodesA.forEach((node, idx) => {
162+
const div = document.createElement("div");
163+
let className = "node arrow";
164+
if (node.shared) className += " shared";
165+
if (idx === pointerA && idx < nodesA.length) {
166+
if (pointerB < nodesB.length && nodesB[pointerB].val === node.val && node.shared) {
167+
className += " both-highlight"; // 🎯 重合节点高亮
168+
} else if (node.shared) {
169+
className += " overlap"; // 🟣 路过共享节点
170+
} else {
171+
className += " highlight";
172+
}
173+
}
174+
div.className = className;
175+
div.textContent = node.val;
176+
listA.appendChild(div);
177+
});
178+
179+
nodesB.forEach((node, idx) => {
180+
const div = document.createElement("div");
181+
let className = "node arrow";
182+
if (node.shared) className += " shared";
183+
if (idx === pointerB && idx < nodesB.length) {
184+
if (pointerA < nodesA.length && nodesA[pointerA].val === node.val && node.shared) {
185+
className += " both-highlight"; // 🎯 重合节点高亮
186+
} else if (node.shared) {
187+
className += " overlap"; // 🟣 路过共享节点
188+
} else {
189+
className += " highlight";
190+
}
191+
}
192+
div.className = className;
193+
div.textContent = node.val;
194+
listB.appendChild(div);
195+
});
196+
}
197+
198+
function log(msg) {
199+
const logDiv = document.getElementById("log");
200+
logDiv.textContent += msg + "\n";
201+
logDiv.scrollTop = logDiv.scrollHeight;
202+
}
203+
204+
function nextStep() {
205+
const nodeA = nodesA[pointerA] || null;
206+
const nodeB = nodesB[pointerB] || null;
207+
208+
const valA = nodeA ? nodeA.val : "null";
209+
const valB = nodeB ? nodeB.val : "null";
210+
211+
log(`Step ${step++}: p1 → ${valA}, p2 → ${valB}`);
212+
213+
if (nodeA && nodeB && nodeA.shared && nodeB.shared && nodeA.val === nodeB.val) {
214+
log(`🎉 找到相交节点:${nodeA.val}`);
215+
renderLists();
216+
clearInterval(timer);
217+
return;
218+
}
219+
220+
pointerA++;
221+
if (pointerA > nodesA.length) pointerA = 0;
222+
223+
pointerB++;
224+
if (pointerB > nodesB.length) pointerB = 0;
225+
226+
renderLists();
227+
}
228+
229+
function startVisualization() {
230+
const valA = document.getElementById("inputA").value || "1,2,3,8,9";
231+
const valB = document.getElementById("inputB").value || "4,5,8,9";
232+
233+
[nodesA, nodesB] = buildLists(valA, valB);
234+
pointerA = 0;
235+
pointerB = 0;
236+
step = 1;
237+
238+
document.getElementById("log").textContent = "";
239+
renderLists();
240+
241+
if (timer) clearInterval(timer);
242+
timer = setInterval(nextStep, 1000);
243+
}
244+
</script>
245+
</body>
246+
</html>

index.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,18 @@ <h1>算法可视化 · 资源导航</h1>
140140

141141
<div class="grid" id="cardGrid">
142142
<!-- 示例卡片 -->
143+
<<<<<<< HEAD
143144

144145
<div class="card" data-tags="binary-tree 二叉树 前序 中序 后序 层序">
145146
<div class="card-title">binary-tree-travel 二叉树遍历</div>
146147
<div class="card-desc">binary-tree-travel 前序、中序、后序、层序遍历</div>
147148
<a href="./binary-tree-travel.html" target="_blank">打开页面</a>
149+
=======
150+
<div class="card" data-tags="linkedlist two-pointer 双指针 T160相交链表 intersection-of-two-linked-lists">
151+
<div class="card-title">T160 相交链表 intersection-of-two-linked-lists</div>
152+
<div class="card-desc">双指针解法</div>
153+
<a href="./T160_linkedlist-two-pointer.html" target="_blank">打开页面</a>
154+
>>>>>>> 960a8ccda8d2e38666a58bf945a8328fe6cbb2f2
148155
</div>
149156

150157
<div class="card" data-tags="difference-array array 差分数组 数组">

0 commit comments

Comments
 (0)