从零学JavaScript:浅入算法思维

64 阅读3分钟

前言:重生之我在地球用JS写算法题

  1. 移动零 —— 数组原地操作
  2. 盛最多水的容器 —— 双指针 + 贪心
  3. 有效的括号 —— 栈的经典应用

1. 移动零:如何优雅地“整理”数组?

题目要求:

给定一个数组 nums,将所有 0 移动到数组末尾,同时保持非零元素的相对顺序。

输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

解法思路:双指针(快慢指针)

  • 慢指针 i:指向下一个非零元素应该放置的位置
  • 快指针 j:遍历整个数组
var moveZeroes = function(nums) {
    let i = 0; // 慢指针
    for (let j = 0; j < nums.length; j++) {
        if (nums[j] !== 0) {
            nums[i] = nums[j];
            i++;
        }
    }
    // 剩余位置填充 0
    nums.fill(0, i);
};

核心技巧:

  • 使用 nums.fill(0, i)i 开始填充 0ES6 新特性,简洁高效
  • 时间复杂度:O(n),空间复杂度:O(1) —— 原地操作,不额外占用内存

类比:就像整理书架,先把有用的书按顺序摆好,再把空位用废纸填满。


2. 盛最多水的容器:双指针 + 贪心的完美结合

题目要求:

给定数组 height,每个元素代表一根竖线的高度,找出两条线,使得它们与 x 轴构成的容器能装最多的水。

解法思路:双指针从两端向中间收缩

  • 面积 = min(左高, 右高) × 距离
  • 贪心策略:每次移动较短的一边,因为面积由短板决定,移动长边不会增加面积
var maxArea = function(height) {
    let left = 0, right = height.length - 1;
    let maxArea = 0;

    while (left < right) {
        const width = right - left;
        const minHeight = Math.min(height[left], height[right]);
        const area = minHeight * width;
        maxArea = Math.max(maxArea, area);

        if (height[left] <= height[right]) {
            left++;
        } else {
            right--;
        }
    }

    return maxArea;
};

为什么贪心是对的?

  • 移动长边:宽度减小,高度不会增加(仍由短板决定)→ 面积可能变小
  • 移动短边:虽然宽度减小,但高度可能增加 → 有机会找到更大的面积

这是双指针贪心的经典案例,面试高频!


3. 有效的括号:栈的教科书级应用

题目要求:

判断一个只包含 '(', ')', '{', '}', '[', ']' 的字符串是否有效。

输入: "()[]{}"true
输入: "([)]"false

解法思路:栈(Stack)

  • 遇到左括号:入栈
  • 遇到右括号:检查栈顶是否匹配的左括号
    • 匹配:出栈
    • 不匹配:返回 false
  • 最后检查栈是否为空
var isValid = function(s) {
    const stack = [];
    const map = {
        ')': '(',
        '}': '{',
        ']': '['
    };

    for (let char of s) {
        if (char === '(' || char === '{' || char === '[') {
            stack.push(char); // 左括号入栈
        } else {
            if (stack.pop() !== map[char]) {
                return false; // 不匹配
            }
        }
    }

    return stack.length === 0; // 栈为空说明全部匹配
};

关键点:

  • stack.pop() 返回栈顶元素并移除
  • 如果栈为空时 pop() 返回 undefined,自动判断为不匹配
  • 时间复杂度 O(n),空间复杂度 O(n)

栈是处理“嵌套结构”和“匹配问题”的利器,如 HTML 标签匹配、表达式求值等。


总结:三道题,三种核心算法思想

题目核心思想应用场景
移动零双指针 + 原地操作数组整理、去重
盛最多水的容器双指针 + 贪心最大值问题、区间优化
有效的括号匹配、嵌套、语法分析