自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 刷题之Leetcode242题(超级详细)

需要定义一个多大的数组呢,定一个数组叫做record,大小为26 就可以了,初始化为0,因为字符a到字符z的ASCII也是26个连续的数值。那看一下如何检查字符串t中是否出现了这些字符,同样在遍历字符串t的时候,对t中出现的字符映射哈希表索引上的数值再做-1的操作。,而且这道题目中字符串只有小写字符,那么就可以定义一个数组,来记录字符串s里字符出现的次数。时间复杂度为O(n),空间上因为定义是的一个常量大小的辅助数组,所以空间复杂度为O(1)。这样就将字符串s中字符出现的次数,统计出来了。

2024-04-23 22:36:57 595

原创 刷题之Leetcode142题(超级详细)

可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。其实这种情况和n为1的时候 效果是一样的,一样可以通过这个方法找到 环形的入口节点,只不过,index1 指针在环里 多转了(n-1)圈,然后再遇到index2,相遇点依然是环形的入口节点。为什么fast 走两个节点,slow走一个节点,有环的话,一定会在环内相遇呢,而不是永远的错开呢。

2024-04-23 15:56:43 677

原创 刷题之Leetcode160题(超级详细)

此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到交点。给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null。这里兄弟们要注意,交点不是数值相等,而是指针相等。为了方便举例,假设节点元素数值相等,则节点指针相等。注意,函数返回结果后,链表必须 保持其原始结构。力扣题目链接(opens new window)简单来说,就是求两个链表交点节点的。

2024-04-22 09:06:07 364

原创 JVM之本地内存以及元空间,直接内存的详细解析

虚拟机内存:Java 虚拟机在执行的时候会把管理的内存分配成不同的区域,受虚拟机内存大小的参数控制,当大小超过参数设置的大小时就会报 OOM又叫做堆外内存,线程共享的区域,本地内存这块区域是不会受到 JVM 的控制的,不会发生 GC;因此对于整个 Java 的执行效率是提升非常大,但是如果内存的占用超出物理内存的大小,同样也会报 OOM。

2024-04-18 23:46:54 317

原创 JVM之方法区的详细解析

2.运行时常量池(Java6之前常量池存放在方法区(永久代中),Java7中将常量池存放在了堆中,Java8之后将运行时常量池和静态常量池存放在元空间中,字符串常量池依然存放在堆中)1.8将这个字符串尝试放入串池,如果有则不会放入,如果没有则放入串池,会把串池中的对象返回(无论有没有都会返回),这个放入是创建一个引用,引用的地址就是这个对象的地址。常量池(编译器生成的字面量和符号引用)中的数据会在类加载的加载阶段放入运行时常量池。运行时常量池是方法区的一部分(一般所说的常量池实际上就是指运行时常量池)

2024-04-17 23:05:33 586

原创 刷题之Leetcode19题(超级详细)

双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。首先这里我推荐大家使用虚拟头结点,这样方便处理删除实际头结点的逻辑,如果虚拟头结点不清楚,可以先去看一看这一篇。给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。输入:head = [1,2], n = 1 输出:[1]力扣题目链接(opens new window)进阶:你能尝试使用一趟扫描实现吗?思路是这样的,但要注意一些细节。

2024-04-17 15:41:02 706

原创 JVM之本地方法栈和程序计数器和堆

在 Eden 区变满的时候,GC 就会将存活的对象移到空闲的 Survivor 区间中,根据 JVM 的策略,在经过几次垃圾回收后,仍然存活于 Survivor 的对象将被移动到 Tenured 区间。Tenured 区主要保存生命周期长的对象,一般是一些老的对象,当一些对象在 Young 复制转移一定的次数以后,对象就会被转移到 Tenured 区。分代原因:不同对象的生命周期不同,70%-99% 的对象都是临时对象,优化 GC 性能。jconsole:图形界面的,多功能的监测工具,可以连续监测。

2024-04-16 23:13:42 863

原创 JVM之JVM栈的详细解析

