刷题日记
记录愉快的刷题时光
Yungang_Young
这个作者很懒,什么都没留下…
展开
-
力扣102_二叉树的层次遍历
题目描述:给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。算法思想:看到层次遍历,立马想到了队列,想到了层次遍历框架void bfs(TreeNode root) { LinkedList<TreeNode> queue = new LinkedList<>(); queue.add(root); while (!queue.isEmpty()) { TreeNode p= queue.re原创 2021-06-21 18:46:36 · 149 阅读 · 1 评论 -
力扣1373_二叉搜索子树的最大键值和
题目描述:给你一棵以 root 为根的 二叉树 ,请你返回 任意 二叉搜索子树的最大键值和。二叉搜索树的定义如下:任意节点的左子树中的键值都 小于 此节点的键值。任意节点的右子树中的键值都 大于 此节点的键值。任意节点的左子树和右子树都是二叉搜索树。示例:算法思想:首先,二叉树题目核心–明确当前节点要做什么!假如此时站在“1”这个节点,首先要判断它是不是一棵BST,如果它不是BST,直接就不用考虑计算键值和的事情了。怎么知道它是不是BST呢?先看它的两个孩子是不是BST,如果有原创 2021-06-15 14:41:43 · 232 阅读 · 2 评论 -
力扣95_不同的二叉搜索树II
题目描述:给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。算法思想:此题和力扣96题的思想一样,都可以运用穷举的方法快速解题,同样的,我们确定一个递归函数public List<TreeNode> buildBST(int lo, int hi){};递归函数buildBST实现构造区间[lo, hi]内所有符合定义的BST。我们从根节点开始,穷举所有根节点的可能,并且递归的得到左右子树的B原创 2021-06-04 15:12:04 · 193 阅读 · 3 评论 -
力扣96_不同的二叉搜索树
题目描述:给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。算法思想:该题属于穷举类型,也就是找到所有符合BST的情况。假如n=3,首先从根节点出发,根节点有三种不同的可能,分别是1,2,3。我们现在以1为例,它的左边只有一种可能,那就是null,它的右边有两种可能,分别是2,null,3和3,2,null,我们把左右的可能性组合(相乘)在一起,就得到了1为根时有几个BST了。根为其他时计算方法也一样。在这里,左原创 2021-06-01 16:12:37 · 151 阅读 · 0 评论 -
力扣98_验证二叉搜索树
题目描述:给定一个二叉树,判断其是否是一个有效的二叉搜索树。示例:算法思想:一看,这道题似乎非常容易,提手就能写以下代码public boolean isValidBST(TreeNode root) { if(root == null) return true; if(root.left != null && root.left.val > root.val) return false; if(root.right != null && ro原创 2021-05-25 21:48:04 · 176 阅读 · 0 评论 -
力扣450_删除二叉搜索树中的节点
题目描述:给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。一般来说,删除节点可分为两个步骤:首先找到需要删除的节点;如果找到了,删除它。示例:算法思想:根据递归的思想,我们很容易写出如下代码TreeNode deleteNode(TreeNode root, int key) { if (root.val == key) { // 找到啦,进行删原创 2021-05-25 21:18:50 · 148 阅读 · 0 评论 -
力扣538_二叉搜索树转换为累加树*
题目描述:给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。算法思想:一拿到题目,我们先思考用二叉树的什么遍历方式,首先好像很容易看出,一个节点的累加值似乎等于它的右子树累加值加上它本身,但是仔细观察不然,比如5那个节点,它的累加值就是它的父节点加上它的本身,我们又没有父节点的指针,所以似乎不可行。二叉搜索树的特性不免让我们想到中序遍历,如果这棵树用中序遍历会从小原创 2021-05-20 20:07:00 · 143 阅读 · 0 评论 -
力扣230_二叉搜索树中第k小的元素
题目描述:给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。示例:算法思想:借助二叉搜索树得天独厚的优势–典型的中序遍历思想我们知道中序遍历可以从小到大的打印二叉搜索树traverse(root.left);print(root.val);traverse(root.right);借助这样的思想,我们可以用一个rank变量做排名,和打印一样,从小到大,当排到k时,返回输出即可。代码实现:class Soluti原创 2021-05-19 17:04:10 · 202 阅读 · 0 评论 -
力扣652_寻找重复的子树
题目描述:给定一棵二叉树,返回所有重复的子树。对于同一类的重复子树,你只需要返回其中任意一棵的根结点即可。两棵树重复是指它们具有相同的结构以及相同的结点值。需要以列表的形式返回上述重复子树的根结点。算法思想:所有的二叉树问题,都逃不过那三个遍历,首先思考我们的问题属于三者中的哪一种。首先,对于某一个节点,它应该做什么?假如我现在站在这个2节点上,想知道以自己为根的子树是不是重复的,该不该加入重复列表中。那么我要知道两个问题:以我为根的子树长啥样其他节点为根的子树长啥样怎么知道自原创 2021-05-18 23:12:17 · 203 阅读 · 3 评论 -
力扣105_从前序与中序遍历序列构造二叉树
题目描述:根据一棵树的前序遍历与中序遍历构造二叉树。(假设树中没有重复元素)例如,给出前序遍历 preorder = [3,9,20,15,7]中序遍历 inorder = [9,3,15,20,7]返回如下的二叉树:算法思想:前序遍历是“根左右”,中序遍历是“左根右”,我们先举例看一下内部关系m代表根节点,l代表根节点的左子树,r代表根节点的右子树。不难发现,根节点的左子树和根节点的右子树它们分别又是同样的处理流程,也就是说,可以使用同样的函数递归处理。先给出代码:public原创 2021-05-14 11:41:40 · 201 阅读 · 0 评论 -
力扣654_最大二叉树
题目描述:给定一个不含重复元素的整数数组 nums 。一个以此数组直接递归构建的 最大二叉树 定义如下:1.二叉树的根是数组 nums 中的最大元素。2.左子树是通过数组中 最大值左边部分 递归构造出的最大二叉树。3.右子树是通过数组中 最大值右边部分 递归构造出的最大二叉树。返回有给定数组 nums 构建的 最大二叉树 。示例:输入nums = [3,2,1,6,0,5] 返回如下图所示的树算法思想:题目已经明确给出了思路–运用递归,对于构造二叉树的问题,根节点要做的就是把想办法把自己构原创 2021-05-11 21:34:45 · 169 阅读 · 0 评论 -
力扣114_二叉树展开为链表
题目描述:给你二叉树的根结点 root ,请你将它展开为一个单链表:展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。展开后的单链表应该与二叉树 先序遍历 顺序相同。算法思想:这道题的函数是 void flatten(TreeNode root) ,我们尝试给出函数定义:给 flatten 函数输入一个节点 root,那么以 root 为根的二叉树就会被拉平为一条链表。具体流程如下:将 root 的左子树和右子树拉平原创 2021-05-07 20:00:00 · 195 阅读 · 0 评论 -
力扣116_填充每个节点的下一个右侧节点指针
题目描述:给定一个 完全二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:struct Node { int val; Node *left; Node *right; Node *next;}填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。初始状态下,所有 next 指针都被设置为 NULL。示例:算法思想:有了前面翻转二叉树的经验,这里我们很容易通过观察发现,可以原创 2021-04-27 17:53:07 · 203 阅读 · 0 评论 -
力扣226_翻转二叉树
题目描述:翻转一棵二叉树。示例:输入:输出:算法思想:一看到树的算法问题,就应该立马从树的遍历框架入手/* 二叉树遍历框架 */void traverse(TreeNode root) { // 前序遍历 traverse(root.left) // 中序遍历 traverse(root.right) // 后序遍历}我们需要先搞清楚当前 root 节点该做什么,然后根据函数定义递归(选择前序、中序还是后序)调用子节点。对于这道题,我们可以原创 2021-04-27 17:30:34 · 160 阅读 · 0 评论 -
力扣25_K个一组翻转链表
题目描述:给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。示例:算法思想:方法一:递归就按示例这样,对链表调用reverseKGroup(head, 2),即以2个节点为一组反转链表,假设前两个节点已经反转,如图所示后面的这些节点也是一条链表,而且规模(长度)比原来这条链表小,这就叫子问题。我们可以直接递归调用reverseKGroup(head, 2),原创 2021-04-19 23:03:28 · 229 阅读 · 0 评论 -
力扣234_回文链表
题目描述:请判断一个链表是否为回文链表。示例 1:输入: 1->2输出: false示例 2:输入: 1->2->2->1输出: true算法思想:方法一:双指针法我们知道,判断一个数组的回文是非常简单的,只需要一头一尾两个指针,边走边检查即可,但是链表怎么办呢?直接暴力,把链表存入数组,用数组的方法判断。class Solution { public boolean isPalindrome(ListNode head) { //辅助数组部原创 2021-04-22 14:58:26 · 184 阅读 · 0 评论 -
力扣92_反转链表II
题目描述:给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回反转后的链表 。示例:算法思想:在上一篇文章 反转链表I 中,我们学会了反转一个完整的链表,在做本题之前,先思考一个容易一点的问题,如何反转一个链表的前N个节点?如图所示:有没有发现与上一篇文章的区别,就在1这个节点上,上一篇文章是把这个节点指向了null,而这里是把1这个节点指向了4,也就是说,如果我们像上一篇原创 2021-04-09 14:24:43 · 160 阅读 · 0 评论 -
力扣503_下一个更大元素II
题目描述给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。示例:输入: [1,2,1]输出: [2,-1,2]解释: 第一个 1 的下一个更大的数是 2;数字 2 找不到下一个更大的数;第二个 1 的下一个最大的数需要循环搜索,结果也是 2。算法思想和力扣496类似,同样运用到单调栈,这道题的难点在原创 2021-03-29 21:48:37 · 117 阅读 · 0 评论 -
力扣496_下一个更大元素I
题目描述:给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。请你找出 nums1 中每个元素在 nums2 中的下一个比其大的值。输入: nums1 = [4,1,2], nums2 = [1,3,4,2].输出: [-1,3,-1]解释:对于 num1 中的数字 4 ,你无法在第二个数组中找到下一个更大的数字,因此输出 -1 。对于 num1 中的数字 1 ,第二个数组中数字1右边的下一个较大数字是 3 。对于 num1 中的数字 2 ,原创 2021-03-25 15:14:56 · 170 阅读 · 0 评论 -
力扣682_棒球比赛
题目描述:你现在是一场采用特殊赛制棒球比赛的记录员。这场比赛由若干回合组成,过去几回合的得分可能会影响以后几回合的得分。比赛开始时,记录是空白的。你会得到一个记录操作的字符串列表 ops,其中 ops[i] 是你需要记录的第 i 项操作,ops 遵循下述规则:整数 x - 表示本回合新获得分数 x“+” - 表示本回合新获得的得分是前两次得分的总和。题目数据保证记录此操作时前面总是存在两个有效的分数。“D” - 表示本回合新获得的得分是前一次得分的两倍。题目数据保证记录此操作时前面总是存在一个有效原创 2021-03-24 15:28:55 · 173 阅读 · 0 评论 -
力扣844_比较含退格的字符串
题目描述:给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果。 # 代表退格字符。注意:如果对空文本输入退格字符,文本继续为空。算法思想:本文采用暴力解决法,分别使用两个栈,用进栈出栈来模拟退格操作,最后栈内的值就是要比较的最终值,注意空文本的处理,若遇到空文本出栈,则直接不做任何操作代码如下:class Solution { public boolean backspaceCompare(String S, String T) {原创 2021-03-22 23:38:00 · 113 阅读 · 0 评论 -
力扣232_用栈实现队列
题目描述:请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):实现 MyQueue 类:void push(int x) 将元素 x 推到队列的末尾int pop() 从队列的开头移除并返回元素int peek() 返回队列开头的元素boolean empty() 如果队列为空,返回 true ;否则,返回 false算法思想:一个栈作为输入栈,用于push数据,一个栈作为输出栈,用于pop和peek数据,当有数据要入队时,全部pu原创 2021-03-17 10:40:44 · 203 阅读 · 0 评论 -
力扣155_最小栈
题目描述:设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。push(x) —— 将元素 x 推入栈中。pop() —— 删除栈顶的元素。top() —— 获取栈顶元素。getMin() —— 检索栈中的最小元素。算法思想:要想在常数时间内检索到最小元素,我们可以设置一个辅助栈,栈顶记录了当前栈中的最小值,辅助栈与主栈同进出,这样的话,就保证了对栈顶元素即最小值的更新代码如下:class MinStack { Deque<Integer&原创 2021-03-16 11:43:10 · 186 阅读 · 0 评论 -
力扣20_有效的括号
题目描述:给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。有效字符串需满足:左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。算法思想:很容易想到使用栈这种数据结构,遇到左括号就入栈,遇到右括号就与栈顶元素进行比对。书写过程中会遇到以下问题:(1)如何知道匹配成功?(2)栈空了怎么办?如{[]}),到‘)’时就会出现栈空报错解决方案:(1)使用一个哈希表来做匹配(2)预先压入’?'防止栈空代码如下:class Sol原创 2021-03-15 17:02:28 · 132 阅读 · 0 评论 -
力扣876_链表的中间结点
题目描述:给定一个头结点为 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点注:这里的头结点就是第一个结点解题思路:本来打算用栈,先把所有结点压入栈中,并记录有多少个结点,然后依次出栈,出一半的结点就能找到中间结点,但是超出了时间限制其实,用快慢指针能做到O(1)空间复杂度的前提下完美达到O(n)的时间复杂度快指针fast一次走两个结点,慢指针slow一次走一个结点,待快指针走到结尾时,慢指针刚好走到中间结点代码如下:class Solution {原创 2021-03-12 12:09:45 · 174 阅读 · 0 评论 -
力扣19_删除链表的倒数第N个结点
题目描述:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。(使用一趟扫描实现)算法思想:使用双指针p,q,q指针比p指针快n个结点,当q指针指向末尾null时,p指针刚好指在待删除的结点n上,不过,要删除此结点,还需要借助它的前驱结点,故引入虚拟结点,令它指向头结点,p结点从虚拟结点开始,如下图所示(n=2)初始状态时:终止状态:代码实现:class Solution { public ListNode removeNthFromEnd(ListNode head,原创 2021-03-11 17:47:51 · 125 阅读 · 0 评论 -
力扣_21 合并两个有序链表
题目描述:将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。思路:创建一个中间点l,分别遍历两个链表,依次把值小的加入中间点后面,注意指针pre指向的是刚插入的结点,每次都得往下一个结点走代码如下:class Solution { public ListNode mergeTwoLists(ListNode l1, ListNode l2) { ListNode l = new ListNode(); ListNode原创 2021-03-10 11:59:37 · 129 阅读 · 0 评论 -
力扣141_环形链表
判断链表是否有环运用快慢指针,类似于“龟兔”,假设表中有环,那么速度快的“兔子”则首先进入环,然后在里面绕圈,“乌龟”后入环,它们都在一个环内绕圈,由于速度不等,则一定会相遇。public boolean hasCycle(ListNode head) { if (head == null || head.next == null) return false; ListNode slow = head; ListNode fast = head.next;原创 2021-01-18 23:04:34 · 176 阅读 · 0 评论 -
力扣206_反转链表
反转链表描述:反转一个单链表。输入: 1->2->3->4->5->NULL输出: 5->4->3->2->1->NULL本文采用迭代的方法反转链表基本思想:在遍历时,将当前结点的next指向前一个结点出现的问题:由于链表的单向,不知道前一个结点的地址若改变当前结点的next值,后续结点的地址丢失解决办法:用prev、cur指针分别指向前驱和当前结点将后继结点的地址存储在nextTemp当中流程如下图所示(仅列出三原创 2021-01-14 13:53:44 · 196 阅读 · 0 评论