75. 颜色分类

思路:将 2 往后放,0 往前放,剩余的1自然就放好了。

  • 使用双指针:left、right 分别指向待插入的 0 和 2 的位置,初始 left 指向数组头,right 指向数组尾部。
  • 从头开始遍历数组,若当前位置数为 2 则与 right 所指向元素互换,然后 right 左移,直到当前位置元素不为2;
  • 当前位置元素若为 0 则 和 left 所指元素互换,然后 left 右移。随后接着遍历,直到 和 right相遇。
  1. class Solution {
  2. public void sortColors(int[] nums) {
  3. int left = 0;
  4. int right = nums.length - 1;
  5. for (int i = 0; i <= right; i++) {
  6. //将2往后放
  7. while (i <= right && nums[i] == 2) {
  8. swap(nums, i, right);
  9. right--;
  10. }
  11. //将0往前放
  12. if (nums[i] == 0) {
  13. swap(nums, i, left);
  14. left++;
  15. }
  16. }
  17. }
  18. private void swap(int[] nums, int i, int j) {
  19. int temp = nums[i];
  20. nums[i] = nums[j];
  21. nums[j] = temp;
  22. }
  23. }

76. 最小覆盖子串

思路:标准滑动窗口

  1. class Solution {
  2. public String minWindow(String s, String t) {
  3. //记录 t 中字符在 window 中的出现频次
  4. Map<Character, Integer> window = new HashMap<>();
  5. //记录 t 中各个字符的频次
  6. Map<Character, Integer> need = new HashMap<>();
  7. for (int i = 0; i < t.length(); i++) {
  8. need.put(t.charAt(i), need.getOrDefault(t.charAt(i), 0) + 1);
  9. }
  10. //窗口边界,左闭右开
  11. int left = 0, right = 0;
  12. // t 中字符在 window 中已经匹配的个数
  13. int match = 0;
  14. //最小子串的起始位置和长度
  15. int start = 0, minLen = Integer.MAX_VALUE;
  16. while (right < s.length()) {
  17. //窗口扩张(右边界右移)
  18. char rightChar = s.charAt(right);
  19. right++;
  20. //如当前 rightChar 是 t 中的字符
  21. if (need.containsKey(rightChar)) {
  22. // window 中对应次数加 1
  23. window.put(rightChar, window.getOrDefault(rightChar, 0) + 1);
  24. // 仅当 rightChar 在 window 中的频次 小于等于 t 中的频次时才说明新匹配了一个字符(想想t中某个字符出现多次的情况)
  25. if (window.get(rightChar).compareTo(need.get(rightChar)) <= 0) {
  26. match++;
  27. }
  28. }
  29. //如果 window 中已经包含了 t 中所有字符
  30. while (match == t.length()) {
  31. int tempLen = right - left;
  32. if (tempLen < minLen) {
  33. minLen = tempLen;
  34. start = left;
  35. }
  36. //收缩窗口(左边界右移)
  37. char leftChar = s.charAt(left);
  38. left++;
  39. if (need.containsKey(leftChar)) {
  40. if (window.get(leftChar).compareTo(need.get(leftChar)) <= 0) {
  41. match--;
  42. }
  43. window.put(leftChar, window.get(leftChar) - 1);
  44. }
  45. }
  46. }
  47. return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
  48. }
  49. }

78. 子集

思路:典型回溯法

  1. lass Solution {
  2. public List<List<Integer>> subsets(int[] nums) {
  3. LinkedList<Integer> track = new LinkedList<>();
  4. dfs(nums, track, 0);
  5. return res;
  6. }
  7. private List<List<Integer>> res = new LinkedList<>();
  8. private void dfs (int[] nums, LinkedList<Integer> track, int start) {
  9. res.add(new LinkedList<>(track));
  10. //通过start来控制当前可以选择的列表
  11. for (int i = start; i < nums.length; i++) {
  12. //选择
  13. track.offerLast(nums[i]);
  14. dfs(nums, track, i + 1);
  15. //撤销选择
  16. track.pollLast();
  17. }
  18. }
  19. }
  20. // {1, 2, 3}对应递归树:
  21. // []
  22. // 1 2 3
  23. // 12 13 23
  24. // 123

79. 单词搜索