基于栈式架构的虚拟机使用的零地址指令更加紧凑,完成一项操作需要使用很多入栈和出栈指令,所以需要更多的指令分派(instruction dispatch)次数和内存读/写次数,由于操作数是存储在内存中的,因此频繁地执行内存读/写操作必然会影响执行速度,所以需要栈顶缓存技术。的,如果一个局部变量过了其作用域,那么之后申明的新的局部变量就可能会复用过期局部变量的槽位,从而达到节省资源的目的。操作数栈:在方法执行过程中,根据字节码指令,往栈中写入数据或提取数据,即入栈(push)或出栈(pop)

2024-04-15 23:33:15 984

原创 刷题之Leetcode24题(超级详细)

建议使用虚拟头结点,这样会方便很多,要不然每次针对头结点(没有前一个指针指向头结点),还要单独处理。你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。力扣题目链接(opens new window)对虚拟头结点的操作,还不熟悉的话,可以看这篇。接下来就是交换相邻两个元素了,这道题目正常模拟就可以了。

2024-04-15 09:23:52 342

原创 刷题之Leetcode206题(超级详细)

关键是初始化的地方,可能有的同学会不理解, 可以看到双指针法中初始化 cur = head,pre = NULL,在递归法中可以从如下代码看出初始化的逻辑也是一样的,只不过写法变了。为什么要保存一下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。递归法相对抽象一些,但是其实和双指针法是一样的逻辑,同样是当cur为空的时候循环结束,不断将cur指向pre的过程。

2024-04-14 22:59:41 594

原创 JVM之JVM的基本介绍

JVM:全称 Java Virtual Machine,即 Java 虚拟机,一种规范,本身是一个虚拟计算机,直接和操作系统进行交互,与硬件不直接交互,而操作系统可以帮我们完成和硬件进行交互的工作特点:Java 虚拟机基于二进制字节码执行,由一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆、一个方法区等组成JVM 屏蔽了与操作系统平台相关的信息,从而能够让 Java 程序只需要生成能够在 JVM 上运行的字节码文件,通过该机制实现的跨平台性。

2024-04-13 22:50:45 928

原创 刷题之Leetcode707题(超级详细)

可以说这五个接口,已经覆盖了链表的常见操作,是练习链表操作非常好的一道题目。下面采用的设置一个虚拟头结点(这样更方便一些,大家看代码就会感受出来)。力扣题目链接(opens new window)

2024-04-10 15:29:40 522

原创 刷题之Leetcode203题(超级详细)

这样移除了一个头结点,是不是发现,在单链表中移除头结点 和 移除其他节点的操作方式是不一样,其实在写代码的时候也会发现,需要单独写一段逻辑来处理移除头结点的情况。那么因为单链表的特殊性,只能指向下一个节点,刚刚删除的是链表的中第二个,和第四个节点,那么如果删除的是头结点又该怎么办呢?移除头结点和移除其他节点的操作是不一样的,因为链表的其他节点都是通过前一个节点来移除当前节点,而头结点没有前一个节点。来看一下,如何移除元素1 呢,还是熟悉的方式,然后从内存中删除元素1。依然还是在这个链表中,移除元素1。

2024-04-10 14:44:37 947

原创 刷题之Leetcode54题(超级详细)

给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]相同的地方是:从右向左遍历行和从下向上遍历列的终止条件都是大于遍历起点start。输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]输出:[1,2,3,4,8,12,11,10,9,5,6,7]中间行或中间列的位置mid = 行和列中的最小值除以二的值。输出:[1,2,3,6,9,8,7,4,5]

2024-04-08 15:47:35 581

原创 刷题之Leetcode59题(超级详细)

这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。代码如下,已经详细注释了每一步的目的,可以看出while循环里判断的情况是很多的,代码里处理的原则也是统一的左闭右开。可以发现这里的边界条件非常多,在一个循环中,如此多的边界条件,如果不按照固定规则来遍历,那就是。就是因为在画每一条边的时候,一会左开右闭,一会左闭右闭,一会又来左闭右开,岂能不乱。这道题目可以说在面试中出现频率较高的题目,由外向内一圈一圈这么画下去。

2024-04-08 09:50:26 1086

原创 java流式计算Stream

