自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(49)
  • 收藏
  • 关注

原创 jvm实现的锁优化

轻量级锁在无竞争的情况下对于每次的加锁请求都使用CAS来避免了互斥量的使用,而偏向锁就是在无竞争的情况下连CAS都不用做了(只是在线程第一次获取偏向锁的时候使用了CAS),通过判断Mark Word中的ThreadID是不是当前线程即可,如不是,则进行重偏向即可。但如果存在锁竞争,那么除了互斥量的开销外,还额外发生了CAS的开销。,那轻量级锁就不再有效,必须要膨胀为重量级锁,锁标志转变为“10”,此时Mark Word 就不再存储锁记录的指针了,而是存储重量级锁互斥量(monitor对象)的指针了。

2023-10-19 12:08:47 486

原创 如何实现线程安全?

简单描述一下线程安全问题:在程序并发执行的过程中,对于临界区的一些共享数据,可能同时会有多个线程对其进行修改,造成数据覆盖、脏读等一系列问题如何实现线程安全?首先想到的就是实现线程同步,让并发线程同步执行,保证共享的数据在同一时刻只能被一个线程使用。

2023-10-18 12:06:55 193

原创 经典垃圾回收器

由于最后的垃圾清除也是用户线程和垃圾收集线程并发运行,所以用户线程再这一时间段内也会产生垃圾,这些垃圾成为“浮动垃圾”,用于并发标记阶段已结束,只能等到下一次GC时进行标记收集。最后用于线程和垃圾收集线程之所以能并发运行的原因也是因为CMS 是基于标记-清除算法实现的,不会涉及到对象的移动。像标记-整理算法涉及到对象的移动,必须进行STW.

2023-09-27 19:42:05 247

原创 为什么wait()要在synchronized块中执行

wait() 方法还没有执行完,notify() / notifyAll() 方法已经执行完,这样 notify() / notifyAll() 就进行了一次空唤醒操作,而 wait() 执行完后由于再没有notify() / notifyAll()的唤醒,会导致wait() 所在线程一直阻塞。ReentrantLock它实现同步/互斥并不会涉及到 monitor,所以 不能用 ReentrantLock 这种可重入锁来实现互斥配合 wait()、notify()、notiryAll()。

2023-09-21 22:50:59 534

原创 I/O多路复用-redis单线程模型快的根本原因

发起请求的一方需要等待操作完成并获得结果后才能继续执行后续的操作,换句话说,同步操作会阻塞当前线程或进程,直到操作完成。:发起请求的一方可以继续执行后续的操作,而不必等待操作完成。异步操作通常会使用回调函数、事件处理器或者轮询的方式来处理结果。在异步模式下,不同的参与方可以独立地进行操作,无需等待其他操作的完成。:在阻塞模式下,当一个I/O操作被调用时,程序会一直等待,直到操作完成或者发生错误才会返回结果。在阻塞状态下,调用线程或进程会被挂起,无法进行其他任务,直到I/O操作完成或者超时。

2023-07-16 23:54:22 322

原创 Redis持久化(RDB和AOF)

Redis是基于内存数据库,宕机后和数据会消失,当Redis用作DB 时,DB数据要完整,所以一定要有一个完整的数据源文件,在系统启动时,从这个完整的数据源中将数据load到 Redis内存中,完成提供持久化机制。:RDB、AOF、RDB-AOF混合持久化RDB:在指定的时间间隔内,形成当前数据集的时间点快照。将快照信息保存到磁盘的RDB文件中。在redis.conf中有如下配置,配置 save 参数即可自动触发rdb,一般RDB快照信息保存在dump.rdb文件中,文件名可以修改。432 #

2023-07-15 13:40:47 142

原创 布隆过滤器BloomFilter原理及使用场景

对redis每一个 key 经过 hash 取值,将 hashCode 对bitmap 的长度 2^32 取余,得到 hashCde 在bitmap 中对应的索引位置,没了减少hash碰撞,我们通常对同一个 key 进行多次hash,得到多个 hashCode ,在 bitmap 中用多个位置标志一个key。这样也就造成了布隆过滤器的删除问题。因为布隆过滤器的每一个bit位并不是独占的,很可能多个元素共享了某一位,如果我们直接直接删除了某一位元素,会影响其他的元素。:(此案例只用了一次hash)

