- 博客(38)
- 收藏
- 关注
原创 不同的二叉搜索树 背包问题理论基础
首先从dp[i][j]的定义出发,如果背包容量j为0的话,即dp[i][0],无论是选取哪些物品,背包价值总和一定为0。如图:在看其他情况。状态转移方程。
2025-04-02 21:21:29
735
原创 不同路径 不同路径|| 整数拆分
从递归公式dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 中可以看出,一定是从左到右一层一层遍历,这样保证推导dp[i][j]的时候,dp[i - 1][j] 和 dp[i][j - 1]一定是有数值。下标(0, j)的初始化情况同理。那么很自然,dp[i][j] = dp[i - 1][j] + dp[i][j - 1],因为dp[i][j]只有这两个方向过来。这样就可以保证推导dp[i][j]的时候,dp[i - 1][j] 和 dp[i][j - 1]一定是有数值的。
2025-04-01 21:38:53
1167
原创 单调自增的数字 斐波那契数列 爬楼梯
例如:98,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]--,然后strNum[i]给为9,这样这个整数就是89,即小于98的最大的单调递增整数。从前向后遍历的话,遇到strNum[i - 1] > strNum[i]的情况,让strNum[i - 1]减一,但此时如果strNum[i - 1]减一了,可能又小于strNum[i - 2]。从递推公式dp[i] = dp[i - 1] + dp[i - 2];
2025-03-31 16:45:01
1177
原创 无重叠区间 划分字母区间 合并区间
就是取 区间1 和 区间2 右边界的最小值,因为这个最小值之前的部分一定是 区间1 和区间2 的重合部分,如果这个最小值也触达到区间3,那么说明 区间 1,2,3都是重合的。先排序,让所有的相邻区间尽可能的重叠在一起,按左边界,或者右边界排序都可以,处理逻辑稍有不同。其实就是用合并区间后左边界和右边界,作为一个新的区间,加入到result数组里就可以了。1.给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。移除区间的最小数量就是3。区间,1,2,3,4,5,6都按照右边界排好序。
2025-03-30 21:25:28
828
原创 柠檬水找零 用最少数量的箭引爆气球
如果真实的模拟射气球的过程,应该射一个,气球数组就remove一个元素,这样最直观,毕竟气球被射了。如果把气球排序之后,从前到后遍历气球,被射过的气球仅仅跳过就行了,没有必要让气球数组remove气球,只要记录一下箭的数量就可以了。可以看出首先第一组重叠气球,一定是需要一个箭,气球3,的左边界大于了 第一组重叠气球的最小右边界,所以再需要一支箭来射气球3了。按照身高排序之后,优先按身高高的people的k来插入,后序插入节点也不会影响前面已经插入的节点,最终按照k的规则完成了队列。
2025-03-29 21:01:39
889
原创 加油站 分发糖果
如果 num[i] > num[i + 1],此时candy[i](第i个小孩的糖果数量)就有两个选择了,一个是candy[i + 1] + 1(从右边这个加1得到的糖果数量),一个是candy[i](之前比较右孩子大于左孩子得到的糖果数量)。如果num[i] > num[i - 1] 那么[i]的糖 一定要比[i - 1]的糖多一个,所以贪心:candy[i] = candy[i - 1] + 1。那么为什么一旦[0,i] 区间和为负数,起始位置就可以是i+1呢,i+1后面就不会出现更大的负数?
2025-03-29 17:10:48
1183
原创 跳跃游戏|| k次取反后最大化的数组和
那么如果将负数都转变为正数了,K依然大于0,此时的问题是一个有序正整数序列,如何转变K次正负,让 数组和 达到最大,那么又是一个贪心:局部最优:只找数值最小的正整数进行反转,当前数值和可以达到最大(例如正整数数组{5, 3, 1},反转1 得到-1 比 反转5得到的-5 大多了),全局最优:整个 数组和 达到最大。思路:贪心的思路,局部最优:当前可移动距离尽可能多走,如果还没到终点,步数再加一。贪心的思路,局部最优:让绝对值大的负数变为正数,当前数值达到最大,整体最优:整个数组和达到最大。
2025-03-27 21:06:47
853
原创 最大子序和 买股票的最佳时机|| 跳跃游戏
遍历 nums,从头开始用 count 累积,如果 count 一旦加上 nums[i]变为负数,那么就应该从 nums[i+1]开始从 0 累积 count 了,因为已经变为负数的 count,只会拖累总和。思路:对于这道题,给了我们一个数组让我们求连续子序列和最大值,我们先来找贪心的地方,如果 -2 1 在一起,计算起点的时候,一定是从 1 开始计算,因为负数只会拉低总和,这就是贪心贪的地方!1.给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
2025-03-27 20:00:30
1183
原创 全排列|| 分发饼干 摆动序列
图中,我们可以看出,按照先前思路会在三个地方记录峰值,但其实结果因为是 2,因为 单调中的平坡 不能算峰值(即摆动)。例如, [1,7,4,9,2,5] 是一个摆动序列,因为差值 (6,-3,5,-7,3) 是正负交替出现的。相反, [1,4,7,2,5] 和 [1,7,4,5,5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
2025-03-25 21:02:11
813
原创 子集|| 递增子序列 全排列
可以看出元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次1,所以处理排列问题就不用使用startIndex了。输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]输出: [ [2], [1], [1,2,2], [2,2], [1,2], [] ]
2025-03-24 17:07:14
923
原创 分割回文串 复原IP地址 子集
在处理组合问题的时候,递归参数需要传入startIndex,表示下一轮递归遍历的起始位置,这个startIndex就是切割线。示例: 输入: nums = [1,2,3] 输出: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]可以使用双指针法,一个指针从前向后,一个指针从后向前,如果前后指针所指向的元素是相等的,就是回文字符串了。其实子集也是一种组合问题,因为它的集合是无序的,子集{1,2} 和 子集{2,1}是一样的。
2025-03-23 21:36:58
1299
原创 组合总和||
可能有的人想,为什么 used[i - 1] == false 就是同一树层呢,因为同一树层,used[i - 1] == false 才能表示,当前取的 candidates[i] 是从 candidates[i - 1] 回溯而来的。used[i - 1] == false,说明同一树层candidates[i - 1]使用过。used[i - 1] == true,说明同一树枝candidates[i - 1]使用过。candidates 中的每个数字在每个组合中只能使用一次。
2025-03-22 19:00:00
1552
原创 组合总和
剪枝操作:对于sum已经大于target的情况,其实是依然进入了下一层递归,只是下一层递归结束判断的时候,会判断sum > target的话就返回。其实如果已经知道下一层的sum会大于target,就没有必要进入下一层递归了。sum变量来统计单一结果path里的总和,从叶子节点可以清晰看到,终止只有两种情况,sum大于target和sum等于target。注意图中叶子节点的返回条件,因为本题没有组合数量要求,仅仅是总和的限制,所以递归没有层数的限制,只要选取的元素总和超过target,就返回!
2025-03-21 21:44:43
568
原创 组合总数||| 电话号码的字母组合
确定的终止条件,例如输入用例"23",两个数字,那么根节点往下递归两层就可以了,叶子节点就是要收集的结果集。之后确定单层遍历逻辑,首先要取index指向的数字,并找到对应的字符集(手机键盘的字符集)。如果此时path里收集到的元素和(sum) 和targetSum(就是题目描述的n)相同了,就用result收集当前的结果。另外这里也用到了剪枝操作,为的是防止2种不必要的情况,1.当startindex指向的位置后面的数值量不足k个时 2.当Sum的值大于targetSum但数值量小于k时。
2025-03-20 21:29:54
1275
原创 组合问题 组合问题的剪枝操作
思路:我们所要优化的情况,来举一个例子,n = 4,k = 4的话,那么第一层for循环的时候,从元素2开始的遍历都没有意义了。第一次取1,集合变为2,3,4 ,因为k为2,我们只需要再取一个数就可以了,分别取2,3,4,得到集合[1,2] [1,3] [1,4],以此类推。示例: 输入: n = 4, k = 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]我们可以看出这棵树,一开始集合是 1,2,3,4, 从左向右取数,取过的数,不再重复取。
2025-03-19 21:03:40
1014
原创 修剪二叉搜索树 将有序数组转化为二叉搜索树 把二叉搜索树转换为累加树
之后我们来递归左子树,确定参数,左区间left,右区间mid-1(默认区间左闭右闭),相应地递归右子树时参数左区间mid+1,右区间right。思路:这道题就是将二叉搜索树中每个结点的值变为累加大于此结点的所有结点(包括累加本身),因此我们在开始时应该从该二叉树的最大值处进行累加,即右子树的最右侧结点,这里我们引入pre和cur指针,开始pre=0,cur指向最大值结点,然后递归遍历,顺序为右中左,每次遍历时我们进行cur->val+=pre,pre=cur->val操作,这样就实现了累加操作。
2025-03-18 20:00:05
610
原创 二叉搜索树的最近公共祖先 二叉搜索树中的插入操作 删除二叉搜索树中的结点
思路:对于删除二叉搜索树的结点,主要是针对于结点的种类进行操作,当根结点存在时,向后进行遍历寻找要删除的结点key,当找到该节点时,要对此结点状态进行判断,如果是叶子结点,就向其父结点返回NULL,如果其左结点不为空右结点为空,就将该节点的左结点返回其父结点出,如果其左结点为空右结点不为空,就将其右结点返回其父结点处,倘若其左右结点均不为空,我们不妨让其右结点继承其位置,那么其左子树就要移到右子树中,位置在右子树最左侧,相当于插入到该位置,我们要事先通过cur指针来寻找空位置。你可以返回任意有效的结果。
2025-03-17 18:40:12
610
原创 验证二叉搜索树 二叉搜索树的最小绝对差 二叉搜索树中的众数 二叉树的最近公共祖先
思路:这道题我们来验证二叉搜索树,可以使用中序遍历,由于该树有序这一特征我们可以入手,那么中序遍历出来的序列必定是递增的(前提是没有重复的数),在遍历时我们可以引入pre,让其与root的值进行比较(中结点处理逻辑),pre开始指向NULL,pre相较于root一直是root的前一个结点,只要在递归的过程中,pre的值始终小于root的值,那么这颗树就是二叉搜索树。pre一开始指向空,cur指向第一个结点,此时count=1,之后如果2个指针指向的结点值相同,则count++,如果不同,则count=1。
2025-03-16 21:25:37
1070
原创 从中序与后序遍历序列构造二叉树 最大二叉树 合并二叉树 二叉搜索树中的搜索
思路:其实就是通过中序遍历(左中右),后序遍历(左右中),来将这棵二叉树还原输出,主要是怎么得到二叉树,在这里我们从根结点入手,后序遍历数组的末尾元素必定是整棵树的根结点,先将其确定,然后再通过遍历中序数组,来找其数组中与根节点相同的值,以其为分割点将中序数值分成左中序数组即用于寻找根结点的左子树,右中序数组即用于寻找根结点的右子树,分割完成后,要先将原后序数组的末尾元素舍去,再通过左中序数组的长度来分割后序数组,即左后序数组用于寻找根节点的左子树,右后序数组用于寻找根结点的右子树,最后通过层序遍历输出。
2025-03-16 17:05:14
935
原创 左叶子之和 找左下角的值 路径总和
思路:这里我们可以这样想,开始遍历时,将目标值target传入,如果存在根节点就先用target减去其val值,先遍历左子树,此时遍历到根节点时减去其左子树的值,之后每遍历一个左节点就继续减去它的左子树的值,直到叶子节点时,如果此时target为0,那么就说明存有路径和为target,返回true,否则就进行回溯,将target回复原来的值转而向另外的路径探索看是否存有这样的路径,遍历右子树也是如此,注意这里我们如果找到了符合的路径,但仍未遍历完整棵树,也是直接返回true,不必继续遍历。
2025-03-15 22:10:18
1052
原创 二叉树的所有路径
遍历过程中如果存在左子树,就递归遍历,同时要记得回溯(path.pop_back()),因为此时已经将记录存在result中了,我们要开始收集下一条路径·,因此要回溯,同样存在右子树,也要递归遍历,也得回溯,所有路径都被保存到result中。思路:在这里我们需要从上向下确定路径即从父结点到子结点,所以我们使用前序遍历,这道题目中涉及到回溯,因为我们要把路径记录下来,需要回溯来回退一个路径再进入另一个路径。1.给定一个二叉树,返回所有从根节点到叶子节点的路径。
2025-03-14 21:16:27
631
原创 完全二叉树节点的数量 平衡二叉树
思路:对于求完全二叉树节点,可以使用求满二叉树的公式2的n次方减1,这里n指的是满二叉树的深度,为什么要用满二叉树的公式,其实我们可以来想,完全二叉树如果不是满二叉树,那么它左右子树深度一定不同,那么此时我们就分别求它左右子树的节点,因为此时它的左右子树必定是满二叉树,最后再加上根节点,就得到了完全二叉树的节点数。根存在情况下,先递归遍历根节点的左子树求左子树高度,其次是根节点右子树高度,然后比较两者的高度,高度差大于1就返回-1,否则就返回根节点的高度。2.给定一个二叉树,判断它是否是高度平衡的二叉树。
2025-03-13 21:28:55
534
原创 对称二叉树 二叉树的最大深度 二叉树的最小深度
在这里我们使用前序遍历的方法,在根节点不为空的情况下,进行遍历,先进行对左子树的递归遍历,然后再是右子树递归遍历,最后返回最小深度,如果左右节点均不为空,返回较小深度的,如果出现左右节点为空的,就返回不为空的那一个再加1。首先我们要搞清楚什么是高度,什么是深度,高度是指节点到叶子节点的距离,深度是指节点到根节点的距离,而这里我们要求的最大深度,就是叶子节点到根节点的距离,不就是根节点的高度吗,所以这道题看似我们求的是高度,其实是深度。注意就是刚开始左右子树若均为NULL,此时该二叉树也是对称的。
2025-03-12 21:04:42
594
原创 翻转二叉树
首先对于前序遍历,如果根不为空,那么就交换其左右子树(swap()),接着递归其左子树,最后递归其右子树(当然前提是左右子树存在)。(前序--中左右的顺序)思路:这里因为中序遍历顺序是左右中,先递归左子树,再交换左右子树,注意此时右子树的元素已经换到了左子树位置,因此最后递归的仍是左子树!思路:大致与前序遍历差不多,就是遍历顺序不同,(后序--左右中),因此先递归左子树,后递归右子树,最后才交换中节点。为了知道最后是否成功将二叉树翻转,层序遍历一下检查。1.翻转一棵二叉树。
2025-03-11 21:46:55
608
原创 二叉树递归遍历 迭代法遍历二叉树 层序遍历
首先,二叉树的结构体,有值域,有左右指针,其实对于这三种方式,只是顺序略有不同,其他的都一样,以前序遍历为例,在这里我们用cur指针做遍历操作,如果cur指向空,就回退,先取中节点的值,然后递归左子树,之后再递归右子树,前提是要有左右子树,顺序就是先中节点,后左子树,最后右子树。当cur不为空或栈不为空时,将cur放入栈中,之后cur=cur->left,直到左子树为空,这时将栈顶元素pop出,放置于数组中,然后cur=cur->right,如果存在右子树就将其放入栈中,就这样,循环下去,最终遍历结束。
2025-03-10 21:28:23
780
原创 前k个高频元素
首先对数组进行遍历,将元素放到map中,同时记录各个元素出现的频率,遍历结束后就要对map进行遍历,注意这里遍历是针对元素频率,先把前k个元素push进入队列,之后再进行遍历,元素数量就超过队列的容纳范围了,因为队列只维护k个有序序列,那么之后再进入的元素就要把队列里的最小值顶出去,这样就保证了队列里面的数总是前k个大的。思路:对于这道题可以将其分解成3个问题来解决,1.统计元素出现的频率 2.将元素出现的频率进行排序 3.找出前k个高频元素。1.给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
2025-03-09 21:33:51
809
原创 有效的括号 删除字符串中的所有相邻重复项 逆波兰表达式求值 滑动窗口最大值
这段范围遍历完后,要向后移动滑动窗口,此时就要除去滑动窗口的最前面的元素,相当于是在单调队列中进行pop操作,还要加入滑动窗口后的那一个元素,也相当于在单调队列中进行push操作,最后记录队列中的最大值(que.front)。思路:所谓逆波兰表达式其实就是后缀表达式,我们可以利用栈来实现,对表达式进行遍历,当遇到数字时就放于栈中,但切记要用stoll把类型转换成long long,如果遇到的是符号,就从栈中弹出2个数字,进行对应运算,将结果返回到栈中。"有效的括号":"无效的括号")<<endl;
2025-03-08 21:39:42
912
原创 用栈实现队列 用队列实现栈
思路:在这里我们·要用栈来实现队列的操作,首先我们先来思考,队列遵循FIFO(先进先出),而栈遵循FILO(先进后出),两者的元素进出顺序可谓是截然不同,如何才能实现呢,这时我们可以想到用2个栈,假设有一个队列,有三个元素1,2,3按顺序进入队列,出去时的顺序仍然是1,2,3,同时有2个栈stIn和stOut,元素先按顺序进入到stIn,然后出来,但是顺序反过来了,变成了3,2,1,这是继续进入到stOut中,当它们再次出栈时,顺序就恢复成了1,2,3,这不就正好是我们想要的结果吗。
2025-03-07 21:37:11
904
原创 翻转字符串里的单词 右旋转字符串
一开始fast和slow都处于初始位置即字符串首位置,先让fast进行遍历,如果fast遇到空格就通过slow进行判断,如果slow所指位置不是首个单词就添加空格,然后将fast所指位置元素赋值给slow,然后两者都向后移动,一直到遍历完字符串。2.字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。思路:其实很简单,我们先进行整体的反转,那么尾部的字符就转移到前面了,然后进行局部反转,先进行前n个字符的反转,再将剩余的字符进行反转,最终能够得到符合的字符串。
2025-03-06 21:11:10
696
原创 三数之和 四数之和 反转字符串 反转字符串||
对于a的去重操作,无外乎我们会在2个选项中感到疑惑,即sum[i]==sum[i+1]和sum[i]==sum[i-1]。反观sum[i]==sum[i-1],当i指向第一个-1时,会发现这是一个满足条件的三元组,会将其放置到result中,而当i继续指向第二个-1时,就会将其continue,因为此时i=-1,如果在此基础上去寻找left和right满足和为0的三元组,结果也必定只能是{-1,-1,2},但是这是不可能找到的,因为往后的值只会越来越大,因此不必再进行无用的遍历。
2025-03-05 21:24:15
885
原创 四数相加
之所以将循环考虑为2次对2个数组进行遍历是对时间复杂度的一个优化,是O(n*n)级别的。之后在遍历CD数组时,根据c+d元素值,到map中寻找是否存在0-(c+d)在其中,之所以要寻找0-(c+d),是因为已知了c+d,而a+b+c+d=0,故a+b=0-(c+d)。如果找到了就把其出现的次数赋值给count。给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。
2025-03-04 21:29:21
404
原创 两数之和(哈希表) 快乐数
如果有就返回,这两个元素分别对应的下标,如果没有就把当前的元素数值与下标保存到map中,往后继续遍历,直到找到符合的两个数,如果仍没有就返回空。思路:既然要把一个正整数,每一次将该数替换为它每个位置上的数字的平方和,可以先将该数对10取余得到其个位,进行相乘,赋给sum,然后再除以10得到其十位,进行类似方法,之后得到的sum值是第一个平方和数,然后判断是否为1,如果不是就到set中寻找是否有重复的痕迹,若没有找到,就先存放到set中,继续找下一个平方和。如果 可以变为 1,那么这个数就是快乐数。
2025-03-03 20:43:47
440
原创 环形链表 有效字母异位词 两个数组的交集
思路:使用双指针法,定义fast指针和slow指针,fast每次移动2个位置,slow每次移动1个位置,在while循环下,要求fast!思路:根据已给的2个字符串,先创建一个数组能够存下26个字母,接着开始遍历第一个字符串,该字符串中有的字母会在数组对应字母下标下进行标记(进行加一操作),遍历结束后,继续遍历第二个字符串,方法类似,操作变为减一,最终遍历改变后的数组,如果发现某些下标值不为零,那么证明这两个字符串的字母不不全一致,如果均为零,则字母均一致。3.给定两个数组,编写一个函数来计算它们的交集。
2025-03-02 17:34:19
650
原创 两两交换链表中的节点 删除链表的倒数第n个节点 链表相交
给出2个链表,首先每个都进行遍历,得到各自的长度,然后根据链表较长的那一个,指定一个指针curA指向其头节点,然后计算出两者之间的差值gap,将2个链表按照尾部照齐的思想,在while(gap--)循环下,等到循环结束,curA此时指向的位置正好等同于另外一个链表的头节点位置,然后2个指针同时遍历,如果出现curA==curB的情况,则此时curA(curB)便是相交的节点。还有在每一次循环cur指针遍历之前,要提前保存前三个节点的位置,否则修改指针指向时可能会导致指针找不到应该指向的位置。
2025-03-01 20:55:51
792
原创 长度最小的子数组(滑动窗口) 螺旋矩阵 区间和
这段代码没有涉及什么算法,主要是对过程的理解和掌握,注意循环不变量,每一圈遍历的时候规则要一致,还有就是奇数和偶数,如果是偶数,那么圈数是一个整数,但如果是奇数,那么圈数不是整数,往往会遗漏最中间的那个数,同时它也就是最大的数即n*n。还有就是对与offset的理解,因为我们设定的规则是每一条边的最后一个数要留给下一条边来遍历,所以为了防止遍历到它,引入了offset来干预,同时随着圈数的增加,每一圈的起点也会向终点靠近,那就会离边的最后一个数越近,因此offset会随着圈数的增加而增加。
2025-02-28 21:28:57
569
原创 移除链表元素 设计链表 反转链表
该代码运用了双指针的思想,引入pre和cur指针,一开始cur指向头节点,pre指向NULL,改变cur->next,使其指向pre,但为了不出错误要提前保存cur->next到temp,而且先移动pre=cur,再移动cur=temp,否则若是先移动cur,那么pre就不能到cur了,因为cur先改变了。这些是一些链表的基本操作,没有啥值得细说的,我觉得看看代码其实就能差不多理解了,挺简单的,反正熟能生巧,多敲几遍,我差不多敲了5遍,又手写了1遍,现在感觉挺熟练的。里面使用了虚拟头节点,操作更简便。
2025-02-28 21:27:12
706
原创 数组移除元素 有序数组的平方
大致思路:创建2个指针fast与slow,各司其职,fast指向的是数组中的元素即val,slow指向的是数组下标,当然两者均从初始位置开始,即num[0],首先就是要通过遍历该数组来找出要求删除的元素,这是fast的任务,而slow的任务是找到新数组,即原数组删除指定元素后剩余元素组成的新数组。本来跟着视频学的方法挺不错的,但是最后总是出现一些问题不能运行,又尝试了新的方法,也挺不错,关键是可以正常运行,分享给大家。和双指针的方法其实差不多,不一样的是创建了一个临时数组temp,复制原数组的数据。
2025-02-27 21:22:38
541
原创 二分查找法
对于二分法,第一个就是要注意区间,左闭右闭还是左闭右开。区分好了区间之后就对边界的判断更明确了。有的人总是对middle,middle+1或是middle-1到底该用哪一个感到晕,这里其实有规律。其实无外乎就是在闭合的那一端,middle要么是加一,要么是减一,在非闭合的那一端,不再考虑加或减一,当left==right时返回middle。在代码里做了一些改动,一开始不再是有序数组,因此多了一步sort排序。首先左闭右开的写法,[left,right]左闭右开的写法 [left,right)
2025-02-26 21:21:34
439
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人