下面的代码中,需求是要把list集合中的元素全部变成乘以2,就需要使用map的stream流式计算方法,map接受的是一个JDK提供的,Function接口,所以lambda实现方法时需要一个返回值,一个参数。是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。相反,他们会返回一个持有结果的新Stream。Stream操作是延迟执行的。偶数工D且年龄大于24且用户名转为大写且用户名字母倒排序。map----映射(将元素映射成另外的元素)collect----stream转list。

2024-04-07 23:03:36 199

原创 刷题之Leetcode844题(超级详细)

844. 比较含退格的字符串https://leetcode.cn/problems/backspace-string-compare/给定 和 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 。 代表退格字符。注意:如果对空文本输入退格字符,文本继续为空。示例 1:输入:s = "ab#c", t = "ad#c"输出:true解释:s 和 t 都会变成 "ac"。示例 2:输入:s = "ab

2024-04-06 22:08:21 681

原创 刷题之Leetcode283题(超级详细)

这道题目,使用暴力的解法,可以两层for循环,模拟数组删除元素(也就是向前覆盖)的过程。双指针法在数组移除元素中,可以达到O(n)的时间复杂度,里已经详细讲解了,那么本题和移除元素其实是一个套路。移动到数组的末尾,同时保持非零元素的相对顺序。,必须在不复制数组的情况下原地对数组进行操作。做这道题目之前,大家可以做一做。,编写一个函数将所有。

2024-04-06 22:02:47 446

原创 刷题之Leetcode209题(超级详细)

