力扣面试150题图解学习

82 阅读9分钟

前言

力扣刷题记录,采用图解的方式,每日温习,方便记忆

算法题归类

来自豆包总结:

🔥 第一梯队(必刷,80% 面试靠这些)

  1. 数组 / 哈希表
  2. 双指针
  3. 滑动窗口
  4. 二分查找
  5. 前缀和 / 差分
  6. 栈 / 单调栈

🧠 第二梯队(高频中等题)

  1. BFS 广度优先
  2. DFS / 回溯
  3. 动态规划 DP(基础型)
  4. 链表
  5. 二叉树 / 二叉搜索树

⚙️ 第三梯队(大厂 / 难题常考)

  1. 图论(最短路径、拓扑排序)
  2. 并查集
  3. 贪心算法
  4. 高级 DP(区间、状态压缩)
  5. 位运算

手写方法

手写 reduce

记住三句话:

  1. 了解参数:callback 是回调参数,preValue 是上一个的返回值,this是该数组,this[index]是当前值
  2. 有传 preValue 则赋值;没传则取 this[0] 数组的第一个元素作为 preValue
  3. preValue = callback(上一个值preValue,当前值this[index])

image.png

时间O(n)空间O(1)

手写快排

递归口诀:递归终止,处理本层,递归调用,递归调用结果传递给上一层

快排核心:选中间,小的放左边,大的放右边

递归树:

image.png

image.png

时间O(nlogn)空间O(nlogn)

力扣面试150题

遇到一道题,脑子里先对它进行归类,该用什么方法

合并两个有序数组【三个尾指针往前】

leetcode.cn/problems/me…

输入: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
解释: 需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

时间O(m+n),空间O(1)

image.png

移除元素

leetcode.cn/problems/re…

输入: nums = [0,1,2,2,3,0,4,2], val = 2
输出: 5, nums = [0,1,4,0,3,_,_,_]
解释: 你的函数应该返回 k = 5,并且 nums 中的前五个元素为 0,0,1,3,4。
注意这五个元素可以任意顺序返回。

image.png

有序数组去重,重复的放后面

leetcode.cn/problems/re…

输入: nums = [0,0,1,1,1,2,2,3,3,4]
输出: 5, nums = [0,1,2,3,4,_,_,_,_,_]
解释: 返回新的长度5,并且原数组 nums 的前五个元素被修改为 0,1,2,3,4。不需要考虑数组中超出新长度后面的元素

image.png

有序数组使得数字最多出现两次

leetcode.cn/problems/re…

输入: nums = [0,0,1,1,1,1,2,3,3]
输出: 7, nums = [0,0,1,1,2,3,3]
解释: 函数应返回新长度 length = 7, 并且原数组的前七个元素被修改为 0, 0, 1, 1, 2, 3, 3。不需要考虑数组中超出新长度后面的元素。

image.png

找出超半数元素

给定一个大小为 `n` **的数组 `nums` ,返回其中的超半数元素
输入: nums = [2,2,1,1,1,2,2]
输出: 2
  1. 快排后,中间那个数就是超半数元素,时间O(nlogn)空间O(nlogn)
  2. 哈希表存储出现次数,时间O(n)空间O(n)
  3. 投票法:相同 + 1,不同 - 1,没票就换人,最后剩下的一定是多数元素

image.png

一维动态规划:爬楼梯

leetcode.cn/problems/cl…

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

输入: n = 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 12. 1 阶 + 23. 2 阶 + 1

第 n 阶的爬法 = 第 n-1 阶的爬法 + 第 n-2 阶的爬法,状态转移方程为:f(n) = f(n - 1) + f(n - 2)

递归树:

image.png

image.png

栈:有效的括号

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

image.png

栈:简化路径

输入: path = "/home/"
输出: "/home"
输入: path = "/home//foo/"
输出: "/home/foo"
输入: path = "/home/user/Documents/../Pictures"
输出: "/home/user/Pictures"
输入: path = "/.../a/../b/c/../d/./"
输出: "/.../b/d"

image.png

栈:表达式求值

输入: tokens = ["4","13","5","/","+"]
输出: 6
解释: 该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

image.png

递归的理解

所谓递归,可以通俗理解为:公司的等级制度:

  • CEO→事业群老大→部门老大→总监→组长→员工

二叉树的4种遍历

对于任意一棵树而言,前3种遍历方式都是 深度优先搜索(DFS)

前序遍历

前序遍历的形式总是(递归式的左右)

[ 根节点, [左子树的前序遍历结果], [右子树的前序遍历结果] ]
function preOrder(root) {
    if (!root) return;
    console.log(root.val);   // 根
    preOrder(root.left);     // 左
    preOrder(root.right);    // 右
}

image.png

中序遍历

而中序遍历的形式总是(递归式的左右)

[ [左子树的中序遍历结果], 根节点, [右子树的中序遍历结果] ]
function inOrder(root) {
    if (!root) return
    inOrder(root.left)      // 左
    console.log(root.val)   // 根
    inOrder(root.right)     // 右
}