2023-07-14 13:45:31 210

原创 二叉树的Morris遍历

利用叶子节点的left , right 这些空指针,使得非叶子节点能够借助这些空指针遍历两次,没有使用额外的空间。前中后遍历都是在第一次 / 第二次 的遍历过程中做不同的处理。Morris遍历可以将非递归遍历中的空间复杂度降为O(1)。从而实现时间复杂度为O(N),而空间复杂度为O(1)的精妙算法。对于没有左子树的节点之遍历一次,有左子树的节点遍历两次。:记作当前节点为cur。

2023-07-13 19:41:58 230

原创 Redis中的bigKey问题

对于bigkey的判定标准,《阿里云redis开发规范》中规定了:对于String类型value,value占用空间大于10kb,对于list,hash,set,zset类型若元素个数超过5000,就算bigkey。scan命令:是一个基于游标的迭代器, 返回一个包含两个元素的数组, 第一个元素是用于进行下一次迭代的新游标, 而第二个元素则是一个数组, 这个数组中包含了所有被迭代的元素。① 超时删除,对于大key,删除是及其耗时的,由于redis命令的执行是单线程的,删除大key会导致主进程阻塞影响性能。

2023-07-13 14:58:38 635

原创 并查集(java详细实现)

查询两个元素是否在同一个集合中,以及合并两个不相交集合。当然我们可以用链表等其他数据结构来实现,担当数据量特别大的时候,使用链表是非常耗时的,采用并查集结构可以大大提高合并及查询的效率。初始化并查集时,我们将每一个元素的根节点都指向自己。根节点,下文成为 “ 代表节点 ”:并查集也是一种树的结构,

2023-07-12 15:19:07 534

原创 数据结构与算法-前缀树(字典树)

前缀树的结构是一个多叉树,每个节点代表一个字符,从根节点到叶子节点的路径表示一个字符串。根节点没有相应的字符,而其他节点表示字符集中的一个字符。每个节点可能有多个子节点,每个节点代表一个字符的可能取值。能够高效的支持字符串的插入、搜索和前缀匹配操作,经常用于搜索引擎、拼写检查、自动完成和单词查找等场景。我们用 pass 标记当前节点有多少个字符串经过, 用 end 标记当前节点是多少字符串的结束字符,就最后一个字符。空间换时间,利用字符串的公共前缀来降低查询时间,不同的公共前缀之保存一份。

2023-07-11 16:12:09 449

原创 “最多可以参加的会议数目”

首先需要按照起始时间对 events 数组进行升序排列,使得起始时间相同的会议放在一起,避免后面在统计当天为起始时间的会议时,每统计一天,都要对 events 数组进行遍历。排序后,我们可以维护一个变量,遍历并标记 events 的位置,使得 events 在统计完所有天的会议后之遍历一遍。过期会议:可能已经有未排的会议的结束时间在当天之前,这时我们需要将过期会议的结束时间从小顶堆中移除。大白画:统计当天为起始时间的所有会议,选取其中结束时间最早的那个会议。注意,一天只能参加一个会议。

2023-06-06 17:17:36 102

原创 二叉树最近公共祖先