思路:直接回溯

  1. class Solution {
  2. public boolean exist(char[][] board, String word) {
  3. boolean[][] visited = new boolean[board.length][board[0].length];
  4. for (int i = 0; i < board.length; i++) {
  5. for (int j = 0; j < board[0].length; j++) {
  6. if (board[i][j] == word.charAt(0)) {
  7. if (dfs(board, word, 0, visited, i, j)) {
  8. return true;
  9. }
  10. }
  11. }
  12. }
  13. return false;
  14. }
  15. private boolean dfs(char[][] board, String word, int index, boolean[][] visited, int row, int col) {
  16. //base case
  17. if (word.length() == index) {
  18. return true;
  19. }
  20. if (!isValid(board, row, col)) {
  21. return false;
  22. }
  23. if (visited[row][col]) {
  24. return false;
  25. }
  26. if (board[row][col] != word.charAt(index)) {
  27. return false;
  28. }
  29. //标记访问过的位置
  30. visited[row][col] = true;
  31. boolean res = dfs(board, word, index + 1, visited, row + 1, col) ||
  32. dfs(board, word, index + 1, visited, row, col + 1) ||
  33. dfs(board, word, index + 1, visited, row - 1, col) ||
  34. dfs(board, word, index + 1, visited, row, col - 1);
  35. //撤销标记
  36. visited[row][col] = false;
  37. return res;
  38. }
  39. private boolean isValid(char[][] board, int row, int col) {
  40. if (row >= 0 && row < board.length && col >= 0 && col < board[0].length) {
  41. return true;
  42. } else {
  43. return false;
  44. }
  45. }
  46. }

推荐题解:回溯算法(Java)

84. 柱状图中最大的矩形

思路:单调递增栈,依次遍历数组,大于等于栈顶元素直接入栈,小于则弹栈并计算一次面积。

  1. class Solution {
  2. public int largestRectangleArea(int[] heights) {
  3. int len = heights.length;
  4. int[] newHeight = new int[len + 2];
  5. //将 heights 复制到 newHeight,同时将首尾各填充一个 -1
  6. newHeight[0] = -1;
  7. newHeight[len - 1] = -1;
  8. for (int i = 1; i <= len; i++) {
  9. newHeight[i] = heights[i - 1];
  10. }
  11. int maxArea = 0;
  12. Deque<Integer> stack = new LinkedList<>();
  13. for (int i = 0; i < newHeight.length; i++) {
  14. //出栈
  15. while (!stack.isEmpty() && newHeight[stack.peek()] > newHeight[i]) {
  16. int high = newHeight[stack.pop()];
  17. int width = i - stack.peek() - 1; // 下标 [stack.peek() + 1, i - 1] 对应元素都 大于等于 high
  18. int area = high * width;
  19. maxArea = Math.max(area, maxArea);
  20. }
  21. //入栈
  22. stack.push(i);
  23. }
  24. return maxArea;
  25. }
  26. }

推荐题解:详解单调栈,‍♀️必须秒懂!

85. 最大矩形

思路:将该题转换为上一题(84. 柱状图中最大的矩形)。如下图,分别获取以每一行为底的柱状图,并计算当前柱状图所能围城的最大矩形面积,最后取最大值。

  1. class Solution {
  2. public int maximalRectangle(char[][] matrix) {
  3. if (matrix == null || matrix.length <= 0 || matrix[0].length <= 0) {
  4. return 0;
  5. }
  6. int row = matrix.length;
  7. int col = matrix[0].length;
  8. int maxArea = 0;
  9. //根据二维矩阵获取柱状图对应数组
  10. int[] tempHeight = new int[col];
  11. for (int i = 0; i < row; i++) {
  12. for (int j = 0; j < col; j++) {
  13. if (matrix[i][j] == '1') {
  14. tempHeight[j] += 1;
  15. } else {
  16. tempHeight[j] = 0;
  17. }
  18. }
  19. maxArea = Math.max(maxArea, largestRectangleArea(tempHeight));
  20. }
  21. return maxArea;
  22. }
  23. //84. 柱状图中最大的矩形
  24. private int largestRectangleArea(int[] nums) {
  25. int len = nums.length;
  26. int[] newHeight = new int[len + 2];
  27. newHeight[0] = -1;
  28. newHeight[len + 1] = -1;
  29. for (int i = 0; i < len; i++) {
  30. newHeight[i + 1] = nums[i];
  31. }
  32. int maxArea = 0;
  33. Deque<Integer> stack = new LinkedList<>();
  34. for (int i = 0; i < newHeight.length; i++) {
  35. while (!stack.isEmpty() && newHeight[stack.peek()] > newHeight[i]) {
  36. int high = newHeight[stack.pop()];
  37. int width = i - stack.peek() - 1;
  38. int area = high * width;
  39. maxArea = Math.max(area, maxArea);
  40. }
  41. stack.push(i);
  42. }
  43. return maxArea;
  44. }
  45. }

