Skip to content

Commit f738470

Browse files
committed
🚧更新文章
1 parent 79dd4dd commit f738470

File tree

1 file changed

+192
-9
lines changed

1 file changed

+192
-9
lines changed

docs/interview/Algorithm/writeAlgorithm.md

Lines changed: 192 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -199,24 +199,207 @@ function maxProfit(prices) {
199199

200200
```javascript
201201
function longestPalindrome(s) {
202+
// 初始化左右边界,表示当前找到的最长回文子串的起始和结束位置
202203
let l = 0;
203204
let r = 0;
204-
205+
// 遍历字符串,以每个字符为中心尝试扩展回文
205206
for (let i = 0; i < s.length; i++) {
206-
helper(i, i);
207-
helper(i, i + 1);
207+
helper(i, i); // 情况 1:回文子串长度为奇数(以 i 为中心)
208+
helper(i, i + 1); // 情况 2:回文子串长度为偶数(以 i 和 i+1 为中心)
208209
}
209-
210+
// 辅助函数,用于扩展回文子串的左右边界
210211
function helper(m, n) {
211-
while (m >= 0 && n < s.length && s[m] == s[n]) {
212-
m--;
213-
n++;
212+
// 当左右指针范围内的字符相等时,继续向外扩展
213+
while (m >= 0 && n < s.length && s[m] === s[n]) {
214+
m--; // 左指针向左移动
215+
n++; // 右指针向右移动
214216
}
217+
// 如果当前回文子串的长度大于之前记录的最长回文子串长度
215218
if (n - m > r - l) {
216-
r = n;
217-
l = m;
219+
r = n; // 更新右边界
220+
l = m; // 更新左边界
218221
}
219222
}
223+
// 返回最长回文子串,通过 slice 提取范围 [l+1, r)
220224
return s.slice(l + 1, r);
221225
}
222226
```
227+
228+
## 11. 爬楼梯
229+
230+
#### 1. 正常递归求解,但是时间空间复杂度很差
231+
232+
```javascript
233+
function climbStairs(n) {
234+
if (n <= 2) return n;
235+
return climbStairs(n - 1) + climbStairs(n - 2);
236+
}
237+
```
238+
239+
#### 2. 利用数组缓存值
240+
241+
```javascript
242+
function climbStairs(n) {
243+
let result = [1, 2];
244+
for (let i = 2; i < n; i++) {
245+
result[i] = result[i - 1] + result[i - 2];
246+
}
247+
return result.pop();
248+
}
249+
```
250+
251+
#### 3. 动态规划求解
252+
253+
```javascript
254+
function climbStairs(n) {
255+
if (n <= 2) return n;
256+
let a = 1;
257+
let b = 2;
258+
let sum = 0;
259+
for (let i = 2; i < n; i++) {
260+
sum = a + b;
261+
a = b;
262+
b = sum;
263+
}
264+
return sum;
265+
}
266+
```
267+
268+
## 12. 三数之和
269+
270+
```javascript
271+
function threeSum(nums) {
272+
// 如果数组为空或长度小于等于2,不可能组成三元组,直接返回
273+
if (!nums || nums.length <= 2) return nums;
274+
// 将数组排序,便于后续双指针查找
275+
nums.sort((a, b) => a - b);
276+
// 定义结果数组,用于存放满足条件的三元组
277+
let result = [];
278+
// 遍历数组,固定第一个数 nums[i]
279+
for (let i = 0; i < nums.length; i++) {
280+
// 如果 nums[i] > 0,后面的数都大于 0,三数之和不可能为 0,直接退出循环
281+
if (nums[i] > 0) break;
282+
// 如果当前数和前一个数相同,跳过,避免重复三元组
283+
if (i > 0 && nums[i] === nums[i - 1]) continue;
284+
// 定义左右指针
285+
let L = i + 1; // 左指针初始化为当前数之后的第一个数
286+
let R = nums.length - 1; // 右指针初始化为数组最后一个数
287+
// 开始双指针查找
288+
while (L < R) {
289+
// 计算三数之和
290+
const sum = nums[i] + nums[L] + nums[R];
291+
if (sum === 0) {
292+
// 如果三数之和为 0,将三元组加入结果数组
293+
result.push([nums[i], nums[L], nums[R]]);
294+
// 跳过重复的右指针值,避免重复三元组
295+
while (L < R && nums[R] === nums[R - 1]) {
296+
R--;
297+
}
298+
// 跳过重复的左指针值,避免重复三元组
299+
while (L < R && nums[L] === nums[L + 1]) {
300+
L++;
301+
}
302+
// 左指针右移,右指针左移,继续检查其他可能的三元组
303+
L++;
304+
R--;
305+
} else if (sum > 0) {
306+
// 如果三数之和大于 0,说明右指针的值过大,右指针左移
307+
R--;
308+
} else {
309+
// 如果三数之和小于 0,说明左指针的值过小,左指针右移
310+
L++;
311+
}
312+
}
313+
}
314+
// 返回结果数组
315+
return result;
316+
}
317+
```
318+
319+
## 13. 环形链表
320+
321+
```javascript
322+
function hasCycle(head) {
323+
// 定义两个指针,slow 和 fast,均初始化为链表的头节点
324+
let slow = head;
325+
let fast = head;
326+
// 当快指针和快指针的下一个节点不为空时,继续循环
327+
while (fast && fast.next) {
328+
// 慢指针每次移动一步
329+
slow = slow.next;
330+
// 快指针每次移动两步
331+
fast = fast.next.next;
332+
// 如果快慢指针相遇,说明链表中存在环
333+
if (slow === fast) return true;
334+
}
335+
// 如果循环结束,说明快指针到达链表末尾,没有环
336+
return false;
337+
}
338+
```
339+
340+
## 14. 二叉树的层序遍历
341+
342+
```javascript
343+
function levelOrder(root) {
344+
// 如果根节点为空,返回空数组,表示没有任何层级
345+
if (!root) return [];
346+
// 初始化结果数组,用于存储每一层的节点值
347+
let result = [];
348+
// 使用队列实现层序遍历,初始队列包含根节点
349+
let queue = [root];
350+
// 当队列不为空时,持续处理队列中的节点
351+
while (queue.length) {
352+
// 用于存储当前层的节点值
353+
let levelNodes = [];
354+
// 获取当前层的节点数量
355+
let levelNodeSize = queue.length;
356+
// 遍历当前层的所有节点
357+
for (let i = 0; i < levelNodeSize; i++) {
358+
// 从队列中取出一个节点
359+
const node = queue.shift();
360+
// 将该节点的值加入当前层的结果中
361+
levelNodes.push(node.val);
362+
// 如果左子节点存在,将其加入队列
363+
if (node.left) queue.push(node.left);
364+
// 如果右子节点存在,将其加入队列
365+
if (node.right) queue.push(node.right);
366+
}
367+
// 将当前层的节点值加入最终结果中
368+
result.push(levelNodes);
369+
}
370+
// 返回结果数组,包含所有层的节点值
371+
return result;
372+
}
373+
```
374+
375+
## 15. 路径总和
376+
377+
#### 1. 通过递归
378+
379+
```javascript
380+
function hasPathSum(root, targetSum) {
381+
if (!root) return false;
382+
if (!root.left && !root.right && root.val === targetSum) return true;
383+
const nextTargetSum = targetSum - root.val;
384+
return (
385+
hasPathSum(root.left, nextTargetSum) ||
386+
hasPathSum(root.right, nextTargetSum)
387+
);
388+
}
389+
```
390+
391+
#### 2. 通过 `BFS`
392+
393+
```javascript
394+
function hasPathSum(root, targetSum) {
395+
if (!root) return false;
396+
let queue = [[root, root.val]];
397+
while (queue.length) {
398+
const [node, currentSum] = queue.shift();
399+
if (!node.left && !node.right && currentSum === targetSum) return true;
400+
if (node.left) queue.push([node.left, node.left.val + currentSum]);
401+
if (node.right) queue.push([node.right, node.right.val + currentSum]);
402+
}
403+
return false;
404+
}
405+
```

0 commit comments

Comments
 (0)