题目:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(3节点5和节点1的最近公共祖先是节点3。

2023-05-14 21:18:15 94

原创 求二叉树的最大宽度

使用层序遍历二叉树(DFS)来求解的化,就必须要处理 null 节点带来的问题,因为我们要借助队列 (Queue) 这一数据结构来实现 DFS ,就要处理 队列 不能加添 null 节点的问题。所以如果要使用队列的话,就不能通过每层的队列中的节点数来统计每层的宽度,这样会忽略每层的null 节点。那用什么数据结构来存储每个节点对应编号呢,第一反应就是哈希表,但是哈希表是无序的,这样每一层做减法就不能得到正确的宽度,java 中提供了一种类似哈希表的一种数据结构 Pair。给你一棵二叉树的根节点。

2023-05-11 19:31:33 565

原创 两个单链表相交问题(有环、无环)

给定两个可能有环也可能无环的单链表,头节点head1和head2,请实现一个函数,如果两个链表相交,返回相交的第一个节点,如果不相交,返回 null。

2023-04-26 17:40:34 130

原创 复制含有随机指针节点的链表

题目描述:一种特殊的单链表节点类描述如下class Nodeint value;Node next;Node rand;rand指针是单链表节点结构中新增的指针,rand可能指向链表中的任意一个节点,也可能指向null。给定一个由Node节点类型组成的无环单链表的头节点head,请实现一个函数完成这个链表的复制,并返回复制的新链表的头节点。

2023-04-24 17:45:34 103

原创 回文链表三种解法

题目描述:给定一个链表的head请判断其是否为回文链表。如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。例如:[1,2,3,3,2,1] 是回文。

2023-04-19 13:07:11 132

原创 堆排序记录

给出一个数组 arr [2,3,4,6,3,1],要把它构建成一个堆结构来实现排序,怎么做呢?我们可以对数组的索引操作,将其变成一个堆结构,例如:arr [0] 作为父节点(堆顶)那么 arr [1] 和arr [2] 就是其左右子节点,也就是 arr [i] 的左右子节点 就是arr [ 2 * i + 1] 和 arr [ 2 * i + 2](arr 可以看作是 2 为根节点的二叉树的层序遍历的结果)简单记录:堆排序顾名思义,借助堆结构来实现排序。heapInsert 过程可以理解为。

2023-04-18 18:51:41 39

原创 荷兰国旗问题 、快排

可是上述快排的时间复杂度是O(N^2),导致N^2的原因是我们每次都默认nums的最后一个数作为划分,这样我们可以人为 的使数组进行两次递归时的权重严重失衡,使得成为了N^2的算法,我们只要使每次的划分值的选取是一个随机事件,最终的时间复杂度就降到了O(NlogN),(具体证明过于复杂,这里不做证明,给出传送门>>>问题:给定一个数组nums,和一个数n,请把小于n的数放在数组的左边,等于n的数放在数组的中间,大于n的数放在数组的右边。,因为它左边全是小于它的数,右边全是大于它的数。这也就是快排的过程。

2023-04-12 00:33:28 76

原创 小和问题(基于归并排序实现)

最简单暴力的解法就是遍历每一个元素之前的元素,并记录每一个小和,最后相加得出整个数组的小和,这样毫无疑问是O(n^2)的时间复杂度。,当左组的元素小于右组的某一元素后,这是我们就不用再继续拿左组的这个元素继续在右组中进行遍历比较,因为右组已经有序了,只需要 r - p2 + 1即可。在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。小和定义:每一个数左边比当前数小的数累加起来,叫做这个数组的小和。我们为什么要进行排序呢,由上图可以看出,比如:[1,3,4,2,5]求小和。

2023-04-11 19:19:10 45

原创 jdk动态代理底层原理

注意,动态代理虽然不用我们来像静态代理那样写代理类,是因为jdk动态代理通Proxy.newProxyInstance()帮助我们实现了,还是会生成字节码对象的。注意,这里的invoke和InvocationHandler中的invoke不一样,前者是反射中执行Method的方法。2):Method method:执行目标方法(就是需要增强的方法),通过反射中的invoke执行,jdk动态代理它的底层原理到底是什么,通过获取生成的代理对象的字节码文件.class,观察底层原理。①:需要创建代理的类加载器。

2023-03-19 20:40:43 357

原创 贪心算法leetcode376.摆动序列

如何得到全部的峰值数量呢,由上图我们可以看到,只要删掉除了红色值的数字(在代码实现中我们并不会真正删除元素),那么剩下的就都是峰值。相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。③ 题目给出只有一个或两个不同的元素时也是摆动序列,所以非空数组最小的摆动序列的长度为1。整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3)。① 单调坡上(出去两端的峰值)

2023-03-17 10:38:34 134

原创 回溯leetcode.90子集Ⅱ

1.树枝去重:保证list集合(result中元素)中没有重复元素,list集合元素的收集来自递归,伴随着每次递归startIndex的增加,list数组被构建。进行树层去重都是在每一层的第一个节点往后的每一个节点进行去重,而这些节点都是经过了回溯的,在回溯的过程中我们已经将当前节点的前一个节点设为false了。由于前一个元素与当前的元素相等,以前一个元素开头的所有遍历情况包含以了当前元素开头的所有情况,继续遍历的话就会和result中已经存在的元素重复。保证result中没有重复元素就要树层去重。