不要以为for里放一个while就以为是O(n^2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。在暴力解法中,是一个for循环滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环 完成了一个不断搜索区间的过程。窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。所以 只用一个for循环,那么这个循环的索引,一定是表示 滑动窗口的终止位置。

2024-04-06 21:55:58 1030

原创 刷题之Leetcode977题(超级详细)

做题的时候自己能分析出来时间复杂度就可以了,至于leetcode上执行用时,大概看一下就行,只要达到最优的时间复杂度就可以了,给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。此时的时间复杂度为O(n),相对于暴力排序的解法O(n + nlog n)还是提升不少的。定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。

2024-04-05 22:59:27 268

原创 刷题之Leetcode27题(超级详细)

示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。很多兄弟这道题目做的很懵,就是不理解 快慢指针究竟都是什么含义,所以一定要明确含义,后面的思路就更容易理解了。元素的顺序可以改变。有的同学可能说了,多余的元素,删掉不就得了。

2024-04-05 21:23:38 785

原创 刷题之Leetcode34题(超级详细)

力扣链接(opens new window)给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。进阶:你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?输入:nums = [5,7,7,8,8,10], target = 8输出:[3,4]输入:nums = [5,7,7,8,8,10], target = 6输出:[-1,-1]

2024-04-04 22:47:17 704

原创 刷题之Leetcode35题(超级详细)

希望通过这道题目,大家会发现平时写二分法,为什么总写不好,就是因为对区间定义不清楚。确定要查找的区间到底是左闭右开[left, right),还是左闭又闭[left, right],这就是不变量。然后在二分查找的循环中,坚持循环不变量的原则,很多细节问题,自然会知道如何处理了。t=N7T8力扣题目链接(opens new window)https://leetcode.cn/problems/search-insert-position/

2024-04-04 21:36:07 1289

原创 刷题之Leetcode704题(超级详细)

二分法是非常重要的基础算法,为什么很多同学对于二分法都是一看就会,一写就废?其实主要就是对区间的定义没有理解清楚,在循环中没有始终坚持根据查找区间的定义来做边界处理。区间的定义就是不变量,那么在循环中坚持根据查找区间的定义来做边界处理,就是循环不变量规则。本篇根据两种常见的区间定义,给出了两种二分法的写法,每一个边界为什么这么处理,都根据区间的定义做了详细介绍。相信看完本篇应该对二分法有更深刻的理解了。

2024-04-04 21:18:18 961

原创 并发编程之线程池的应用以及一些小细节的详细解析

可以给出一些关键的参数来自定义。在下面的代码中可以看到,该线程池的最大并行线程数是5,线程等候区(阻塞队列)是3,即该线程池最多接受8个线程任务的同时提交。一旦超过了8这个任务数,就会抛出java.util.concurrent.RejectedExecutionException。

2024-04-03 23:02:57 476

原创 并发编程之线程池的底层原理的详细解析

2.3如果这个时候队列满了且正在运行的线程数量还小于maximumPoolSize,那么还是要创建非核心线程立刻运行这个任 务;2.4如果队列满了且正在运行的线程数量大于或等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行。如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉。2.1如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务;2.2如果正在运行的线程数量大于或等corePoolSize,那么将这个任务放入队列;

2024-04-02 23:06:41 510

原创 并发编程之线程池的详细解析

线程池的优势: 线程池做的工作只要是控制运行的线程数量,处理过程中将任务放入队列,然后线程创建石后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会销耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。模拟各个线程排队过来执行任务,线程池只需要开辟一个线程就正好可以一个一个执行任务。模拟各个线程同时过来执行任务,线程池同时创建五个线程来执行任务。

2024-04-01 23:42:22 189

原创 并发编程之BlockingQueue(阻塞队列)的详细解析

抛出异常(插入时队满,或移除时队空 抛出异常 IllegalStateException:Queue full 或 NoSuchElementExcept)超时(插入或移除失败时,会阻塞等待,等待队列有空位或者有元素,但是可以设置具体超时等待时间)ArrayBlockingQueue用于解决多线程问题:生产者消费者案例。阻塞(插入或移除失败时,会阻塞等待,等待队列有空位或者有元素)特殊值(插入或移除失败时,返回特殊值:null或false)对于这个队列的操作,给出三种操作方法: 插入、移除、检查。

2024-03-31 23:10:05 185

原创 并发编程之读写锁ReadWriteLock的详细解析(带小案例)

lock锁,只允许一个进程进行读/写。同一时间只允许一个线程写。

2024-03-30 23:37:00 197

原创 并发编程之CountDownLatch和CyclicBarrier的详细解析(带小案例)

和上面的CountDownLatch(做减法倒计时开始任务)不同,CyclicBarrier是做加法来开始任务的。CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会阻塞。其它线程调用countDown方法会将计数器减1(调用countDown方法的线程不会阻塞),当计数器的值变为o时,因await方法阻塞的线程会被唤醒,继续执行。---------------------(循环屏障)解决方法:使用CountDownLatch。

2024-03-29 23:50:48 437

原创 并发编程之Callable方法的详细解析(带小案例)

原生Thread多次执行start会抛出IllegalThreadStateException非法的线程状态异常,Callable也是。使用callable就相当于另外开了一条线程运行,调用get方法就相当于要获取这条线程的运行结果。运行结果:(可以看到 只执行了一次come in的输出,即call()这个方法的代码只运行了一次)callable多次运行,只会计算一次结果。Callable与Runnable的区别。(第三种线程实现方式)

2024-03-28 23:05:41 491

原创 并发编程之的HashSet和HashMap的详细解析

在下面的demo中,hashset在多线程情况下和arrayList一样会抛出java.util.ConcurrentModificationException。HashMap同上面两个类一样,在多线程情况下会出现并发修改异常java.util.ConcurrentModificationException。HashSet也是线程不安全的,底层没有进行任何线程同步处理。使用HashMap空参构造,其初始容量是16,负载因子0.75。:使用ConcurrentHashMap。

2024-03-27 23:10:22 240

原创 并发编程之的ArrayList安全性的详细解析

往一个容器添加元素的时候,不直接往当前容涨object[]添加,而是先将当前容器 object[ ]进行copy,复制出一个新的容器object[ ] newELements,然后新的容器object[ ] newELements里添加元素,添加 完元素之后, 再将原容器的引用指向新的容器setArray(newELements);所以Copyonwdrite容器也是一种读写分离的思想,读和写不同的容器。CopyOnWriteArrayList 利用的是读写分离的思想,读和写的是不同的容器。

2024-03-26 23:09:27 284

原创 并发编程之的虚假唤醒和精准唤醒的详细解析

当线程成功进入if语句块中,发生了中断,cpu跑去调度别的进程了,再次调度这个线程的时候,应该需要再经历一次if的判断,但是并没有这样做。下面这个例子中,一共创建了三个Condition,可以根据业务对这三个Condition依次唤醒。来达到精准唤醒的功能。wait()是object类自带的方法,在jdk有介绍,有可能出现中断、虚假唤醒。按照jdk文档的指示,应该将if换成while。,而不是像notifyAll那样唤醒全部线程。也就是在下面的例子中。

2024-03-25 23:36:36 160

原创 并发编程之的await和signal等方法的详细解析

wait()是Object超类中的方法,而await()是ConditionObject类里面的方法.使用位置不同,wait只能在同步代码块或同步控制块中使用,而sleep可以在任何位置使用。==所在的超类不同使用场景也不同,wait一般用于Synchronized中,而await。都是线程同步时会用到的方法,使当前线程暂停运行,把机会交给其他线程。对锁的持有不同,wait()会释放锁,而sleep()并不释放锁。await会导致当前线程被阻塞,会释放锁,这点和wait是一样的。

2024-03-24 22:55:28 387

原创 并发编程之Java 对象头的详细解析

64 位虚拟机 Mark Word。其中 Mark Word 结构为。以 32 位虚拟机为例。

2024-03-23 23:15:01 154

原创 并发编程之一些多线程习题的详细解析

注意只将对count进行修改的一行代码用synchronized括起来也不行。对count大小的判断也必须是为原子操作的一部分,否则也会导致count值异常。将transfer方法的方法体用同步代码块包裹,将当Account.class设为锁对象。两段没有前后因果关系的临界区代码,只需要保证各自的原子性即可,不需要括起来。不行,因为sellCount会被多个线程共享,必须使用线程安全的实现类。不行,因为不同线程调用此方法,将会锁住不同的对象。另外,用下面的代码行不行,为什么?这样改正行不行,为什么?

2024-03-22 23:21:08 267

原创 并发编程之常见线程安全类以及一些示例的详细解析

StringIntegerRandomVectorHashtablejava.util.concurrent 包下的类这里说它们是线程安全的是指,多个线程调用它们同一个实例的某个方法时,是线程安全的。也可以理解为它们的每个方法是原子的但注意它们多个方法的组合不是原子的,见后面分析分析下面代码是否线程安全?

2024-03-21 23:56:59 296

原创 并发编程之变量的线程安全分析的详细解析

方法访问修饰符带来的思考,如果把 method2 和 method3 的方法修改为 public 会不会代理线程安全问题?情况2:在 情况1 的基础上,为 ThreadSafe 类添加子类,子类覆盖 method2 或 method3 方法,每个线程调用 test1() 方法时局部变量 i,会在每个线程的栈帧内存中被创建多份,因此不存在共享。无论哪个线程中的 method2 引用的都是同一个对象中的 list 成员变量。如果该对象没有逃离方法的作用访问,它是线程安全的。如果它们没有共享,则线程安全。

2024-03-20 23:44:23 399

原创 并发编程之synchronized的详细解析

本次课使用阻塞式的解决方案:synchronized,来解决上述问题,即俗称的【对象锁】,它采用互斥的方式让同一 时刻至多只有一个线程能持有【对象锁】,其它线程再想获取这个【对象锁】时就会阻塞住。这样就能保证拥有锁 的线程可以安全的执行临界区内的代码,不用担心线程上下文切换。synchronized 实际是用对象锁保证了临界区内代码的原子性,临界区内的代码对外是不可分割的,不会被线程切 换所打断。情况3:3 1s 12 或 23 1s 1 或 32 1s 1。情况2:1s后12,或 2 1s后 1。

2024-03-19 23:13:15 626

面试必会Java基础篇

这是Java面试的一些基础必会的内容,适合想找工作的基础不太好的人来看.这份Java面试复习体系总结包含了Java基础篇必须掌握的内容,内容十分真实,所有的面试题目都不是一成不变的,特别是像一线大厂,面试题只是给大家一个借鉴作用,最主要的是给自己增加知识的储备,有备无患。行业浮浮沉沉,希望能帮助大家提升面试复习效率找到一个更好的工作!

2023-09-08

空空如也

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

TA关注的人

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