LeetCode_Hot100_Java_Solution
本文将Leetcode hot 100题目按照类型分类。部分题目可能属于多个类型。
刷leetcode hot 100以前需要了解一些基础知识:
- 常见排序:冒泡排序,插入排序,选择排序,归并排序,快速排序,堆排序。 时间复杂度为O(nlogn):归并排序和堆排序。快速排序时间复杂度最好的情况下是O(nlogn),最坏的情况下是O(n^2)。
- 字符串的常用方法:length(),substring(),spilt()。 StringBuffer()的常用方法:deleteCharAt(),reverse(),toString(),append(),insert。
- 常用数据结构及其常用方法:List,HashMap,HashSet,PriorityQueue,stack,queue。
- Arrays.sort()自定义排序,PriorityQueue()自定义排序。
| 数据结构 | 常用方法 |
|---|---|
| List | add(),remove(), get() |
| HashMap | put(),size(),remove(),containsKey() |
| HashSet | add(),remove(),size(),contains() |
| PriorityQueue | poll(),offer(),isEmpty(),size(),peek() |
| stack | push(),size(),pop(),isEmpty(),peek() |
| queue | poll(),offer(),isEmpty(),size(),peek() |
dp
-
dp数组和下标的含义,递推公式,初始化,遍历顺序。
-
01背包和完全背包。
| 题号 | 题目 | 题目说明 | 文字版题解 | 题解 |
|---|---|---|---|---|
| 198 | 打家劫舍 | 给定一个数组: 求不相邻的价值总和最大值 |
1. dp$dp[i] = max(dp[i-1],dp[i-2]+num[i])$ 2. dfs:DFS 枚举每个房子的选择:偷或不偷,记忆化避免重复子问题。本质上和动态规划思路相同,只是递归实现而非迭代 |
Java |
| 238 | 除自身数组以外的乘积 | 给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除了 nums[i] 之外其余各元素的乘积 。 |
用三个数组分别存储前缀、后缀乘积和 | Java |
| 221 | 最大正方形 | 在一个由 '0' 和 '1' 组成的二维矩阵内,找到只包含 '1' 的最大正方形,并返回其面积。 |
dp[i][j] 表示:以 (i,j) 这个位置作为右下角时,能形成的最大正方形的边长。形成递推公式: dp[i][j] = Math.min(dp[i-1][j], dp[i][j - 1], dp[i - 1][j - 1])+1因为一个正方形能不能变大,取决于它左、上、左上的最小正方形。 |
Java |
| 152 | 乘积最大子数组 | 给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续 子数组,例如 输入: nums = [2,3,-2,4] 输出:6 |
1. 用两个变量,记录以某个索引为末尾的子数组的最大乘积和最小乘积.全局最大值即max(max*curnum,min*curnum,curnum)2. 也可以采用数组存储的形式 |
Java |
| 139 | 单词拆分 | 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。 |
遍历i->n,dp[i] 表示前 i 个字符是否可被字典拼接;枚举字典单词 word,若 dp[i-len(word)] 为真且当前子串等于 word,则 dp[i]=true。 |
Java |
| 647 | 回文子串 | 给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。 |
使用二维动态规划解决回文子串问题。定义 dp[i][j] 表示字符串 s[i..j] 是否为回文串。随着len的依次递增,来表示出状态转移:dp[i][j] = dp[i+1][j-1] |
Java |
| 322 | 零钱兑换 | 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。计算并返回可以凑成总金额所需的 最少的硬币个数 。 |
完全背包: 1. dp[i] 表示最少硬币数2.初始化为“无穷大” 3.状态转移: $dp[j] = min(dp[j], dp[j - coin] + 1)$ |
Java |
| 494 | 目标和 | 给你一个非负整数数组 nums 和一个整数 target 。向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :- 例如, nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。 |
1. 回溯,但是回溯的时间复杂度过大$O(n^2)$; 2**. 背包问**题: 设:正数集合和 = P负数集合和 = N 即$P - N = target$,$P + N = sum$ 两式相加: $2P = target + sum$ $=> P = (target + sum) / 2$ 问题变成: > 从 nums 中选一些数,使它们的和 = (target + sum) / 2,有多少种选法?解法:0/1背包+计数 java<br>for (int i = 0; i < nums.length; i++) {<br> for (int j = (target + sum) / 2; j >= nums[i]; j--) {<br> pos[j] += pos[j - nums[i]];<br> }<br>}<br> |
Java |
| 416 | 分割等和子集 | 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 |
和上一道一样:0/1背包+计数 | Java |
| 337 | 打家劫舍 III | 给定二叉树的 root 。返回 在不触动警报的情况下 (需要父节点和子节点都拿),小偷能够盗取的最高金额 。 |
1. 对于每一个节点,都有选或者不选两种决定,选了该节点,则它的左子节点和右子节点不能选 2. 设定一个数组,下标0代表选了该节点的最大偷盗金额,下标1代表未选择该节点的最小偷盗金额 3. 使用dfs + dp |
Java |
| 312 | 戳气球 | Java | ||
| 309 | 买卖股票的最佳时期含冷冻期 | Java | ||
| 300 | 最长递增子序列 | Java | ||
| 279 | 完全平方数 | Java | ||
| 42 | 接雨水 | Java | ||
| 32 | 最长有效括号 | Java | ||
| 10 | 正则表达式匹配 | Java | ||
| 5 | 最长回文子串 | Java | ||
| 96 | 不同的二叉搜索树 | Java | ||
| 85 | 最大矩形 | Java | ||
| 72 | 编辑距离 | Java | ||
| 70 | 爬楼梯 | Java | ||
| 62 | 不同路径 | Java | ||
| 53 | 最大子数组和 | Java |
链表
- 链表的题目往往使用虚拟头结点的方法,以避免对头结点为空的情况进行特判。
- 做链表的题目是,我们需要记住的是链表的增删节点都是使用的双指针。
| 题号 | 题目 | 题目说明 | 文字版题解 | 题解 |
|---|---|---|---|---|
| 160 | 相交链表 | 返回两个单链表相交的起始节点。 | 1. 哈希表(很容易想到,但是空间复杂度太大了) 2. 双指针:当两个链表长度不同的时候,直接遍历可能不同步,通过跳转到另一条链表头,可以让两个指针在第二轮遍历时“对齐” |
Java |
| 234 | 回文链表 | 给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。 |
将值复制到数组中后用双指针法 | Java |
| 206 | 反转链表 | 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 |
1. 使用虚拟头结点的方法 ListNode dummy 让虚拟头结点指向head,避免对head特判 2. 链表的题删除链表、翻转节点、添加节点都要用双指针 |
Java |
| 148 | 排序链表 | 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。 |
使用归并排序 | Java |
| 146 | LRU 缓存 | Java | ||
| 142 | 环形链表 II | Java | ||
| 141 | 环形链表 | Java | ||
| 23 | 合并 K 个升序链表 | Java | ||
| 21 | 合并两个有序链表 | Java | ||
| 114 | 二叉树展开为链表 | Java | ||
| 19 | 删除链表的倒数第 N 个结点 | Java | ||
| 2 | 两数相加 | Java |
单调栈
- 单调栈按照从栈底到栈顶的大小变化可以分为单调递增栈和单调递减栈。
- 单调栈中存储的是元素的索引。
| 题号 | 题目 | 题目说明 | 文字版题解 | 题解 |
|---|---|---|---|---|
| 739 | 每日温度 | 给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。 |
维护一个单调递减的栈(存下下标),遇到更大的数,则进行出栈 | Java |
| 84 | 柱状图中最大的矩形 | 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 求在该柱状图中,能够勾勒出来的矩形的最大面积。 |
从i=0开始,寻找heights[i] 作为矩形的 最低高度,那么它能扩展的宽度是(维护一个单调栈):1. 向左找到第一个比它小的柱子 2. 向右找到第一个比它小的柱子 |
Java |
构建数据结构
- 构建特殊数据结构。
| 题号 | 题目 | 题目说明 | 文字版题解 | 题解 |
|---|---|---|---|---|
| 207 | 课程表 | 给定课程数和前置条件如numCourses = 2, prerequisites = [[1,0]],判断是都可以完成所有课程的学习 |
拓扑排序:判断是否存在循环依赖。当前课程——>前置课程画图。使用dfs进行求解。 | Java |
| 399 | 除法求值 | 输入:equations = [["a","b"],["b","c"]], values = [2.0,3.0], queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]输出: [6.00000,0.50000,-1.00000,1.00000,-1.00000] |
本题可以抽象为 带权有向图问题。注意: 1. 有的节点是没有的,直接返回-1 2. dfs的时候末尾没有边的不能再继续探索 |
Java |
| 208 | 实现 Trie (前缀树) | Java |
二进制
- ^异或:任何数^自身 = 0,^0不变。
- &1:判断末尾数是否为1。
- «:向左位移1位,»:向右位移1位。
| 题号 | 题目 | 题目说明 | 文字版题解 | 题解 |
|---|---|---|---|---|
| 461 | 汉明距离 | 两个数字对应二进制位不同的位置的数目。 | 异或^解决,再利用按位与&判断尾数是否为1, »=进行自身的右移即可 | Java |
| 338 | 比特位计数 | Java |
贪心
- 通过局部最优,得到全局最优,需要会自定义排序,建议使用lamda表达式。
| 题号 | 题目 | 题目说明 | 文字版题解 | 题解 |
|---|---|---|---|---|
| 406 | 根据身高重建队列 | 打乱顺序的一群人重新排成队列,如输入输入:people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]输出[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]分别表示身高和前面大于等于他的人数 |
1. 先安排高个子的位置 2. 通过插队的方式安排矮个子的位置 |
Java |
| 253 | 会议室II | Java | ||
| 621 | 任务调度器 | Java |
优先队列
- PriorityQueue是底层是堆排序。
| 题目 | 题号 | 题目说明 | 文字版题解 | 题解 |
|---|---|---|---|---|
| 239 | 滑动窗口最大值 | 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧,求出滑动窗口中的最大值的数组,长度应该为**nums.length-k+1**。 |
1. 优先队列存储当前元素值和索引,用大顶堆进行排序 2. 使用单调队列维护一个递减的队列 |
Java |
| 23 | 合并 K 个升序链表 | Java |
回溯
- 回溯三要素:1.传递的参数和返回类型;2.终止条件;3.回溯的逻辑。
| 题号 | 题目 | 题目说明 | 文字版题解 | 题解 |
|---|---|---|---|---|
| 22 | 括号生成 | 数字 n 代表生成括号的对数,返回所有可能的并且 有效的 括号组合。**输入:**n = 3输出: ["((()))","(()())","(())()","()(())","()()()"] |
回溯,全排列,有效的括号组合,对于任意括号左边的左括号的数量大于等于右括号的数量 | Java |
| 46 | 全排列 | Java | ||
| 17 | 电话号码的字母组合 | Java | ||
| 78 | 子集 | Java | ||
| 39 | 组合总和 | Java |
数组
- 需要会二分法的使用和双指针、滑动窗口。
| 题号 | 题目 | 题目说明 | 文字版题解 | 题解 |
|---|---|---|---|---|
| 48 | 旋转图像 | 给定一个矩阵,求出其顺时针旋转后的矩阵 | 原地旋转(两次折叠):先[i,j] -> [j,i],再进行[i,j] -> [i,n-j+1]的交换 |
Java |
| 33 | 搜索旋转排序数组 | Java | ||
| 34 | 在排序数组中查找元素的第一个和最后一个位置 | Java | ||
| 31 | 下一个排列 | Java | ||
| 15 | 三数之和 | Java | ||
| 11 | 盛最多水的容器 | Java | ||
| 4 | 寻找两个正序数组的中位数 | Java | ||
| 1 | 两数之和 | Java | ||
| 75 | 颜色分类 | Java | ||
| 56 | 合并区间 | Java | ||
| 55 | 跳跃游戏 | Java | ||
| 215 | 数组中的第K个最大元素 | Java | ||
| 287 | 寻找重复数 | Java | ||
| 283 | 移动零 | Java | ||
| 240 | 搜索二维矩阵 II | Java |
二叉树
- 需要会前中后序遍历的递归、迭代实现和层序遍历。
| 题号 | 题目 | 题目说明 | 文字版题解 | 题解 |
|---|---|---|---|---|
| 236 | 二叉树的最近公共祖先 | 给定一颗树root,和两个节点,求两个节点最近的公共祖先 | 递归 -> 递归当前节点的左右子树中是否包含p || q,1. 如果都不为 null,则说明左右两个子树各包含一个p || q,即当前root是最近公共祖先2. 若有一个为 null,另一个不为null,即root节点返回该不为null的节点3. 若都为 null,如果root不包含任意一个,即返回null |
Java |
| 226 | 翻转二叉树 | Java | ||
| 124 | 二叉树中的最大路径和 | Java | ||
| 297 | 二叉树的序列化与反序列化 | Java | ||
| 543 | 二叉树的直径 | Java | ||
| 538 | 把二叉搜索树转换为累加树 | Java | ||
| 114 | 二叉树展开为链表 | Java | ||
| 617 | 合并二叉树 | Java | ||
| 105 | 从前序与中序遍历序列构造二叉树 | Java | ||
| 104 | 二叉树的最大深度 | Java | ||
| 102 | 二叉树的层序遍历 | Java | ||
| 101 | 对称二叉树 | Java | ||
| 98 | 验证二叉搜索树 | Java | ||
| 96 | 不同的二叉搜索树 | Java | ||
| 437 | 路径总和 III | Java | ||
| 94 | 二叉树的中序遍历 | Java |
Stack、Queue、HashMap()、HashSet()
- Stack、Queue、HashMap和HashSet的常见方法需要会使用。
| 题号 | 题目 | 题目说明 | 文字版题解 | 题解 |
|---|---|---|---|---|
| 169 | 多数元素 | 给出一个数组,返回元素个数大于1/2的元素,没有返回-1 |
维护一个hashMap<Integer,Integer>,一个是元素,另一个是关于元素的个数,一直判断即可 |
Java |
| 128 | 最长连续序列 | Java | ||
| 438 | 找到字符串中所有字母异位词 | Java | ||
| 394 | 字符串解码 | Java | ||
| 560 | 和为 K 的子数组 | Java | ||
| 20 | 有效的括号 | Java | ||
| 3 | 无重复字符的最长子串 | Java |
深度优先搜索和广度优先搜索
-
深度优先搜索:按照既定的搜索顺序,在一个方向搜索到头之后,回溯搜索下一个方向。
-
广度优先搜索:从起始位置开始,逐层遍历(按照距离)所有可能到达的位置。
| 题号 | 题目 | 题目说明 | 文字版题解 | 题解 |
|---|---|---|---|---|
| 79 | 单词搜索 | 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。 |
回溯;八皇后的写法 | Java |
| 200 | 岛屿数量 | Java |