leetcode 2022年 秋招算法题
1 数组
1.1 两数之和
1 | 输入:nums = [2,7,11,15], target = 9 |
1 | // 【哈希表】 |
1.2 三数之和
- 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组
1 | 输入:nums = [-1,0,1,2,-1,-4] |
1 | // 【排序 + 双指针】 |
1.3 合并两个有序数组
- 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
1 | 输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 |
1 | // 正常思路为双指针,新开一个数组,双指针比较,小的放入新数组,指针后移 |
1.4 螺旋矩阵
- 给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
1 | 输入:n = 3 |
1 | // 【按层模拟】 |
2 字符串
2.1 有效的括号
- 给定一个只包括
'(',')','{','}','[',']'
的字符串 s ,判断字符串是否有效。 - 有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
1 | 输入:s = "([)]" |
1 | // 【栈】 |
2.2 字符串相加
- 给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。
1 | 输入:num1 = "11", num2 = "123" |
1 | // 【模拟竖直相加】 |
2.3 最长回文子串
- 给你一个字符串 s,找到 s 中最长的回文子串。
1 | 输入:s = "babad" |
1 | // 【中心拓展法】 |
3 单链表
3.1 合并两个单链表
- 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
1 | 输入:l1 = [1,2,4], l2 = [1,3,4] |
1 | // 【单链表数据结构】 |
1 | // 【迭代循环】 |
3.2 单链表反转
- 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表
1 | 输入:head = [1,2,3,4,5] |
1 | // 【迭代循环】 |
3.3 两链表相加
- 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
- 请你将两个数相加,并以相同形式返回一个表示和的链表。
- 你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
1 | 输入:l1 = [2,4,3], l2 = [5,6,4] |
1 | // 【循环迭代】 |
3.4 重排链表
- 给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
- 请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
- 不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换
1 | 输入:head = [1,2,3,4,5] |
1 | // 【寻找链表中点 + 链表逆序 + 合并链表】 |
4 双链表
4.1 LRU算法
5 双指针
5.1 数组
5.1.1 移除元素
- 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
- 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
- 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
1 | 输入:nums = [0,1,2,2,3,0,4,2], val = 2 |
1 | // 【双指针向中间遍历】 |
5.1.2 有序数组的平方
- 给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
1 | 输入:nums = [-4,-1,0,3,10] |
1 | // 【双指针向中间遍历】 |
5.1.3 长度最小的子数组
- 给定一个含有 n 个正整数的数组和一个正整数 target 。
- 找出该数组中满足其和≥target 的长度最小的 连续子数组
[numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0 。
1 | 输入:target = 7, nums = [2,3,1,2,4,3] |
1 | // 【滑动窗口(双指针)】 |
5.2 字符串
5.2.1 反转字符串
- 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
- 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
1 | 输入:s = ["h","e","l","l","o"] |
1 | // 【双指针(中间靠拢)】 |
5.2.2 无重复字符的最长字串
- 给定一个字符串 s ,请你找出其中不含有重复字符的最长子串的长度。
1 | 输入: s = "abcabcbb" |
1 | // 【滑动窗口(双指针)】 |
5.2.3 字符串的排列
- 给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。
- 换句话说,s1 的排列之一是 s2 的 子串 。
1 | 输入:s1 = "ab" s2 = "eidbaooo" |
1 | // 【双指针】 |
5.3 链表
5.3.1 环形链表
- 给你一个链表的头节点 head ,判断链表中是否有环。
1 | 输入:head = [3,2,0,-4], pos = 1 |
1 | // 【快慢指针】 |
5.3.2 删除链表的倒数第N个结点
- 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
1 | 输入:head = [1,2,3,4,5], n = 2 |
1 | // 【双指针】 |
5.3.3 链表的中间结点
- 给定一个头结点为 head 的非空单链表,返回链表的中间结点。
- 如果有两个中间结点,则返回第二个中间结点。
1 | 输入:[1,2,3,4,5,6] |
1 | // 双指针 |
5.3.4 环形链表Ⅱ
- 给定一个链表的头节点 head,返回链表开始入环的第一个节点。 如果链表无环,则返回null。
1 | 输入:head = [3,2,0,-4], pos = 1 |
1 | // 【双指针】 |
6 哈希表
6.1 有效的字母异位词
- 给定两个字符串s和t ,编写一个函数来判断t是否是s的字母异位词。
1 | 输入: s = "anagram", t = "nagaram" |
1 | // 【哈希表】 |
6.2 存在重复元素
- 给你一个整数数组nums。如果任一值在数组中出现至少两次 ,返回true ;如果数组中每个元素互不相同,返回false 。
1 | 输入:nums = [1,2,3,1] |
1 | // 【Set】 |
6.3 两个数组的交集
- 给定两个数组nums1和nums2,返回它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
1 | 输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4] |
1 | // 【Set】 |
6.4 四数相加Ⅱ
- 给你四个整数数组 nums1、nums2、nums3和nums4 ,数组长度都是n,请你计算有多少个元组(i, j, k, l) 能满足:
0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
1 | 输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2] |
1 | // 【分组 + 哈希表】 |
7 队列
7.1 用队列实现栈
- 请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
1 | 输入: |
1 | public class MyStack { |
7.2 前K个高频元素
- 给你一个整数数组nums和一个整数 k ,请你返回其中出现频率前k高的元素。你可以按任意顺序返回答案。
1 | 输入: nums = [1,1,1,2,2,3], k = 2 |
1 | // 【优先队列】 |
7.3 滑动窗口最大值
- 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
- 返回滑动窗口中的最大值。
1 | 输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 |
1 | // 【单调队列】 |
8 栈
8.1 用栈实现队列
- 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
1 | 输入: |
1 | public class MyQueue { |
8.2 . 逆波兰表达式求值
- 根据逆波兰表示法(后缀表达式),求表达式的值。
- 有效的算符包括
+、-、*、/
。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
1 | 输入:tokens = ["2","1","+","3","*"] |
1 | public int evalRPN(String[] tokens) { |
8.3 接雨水
- 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
1 | 输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] |
1 | //【单调栈】 |
9 二叉树
9.1 二叉树遍历
9.1.1 二叉树中序遍历
- 给定一个二叉树的根节点 root ,返回它的中序遍历 。
1 | // 【二叉树结构】 |
1 | public List<Integer> inorderTraversal(TreeNode root) { |
9.1.2 二叉树的层序遍历
- 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。(即逐层地,从左到右访问所有节点)。
1 | 输入:root = [3,9,20,null,null,15,7] |
1 | // 【广度优先搜索】 |
9.1.3 二叉树的锯齿层序遍历
- 给你二叉树的根节点 root ,返回其节点值的锯齿形层序遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
1 | 输入:root = [3,9,20,null,null,15,7] |
1 | // 【广度优先搜索】 |
9.2 二叉树的属性
9.2.1 二叉树的最大深度
- 给定一个二叉树,找出其最大深度。
1 | 给定二叉树 [3,9,20,null,null,15,7], |
1 | // 【递归】【深度优先】 |
9.2.2 二叉树的直径
- 给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
1 | 给定二叉树 |
1 | // 【递归】【深度优先搜索】 |
9.2.3 二叉树中的最大路径和
- 给你一个二叉树的根节点 root ,返回其最大路径和 。
1 | 输入:root = [-10,9,20,null,null,15,7] |
1 | // 【递归】【深度优先搜索】 |
9.3 二叉树的构造
9.3.1 从中序与后序遍历序列构造二叉树
- 给定两个整数数组inorder和postorder ,其中inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
1 | 输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3] |
1 | // 【递归】 |
10 贪心算法
10.1 基础常见问题
10.1.1 分发饼干
- 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
- 对每个孩子 i,都有一个胃口值
g[i]
,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸s[j]
。如果s[j]
>=g[i]
,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
1 | 输入: g = [1,2,3], s = [1,1] |
1 | // 【贪心算法】 |
10.2 区间问题
10.2.1 跳跃游戏
- 给定一个非负整数数组 nums ,你最初位于数组的第一个下标。
- 数组中的每个元素代表你在该位置可以跳跃的最大长度。
- 判断你是否能够到达最后一个下标。
1 | 输入:nums = [2,3,1,1,4] |
1 | // 【贪心算法】 |
10.2.2 跳跃游戏Ⅱ
- 给你一个非负整数数组nums,你最初位于数组的第一个位置。
- 数组中的每个元素代表你在该位置可以跳跃的最大长度。
- 你的目标是使用最少的跳跃次数到达数组的最后一个位置。
- 假设你总是可以到达数组的最后一个位置。
1 | 输入: nums = [2,3,1,1,4] |
1 | // 【贪心算法】(局部最优) |
10.2.3 划分字母区间
- 字符串S由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。
1 | 输入:S = "ababcbacadefegdehijhklij" |
1 | // 【贪心算法】 |
10.3 两个维度权衡问题
10.3.1 根据身高重建队列
- 假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个
people[i] = [hi, ki]
表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。 - 请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中
queue[j] = [hj, kj]
是队列中第 j 个人的属性(queue[0]
是排在队列前面的人)。
1 | 输入:people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]] |
1 | public int[][] reconstructQueue(int[][] people) { |
10.3.2 分发糖果
- n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。
- 你需要按照以下要求,给这些孩子分发糖果:
- 每个孩子至少分配到 1 个糖果。
- 相邻两个孩子评分更高的孩子会获得更多的糖果。
- 请你给每个孩子分发糖果,计算并返回需要准备的最少糖果数目。
1 | 输入:ratings = [1,0,2] |
1 | // 【规律得出】 |
11 动态规划
11.1 基础
11.1.1 爬楼梯
- 假设你正在爬楼梯。需要n阶你才能到达楼顶。
- 每次你可以爬1或2个台阶。你有多少种不同的方法可以爬到楼顶呢?
1 | 输入:n = 3 |
1 | // 【动态规划】 |
11.1.2 杨辉三角
- 给定一个非负整数 numRows,生成「杨辉三角」的前numRows行。
- 在「杨辉三角」中,每个数是它左上方和右上方的数的和。
1 | 输入: numRows = 5 |
1 | // 【动态规划】 |
11.1.3 不同路径
- 一个机器人位于一个m x n网格的左上角 (起始点在下图中标记为 “Start” )。
- 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
- 问总共有多少条不同的路径?
1 | 输入:m = 3, n = 7 |
1 | // 【动态规划】 |
11.2 线性问题
11.2.1 打家劫舍
- 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
- 给定一个代表每个房屋存放金额的非负整数数组,计算你不触动警报装置的情况下,一夜之内能够偷窃到的最高金额。
1 | 输入:[1,2,3,1] |
1 | // 【动态规划】 |
11.2.2 打家劫舍Ⅲ
- 小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。
- 除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。
- 给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额。
1 | 输入: root = [3,2,3,null,3,null,1] |
1 | // 【动态规划】 |
11.2.3 买卖股票最佳时机
- 给定一个数组 prices ,它的第i个元素
prices[i]
表示一支给定股票第i天的价格。 - 你只能选择某一天买入这只股票,并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。
- 返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
1 | 输入:[7,1,5,3,6,4] |
1 | //【动态规划】 |
11.2.4 买卖股票的最佳时机Ⅱ
- 给你一个整数数组prices,其中
prices[i]
表示某支股票第i天的价格。 - 在每一天,你可以决定是否购买和/或出售股票。你在任何时候最多只能持有一股股票。
- 返回你能获得的最大利润。
1 | 输入:prices = [7,1,5,3,6,4] |
1 | // 【动态规划】 |
11.2.5 最大子数组和
- 给你一个整数数组nums,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
1 | 输入:nums = [-2,1,-3,4,-1,2,1,-5,4] |
1 | // 【动态规划】 |
11.2.6 最长递增子序列
- 给你一个整数数组nums,找到其中最长严格递增子序列的长度。
1 | 输入:nums = [10,9,2,5,3,7,101,18] |
1 | / 【动态规划】 |
11.2.7 编辑距离
- 给你两个单词word1和word2,请返回将word1转换成word2所使用的最少操作数。
1 | 输入:word1 = "horse", word2 = "ros" |
1 | // 【动态规划】 |
11.3 背包问题
11.3.1 单词拆分
- 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。
- 注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
1 | 输入: s = "leetcode", wordDict = ["leet", "code"] |
1 | // 【动态规划】 |
11.2.2 零钱兑换
- 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
- 计算并返回可以凑成总金额所需的最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
- 你可以认为每种硬币的数量是无限的。
1 | 输入:coins = [1, 2, 5], amount = 11 |
1 | // 【动态规划】 |
11.2.3 完全平方数
- 给你一个整数 n ,返回0和为n的完全平方数的最少数量
1 | 输入:n = 12 |
1 | // 动态规划 |
11.3 区间问题
11.3.1 最长回文子序列
- 给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。
- 子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
1 | 输入:s = "bbbab" |
1 | // 动态规划 |