2023-03-11 14:55:08 60

原创 回溯leetcode93.复原IP地址

若pointSum == 3并且judge(s,startIndex,s.length() - 1) == true。进行递归时startIndex要加2,因为递归之前有插“.”的操作,在进行下一个子串递归判断之前要跳过插入的“.”,所以start Index + 2。IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "例如:"0.1.2.201" 和 "192.168.1.1" 是。,用以表示一个 IP 地址,返回所有可能的。,这些地址可以通过在。

2023-03-07 16:39:58 27

原创 回溯leetcode131.分割字符串

从在上一步我们可以知道,能进入递归的说明之前分割的子串都是回文子串,( 不是回文子串的我们直接跳出循环,不会进入递归)所以我们只需要判断startIndex是否已经遍历到s的末尾,startIndex到末尾说明我们已经找到符合要求的一组分割方案,直接加入到result中就行。因为我们要的是分割的所有字串都是回文串,当出现一种情况不是回文串是就已经不符合要求。如:abab,当我们开始判断a|ba|b。,startIndex指向b,i指向第二个a,发现ba并不是回文串,就直接跳过当前循环,开始判断bab。

2023-03-06 18:35:50 82

原创 回溯leetcode41.组合总和Ⅱ

这道题区别于之前的几篇文章的是canidates数组中存在相同的数字,这就可能使解集中存在相同的集合,所以这道题主要就是要去重。(剪枝时也会用到),因为如果前后相同的话,后面的数字的所有情况已经包含在它之前的与他相同的数字的所有情况里面了,后面数字的所有情况就不用进行判断了。关于去重,是避免最终的输出解集中出现相同的集合,至于解集的子集中是可以出现相同元素的,而这里的相同只是数字相同,并不是同一个位置的元素。在进行去重前一定要对canidates数组进行升序排列,目的是把相同的数字放在一起。

2023-03-04 15:36:51 28

原创 回溯leetcode39.组合总和

通过上图我们可以看到,当当前层的sum + canidates[i]已经大于target,那么我们就直接跳过该循环,不过这样做的前提是首先要对数组candidates做升序排序。不同的是,这道题允许一个组合中出现重复的数字,其他并无很大差别。如果至少一个数字的被选数量不同,则两种组合是不同的。,并以列表形式返回。中可以使数字和为目标数。对于给定的输入,保证和为。

2023-03-03 12:13:09 17

原创 leetcode17. 电话号码的字母组合(回溯)

此题也是回溯算法的经典题目:与上篇文章“组合”相比较,“组合”是在一个集合中进行组合,而此题目是从两个集合中进行组合。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。的字符串,返回所有它能表示的字母组合。

2023-03-02 22:51:43 25

原创 回溯算法:leetcode77.组合

题目:给定两个整数n和k,返回范围[1, n]中所有可能的k个数的组合。你可以按任何顺序返回答案。

2023-02-21 12:27:58 53

原创 leetcode459. 重复的子字符串Java两行代码实现思路

字符串“abcdabcd”,对“abcd”进行向右第一次移位变成:“bcdabcda”,第二次移位:“cdabcdab”,第三次移位:“dabcdabc”,第四次移位置:“abcdabcd”,我们可以发现在对字符串“abcdabcd”进行了四次移位后,回到了原字符串。主要思想:字符串s如果由某一个子串重复构成,那么对字符串进行一次次的“移位”时,总会有一次会重新移位成原字符串。如果s是由重复子串构建而成的话,那么在str中我们就可以找到原字符串每一次移位后的字符串,可由子串 "ab" 重复两次构成。

2023-02-13 21:09:54 75

原创 KMP字符串匹配算法

给你两个字符串haystack和needle,请你在haystack字符串中找出needle字符串的第一个匹配项的下标(下标从 0 开始)。如果needle不是haystack的一部分,则返回-1。示例 1:输入:输出:0解释:"sad" 在下标 0 和 6 处匹配。第一个匹配项的下标是 0 ,所以返回 0。示例 2:输入:输出:-1解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1。

