LeetCode 热题 HOT 100(P31~P40)

 系列文章: 

LeetCode 热题 HOT 100(P1~P10)-CSDN博客

LeetCode 热题 HOT 100(P11~P20)-CSDN博客

LeetCode 热题 HOT 100(P21~P30)-CSDN博客

LeetCode 热题 HOT 100(P31~P40)-CSDN博客

LC76minimum_window

. - 力扣(LeetCode)

题目:

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。

解法:

滑动窗口的思路,右游标可以探查到能满足条件的位置,关键的是左游标怎么确定合适的位置,因为左游标前面可能刚好是不在t中的字母。这个是第一个难点,这里通过维护一个缓存来表示字母的消耗情况,然后左游标就可以根据当前所在字母是否被过量使用判断。还有就是确定好了第一个滑动窗口left、right 之后怎么进入下一个滑动窗口的判断。这个时候left 游标要往前移动一位,同时字母消耗的缓存需要相应的处理,然后就可以继续往前滚动。

public String minWindow(String s, String t) {// 这里根据题目给出的限定条件,只有英文字母,所以可以使用128位asc 来表示int[] cache = new int[128];int cnt = t.length();for (int i = 0; i < t.length(); i++) {cache[t.charAt(i)]++;}int begin = 0, min = 0;for (int left = 0, right = 0; right < s.length(); right++) {if (cache[s.charAt(right)] > 0) {cnt--;}// 这里无差别-1,这样如果是负数就说明是t之外多余的cache[s.charAt(right)]--;if (cnt == 0) { //说明包含twhile (cache[s.charAt(left)] < 0) { // left指针尽可能往右走cache[s.charAt(left)]++;left++;}final int len = right - left + 1;if (min == 0 || len < min) {min = len;begin = left;}//left 指针继续往前走,这个时候就破坏原来符合的情况了cache[s.charAt(left)]++;cnt++;left++;}}return s.substring(begin, begin + min);}

根据上面的思路结合代码就比较好理解了,这里缓存用int 数组表示,我发现很多时候数组比map 操作起来方便太多,这里先通过t 进行int 数组的初始化,然后在迭代过程中直接对下标-1,这样就能方便左游标是否可以往前移动。

这里还有个小技巧就是用cnt 来辅助判断是否满足条件,这样就不用轮询数组来判断。

LC78subsets

. - 力扣(LeetCode)

题目:

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的
子集(幂集)。解集 不能包含重复的子集。你可以按 任意顺序 返回解集。

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

解法:

这类题目一闻就是递归的味道,基本套递归模板就可以了,这里要注意的是不要走回头路。

List<List<Integer>> result = new ArrayList<>();public List<List<Integer>> subsets(int[] nums) {dfs(nums, new ArrayList<>(), 0);return result;}private void dfs(int[] nums, List<Integer> path, int level) {result.add(new ArrayList<>(path));for (int i = level; i < nums.length; i++) {path.add(nums[i]);dfs(nums, path, i + 1);path.remove(path.size() - 1);}}

在上面就是通过level 控制,注意在for 循环中下一次递归的时候不是level+1 而是i+1,需要注意体会里面的区别。

LC79word_search

. - 力扣(LeetCode)

题目:

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true

解法:

基本也是递归的思路,首选肯定能通过循环判断word 第一个字母是否匹配,这样才有继续的基础,接下来就是往上下左右遍历可能的情况,这里的难点是怎么不走回头路,主要有2种思路:

  1. 使用一个额外的缓存来标识已经走过的路。
  2. 直接在原数组中用一个特殊字符覆盖已经走过的路径,这样肯定不会走回头路,因为字符肯定不匹配。

从代码整洁性来说第二种方式更优,这里的难点是递归完下一层之后要对之前造成的影响进行复原,这个不论选择哪种方式都一样。

public boolean exist(char[][] board, String word) {final int m = board.length, n = board[0].length;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (dfs(board, i, j, word, 0)) {return true;}}}return false;}private boolean dfs(char[][] board, int i, int j, String word, int index) {if (index == word.length()) {return true;}if (i < 0 || i == board.length || j < 0 || j == board[0].length || word.charAt(index) != board[i][j]) {return false;}// 占掉一个位置,避免走回头路board[i][j] = '#';boolean result = dfs(board, i - 1, j, word, index + 1) || dfs(board, i, j - 1, word, index + 1) ||dfs(board, i + 1, j, word, index + 1) || dfs(board, i, j + 1, word, index + 1);board[i][j] = word.charAt(index);return result;}

LC84largest_rectangle

. - 力扣(LeetCode)

题目:

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

解法:

一般这类n根柱子、n个容器求最大面积的问题基本是用单调递增栈来解决。但是常规的单调递增栈需要解决刚开始栈中没元素的情况,以及最后栈中还遗留元素的情况。这样代码写起来就非常冗长,而且容易出错。

这里就涉及一个单调栈的优化技巧,通过左右哨兵的加入,就可以避免处理这些异常情况。

 public int largestRectangleArea(int[] heights) {//维护一个单调递增栈Deque<Integer> stack = new ArrayDeque<>();stack.push(-1); //放入左哨兵,能保证他始终在栈里面int max = 0;for (int i = 0; i <= heights.length; i++) { // 这里使用heights.length 作为右哨兵while (getH(heights, i) < getH(heights, stack.peek())) {final Integer pre = stack.pop();int area = (i - stack.peek() - 1) * getH(heights, pre);max = Math.max(max, area);}stack.push(i);}return max;}private int getH(int[] heights, int index) {if (index == -1 || index == heights.length) {return -1;}return heights[index];}

这里通过左哨兵-1,保证了栈中肯定有值,而且下标0 的元素加入的时候天然满足递增条件。然后右哨兵-1 能保证把栈中所有元素都倒逼出来,这样就不用处理栈中还留有元素的情况。

LC94binary_tree

. - 力扣(LeetCode)

题目:

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

解法:

如果用递归的方法是很简单的,思路也很清晰。通过代码能直观感受

 public List<Integer> inorderTraversalRecur(TreeNode root) {List<Integer> result = new ArrayList<>();if (root == null) {return result;}result.addAll(inorderTraversalRecur(root.left));result.add(root.val);result.addAll(inorderTraversalRecur(root.right));return result;}

如果不能使用递归,或者想要挑战下自己,那这道题的难度就上升了一个等级。核心是遍历的时候必然会用到栈,但是怎么判断当前节点是之前已经迭代过可以直接输出,还是需要迭代子节点。这里有2种解法:

第一种:颜色标记法,就是在node 中增加颜色属性,用于标识当前是否可以直接输出

public List<Integer> inorderTraversalColor(TreeNode root) {List<Integer> result = new ArrayList<>();if (root == null) {return result;}Deque<ColorNode> stack = new ArrayDeque<>();stack.push(new ColorNode(0, root));while (!stack.isEmpty()) {final ColorNode cnode = stack.pop();TreeNode node = cnode.node;if (node == null) {continue;}if (cnode.color == 0) {//需要注意这里的顺序,因为是栈所以要先放最后轮询的节点stack.push(new ColorNode(0, node.right));stack.push(new ColorNode(1, node));stack.push(new ColorNode(0, node.left));} else {result.add(node.val);}}return result;}static class ColorNode {/*** 表示是否应该输出,0,表示未遍历子树,1表示输出当前值*/int color;TreeNode node;public ColorNode(int color, TreeNode node) {this.color = color;this.node = node;}}

可以发现,通过增加一个颜色字段之后这里用0、1 表示是否需要迭代子节点,整体代码逻辑就很顺,比较符合我们的逻辑。

还有一种是纯用栈的方式,这样就需要维护一个cur 指针,同时判断cur 和栈的情况,在cur 不为空的时候不断往左树迭代同时入栈,如果cur 为空就出栈,并把cur 指向右节点。

 public List<Integer> inorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();Deque<TreeNode> stack = new ArrayDeque<>();TreeNode cur = root;while (cur != null || !stack.isEmpty()) {if (cur != null) {//不断往左子树迭代,并将当前节点保存到栈中stack.push(cur);cur = cur.left;} else { //左子树走到底,进行出栈并记录final TreeNode node = stack.pop();result.add(node.val);// 如果有右节点继续上面的过程cur = node.right;}}return result;}

代码虽然比上一种简洁,但是理解难度高了不少,如果吃透这种写法,基本也能玩得转二叉树类型的题目了。

LC96unique_binary

. - 力扣(LeetCode)

题目:

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

输入:n = 3
输出:5

解法:

看着像二叉树类型的题目,实际是动态规划的思路,核心就是动态数组的定义和动态方程的推导:

i 表示以第i个节点(从1开始)为根节点的子树,左子树个数为i,右子树个数为n-i-1
f(i) 表示i为根节点时组合个数,G(i) 表示i个节点存在的组合
G(n)=f(1)+f(2)+...+f(n)
f(i)=G(i−1)∗G(n−i)
G(n) = G(0)*G(n-1) + G(1)*G(n-2)+...+G(n-1)*G(0)
dp[n] 表示n 个节点的组合数

尝试自己推导一遍,还是能理解的,代码写出来其实很简单

 public int numTrees(int n) {if (n < 2) {return 1;}int[] dp = new int[n + 1];dp[0] = 1;dp[1] = 1;for (int i = 2; i <= n; i++) {//以第j个为 根节点时对应的组合数for (int j = 1; j <= i; j++) {dp[i] += dp[j - 1] * dp[i - j];}}return dp[n];}

但是不理解上面的推导过程,确实是看不懂。

LC98validate_binary

. - 力扣(LeetCode)

题目:

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左

    子树

    只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

解法:

刚一开始,就想到了用递归的方法来解决这个问题,先判断当前节点是否合法(左值<当前值<右值),递归判断左节点,最后递归右节点。结果啪啪打脸,这里存在一个问题是这样的判断不严谨,可能左子树其中一个叶子节点满足直属父节点和兄弟节点的关系,但是并不满足跟祖父节点的约束。

因此这里需要基于中序遍历是递增关系这条更严格的约束条件。

 Integer preVal;public boolean isValidBST(TreeNode root) {if (root == null) {return true;}if (!isValidBST(root.left)) {return false;}if (preVal != null && root.val <= preVal) {return false;}preVal = root.val;return isValidBST(root.right);}

注意这里使用了包装类型Integer,方便处理第一次赋值的特殊情况。

LC101symmetric_tree

. - 力扣(LeetCode)

题目:

给你一个二叉树的根节点 root , 检查它是否轴对称。

解法:

这类一想就有很多子情况需要判断的题目,基本要么递归要么动态规划。或者说他俩基本是一回事。

实际就是判断左节点跟右节点是否对称

 public boolean isSymmetric(TreeNode root) {if (root == null) {return true;}return dfs(root.left, root.right);}private boolean dfs(TreeNode left, TreeNode right) {if (left == null && right == null) {return true;}// 到这里说明left和right 不会同时为null,那么其中有一个null 就说明不对称if (left == null || right == null) {return false;}if (left.val != right.val) {return false;}return dfs(left.left, right.right) && dfs(left.right, right.left);}

可以看到复杂的地方是对边界情况的处理,是否都为null啊,或者其中一个为null,当都不为null 的时候判断是否相等。然后最后再递归,注意这里left.left 对应right.right,这个看下轴对称示意图就很好理解了。

LC102binary_tree

. - 力扣(LeetCode)

题目:

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]

解法:

首先想到的是通过队列进行广度遍历,但是第二个问题是怎么知道当前是那一层,因为需要按层输出。这里有个小技巧就是在遍历队列的时候,直接判断当前队列的长度,这个就是当前层的节点数。

 public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> result = new ArrayList<>();if (root == null) {return result;}Queue<TreeNode> queue = new ArrayDeque<>();queue.add(root);while (!queue.isEmpty()) {final int size = queue.size();List<Integer> levelResult = new ArrayList<>();for (int i = 0; i < size; i++) {final TreeNode node = queue.poll();levelResult.add(node.val);if (node.left != null) {queue.offer(node.left);}if (node.right != null) {queue.offer(node.right);}}result.add(levelResult);}return result;}

行数虽多,但是很多是对边界情况的处理,整体还是很好理解的。

LC104maximum_depth

. - 力扣(LeetCode)

题目:

给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

输入:root = [3,9,20,null,null,15,7]
输出:3

题解:

这个也是递归的思路,从左子树、右子树中选择最深的节点数+1 就是当前的最大深度。

 public int maxDepth(TreeNode root) {if (root == null) {return 0;}return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;}

代码非常简单,只能说递归真是非常强大。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/815352.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自动化测试-web(PO:Page Object 模式)

一、PO模式 PO&#xff1a;Page Object&#xff08;页面对象&#xff09;&#xff0c;将自动化涉及的页面或模块封装成对象。 PO能解决什么问题&#xff1f; 代码复用性便于维护&#xff08;脚本层与业务分离&#xff09;--如果元素信息发生变化了&#xff0c;也不用去修改脚…

leetcode经典困难题-接雨水

. - 力扣&#xff08;LeetCode&#xff09; 42. 接雨水 困难 相关标签 相关企业 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,…

c++的学习之路:22、多态(1)

摘要 本章主要是说一些多态的开头。 目录 摘要 一、多态的概念 二、多态的定义及实现 2.1、多态的构成条件 2.2、虚函数 2.3、虚函数的重写 2.4、C11 override 和 final 2.5、重载、覆盖(重写)、隐藏(重定义)的对比 三、思维导图 一、多态的概念 多态的概念&#…

HCIP实验:MGRE、星型拓扑

一、实验要求 1&#xff0c;R6为ISP只能配置IP地址&#xff0c;R1-R5的环回为私有网段 2&#xff0c;R1/4/5为全连的MGRE结构&#xff0c;R1/2/3为星型的拓扑结构&#xff0c;R1为中心站点 3&#xff0c;所有私有网段可以互相通讯&#xff0c;私有网段使用OSPF完成。 二、实验…

数字乡村创新实践探索农业现代化与农村治理现代化新路径:科技赋能农村全面振兴与农民幸福生活

目录 引言 一、数字乡村与农业现代化 1、智慧农业技术的应用 2、农业产业链的数字化转型 二、数字乡村与农村治理现代化 1、农村信息化水平的提升 2、农村治理模式的创新 三、科技赋能农村全面振兴与农民幸福生活 1、提升农业生产效益与农民收入 2、促进农村产业结构…

SpringCloud系列(2)--SpringCloud和SpringBoot技术选型

前言&#xff1a;SpringCloud是微服务架构的一揽子解决方案&#xff0c;SpringBoot是一种技术&#xff0c;要使用SpringCloud&#xff0c;也需要使用到SpringBoot&#xff0c;所以要使用SpringCloud时&#xff0c;必须也要考虑到SpringBoot的适配问题 1、查看SpringCloud和与之…

学生管理系统控制台版(java)

首先得先写个Student类&#xff0c;用来存放学生信息 public class Student {private String id;private String name;private int age;private String address;public Student() {}public Student(String id, String name, int age, String address) {this.id id;this.name…

C++面向对象程序设计-北京大学-郭炜【课程笔记(六)】

C面向对象程序设计-北京大学-郭炜【课程笔记&#xff08;六&#xff09;】 1、可变长数组类的实现2、流插入运算符和流提取运算符的重载2.1、对形如cout << 5 ; 单个"<<"进行重载2.2、对形如cout << 5 << “this” ;连续多个"<<&…

蓝桥杯-最大子矩阵

问题描述 下面是一个 20x20 的矩阵&#xff0c;矩阵中的每个数字是一个1到9之间的数字&#xff0c;请注意显示时去除了分隔符号。 6985924183938786894117615876963131759284373473483266274834855367125655616786474316121686927432329479135474133499627734472797994592984…

⑤-1 学习PID--什么是PID

​ PID 算法可以用于温度控制、水位控制、飞行姿态控制等领域。后面我们通过PID 控制电机进行说明。 自动控制系统 在直流有刷电机的基础驱动中&#xff0c;如果电机负载不变&#xff0c;我们只要设置固定的占空比&#xff08;电压&#xff09;&#xff0c;电机的速度就会稳定在…

ceph rbd部署与使用

一、前言 Ceph RBD&#xff08;Rados Block Device&#xff09;是 Ceph 存储解决方案的一部分&#xff0c;它提供了一个分布式块设备服务&#xff0c;允许用户创建和管理虚拟块设备&#xff0c;类似于传统的本地磁盘&#xff0c;Ceph RBD 是一个高度可扩展的存储解决方案&#…

C语言:关于动态内存管理我到底应该懂些什么?看了我这篇你就通透了。

1.动态内存的分配 在我们初学C语言的时候&#xff0c;我们经常用一下几种方式申请内存空间。 int a 10;//在栈空间上开辟4个字节存放这个值。 char arr[10] {1,2,3,4,5,6,7,8,9,10};//在栈空间上开辟10个字节的连续空间。但是上述开辟空间有两个特点 1.空间开辟大小是固定的…

FJSP:袋鼠群优化(Kangaroo Swarm Optimization ,KSO)算法求解柔性作业车间调度问题(FJSP),提供MATLAB代码

一、柔性作业车间调度问题 柔性作业车间调度问题&#xff08;Flexible Job Shop Scheduling Problem&#xff0c;FJSP&#xff09;&#xff0c;是一种经典的组合优化问题。在FJSP问题中&#xff0c;有多个作业需要在多个机器上进行加工&#xff0c;每个作业由一系列工序组成&a…

微服务之Consul 注册中心介绍以及搭建

一、微服务概述 1.1单体架构 单体架构&#xff08;monolithic structure&#xff09;&#xff1a;顾名思义&#xff0c;整个项目中所有功能模块都在一个工程中开发&#xff1b;项目部署时需要对所有模块一起编译、打包&#xff1b;项目的架构设计、开发模式都非常简单。 当项…

C++ | Leetcode C++题解之第22题括号生成

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<string> res; //记录答案 vector<string> generateParenthesis(int n) {dfs(n , 0 , 0, "");return res;}void dfs(int n ,int lc, int rc ,string str){if( lc n && rc n…

美团笔试复盘

昨天做了美团的笔试&#xff0c;现在复盘一下。 1、将数组按照绝对值大小排序 有道算法题解决思路需要将数组按照绝对值大小进行排序&#xff0c;我使用的是sort方法Comparator比较器实现的&#xff0c;这里记录一下&#xff1a; public static void main(String[] args) {In…

第二证券策略:股指预计维持震荡格局 关注汽车、工程机械等板块

第二证券指出&#xff0c;指数自今年2月份阶段低点反弹以来&#xff0c;3月份持续高位整理。进入4月份之后面对年报和一季报的双重财报发表期&#xff0c;预计指数短期保持高位整理概率比较大。前期缺乏成绩支撑的概念股或有回落的危险&#xff0c;主张重视成绩稳定、估值低、分…

【Leetcode】1702. 修改后的最大二进制字符串

文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接&#x1f517; 给你一个二进制字符串 b i n a r y binary binary &#xff0c;它仅有 0 0 0 或者 1 1 1 组成。你可以使用下面的操作任意次对它进行修改&#xff1a; 操作 1 &#xff1a;如果…

Golang(一):基础、数组、map、struct

目录 hello world 变量 常量&#xff0c;iota 函数 init函数和导包过程 指针 defer 数组和动态数组 固定长度数组 遍历数组 动态数组 len 和 cap 截取 切片的追加 map 四种声明方式 遍历map 删除 查看键是否存在 结构体 声明 作为形参 方法 封装 继承…

[入门到放弃]设计模式-笔记

模块化设计 20240448 模块不包含数据&#xff0c;通过实例的指针&#xff0c;实现对实例的操作&#xff1b;唯一包含的数据是用于管理这些模块的侵入式链表模块只负责更具定义的数据结构&#xff0c;执行对应的逻辑&#xff0c;实现不同实例的功能&#xff1b; 参考资料 使用…