94. 二叉树的中序遍历

非递归解法:

  1. class Solution {
  2. public List<Integer> inorderTraversal(TreeNode root) {
  3. List<Integer> res = new LinkedList<>();
  4. if (root == null) {
  5. return res;
  6. }
  7. TreeNode temp = root;
  8. Deque<TreeNode> stack = new LinkedList<>();
  9. while (temp != null || !stack.isEmpty()) {
  10. while (temp != null) {
  11. stack.push(temp); // 加入栈
  12. temp = temp.left; // 到最左边结点停止
  13. }
  14. temp = stack.pop(); // 访问栈顶元素
  15. res.add(temp.val);
  16. temp = temp.right; //下一个遍历的元素是temp的右子树的最左边结点
  17. }
  18. return res;
  19. }
  20. }

96. 不同的二叉搜索树

思路:动态规划

  1. class Solution {
  2. public int numTrees(int n) {
  3. // 由小到大的 n 个结点所能组成的不同二叉搜索树个数
  4. int[] dp = new int[n + 1];
  5. //base case
  6. dp[0] = 1;
  7. dp[1] = 1;
  8. //状态转移 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
  9. for (int i = 2; i < n + 1; i++) {
  10. for (int j = 1; j <= i; j++) {
  11. dp[i] += dp[j - 1] * dp[i - j];
  12. }
  13. }
  14. return dp[n];
  15. }
  16. }

推荐题解:画解算法:96. 不同的二叉搜索树

98. 验证二叉搜索树

  1. /**
  2. * Definition for a binary tree node.
  3. * public class TreeNode {
  4. * int val;
  5. * TreeNode left;
  6. * TreeNode right;
  7. * TreeNode() {}
  8. * TreeNode(int val) { this.val = val; }
  9. * TreeNode(int val, TreeNode left, TreeNode right) {
  10. * this.val = val;
  11. * this.left = left;
  12. * this.right = right;
  13. * }
  14. * }
  15. */
  16. class Solution {
  17. public boolean isValidBST(TreeNode root) {
  18. return isValidBST(root, null, null);
  19. }
  20. //二叉搜索树的每个结点都有一个上下界(除了根节点)
  21. private boolean isValidBST(TreeNode node, TreeNode low, TreeNode high) {
  22. //base case
  23. if (node == null) {
  24. return true;
  25. }
  26. //base case
  27. if (low != null && node.val <= low.val) return false;
  28. if (high != null && node.val >= high.val) return false;
  29. boolean ret = isValidBST(node.left, low, node) && isValidBST(node.right, node, high);
  30. return ret;
  31. }
  32. }

推荐题解:验证二叉搜索树(BST:给子树上所有节点都加一个边界)

101. 对称二叉树

  1. class Solution {
  2. public boolean isSymmetric(TreeNode root) {
  3. return isMirror(root, root);
  4. }
  5. private boolean isMirror(TreeNode node1, TreeNode node2) {
  6. if (node1 == null && node2 == null) {
  7. return true;
  8. }
  9. // 联系前面的判断,此处表示只有一个为null
  10. if (node1 == null || node2 == null) {
  11. return false;
  12. }
  13. return (node1.val == node2.val) && isMirror(node1.left, node2.right) && isMirror(node1.right, node2.left);
  14. }
  15. }

推荐题解:画解算法:101. 对称二叉树