2023-02-12 16:10:48 70

原创 leetcode151. 反转字符串中的单词

返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。setCharAt()是StringBuffer,StringBuilder类中的方法,不是String类中的。我们可以直接使用Java中的方法split(),reverse(),join() ,trim()可以解决。String.join():第1个参数是分隔符,第2个参数是需要进行拼接的元素,可以是。如果两个单词间有多余的空格,反转后的字符串需要将单词间的空格减少到仅有一个。反转后的字符串中不能存在前导空格和尾随空格。

2023-02-01 22:18:09 134

原创 leetcode541. 反转字符串 II

对题目进行分析,可以总结出字符串翻转规律:每隔2k个字符就翻转前k个字符,并对每次反转的剩余字符进行判断,若剩余字符大于k个,则翻转前k个,反之全部反转。如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。如果i+k小于n,表示剩余的字符大于k个,若n小于i+k,表示剩余字符不足k个。这里很巧妙的利用了reverse(arr , i ,如果剩余字符少于 k 个,则将剩余字符全部反转。,从字符串开头算起,每计数至。

2023-01-31 22:13:51 49

原创 leetcode530. 二叉搜索树的最小绝对差

由于中序遍历后得到的是升序序列,所有我们只需要比较相邻节点的差值即可,用变量min记录,并在中序遍历的过程中对min进行更新即可。我们对二叉搜索树进行中序遍历,每一次遍历用变量pre记录下当前节点值,用于下一次遍历时进行比较。差值是一个正数,其数值等于两值之差的绝对值。树中任意两不同节点值之间的最小差值。遇到二叉搜索树的问题,一般利用。给你一个二叉搜索树的根节点。的特殊性质,能解决大部分问题。其中序遍历是升序序列。

2023-01-05 11:38:15 26

原创 验证二叉搜索树

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

2022-12-26 21:08:33 435

原创 leetcode700. 二叉搜索树中的搜索

题目:给定二叉搜索树(BST)的根节点root和一个整数值val。你需要在 BST 中找到节点值等于val的节点。返回以该节点为根的子树。如果节点不存在,则返回null。

2022-12-24 16:37:35 25

原创 leetcode617.合并二叉树

给你两棵二叉树:root1和root2。想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,null 的节点将直接作为新二叉树的节点。返回合并后的二叉树。合并过程必须从两个树的根节点开始。

2022-12-23 18:27:00 86

原创 leetcode654.最大二叉树

题目: 实现思路:我们需要对原数组不断地进行递归分割,从而来确定左右子树。代码实现:笔者在第一次解答时,由于将 index 初始化为0,导致栈溢出,后初始化 index = left 解决报错。 上述递归法虽然解决了问题,但是在每次递归遍历数组找最大值时存在多次重复遍历,这样实现若是在数据量很大的情况下,时间复杂度很高(O())使用单调栈我们就可以只对数组进行一次遍历的情况下完成最大二叉树的构建。最大二叉树的构建就是在每次的出入栈操作中进行构建。① 当栈顶节点值(topNode)大于

2022-12-21 19:15:29 32

原创 leetcode106.从中序与后序遍历序列构造二叉树

根据后序遍历的特点,我们可以得到postorder数组最后一个元素就是根节点,root = 3,在中序遍历中找到该节点,根据中序遍历的特点就可以找到根节点的左右子树,[9]就是左子树的所有值,[15 , 20 , 7]就是右子树的所有的值。按此思路我们用递归实现时,应该先递归创建右子树,在递归创建左子树。表示当前递归到中序序列中当前子树的左右边界,递归入口为buildTree。中序遍历特点:先遍历左子树,再遍历根节点,最后遍历右子树。后序遍历特点:先遍历左子树,再遍历右子树,最后遍历根节点。

2022-12-20 18:15:57 61

原创 leetcode226.翻转二叉树

题目:第一次做错误思路:想着直接将两边节点进行交换,2和7,1和9,3和6,这种解法实现比较困难,偏于暴力解法正确解法:我们只需将每个节点的左右节点进行交换即可;

2022-12-19 20:34:21 26

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除