🔥 LeetCode 热题 HOT 100(31-40)
75. 颜色分类
思路:将 2 往后放,0 往前放,剩余的1自然就放好了。
- 使用双指针:left、right 分别指向待插入的 0 和 2 的位置,初始 left 指向数组头,right 指向数组尾部。
- 从头开始遍历数组,若当前位置数为 2 则与 right 所指向元素互换,然后 right 左移,直到当前位置元素不为2;
- 当前位置元素若为 0 则 和 left 所指元素互换,然后 left 右移。随后接着遍历,直到 和 right相遇。
class Solution {
public void sortColors(int[] nums) {
int left = 0;
int right = nums.length - 1;
for (int i = 0; i <= right; i++) {
//将2往后放
while (i <= right && nums[i] == 2) {
swap(nums, i, right);
right--;
}
//将0往前放
if (nums[i] == 0) {
swap(nums, i, left);
left++;
}
}
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
76. 最小覆盖子串
思路:标准滑动窗口
class Solution {
public String minWindow(String s, String t) {
//记录 t 中字符在 window 中的出现频次
Map<Character, Integer> window = new HashMap<>();
//记录 t 中各个字符的频次
Map<Character, Integer> need = new HashMap<>();
for (int i = 0; i < t.length(); i++) {
need.put(t.charAt(i), need.getOrDefault(t.charAt(i), 0) + 1);
}
//窗口边界,左闭右开
int left = 0, right = 0;
// t 中字符在 window 中已经匹配的个数
int match = 0;
//最小子串的起始位置和长度
int start = 0, minLen = Integer.MAX_VALUE;
while (right < s.length()) {
//窗口扩张(右边界右移)
char rightChar = s.charAt(right);
right++;
//如当前 rightChar 是 t 中的字符
if (need.containsKey(rightChar)) {
// window 中对应次数加 1
window.put(rightChar, window.getOrDefault(rightChar, 0) + 1);
// 仅当 rightChar 在 window 中的频次 小于等于 t 中的频次时才说明新匹配了一个字符(想想t中某个字符出现多次的情况)
if (window.get(rightChar).compareTo(need.get(rightChar)) <= 0) {
match++;
}
}
//如果 window 中已经包含了 t 中所有字符
while (match == t.length()) {
int tempLen = right - left;
if (tempLen < minLen) {
minLen = tempLen;
start = left;
}
//收缩窗口(左边界右移)
char leftChar = s.charAt(left);
left++;
if (need.containsKey(leftChar)) {
if (window.get(leftChar).compareTo(need.get(leftChar)) <= 0) {
match--;
}
window.put(leftChar, window.get(leftChar) - 1);
}
}
}
return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
}
}
78. 子集
思路:典型回溯法
lass Solution {
public List<List<Integer>> subsets(int[] nums) {
LinkedList<Integer> track = new LinkedList<>();
dfs(nums, track, 0);
return res;
}
private List<List<Integer>> res = new LinkedList<>();
private void dfs (int[] nums, LinkedList<Integer> track, int start) {
res.add(new LinkedList<>(track));
//通过start来控制当前可以选择的列表
for (int i = start; i < nums.length; i++) {
//选择
track.offerLast(nums[i]);
dfs(nums, track, i + 1);
//撤销选择
track.pollLast();
}
}
}
// {1, 2, 3}对应递归树:
// []
// 1 2 3
// 12 13 23
// 123
79. 单词搜索
思路:直接回溯
class Solution {
public boolean exist(char[][] board, String word) {
boolean[][] visited = new boolean[board.length][board[0].length];
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if (board[i][j] == word.charAt(0)) {
if (dfs(board, word, 0, visited, i, j)) {
return true;
}
}
}
}
return false;
}
private boolean dfs(char[][] board, String word, int index, boolean[][] visited, int row, int col) {
//base case
if (word.length() == index) {
return true;
}
if (!isValid(board, row, col)) {
return false;
}
if (visited[row][col]) {
return false;
}
if (board[row][col] != word.charAt(index)) {
return false;
}
//标记访问过的位置
visited[row][col] = true;
boolean res = dfs(board, word, index + 1, visited, row + 1, col) ||
dfs(board, word, index + 1, visited, row, col + 1) ||
dfs(board, word, index + 1, visited, row - 1, col) ||
dfs(board, word, index + 1, visited, row, col - 1);
//撤销标记
visited[row][col] = false;
return res;
}
private boolean isValid(char[][] board, int row, int col) {
if (row >= 0 && row < board.length && col >= 0 && col < board[0].length) {
return true;
} else {
return false;
}
}
}
推荐题解:回溯算法(Java)
84. 柱状图中最大的矩形
思路:单调递增栈,依次遍历数组,大于等于栈顶元素直接入栈,小于则弹栈并计算一次面积。
class Solution {
public int largestRectangleArea(int[] heights) {
int len = heights.length;
int[] newHeight = new int[len + 2];
//将 heights 复制到 newHeight,同时将首尾各填充一个 -1
newHeight[0] = -1;
newHeight[len - 1] = -1;
for (int i = 1; i <= len; i++) {
newHeight[i] = heights[i - 1];
}
int maxArea = 0;
Deque<Integer> stack = new LinkedList<>();
for (int i = 0; i < newHeight.length; i++) {
//出栈
while (!stack.isEmpty() && newHeight[stack.peek()] > newHeight[i]) {
int high = newHeight[stack.pop()];
int width = i - stack.peek() - 1; // 下标 [stack.peek() + 1, i - 1] 对应元素都 大于等于 high
int area = high * width;
maxArea = Math.max(area, maxArea);
}
//入栈
stack.push(i);
}
return maxArea;
}
}
推荐题解:详解单调栈,♀️必须秒懂!
85. 最大矩形
思路:将该题转换为上一题(84. 柱状图中最大的矩形)。如下图,分别获取以每一行为底的柱状图,并计算当前柱状图所能围城的最大矩形面积,最后取最大值。
class Solution {
public int maximalRectangle(char[][] matrix) {
if (matrix == null || matrix.length <= 0 || matrix[0].length <= 0) {
return 0;
}
int row = matrix.length;
int col = matrix[0].length;
int maxArea = 0;
//根据二维矩阵获取柱状图对应数组
int[] tempHeight = new int[col];
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (matrix[i][j] == '1') {
tempHeight[j] += 1;
} else {
tempHeight[j] = 0;
}
}
maxArea = Math.max(maxArea, largestRectangleArea(tempHeight));
}
return maxArea;
}
//84. 柱状图中最大的矩形
private int largestRectangleArea(int[] nums) {
int len = nums.length;
int[] newHeight = new int[len + 2];
newHeight[0] = -1;
newHeight[len + 1] = -1;
for (int i = 0; i < len; i++) {
newHeight[i + 1] = nums[i];
}
int maxArea = 0;
Deque<Integer> stack = new LinkedList<>();
for (int i = 0; i < newHeight.length; i++) {
while (!stack.isEmpty() && newHeight[stack.peek()] > newHeight[i]) {
int high = newHeight[stack.pop()];
int width = i - stack.peek() - 1;
int area = high * width;
maxArea = Math.max(area, maxArea);
}
stack.push(i);
}
return maxArea;
}
}
94. 二叉树的中序遍历
非递归解法:
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new LinkedList<>();
if (root == null) {
return res;
}
TreeNode temp = root;
Deque<TreeNode> stack = new LinkedList<>();
while (temp != null || !stack.isEmpty()) {
while (temp != null) {
stack.push(temp); // 加入栈
temp = temp.left; // 到最左边结点停止
}
temp = stack.pop(); // 访问栈顶元素
res.add(temp.val);
temp = temp.right; //下一个遍历的元素是temp的右子树的最左边结点
}
return res;
}
}
96. 不同的二叉搜索树
思路:动态规划
class Solution {
public int numTrees(int n) {
// 由小到大的 n 个结点所能组成的不同二叉搜索树个数
int[] dp = new int[n + 1];
//base case
dp[0] = 1;
dp[1] = 1;
//状态转移 dp[i] = dp[0]dp[i - 1] + dp[1]dp[i - 2] ... + ... dp[i - 1]dp[0],即:sum(dp[j - 1] + dp[i - j]), j从1到i
for (int i = 2; i < n + 1; i++) {
for (int j = 1; j <= i; j++) {
dp[i] += dp[j - 1] * dp[i - j];
}
}
return dp[n];
}
}
推荐题解:画解算法:96. 不同的二叉搜索树
98. 验证二叉搜索树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isValidBST(TreeNode root) {
return isValidBST(root, null, null);
}
//二叉搜索树的每个结点都有一个上下界(除了根节点)
private boolean isValidBST(TreeNode node, TreeNode low, TreeNode high) {
//base case
if (node == null) {
return true;
}
//base case
if (low != null && node.val <= low.val) return false;
if (high != null && node.val >= high.val) return false;
boolean ret = isValidBST(node.left, low, node) && isValidBST(node.right, node, high);
return ret;
}
}
推荐题解:验证二叉搜索树(BST:给子树上所有节点都加一个边界)
101. 对称二叉树
class Solution {
public boolean isSymmetric(TreeNode root) {
return isMirror(root, root);
}
private boolean isMirror(TreeNode node1, TreeNode node2) {
if (node1 == null && node2 == null) {
return true;
}
// 联系前面的判断,此处表示只有一个为null
if (node1 == null || node2 == null) {
return false;
}
return (node1.val == node2.val) && isMirror(node1.left, node2.right) && isMirror(node1.right, node2.left);
}
}
推荐题解:画解算法:101. 对称二叉树
🔥 LeetCode 热题 HOT 100(31-40)的更多相关文章
- LeetCode 热题 HOT 100(05,正则表达式匹配)
LeetCode 热题 HOT 100(05,正则表达式匹配) 不够优秀,发量尚多,千锤百炼,方可成佛. 算法的重要性不言而喻,无论你是研究者,还是最近比较火热的IT 打工人,都理应需要一定的算法能力 ...
- 🔥 LeetCode 热题 HOT 100(81-90)
337. 打家劫舍 III 思路:后序遍历 + 动态规划 推荐题解:树形 dp 入门问题(理解「无后效性」和「后序遍历」) /** * Definition for a binary tree nod ...
- 🔥 LeetCode 热题 HOT 100(71-80)
253. 会议室 II(NO) 279. 完全平方数 class Solution { public int numSquares(int n) { // dp[i] : 组成和为 i 的最少完全平方 ...
- 🔥 LeetCode 热题 HOT 100(51-60)
142. 环形链表 II 思路:快慢指针,快慢指针相遇后,慢指针回到头,快慢指针步伐一致一起移动,相遇点即为入环点 /** * Definition for singly-linked list. * ...
- 🔥 LeetCode 热题 HOT 100(21-30)
46. 全排列 思路:典型回溯法 class Solution { public List<List<Integer>> permute(int[] nums) { Linke ...
- 🔥 LeetCode 热题 HOT 100(11-20)
20. 有效的括号 class Solution { public boolean isValid(String s) { Map<Character, Character> map = ...
- 🔥 LeetCode 热题 HOT 100(61-70)
207. 课程表 思路:根据题意可知:当课程之间不存在 环状 循环依赖时,便能完成所有课程的学习,反之则不能.因此可以将问题转换成: 判断有向图中是否存在环.使用 拓扑排序法 : 构建 入度表:记录每 ...
- 🔥 LeetCode 热题 HOT 100(41-50)
102. 二叉树的层序遍历 思路:使用队列. /** * Definition for a binary tree node. * public class TreeNode { * int val; ...
- 🔥 LeetCode 热题 HOT 100(1-10)
1. 两数之和 思路一:暴力遍历所有组合 class Solution { public int[] twoSum(int[] nums, int target) { for (int i = 0; ...
随机推荐
- 大数据初级sy
1.spark 是用以下哪种编程语言实现的? A.C B C++ C JAVA D.Scala (正确答案) 2.FusionIn ...
- Java进阶 | Proxy动态代理机制详解
一.Jvm加载对象 在说Java动态代理之前,还是要说一下Jvm加载对象的过程,这个依旧是理解动态代理的基础性原理: Java类即源代码程序.java类型文件,经过编译器编译之后就被转换成字节代码.c ...
- Linux网络命令与脚本使用
作为系统管理员,经常需要诊断和解决网络问题,而配置.监控与保护网络有助于发现问题并在事情范围扩大前得意解决,并且网络的性能与安全也是管理与诊断网络的重要部分.这里总结一下常用与Linux网络管理的命令 ...
- 【spring源码系列】之【Bean的生命周期】
为源码付出的每一分努力都不会白费. 1. Bean的实例化概述 前一篇分析了BeanDefinition的封装过程,最终将beanName与BeanDefinition以一对一映射关系放到beanDe ...
- 重新整理 .net core 实践篇————网关中的身份签名认证[三十七]
前言 简单整理一下网关中的jwt,jwt用于授权认证的,其实关于认证授权这块https://www.cnblogs.com/aoximin/p/12268520.html 这个链接的时候就已经写了,当 ...
- AcWing 1128. 信使
战争时期,前线有 n个哨所,每个哨所可能会与其他若干个哨所之间有通信联系. 信使负责在哨所之间传递信息,当然,这是要花费一定时间的(以天为单位). 指挥部设在第一个哨所.当指挥部下达一个命令后,指挥部 ...
- AcWing 1303. 斐波那契前 n 项和
输出斐波那契数列前 n 项和 对m取摸的结果 #include<bits/stdc++.h> #define LL long long #define N 3 using namespac ...
- Java:Java的堆区、栈区和方法区详解
Java内存空间理解 堆:堆主要存放Java在运行过程中new出来的对象,凡是通过new生成的对象都存放在堆中,对于堆中的对象生命周期的管理由Java虚拟机的垃圾回收机制GC进行回收和统一管理.类的非 ...
- Java多线程事务管理
今天要讨论的是"Java实现多线程单条数据事务管理",在此之前,顺便回顾一下实现多线程的几种方式 实现多线程的三种方式 一.继承Thread类 第一种方法是继承Thread类,重写 ...
- 排序---python版
冒泡排序: 比较相邻的元素.如果第一个比第二个大,就交换它们两个: 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数: 针对所有的元素重复以上的步骤,除了最 ...