🔥 LeetCode 热题 HOT 100(31-40)的更多相关文章

  1. LeetCode 热题 HOT 100(05,正则表达式匹配)

    LeetCode 热题 HOT 100(05,正则表达式匹配) 不够优秀,发量尚多,千锤百炼,方可成佛. 算法的重要性不言而喻,无论你是研究者,还是最近比较火热的IT 打工人,都理应需要一定的算法能力 ...

  2. 🔥 LeetCode 热题 HOT 100(81-90)

    337. 打家劫舍 III 思路:后序遍历 + 动态规划 推荐题解:树形 dp 入门问题(理解「无后效性」和「后序遍历」) /** * Definition for a binary tree nod ...

  3. 🔥 LeetCode 热题 HOT 100(71-80)

    253. 会议室 II(NO) 279. 完全平方数 class Solution { public int numSquares(int n) { // dp[i] : 组成和为 i 的最少完全平方 ...

  4. 🔥 LeetCode 热题 HOT 100(51-60)

    142. 环形链表 II 思路:快慢指针,快慢指针相遇后,慢指针回到头,快慢指针步伐一致一起移动,相遇点即为入环点 /** * Definition for singly-linked list. * ...

  5. 🔥 LeetCode 热题 HOT 100(21-30)

    46. 全排列 思路:典型回溯法 class Solution { public List<List<Integer>> permute(int[] nums) { Linke ...

  6. 🔥 LeetCode 热题 HOT 100(11-20)

    20. 有效的括号 class Solution { public boolean isValid(String s) { Map<Character, Character> map = ...

  7. 🔥 LeetCode 热题 HOT 100(61-70)

    207. 课程表 思路:根据题意可知:当课程之间不存在 环状 循环依赖时,便能完成所有课程的学习,反之则不能.因此可以将问题转换成: 判断有向图中是否存在环.使用 拓扑排序法 : 构建 入度表:记录每 ...

  8. 🔥 LeetCode 热题 HOT 100(41-50)

    102. 二叉树的层序遍历 思路:使用队列. /** * Definition for a binary tree node. * public class TreeNode { * int val; ...

  9. 🔥 LeetCode 热题 HOT 100(1-10)

    1. 两数之和 思路一:暴力遍历所有组合 class Solution { public int[] twoSum(int[] nums, int target) { for (int i = 0; ...

随机推荐

  1. 「10.12」木板(数学)·打扫卫生(神仙DP)

    A. 木板 一个很简单的数学题,简单推一下就好,路丽姐姐教你学数学. 将式子化出我们发现只需求出$i\times i/n$的个数 那么我们将$n$质因数分解,可知因子个数 为了整除$n$,令$i==\ ...

  2. LCD1602液晶显示模块的单片机驱动深入详解之软件篇(AVR)

    LCD1602液晶显示模块的驱动虽然比七段数码管之类的显示要复杂一些,但实际上也并不是很难,最主要的还是初始化,为什么这么说呢?我们在调试一块新液晶屏的时候,都会先初始化看看有没有光标在闪,没有光标前 ...

  3. ceph-csi源码分析(7)-rbd driver-IdentityServer分析

    更多 ceph-csi 其他源码分析,请查看下面这篇博文:kubernetes ceph-csi分析目录导航 ceph-csi源码分析(7)-rbd driver-IdentityServer分析 当 ...

  4. Unity 异步加载 进度条

    当我们进行游戏开发时,时常会进行场景切换,如果下个场景较大,切换时就会出现卡顿现象,甚至看起来像是"死机",非常影响用户体验,我们这时就可以运用异步加载,在界面上显示加载的进度条以 ...

  5. 学会这些CSS技巧让你写样式更加丝滑

    目录 1,前言 1,calc() 2,min() 3,max() 4,clamp() 5,gap 6,writing-mode 1,前言 记录一些很好用的css属性 1,calc() calc()函数 ...

  6. CentOS-Docker搭建Kafka(单点,含:zookeeper、kafka-manager)

    Docker搭建Kafka(单点,含:zookeeper.kafka-manager) 下载相关容器 $ docker pull wurstmeister/zookeeper $ docker pul ...

  7. 暑假自学java第六天

    1,方法的覆盖:当子类继承父类,而子类中的方法与父类中方法的名称,返回类型及参数都完全一致时,就称子类中的方法覆盖了父类中的方法,有时也称方法的"重写" [不需要关键字] 2,th ...

  8. Python日志模块的管理(二)

    日志模块可以通过封装一个类,也可以通过配置文件取管理 新建1个log.ini文件 [loggers] keys=root [handlers] keys=fileHandler,streamHandl ...

  9. Activiti7 与 Spring Boot 及 Spring Security 整合 踩坑记录

    1.  前言 实话实说,网上关于Activiti的教程千篇一律,有参考价值的不多.很多都是老早以前写的,基本都是直接照搬官方提供的示例,要么就是用单元测试跑一下,要么排除Spring Security ...

  10. 二进制方式搭建Kubernetes集群

    环境准备: 演练暂时用单节点一台master和一台node节点来进行部署搭建(kubernetes 1.19版本) 角色 IP 组件 master 10.129.246.114 kube-apiser ...