飞跃高山与大洋的鱼飞跃高山与大洋的鱼
首页
先看
计算机
  • 数学
  • Linux
  • Arch
  • Manjaro
  • Ubuntu
  • CentOS
  • Kubernetes
  • Web
  • JavaScript
  • TypeScript
  • CSS
  • Canvas
  • Vue
  • Vite
  • NuxtJS
  • Webpack
  • Flutter
  • D3
  • Jest
  • WeApp
  • Utils
  • Nodejs
  • Nestjs
  • Golang
  • Nginx
  • Traefik
  • MySQL
  • MongoDB
  • Redis
  • Docker
算法
  • 像素风
  • Git
  • Github
  • VSCode
  • Chrome
  • Google
  • Bookmark scripts
  • 导航 🎉
  • VuePress 侧边栏插件
  • VuePress 官网
🚇 开往
首页
先看
计算机
  • 数学
  • Linux
  • Arch
  • Manjaro
  • Ubuntu
  • CentOS
  • Kubernetes
  • Web
  • JavaScript
  • TypeScript
  • CSS
  • Canvas
  • Vue
  • Vite
  • NuxtJS
  • Webpack
  • Flutter
  • D3
  • Jest
  • WeApp
  • Utils
  • Nodejs
  • Nestjs
  • Golang
  • Nginx
  • Traefik
  • MySQL
  • MongoDB
  • Redis
  • Docker
算法
  • 像素风
  • Git
  • Github
  • VSCode
  • Chrome
  • Google
  • Bookmark scripts
  • 导航 🎉
  • VuePress 侧边栏插件
  • VuePress 官网
🚇 开往
  • ALGORITHMS

    • 算法
      • 一些思想
        • 递归
        • 分治
        • 动态规划
        • 贪心算法
      • 从排序开始
        • 交换函数
        • 冒泡排序
        • 选择排序
        • 插入排序
        • 快速排序
    • 两数之和
    • 整数反转
    • 字符串转换整数 (atoi)
    • 回文数
    • 罗马数字转整数
    • 最长公共前缀
    • 删除链表的倒数第 N 个结点
    • 有效括号
    • 合并两个有序链表
    • 删除排序数组中的重复项
    • 移除元素
    • 实现 strStr
    • 搜索插入位置
    • 有效的数独
    • 外观数列
    • 旋转图像
    • 最大子序和
    • 跳跃游戏
    • 最后一个单词的长度
    • 加一
    • 求平方根
    • 爬楼梯
    • 删除排序链表中的重复元素
    • 合并两个有序数组
    • 二叉树的中序遍历
    • 验证二叉搜索树
    • 相同的树
    • 对称二叉树
    • 二叉树的层序遍历
    • 二叉树的最大深度
    • 将有序数组转为二叉搜索树
    • 平衡二叉树
    • 二叉树的最小深度
    • 路径总和
    • 杨辉三角
    • 杨辉三角 II
    • 买卖股票的最佳时机
    • 验证回文串
    • 只出现一次的数字
    • 环形链表
    • 二叉树的前序遍历
    • 二叉树的后序遍历
    • 最小栈
    • 相交链表
    • 两数之和 II - 输入有序数组
    • Excel 表列名称
    • 多数元素
    • Excel 表列序号
    • 组合两个表
    • 超过经理收入的员工
    • 超找重复的电子邮箱
    • 从不订购的客户
    • 颠倒二进制位
    • 位 1 的个数
    • 有效电话号码
    • 第十行
    • 删除重复的电子邮箱
    • 上升的温度
    • 打家劫舍
    • 快乐数
    • 移除链表元素
    • 计数质数
    • 同构字符串
    • 反转链表
    • 打家劫舍 II
    • 存在重复元素
    • 存在重复元素 II
    • 用队列实现栈
    • 翻转二叉树
    • 汇总区间
    • 2 的幂
    • 用栈实现队列
    • 回文链表
    • 二叉搜索树的最近公共祖先
    • 删除链表中的节点
    • 有效的字母异位词
    • 二叉树的所有路径
    • 各位相加
    • 丑数
    • 丢失的数字
    • 第一个错误的版本
    • 移动零
    • 单词规律
    • Nim 游戏
    • 区域和检索 - 数据不可变
    • 零钱兑换
    • 3 的幂
    • 比特位计数
    • 4 的幂
    • 反转字符串
    • 反转字符串中的元音字母
    • 两个数组的交集
    • 两个数组的交集 II
    • 有效的完全平方数
    • 猜数字大小
    • 赎金信
    • 打乱数组
    • 字符串中的第一个唯一字符
    • 找不同
    • 判断子序列
    • 二进制手表
    • 左子叶之和
    • 数字转换为十六进制数
    • 最长回文串
    • Fizz Buzz
    • 第三大的数
    • 字符串相加
    • 字符串中的单词数
    • 排列硬币
    • 找到数组中消失的所有数字
    • 分发饼干
    • 重复的子字符串
    • 汉明距离
    • 岛屿的周长
    • 数字的补数
    • 密钥格式化
    • 最大连续 1 的个数
    • 构造矩形
    • 提莫攻击
    • 下一个更大元素 I
    • 键盘行
    • 二叉搜索树中的众数
    • 七进制数
    • 相对名次
    • 完美数
    • 斐波那契数
    • 检测大写字母
    • 最长特殊序列 Ⅰ
    • 二叉搜索树的最小绝对差
    • 反转字符串 II
    • 二叉树的直径
    • 学生出勤记录 I
    • 反转字符串中的单词 III
    • N 叉树的最大深度
    • 数组拆分
    • 二叉树的坡度
    • 重塑矩阵
    • 另一棵树的子树
    • 分糖果
    • N 叉树的前序遍历
    • N 叉树的后序遍历
    • 最长和谐子序列
    • 大的国家
    • 超过 5 名学生的课
    • 范围求和
    • 两个列表的最小索引总和
    • 种花问题
    • 根据二叉树构造字符串
    • 合并二叉树
    • 有趣的电影
    • 变更性别
    • 三个数的最大乘积
    • 二叉树的层平均值
    • 子数组最大平均数
    • 错误的集合
    • 两数之和 IV - 输入 BST
    • 机器人能否返回原点
    • 图片平滑器
    • 二叉树中第二小的节点
    • 最长连续递增序列
    • 验证回文字符串 Ⅱ
    • 棒球比赛
    • 交替位二进制数
    • 二叉搜索树中的搜索
    • 设计哈希集合
    • 设计哈希映射
    • 转换成小写字母
    • 寻找数组的中心下标
    • 使用最小花费爬楼梯
    • 至少是其他数字两倍的最大数
    • 宝石与石头
    • 保持城市天际线
    • 可以被一步捕获的棋子数
    • 第 N 个泰波那契数
    • 一年中的第几天
    • 比赛中的配对次数
    • 截断句子

