- 博客(56)
- 收藏
- 关注
原创 优选算法系列(6. BFS 解决 FloodFill 算法)
并且将这个陆地相连的所有陆地,也就是这块「岛屿」,全部「变成海洋」。这样的话,我们下次 遍历到这块岛屿的时候,它「已经是海洋」了,不会影响最终结果。我们可以从起点开始层序遍历,并且在遍历的过程中记录当前遍历的层数。这样就能在找到出口的时候,得到起点到出⼝的最短距离。可以利⽤「深搜」或者「宽搜」,遍历到与该点相连的所有「像素相同的点」,然后将其修改成指定的像素即可。其中「变成海洋」的操作,可以利⽤「深搜」和「宽搜」解决,其实就是。这道题~这样,当我们,遍历完全部的矩阵的时候, ret。
2025-04-08 20:37:34
444
原创 优选算法系列(6.模拟)
第⼆⾏、第三⾏除了第⼀个数取值为行数,每组下标为(2n - 1, 2n)的数围绕(2row - 2)的倍数左右取值。第二行的数是:1, (2row - 2) - 1, (2row - 2) + 1, (4row - 4) - 1, (4row - 4) + 1;第三行的数是:2, (2row - 2) - 2, (2row - 2) + 2, (4row - 4) - 2, (4row - 4) + 2;第四行的数是:3, (2row - 2) + 3, (4row - 4) + 3。
2025-04-08 20:37:12
529
原创 动态规划(11.按摩师)
位置在不选的情况下的最长预约时长,然后加上 nums[i]f[0] = nums[0], g[0] = 0 即可。i - 1 位置上选或者不选两种情况下的最长时长,因此。这道题的初始化比较简单,因此⽆需加辅助节点,仅需初始化。位置时, nums[i] 不选,此时的最长预约时长。根据「状态转移方程」得「从左往右,两个表⼀起填」。以某个位置为结尾,巴拉巴拉;以某个位置为起点,巴拉巴拉。位置时,此时的最长预约时长。必选,此时的最长预约时长;根据「状态表示」,应该返回。必选,那么我们仅需知道。
2025-03-31 19:17:40
351
原创 优选算法系列(5.位运算)
一.常见的位运算总结直接让那个位置的数字右移到最低位与(&)1取出最低位。让第x位置或(|)1,其他位不变(或0),即n要或的数就是1左移x位置让第x位置与(&)1,其他位不变(与1),即n要或的数就是(1左移x位置然后取反~)本质就是一个哈希表,但是之前的哈希表是一个数组,但是现在这里的哈希表是一个int的二进制位,让每一个比特位记录信息eg:只需要 n & -n因为-n的本质是,将最右侧的1,左边的区域全部变成相反只需要 n & (n-1)
2025-03-31 13:27:44
698
原创 动态规划(9.最小路径和)
在本题中,「添加⼀行」,并且「添加⼀列」后,所有位置的值可以初始化为无穷大,然后让dp[0][1] = dp[1][0] = 1 即可。根据「状态转移方程」的推导来看,填表的顺序就是「从上往下」填每⼀⾏,每⼀⾏「从左往后」。可以在最前面加上⼀个「辅助结点」,帮助我们初始化。位置两种情况,并且我们要找的是最⼩路径,因此只需要这两种情况下的最⼩。[i, j - 1] 向右走一步,转移到 [i, j]辅助结点里面的值要「保证后续填表是正确的」;根据「状态表示」,我们要返回的结果是。位置处,最小路径和是多少。
2025-03-27 17:19:12
241
原创 动态规划(10.地下城游戏)
因为我们要的是最小值,因此这种情况下的 x = dp[i][j + 1] - dungeon[i][j];位置的最低健康点数加上这⼀个位置的消耗,应该要大于等于下边位置的最低健康点数,也就是: x + dungeon[i][j] >= dp[i + 1][j]表最后⾯添加⼀行,并且添加⼀列后,所有的值都先初始化为无穷大,然后让dp[m][n - 1] = dp[m - 1][n] = 1 即可。因为我们要的是最小值,因此这种情况下的 x = dp[i + 1][j] - dungeon[i][j]
2025-03-27 17:18:57
961
原创 优选算法系列(4.前缀和 _下) k
因此,我们仅需⽤⼀个哈希表,⼀边求当前位置的前缀和,⼀边记录第⼀次出现该前缀和的。⽤文字叙述就是,如果两个数相减的差能被 n 整除,那么这两个数对 n 取模的结果相同。⼆维前缀和的简单应用题,关键就是我们在填写结果矩阵的时候,要找到原矩阵对应区域的「左上。中关于负数的取模运算,结果是「把负数当成正数,取模之后的结果加上⼀个负号」。因此,我们仅需用⼀个哈希表,⼀边求当前位置的前缀和,⼀边存下之前每⼀种前。因此,我们仅需⽤⼀个哈希表,⼀边求当前位置的前缀和,⼀边存下之前每⼀种。
2025-03-26 22:23:21
979
原创 优选算法系列(4.前缀和_上)
一.【模板】一维前缀和(easy)解法:暴力会超时解法(前缀和):算法思路:先预处理出来⼀个「前缀和」数组:⽤ dp[i] 表示[1, i]区间内所有元素的和,那么dp[i - 1]⾥⾯存的就是[1,i - 1] 区间内所有元素的和,那么:可得递推公式:使用前缀和数组,「快速」求出「某⼀个区间内」所有元素的和:当询问的区间是 [l, r]时:区间内所有元素的和为:。
2025-03-25 21:33:15
890
原创 动态规划(8.下降路径最小和(medium))
在本题中,需要「加上一行」,并且「加上两列」。所有的位置都初始化为无穷⼤,然后将第⼀⾏初始化为 0。关于这⼀类题,由于我们做过类似的,因此「状态表示」以及「状态转移」是比较容易分析出来的。题目要求「只要到达最后⼀⾏」就行了,因此这⾥应该返回「 dp 表中最后一行的最小值」。可以在最前⾯加上⼀个「辅助结点」,帮助我们初始化。我们要的是三种情况下的「最小值」,然后再加上矩阵在。比较难的地方可能就是对于「边界条件」的处理。辅助结点里面的值要「保证后续填表是正确的」;根据「状态表示」,填表的顺序是「从上往下」。
2025-03-25 21:33:06
412
原创 动态规划(7.礼物的最大价值)
根据「状态转移方程」,填表的顺序是「从上往下填写每⼀⾏」,「每⼀⾏从左往右」。可以在最前面加上⼀个「辅助结点」,帮助我们初始化。位置能拿到的礼物价值为 dp[i - 1][j] + grid[i][j]位置能拿到的礼物价值为 dp[i][j - 1] + grid[i][j]在本题中,「添加⼀⾏」,并且「添加⼀列」后,所有的值都为。辅助结点里面的值要「保证后续填表是正确的」;根据「状态表示」,我们应该返回。位置,向下⾛⼀步,此时到达。位置,向右⾛⼀步,此时到达。位置处,此时的最大价值。位置出发,巴拉巴拉;
2025-03-21 20:59:39
289
原创 优选算法系列(3.二分查找 )
⽤的还是⼆分思想,就是根据数据的性质,在某种判断条件下将区间⼀分为⼆,然后舍去其中⼀个区间,然后再另⼀个区间内查找;但是这个数组是一个升序的,如果随便取一个数比他小,那么所取得数左边的数都比目标小这样就只需要向他右边找,如果比目标值大也一样那么去它左边找。因此,我们可以遍历数组内的每⼀个元素,找到某⼀个元素比两边的元素大即可。不可以舍去,因为有可能是最终结果) 都是可以舍去的,此时更新。在第⼀个缺失位置的左边,数组内的元素都是与数组的下标相等的;在第⼀个缺失位置的右边,数组内的元素与数组下标是不相等的。
2025-03-21 20:36:35
963
原创 动态规划(6.不同路径II)
由此我们可以得出⼀个结论,只要这个位置上Γ有障碍物」,那么我们就不需要计算这个位置上的值,直接让它等于 0。本题为不同路径的变型,只不过有些地方有「障碍物」,只要在「状态转移」上稍加修改就可解决。根据Γ状态转移」的推导,填表的顺序就是Γ从上往下」填每⼀⾏,每⼀⾏Γ从左往右」。位置都是可能有障碍的,此时从上面或者左边是不可能到达 [i, j][i, j - 1] 的位置)向右走一步,转移到 [i, j]位置的,也就是说,此时的⽅法数应该是 0。在本题中,添加一行,并且添加⼀列后,只需将。位置出发,巴拉巴拉;
2025-03-20 21:38:49
340
原创 动态规划(5.不同路径)
根据「状态转移方程」的推导来看,填表的顺序就是「从上往下」填每一行,在填写每⼀⾏的时候。可以在最前面加上⼀个「辅助结点」,帮助我们初始化。在本题中,「添加一行」,并且「添加一列」后,只需将。辅助结点里面的值要「保证后续填表是正确的」;根据「状态表示」,我们要返回。的位置)向下走一步,转移到。的位置)向右走⼀步,转移到。位置处,⼀共有多少种方式。位置的⽅法数,那么到达。位置出发,巴拉巴拉;从起始位置出发,到达。「下标的映射关系」。
2025-03-19 20:53:14
261
原创 优选算法系列(2.滑动窗口_下)
五:水果成篮(medium)解法:问题可以转化为:找出一个最长的子数组满足值数组里只有不超过两种水果。暴力解法就是利用 hash + 暴力枚举 所有子数组当我们的区间rifght下一个x位置会出现第三种水果,暴力的思想我们会让left后移一位,right重走,但是如果让right回去重走到原本的位置有两种可能。因为left少了一个水果所以如果right重新走到原来的位置kinds不可能增加所以right没必要重新走。这样我们可以使用滑动窗口。初始化哈希表 hash 来统计窗⼝内⽔果的种类和数量。
2025-03-19 20:23:15
1023
原创 优选算法系列(2.滑动窗口 _ 上)
如上图所示,当我们选择 2 3 1 2 的区间时候 sum=8 就已经满足题意,此时长度为4,若我们继续向后扩大区间那么长度会一直增大,因此当 right=4 的时候我们其实就可以不继续扩大区间了。那么此时我们保持 right 不动移动 left ,因为我们知道上一个区间的值 sum=8 当我们移动 left 后只需要减去移出区间的值2我们就可以知道新区间的值。此时我们移动left,但是由于我们right前面的区间<目标值,如果right回去重新走那么依旧会白走前面的区间。找出其中长度最⼤的即可。
2025-03-17 22:25:42
1110
1
原创 动态规划(4. 解码方法)
最终的结果应该是上⾯四种情况下,解码成功的两种的累加和(因为我们给关心的是解码方法,既然解码失败,就不⽤加⼊到最终结果中去),因此可以得到状态转移方程( dp[i]位置如果单独参与解码,但是解码失败了,那么前⾯做的努⼒就全部⽩费了。,我们经验上都是「以某个位置结束或者开始」做⽂章,这。值,因此要先初始化「前两个位置」。值,如何由「前⾯」或者「后⾯」的信息推导出来。间上的解码⽅法就不存在了,原因依旧同上。区间上的所有解码结果,后⾯填上⼀个。位置上的数结合,解码成⼀个字⺟。区间上,⼀共有多少种编码⽅法。
2025-03-14 15:39:49
1004
原创 动态规划(3.使用最小花费爬楼梯)
容易得到dp[0] = dp[1] = 0 ,因为不需要任何花费,就可以直接站在第。位置: dp[i - 1] + csot[i - 1];位置:dp[i - 2] + csot[i - 2]。根据「状态转移⽅程」可得,遍历的顺序是「从左往右」。根据「状态转移⽅程」可得,遍历的顺序是「从右往左」。从我们的递推公式可以看出,我们需要先初始化。根据「状态表示以及题目要求」,需要返回。根据「状态表⽰以及题⽬要求」,需要返回。位置出发,到达楼顶,此时的最⼩花费。,往后⾛⼀步,接下来从。,往后⾛两步,接下来从。
2025-03-13 22:47:00
301
原创 动态规划(2. 三步问题)
(dp[i - 1] + dp[i - 2] + dp[i - 3]) % MOD 是不可取的,对于这类需要取模的问题,我们每计算⼀次(两个数相加/乘等),都需要取⼀次模。比如你要到达i位置你可以直接从i-3直接到i,从i-2直接到i也可以从i-1直接到i。根据题意, dp[1] = 1, dp[2] = 2, dp[3] = 4。的时候是没有办法进⾏推导的,因为 dp[-3] dp[-2]这道题目说,由于结果可能很⼤,需要对结果取模。在计算的时候,三个值全部加起来再取模,即。位置时,⼀共有多少种⽅法。
2025-03-13 13:16:55
423
原创 动态规划(1. 第 N 个泰波那契数)
===== 题目经验 经验+题目要求 分析问题的过程中发现重复子问题 =================== 填写当前状态时,所需状态已经填过了 ===================== 题目要求+状态表示 =================== dp[i]等于什么 ==================== 保证填表不越界 =============:dp[i] 表示:第。
2025-03-12 23:10:14
435
原创 优选算法系列(1.双指针_下)
五. 有效三角形的个数(medium)思路一:(暴力求解)(会超时):三层for循环枚举出所有的三元组,并且判断是否能构成三⻆形。因为判断三角形是否构成只需要看三个边长的最小的两个边加起来是否大于第三边即可。因为题目给的数组是无序的所以我们需要先对数组进行排序,排序之后就利用「对撞指针」去解决此问题。设最长边枚举到i位置,区间是i位置左边的区间(也就是比它小的区间):如果说明 [left, right - 1]区间上的所有元素均可以与构成比nums[i] ⼤的⼆元组。
2025-03-11 23:54:45
909
原创 优选算法系列(1. 双指针_上)
双指针常见的双指针有两种形式,⼀种是对撞指针,⼀种是左右指针。⼀般⽤于顺序结构中,也称左右指针。对撞指针从两端向中间移动。⼀个指针从最左端开始,另⼀个从最右端开始,然后逐渐往中间逼近。对撞指针的终⽌条件⼀般是两个指针相遇或者错开(也可能在循环内部找到结果直接跳出循环),也就是:(两个指针指向同⼀个位置)(两个指针错开)⼜称为⻳兔赛跑算法,其基本思想就是使⽤两个移动速度不同的指针在数组或链表等序列结构上移动。这种⽅法对于处理环形链表或数组⾮常有⽤。
2025-03-10 23:19:45
747
原创 C++基础(16 智能指针)
RAII在获取资源时把资源委托给⼀个对象,接着控制对资源的访问, 资源在对象的⽣命周期内始终保持有效·,最后在对象析构的时候释放资源,这样保障了资源的正常 释放,避免资源泄漏问题。下⾯程序中我们可以看到,new了以后,我们也delete了,但是因为抛异常导,后⾯的delete没有得到执行,所以就内存泄漏了,所以我们需要new以后捕获异常,捕获到异常后delete内存,再把异常抛出,但是因为new本⾝也可能抛异常,连续的两个new和下⾯的Divide都可能会抛异常,让我们处理起来很麻烦。
2025-03-05 22:06:26
796
原创 C++基础(16 异常)
1.异常的概念及使用1.1异常的概念异常处理机制允许程序中独立开发的部分能够在运⾏时就出现的问题进⾏通信并做出相应的处理,异常使得我们能够将问题的检测与解决问题的过程分开,程序的⼀部分负责检测问题的出现,然后解决问题的任务传递给程序的另⼀部分,检测环节无须知道问题的处理模块的所有细节。C语言主要通过错误码的形式处理错误,错误码本质就是,拿到错误码以后还要去,比较麻烦。异常时抛出⼀个对象,这个对象可以函数。1.2异常的抛出和捕获程序出现问题时,我们通过抛出(throw)⼀个对象。
2025-03-03 21:28:58
971
原创 C++基础(15 C++11下)
4.可变参数模板4.1基本语法及原理C++11⽀持可变参数模板,也就是说⽀持可变数量参数的函数模板和类模板,可变数⽬的参数被称为参数包,存在两种参数包:模板参数包,表示零或多个模板参数;函数参数包:表示零或多个函数参数我们⽤省略号来指出⼀个模板参数或函数参数的表⽰⼀个包,在模板参数列表中,class...或typename...指出接下来的参数表⽰零或多个类型列表;在函数参数列表中,类型名后⾯跟...指出接下来表⽰零或多个形参对象列表;函数参数包可以⽤左值引⽤或右值引⽤表⽰,跟前⾯普通模板。
2025-03-01 15:50:05
720
原创 C++基础(14. 哈希 )
1.哈希概念哈希(hash)又称散列,是⼀种组织数据的⽅式。从译名来看,有散乱排列的意思。本质就是,查找时通过这个哈希函数计算出Key存储的位置,进行快速查找。1.1直接定址法当关键字的范围⽐较集中时,直接定址法就是非常简单高效的⽅法eg1:⼀组关键字都在[0,99]之间, 那么我们开⼀个100个数的数组,每个关键字的值直接就是存储位置的下标。eg2:⼀组关键字值都在[a,z]的小写字母,那么我们开⼀个26个数的数组,每个关键字acsii码-a ascii码就是存储位置的下标。
2024-11-27 20:03:56
1051
原创 C++基础(13.unordered_map和unordered_set的使用)
第⼆个差异是迭代器的差异,map的iterator是双向迭代器,unordered_map是单向迭代器,其次map底层是红⿊树,⾛中序遍历是有序的,所以map迭代器遍历是Key有序+去重,而unordered_map底层是哈希表,迭代器遍历是Key⽆序+去重。unordered_multimap/unordered_multiset跟multimap/multiset的差异也是三个⽅⾯的差异, key的要求的差异,iterator及遍历顺序的差异,性能的差异。
2024-11-26 18:03:57
279
原创 C++基础(12.红黑树实现)
因为p和u都是红⾊,g是⿊⾊,把p和u变⿊,左边⼦树路径各增加⼀个⿊⾊结点,g再变红,相当于保持g所在⼦树的⿊⾊结点的数量不变,同时解决了c和p连续红⾊结点的问题,需要继续往上更新是因为,g是红⾊,如果g的⽗亲还是红⾊,那么就还需要继续处理;,u不存在,则c⼀定是新增结点,u存在且⿊,则c⼀定不是新增,c之前是黑⾊的,是在c的⼦树中插⼊,符合情况1,变⾊将c从⿊⾊变成红⾊,更新上来的。p必须变⿊,才能解决,连续红⾊结点的问题,u不存在或者是⿊⾊的,这⾥单纯的变⾊⽆法解决问题,需要旋转+变⾊。
2024-11-12 22:59:25
772
原创 C++基础(11.AVL树的实现)
AVL的概念:AVL树是最先发明的⾃平衡⼆叉查找树,AVL是⼀颗空树,或者具备下列性质的⼆叉搜索树:它的。AVL树是⼀颗⾼度平衡搜索⼆叉树, 通过控制⾼度差去控制平衡。AVL树得名于它的发明者G. M. Adelson-Velsky和E. M. Landis是两个前苏联的科学家,他们在1962 年的论⽂《An algorithm for the organization of information》中发表了它。AVL树实现这⾥我们引⼊⼀个平衡因⼦(balance factor)的概念。
2024-11-01 20:15:09
652
原创 C++基础(10. map_set 的使用)
可以通过提供自定义比较函数来改变元素的排序方式。way1:// 降序排列// 创建一个降序排列的setway2:使用greater<>, less<>// 创建一个降序排列的set// 创建一个升序排列的setmultiset。
2024-10-16 23:02:38
1012
原创 Linux(1. 基本操作_命令)
man 手册可以说是“长篇大论了”,用户只想要知道某个命令大概可以做哪些事,此时可以使用 whatis 命令。whatis 命令可以从手册页中抽出一行简单的介绍性文字,帮助用户了解这个程序的大致用途。whatis 命令的原理同 locate 命令基本一致。
2024-10-12 21:11:37
814
1
原创 C++基础(9.二叉搜索树)
1. ⼆叉搜索树的概念:⼆叉搜索树⼜称⼆叉排序树,它或者是⼀棵空树,或者是具有以下性质的⼆叉树:若它的左⼦树不为空,则左⼦树上所有结点的值都⼩于等于根结点的值若它的右⼦树不为空,则右⼦树上所有结点的值都⼤于等于根结点的值它的左右⼦树也分别为⼆叉搜索树。
2024-09-26 17:58:39
807
原创 C++基础(8.继承_多态)
Person是父类,也称作基类。Student是子类,也称作派生类。继承基类成员访问方式的变化类成员继承方式public继承protected继承private继承基类的public成员派生类的public成员派生类的protected成员派生类的private成员基类的protected成员派生类的protected成员派生类的protected成员派生类的private成员基类的private成员在派生类中不可见在派生类中不可见。
2024-09-22 21:32:40
1138
原创 C++基础(7.Stack_Quene_List)
std::list是 C++ 标准库中的一个双向链表容器,适合于频繁插入和删除操作。以下是std::list的常用接口和重载的详细介绍。stack是 C++ 标准库中的一个容器适配器,提供了后进先出的数据结构。它是基于其他容器(如deque或vector)实现的。std::queue是 C++ 标准库中的一个容器适配器,提供了先进先出(FIFO)的数据结构。它通常基于其他容器(如std::deque或std::list)实现。以下是std::queue的常用接口和重载的详细介绍。
2024-09-06 21:18:29
804
原创 C++基础(6.vector与迭代器失效)
C++ 中的 vector 是一种序列容器,它允许你在运行时动态地插入和删除元素。vector 是基于数组的数据结构,但它可以自动管理内存,这意味着你不需要手动分配和释放内存与 C++ 数组相比,vector 具有更多的灵活性和功能,使其成为 C++ 中常用的数据结构之一。vector 是 C++ 标准模板库(STL)的一部分,提供了灵活的接口和高效的操作。基本特性:动态大小vector的大小可以根据需要自动增长和缩小。连续存储vector中的元素在内存中是连续存储的,这使得访问元素非常快速。
2024-09-02 23:17:22
903
原创 C++基础(5.模板+string)
malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地方是: 模板的定义格式例子(实现一个任意栈的push): 原始版本Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。唯一的条件就是也需要向原始版本一样做开源使用。HP版本 -- 所有STL实现版本的始祖。P.J.版本由P.J.Plauger开发,继承自HP版本,被Window
2024-08-12 15:06:27
468
原创 C++基础(4.内存管理)
对于p2和p3开辟的空间如同,开辟空间后对p3来说返回的位置如图(因为p2没有写析构函数同时也没有动态申请的空间需要析构于是编译器就优化掉了,对于p2的delete也就没有问题)。当时对于p3来说在头部有额外开辟的空间 ,加了方括号才会向前偏移到正确的位置释放,而不加方括号就会在如图位置析构一次,而开辟的空间是不能部分析构的所以会报错。对于new申请的空间如果失败了那么就会抛异常跳过后面的代码。对于写了析构函数的类系统在开空间时候会在头上多开4个字节来记录个数来调用析构函数。
2024-07-25 18:34:51
403
原创 C++基础(3.类和对象)
赋值运算符重载:const限制权限:隐式类型转换:再探构造函数:static成员:有元:内部类:赋值运算符重载的特点:重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,无法很好的区分。 C++规定,后置++重载时,增加一个int形参,跟前置++构成函数重载,方便区分。重载 >时,需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第一个形参位置,第一个形参位置是左侧运算对象,调用时就变成了对象
2024-07-19 20:54:55
843
原创 C++基础(2.类和对象)
class为定义类的关键字,Stack为类的名字,0}中为类的主体,注意类定义结束时后面分号不能省略。类体中内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的方法或者成员函数。为了区分成员变量,一般习惯上成员变量会加一个特殊标识,如成员变量前面或者后面加_或者m开头,注意C++中这个并不是强制的,只是一些惯例,具体看公司的要求。
2024-07-14 23:20:45
958
1
原创 C++基础(1)
在传地函数中,由于形参是实参的拷,拷贝需要消耗空间和效率,于是我们可以直接通过在函数内为实参引用但是由于我们不想改变实参数或者类型不一样等原因我们就加上const。一个对象可以有多个别名,别名也可以有别名。在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器。以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调。1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会。
2024-07-09 16:10:19
618
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人