返回

使用 JavaScript 算法解决经典问题:有效括号、合并链表、计数排序、二叉树前序遍历

前端

有效括号

问题

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

有效括号的定义如下:

  • 空字符串为有效括号
  • 如果一个字符串 A 是有效括号,那么 A 的前缀 A + B 和 A 的后缀 B + A 也是有效括号
  • 如果 A 和 B 都是有效括号,那么 AB 也是有效括号

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

示例 3:

输入:s = "(]"
输出:false

代码实现:

/**
 * 判断字符串中的括号是否有效
 *
 * @param {string} s
 * @return {boolean}
 */
const isValid = (s) => {
  if (s.length === 0) {
    return true;
  }

  const stack = [];

  for (let i = 0; i < s.length; i++) {
    const char = s[i];

    if (char === '(' || char === '{' || char === '[') {
      stack.push(char);
    } else {
      const top = stack.pop();

      if (
        (char === ')' && top !== '(') ||
        (char === '}' && top !== '{') ||
        (char === ']' && top !== '[')
      ) {
        return false;
      }
    }
  }

  return stack.length === 0;
};

时间复杂度:

O(n),其中 n 是字符串 s 的长度。

空间复杂度:

O(n),其中 n 是字符串 s 的长度。

合并链表

问题:

合并两个有序链表。

示例 1:

输入:l1 = [1, 2, 4], l2 = [1, 3, 4]
输出:[1, 1, 2, 3, 4, 4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

代码实现:

/**
 * 合并两个有序链表
 *
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
const mergeTwoLists = (l1, l2) => {
  if (l1 === null) {
    return l2;
  }

  if (l2 === null) {
    return l1;
  }

  if (l1.val < l2.val) {
    l1.next = mergeTwoLists(l1.next, l2);
    return l1;
  } else {
    l2.next = mergeTwoLists(l1, l2.next);
    return l2;
  }
};

时间复杂度:

O(n + m),其中 n 是链表 l1 的长度,m 是链表 l2 的长度。

空间复杂度:

O(n + m),其中 n 是链表 l1 的长度,m 是链表 l2 的长度。

计数排序

问题:

给定一个包含 n 个整数的数组 nums,对数组进行排序。

示例 1:

输入:nums = [5, 3, 1, 2, 4]
输出:[1, 2, 3, 4, 5]

示例 2:

输入:nums = [5, 4, 3, 2, 1]
输出:[1, 2, 3, 4, 5]

示例 3:

输入:nums = []
输出:[]

代码实现:

/**
 * 对一个数组进行计数排序
 *
 * @param {number[]} nums
 * @return {number[]}
 */
const countingSort = (nums) => {
  if (nums.length === 0) {
    return [];
  }

  const maxValue = Math.max(...nums);
  const minValue = Math.min(...nums);
  const range = maxValue - minValue + 1;

  const countArray = new Array(range).fill(0);

  for (let i = 0; i < nums.length; i++) {
    const index = nums[i] - minValue;
    countArray[index]++;
  }

  let sortedIndex = 0;
  for (let i = 0; i < range; i++) {
    while (countArray[i] > 0) {
      nums[sortedIndex++] = minValue + i;
      countArray[i]--;
    }
  }

  return nums;
};

时间复杂度:

O(n + k),其中 n 是数组 nums 的长度,k 是数组 nums 中的最大值和最小值之差。

空间复杂度:

O(n + k),其中 n 是数组 nums 的长度,k 是数组 nums 中的最大值和最小值之差。

二叉树前序遍历

问题描述:

给定一棵二叉树,进行前序遍历。

示例 1:

输入:root = [1, null, 2, 3]
输出:[1, 2, 3]

示例 2:

输入:root = []
输出:[]

示例 3:

输入:root = [1]
输出:[1]

代码实现:

/**
 * 对一棵二叉树进行前序遍历
 *
 * @param {TreeNode} root
 * @return {number[]}
 */
const preorderTraversal = (root) => {
  if (root === null) {
    return [];
  }

  const result = [];

  const stack = [root];

  while (stack.length > 0) {
    const node = stack.pop();

    result.push(node.val);

    if (node.right !== null) {
      stack.push(node.right);
    }

    if (node.left !== null) {
      stack.push(node.left);
    }
  }

  return result;
};

时间复杂度:

O(n),其中 n 是二叉树的节点数。

空间复杂度:

O(n),其中 n 是二叉树的节点数。