算法

算法是很重要的,但我懒。

一些思想

递归

要理解递归,就得先理解什么是递归。

递归的基本思想是直接或间接的调用自身,这样原问题的求解就被转为了许多性质相同但是规模更小的子问题。 递归最重要的两个特征:调用自身、结束条件。调用自身是在解决子问题,而结束条件则一般为最简子问题的答案。 执行函数时会创建对应的执行上下文栈,而栈被创建过多层时存在 栈溢出 的风险。

分治

分治的核心思想就是 “分而治之”:

  1. 分解:将原问题分解为相互独立,与原问题形式相同的子问题
  2. 解决:分解到某个容易求解的边界后,递归求解
  3. 合并:将子问题的解合并为原问题的解

动态规划

使用分治法时,若子问题并不独立,则更推荐使用动态规划。

贪心算法

贪心算法是一种在每一步选择中都采取当前状态下最好或最优选择,从而希望导致结果是最好或最优算法。 贪心算法与动态规划的不同在于它对每个问题的解决方案都做出选择,不能回退。动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。

从排序开始

交换函数

const swap = (arr: number[], i: number, j: number) => {
  [arr[j], arr[i]] = [arr[i], arr[j]]
}

冒泡排序

冒泡排序就是重复 “从序列右边开始比较相邻两个数字大小,再根据结果交换两个数字的位置”。

const bubbleSort = (arr: number[]): number[] => {
  const len = arr.length

  for (let i = 0; i < len; i++) {
    // 每轮 i 循环都能确认最大值
    for (let j = 0; j < len - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        swap(arr, j + 1, j)
      }
    }
  }

  return arr
}

选择排序

选择排序就是 “从待排序的数据中寻找最小值,将其放到已排序队列的末尾”。

const selectionSort = (arr: number[]): number[] => {
  const len = arr.length

  for (let i = 0; i < len; i++) {
    let minIndex = i

    for (let j = i + 1; j < len; j++) {
      if (arr[j] < arr[minIndex]) {
        minIndex = j
      }
    }

    if (minIndex !== i) {
      swap(arr, i, minIndex)
    }
  }

  return arr
}

插入排序

插入排序就是 “从右侧的未排序区域内取出一个数据,然后将其插入到已排序区域内合适的位置上”。

const insertionSort = (arr: number[]): number[] => {
  const len = arr.length

  for (let i = 1; i < len; i++) {
    // 每轮 i 循环为左区域排好序
    for (let j = i; j > 0; j--) {
      if (arr[j] < arr[j - 1]) {
        swap(arr, j, j - 1)
      } else {
        break
      }
    }
  }

  return arr
}

快速排序

快速排序就是 “从待排序的数据原地排序并利用分治的思想解决,有点类似冒泡的增强版”。

// 分区操作
const partition = (arr: number[], left: number, right: number) => {
  const pivot = left
  let index = pivot + 1

  // 原地排序
  for (let i = index; i <= right; i++) {
    if (arr[i] < arr[pivot]) {
      swap(arr, i, index)
      index++
    }
  }

  // 将基准 pivot 移至中间
  swap(arr, pivot, index - 1)
  return index - 1
}

const quickSort = (arr: number[], left = 0, right = arr.length - 1): number[] => {
  if (left < right) {
    const partitionIndex = partition(arr, left, right)
    quickSort(arr, left, partitionIndex - 1)
    quickSort(arr, partitionIndex + 1, right)
  }

  return arr
}
编辑文档!
上次更新:
贡献者: shanyuhai123
Next
两数之和