image.png

后序遍历

而后序遍历的形式总是(递归式的左右

[ [左子树的中序遍历结果], [右子树的中序遍历结果] , 根节点]
function postOrder(root) {
    if (!root) return
    postOrder(root.left)    // 左
    postOrder(root.right)   // 右
    console.log(root.val)   // 根
}

image.png

层序遍历

层序遍历是广度优先搜索(BFS),采用队列的方式处理,需要O(n)的空间去存储队列

function levelOrder(root) {
    if (!root) return []
    let queue = [root]
    let res = []
    while (queue.length) {
        let node = queue.shift()
        res.push(node.val)
        if (node.left) queue.push(node.left)
        if (node.right) queue.push(node.right)
    }
    return res
}

image.png

二叉树:求最大深度

递归口诀:递归终止,处理本层,递归调用,递归调用结果传递给上一层

  • 递归退出条件:叶子节点的深度为 0
  • 本层逻辑核心:当前节点的左节点深度和右节点深度的较大值 + 1 则是当前节点的深度
image.png
输入: root = [3,9,20,null,null,15,7]
输出: 3

image.png

二叉树:两棵树是否相同

递归口诀:递归终止,处理本层,递归调用,递归调用结果传递给上一层

  • 递归终止条件:左(右)节点都是空 || 有其中一个节点的左(右)节点是空,但另一个不是
  • 本层处理核心逻辑:当前节点的值要相同 && 左节点相同 && 右节点相同
image.png
输入: p = [1,2,3], q = [1,2,3]
输出: true

image.png

二叉树:对称二叉树

递归口诀:递归终止,处理本层,递归调用,递归调用结果传递给上一层

  • 递归终止条件:左(右)节点都是空 || 有其中一个节点的左(右)节点是空,但另一个不是
  • 本层处理核心逻辑:

滑动窗口:找出长度最小的子数组

输入: target = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的子数组。

输入: target = 11, nums = [1,1,1,1,1,1,1,1]
输出: 0
解释: 因为不存在符合条件的子数组,返回0

时间O(n)空间O(1)

思路:

  • 滑动窗口右端点一直右移,直到满足当前窗口总和 sum >= target
  • 滑动窗口左端点一直右移,直到满足当前窗口总和 sum < target

image.png

image.png

滑动窗口:找无重复字符的最长子串

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。注意 "bca""cab" 也是正确答案。

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。注意,"pwke" 是一个子序列,不是子串。

时间O(n)空间O(n)

思路:

  • 因为需要判断字符是否重复了,所以得有一个 map 存一下 每个字符(去重),标记是否出现过
  • 滑动窗口右端点一直右移,直到满足 set 集合里包含该字符
  • 滑动窗口左端点一直右移,直到满足 set 集合里不包含该字符

image.png

image.png

回溯:9键键盘的字母组合

回溯算法用于寻找所有的可行解,如果发现一个解不可行就舍弃掉。如果不存在不可行的解,直接穷举所有的解即可。

image.png
输入: digits = "23"
输出: ["ad","ae","af","bd","be","bf","cd","ce","cf"]

输入: digits = "2"
输出: ["a","b","c"]

image.png

贪心算法:能不能跳到终点【维护最远可达】

最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。要求判断能不能到达最后一个位置

输入: nums = [2,3,1,1,4]
输出: true
解释: 可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 13 步到达最后一个下标。

输入: nums = [3,2,1,0,4]
输出: false
解释: 无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。

思路:遍历每个位置,维护出一个最远可达位置

image.png

可达的情况:

image.png

不可达的情况:

image.png

贪心算法:跳到终点最小步数【维护最远可达+边界再跳】

输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
     从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。

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

image.png

image.png

图:岛屿数量

image.png
输入:grid = [
  ['1','1','1','1','0'],
  ['1','1','0','1','0'],
  ['1','1','0','0','0'],
  ['0','0','0','0','0']
]
输出:1

输入:grid = [
  ['1','1','0','0','0'],
  ['1','1','0','0','0'],
  ['0','0','1','0','0'],
  ['0','0','0','1','1']
]
输出:3

二叉树的递归和网格图的递归有何区别?

image.png

时间O(mn)寻找岛屿,发现岛屿后 DFS 递归(插旗标记,避免无限递归)

image.png

链表:判断是否存在环

image.png

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

快慢指针会相遇,说明有环,否则没环。时间O(n)空间O(1)

image.png

链表:两数相加

image.png

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
  1. 直接求和
  2. 对 sum 取余,并修改结果链表的头尾指针(用于返回结果)
  3. 对 sum 取整
  4. 较长链表继续走,走完的也要等
  5. 最后判断是否还有一次进位

时间O(max(m,n))空间O(1)

image.png

链表: 合并两个有序链表

直接原地改指向即可:

  1. 谁更小,prev指向谁,谁走一格
  2. prev也得走一格
  3. 直接将链表末尾指向未合并完的链表即可

image.png

链表:反转链表部分节点

image.png

输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]

image.png