- 博客(210)
- 收藏
- 关注
原创 数据流的中位数
新的中位数将小于等于原来的中位数,因此我们可能需要将queMin中最大的数移动到queMax中。新的中位数将大于等于原来的中位数,因此我们可能需要将queMax中最小的数移动到queMin中。当累计添加的数的数量为奇数时,queMin中的数的数量比queMax多一个,此时中位数为queMin的队头。是有序整数列表中的中间值。当累计添加的数的数量为偶数时,两个优先队列中的数的数量相同,此时中位数为它们的队头的平均值。特别地,当累计添加的数的数量为0时,我们将num添加到queMin中。
2025-03-03 20:37:14
215
原创 旋转字符串
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。用空间复杂度为O(1)的原地算法解决这个问题。b.反转区间为n到末尾的子串。c.反转区间为n到末尾的子串。a.反转区间为前n的子串。b.反转区间为前n的子串。
2025-02-10 10:35:06
129
原创 垃圾回收机制
倘若有一处内存区间由于程序员编码的问题忘记被回收,那么就会产生内存泄漏,垃圾对象永远无法被清除,随着系统运行时间的不断增长,垃圾对象所耗内存可能持续上升,直到出现内存溢出并造成应用程序崩溃。如今,垃圾收集几乎成为现代语言的标配,即使经过如此长时间的发展,Java的垃圾收集机制仍然在不断的演进中,不同大小的设备、不同特征的应用场景,对垃圾收集提出了新的挑战,这当然也是面试的热点。如果不及时对内存中的垃圾进行清理,那么,这些垃圾对象所占的内存空间会一直保留到应用程序结束,被保留的空间无法被其他对象使用。
2025-02-09 11:08:29
564
原创 单调栈类型
更直白来说,就是用一个栈来记录我们遍历过的元素,因为遍历数组的时候,不知道之前都遍历了哪些元素,以至于遍历一个元素找不到是不是之前遍历过一个更小的,所以需要用一个容器(这里用单调栈)来记录遍历过的元素。单调栈解决的问题通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时就要想到可以用单调栈。如果求一个元素右边第一个更大元素,单调栈就是递增的,如果求一个元素右边第一个更小元素,单调栈就是递减的。依次从单调栈中弹出多个元素,直到单调栈为空或者栈顶元素大于当前遍历的元素为止。
2025-02-05 15:40:20
226
原创 StringTable
如果放进String Pool的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用String.intern时性能会大幅下降。在jdk6中StringTable是固定的,就是1009的长度,所以如果常量池中的字符串过多就会导致效率下降很快。当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
2025-02-05 12:13:34
175
原创 JVM执行引擎
虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面上的,而虚拟机的执行引擎则是由软件自行实现的,因此可以不受物理条件制约地定制指令集与执行引擎的结构体系,能够执行那些不被硬件直接支持的指令集格式。JVM平台支持一种叫作即时编译的技术。从外观上看,所有的Java虚拟机的执行引擎的输入、输出都是一致的,输入的是字节码二进制流,处理过程是字节码解析执行的等效过程,输出的是执行结果。不同的硬件平台,各自支持的指令,是有差别的。
2025-02-04 12:20:37
754
原创 JVM直接内存
不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。直接内存是在Java堆外的、直接向系统申请的内存区间。通常,访问直接内存的速度会优于Java堆。因此出于性能考虑,读写频繁的场合可能会考虑使用直接内存。Java的NIO库允许Java程序使用直接内存,用于数据缓冲区。由于直接内存在Java堆外,因此它的大小不会直接受限于-Xmx指定的最大堆大小,但是系统内存是有限的,Java堆和直接内存的总和依然受限于操作系统能给出的最大内存。缺点是分配回收成本较高,不受JVM内存回收管理。
2025-02-03 10:44:35
234
原创 对象的实例化、内存布局与访问定位
意思是虚拟机维护了一个列表,记录上哪些内存块是可用的,再分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的内容。把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲区(TLAB,ThreadLocalAllocation Buffer)虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来设定。将对象的所属类(即类的元数据信息)、对象的Hashcode和对象的GC信息、锁信息等数据存储在对象的对象头中。
2025-02-02 11:04:50
831
原创 JVM方法区
尽管所有的方法区在逻辑上属于堆的一部分,但是一些简单的实现可能不会去进行垃圾收集或者进行压缩,方法区可以看作是一块独立于Java堆的内存空间。方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误。方法区在JVM启动的时候被创建,并且它的实际的物理内存空间中和Java堆区一样都可以是不连续的。方法区(Method Area)与Java堆一样,是各个线程共享的内存区域。方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展。
2025-01-30 12:08:12
578
原创 JVM堆空间
所有的线程共享Java堆,在这里还可以划分线程私有的缓冲区(ThreadLocal Allocation Buffer,TLAB)。Java堆区在JVM启动的时候即被创建,其空间大小也就确定了。是JVM管理的最大一块内存空间。堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。一个JVM实例只存在一个堆内存,堆也是Java内存管理的核心区域。堆内存的大小是可以调节的。
2025-01-25 00:07:56
567
原创 本地方法接口
例如类java.lang.Thread的setPriority()方法是用Java实现的,但是它实现调用的是该类里的本地方法setPriority()。通过使用本地方法,我们得以用Java实现了jre的与底层系统的交互,甚至JVM的一些部分就是用c写的。如果本地方法栈可以动态扩展,并且在尝试扩展的时候无法申请到足够的内存或者在创建新的线程时没有足够的内存去创建对应的本地方法栈,那么Java虚拟机将会抛出一个OutOfMemoryError 异常。本地方法栈,也是线程私有的。本地方法是使用C语言实现的。
2025-01-24 23:53:02
515
原创 动态规划解决子序列问题
给你一个整数数组nums ,找到其中最长严格递增子序列的长度。子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如[3,6,2,7] 是数组[0,3,1,6,2,2,7] 的子序列。位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列 + 1 的最大值。这里采用一维dp数组的形式,数组的长度为整数数组nums的长度,其中每个元素。dp[i]是有0到i-1各个位置的最长递增子序列 推导而来,那么遍历。注意不是要dp[i]与dp[j] + 1进行比较,而是。
2025-01-21 17:47:50
292
原创 JVM虚拟机栈
如果采用固定大小的Java虚拟机栈,那每一个线程的Java虚拟机栈容量可以在线程创建的时候独立选定。Java虚拟机栈早期叫做Java栈,每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个的栈帧,对应着一次次方法调用。生命周期和线程一致;由于跨平台的设计,Java的指令都是根据栈来设计的,不同平台的CPU架构不同,所以不能设计为基于寄存器的。如果Java虚拟机栈可以动态扩展,并且在尝试扩展的时候无法中请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的虚拟机栈,那Java虚拟机将会抛出一个。
2025-01-17 21:07:09
201
原创 程序计数器(PC寄存器)
由于CPU时间片轮限制,众多线程在并发执行过程中,任何一个确定的时刻,一个处理器或者多核处理器中的一个内核,只会执行某个线程中的一条指令。它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。在JVM规范中,每个线程都有它自己的程序计数器,是线程私有的,生命周期与线程的生命周期保持一致。
2025-01-17 20:32:31
418
原创 运行时数据区概述及线程
Java虚拟机定义了若干种程序运行期间会使用到的运行时数据区,其中有一些会随着虚拟机启动而创建,随着虚拟机退出而销毁,另外一些则是与线程一一对应的,这些与线程对应的数据区域会随着线程开始和结束而创建和销毁。在HotSpot JVM里,每个线程都与操作系统的本地线程直接映射,当一个Java线程准备好执行以后,此时一个操作系统的本地线程也同时创建,Java线程执行终止后,本地线程也会回收。操作系统负责所有线程的安排调度到任何一个可用的CPU上,一旦本地线程初始化成功,他就会调用Java线程中的run()方法。
2025-01-16 20:29:08
235
原创 最佳股票买卖时机问题
其中,对于dp[i][1],由于其表示的是第i天不持有股票所能获得的最大利润,因此其有两种推导方法,第一种是保持第i-1天的状态,也就是第i-1天不持有股票,第i天同样不持有股票而不购入,此时对应的值为dp[i-1][1];其中,对于dp[i][0],由于其表示的是第i天持有股票所能获得的最大利润,因此其有两种推导方法,第一种是保持第i-1天的状态,也就是第i-1天持有股票,第i天同样持有股票而不售出,此时对应的值为dp[i-1][0];对于每一天i,需要有dp[i][0]和dp[i][1]需要获得。
2025-01-16 16:09:17
416
原创 打家劫舍问题
从第i个房屋中获得现金,此时需要该房屋的前一个房屋不能被偷盗,因此获得的金额为dp[i - 2] + nums[i],也就是第i-1房一定是不考虑的,找出下标i-2(包括i-2)以内的房屋,最多可以偷窃的金额为dp[i-2] 加上第i房间偷到的钱。dp数组的长度为房屋数组的长度,其中每个元素dp[i]表示考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]如果不偷第i房间,那么dp[i] = dp[i - 1],即考虑i-1房,(注意这里是考虑,并不是一定要偷i-1房。这个地方所有的房屋都。
2025-01-15 19:53:40
383
原创 JVM相关面试题
JavaVirtualMachine,Java的运行环境(java二进制字节码的运行环境);一次编写、到处运行;自动管理内存,提供垃圾回收机制。程序计数器是线程私有的,内部保存的字节码行号,用于记录正在执行的字节码指令的地址。
2025-01-15 11:46:20
497
原创 类加载子系统
初始化阶段就是执行类构造器方法()的过程,此方法不需要定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来;()不同于类的构造器,若该类具有父类,则JVM会保证子类的()执行前父类的()已经执行完毕。加载的类信息存放于一块称为方法区的内存空间。符号引用就是一组符号来描述所引用的目标,符号引用的字面量形式明确定义在Class文件格式中,直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。
2025-01-14 19:04:20
325
原创 动态规划解决单词拆分问题
这里采用一维数组的形式,其中数组长度为目标字符串s的长度+1,其中每个元素dp[i]表示字符串长度为i的话,dp[i]为true则可以拆分为一个或多个在字典中出现的单词。dp[i]的状态依靠dp[j]是否为true,那么dp[0]就是递推的根基,dp[0]一定要为true,否则递推下去后面都都是false。如果确定dp[j]是true,且[j, i]这个区间的子串出现在字典里,那么dp[i]一定是true。对于dp数组中的每个位置的元素dp[i]来说,其值取决于前面的元素dp[j]
2025-01-14 14:43:45
267
原创 动态规划解决零钱兑换问题
采用一维数组的形式,其中数组长度为amount+1,数组中的每个元素dp[j]表示凑足总额为j所需钱币的最少个数为dp[j],否则就会在min(dp[j - coins[i]] + 1, dp[j])比较的过程中被初始值覆盖。所以dp[j]要取所有dp[j - coins[i]] + 1中最小的。首先凑足总金额为0所需钱币的个数一定是0,那么dp[0] = 0;每种硬币的数量是无限的,可以看出是典型的完全背包问题。dp问题求解最大值:dp[j]初始化为最小值。就是dp[j](考虑coins[i])
2025-01-13 20:54:19
274
原创 动态规划解决组合总和问题IV
因为递推公式dp[i] += dp[i - nums[j]]的缘故,dp[0]要初始化为1,这样递归其他dp[i]的时候才会有数值基础。dp[i](考虑nums[j])可以由dp[i - nums[j]](不考虑nums[j])推导出来。因为只要得到nums[j],排列个数dp[i - nums[j]],就是dp[i]的一部分。其余下标的元素初始化为0,这样才不会影响dp[i]累加所有的dp[i - nums[j]]这里采用一维数组的形式,其中dp[i]表示凑成目标正整数为i的排列个数为dp[i]
2025-01-10 14:16:52
340
原创 动态规划解决完全背包问题
第i件物品的重量是weight[i],得到的价值是value[i]。放物品i,背包需要空出物品i的容量,此时背包容量为j - weight[i],dp[i][j - weight[i]] 为背包容量为。dp[i][j]表示从下标为[0-i]的物品,每个物品可以取无限次,放进容量为j的背包,价值总和最大是多少。其中,对于第一列元素,由于此时的背包容量为0,因此无法装入物品,所以第一列的元素均为0。不放物品i,此时背包容量为j,里面不放物品i的最大价值是dp[i - 1][j]需要初始化第一行和第一列。
2025-01-09 22:01:22
362
原创 动态规划解决零和一问题
因此递推公式为:dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);字符串的zeroNum和oneNum相当于物品的重量(weight[i]),字符串本身的个数相当于物品的价值(value[i])dp[i][j]可以由前一个strs里的字符串推导出来,strs里的某一个字符串有zeroNum个0,oneNum个1。dp[i][j]:最多有i个0和j个1的strs的最大子集的大小为dp[i][j]在遍历的过程中,取dp[i][j]的最大值。
2025-01-09 12:01:10
234
原创 动态规划解决目标和问题
可以将数组分为两部分,其中一部分记作left,其中数字的符号全为+,而另外一部分记作right,其中数字的符号全为-。这里全为-的意思不是真正的符号为-,而表示这一堆数字在计算时取值为负left + right = sum,其中sum为数组和left - right = target,其中target为目标值可以得出left = (sum + target) / 2因此原问题转换为在集合nums中找出和为left的组合共有多少种也就是用nums装满容量为x的背包,有几种方法。
2025-01-07 21:45:28
898
原创 动态规划局解决分割等和子集问题
如果背包所载重量为target, dp[target]就是装满 背包之后的总价值,因为本题中每一个元素的数值既是重量,也是价值,所以当dp[target] == target的时候,背包就装满了。这里采用一维数组,dp[j]表示容量(所能装的重量)为j的背包所背的物品价值最大可以为dp[j]当数字可以装满承载重量为sum / 2的背包的背包时,这个背包的价值也是sum / 2。既有一个只能装重量为sum / 2的背包,商品为数字,这些数字能不能把这个背包装满。一个数字只有一个维度,即重量等于价值。
2025-01-06 20:37:37
351
原创 动态规划解决0-1背包问题
如果j>=weight[i],则dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-weight[i]+value[i]);对于第一行来说,判断背包的容量是否能装入第0件物品,如果可以,则该位置的值为第0件物品的值,否则为0。其中,对于第一列来说,由于此时背包的容量为0,因此无法装入物品,所以第一列的值都为0。否则不能装入第i件物品,此时dp[i][j] = dp[i-1][j]此时背包容量为j,里面不放物品i的最大价值是dp[i - 1][j]的容量后,背包容量为。
2025-01-03 14:53:34
307
原创 Java多线程
很多多线程是模拟出来的,真正的多线程是指有多个CPU,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点cpu只能执行一个代码,因为切换的很快所有就有同时执行的错觉。在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的。通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义,线程是CPU调度和执行的单位。进程则是执行程序的一次执行过程,它是一个动态的概念,是系统资源分配的单位;
2025-01-02 22:46:21
1078
原创 动态规划解决不同的二叉搜索树问题
所以dp[3] = dp[2] * dp[0] + dp[1] * dp[1] + dp[0] * dp[2],当根节点为j时,它的左子树只能包含j-1个节点,而右子树包含i-j个节点。从定义上来讲,空节点也是一棵二叉树,也是一棵二叉搜索树,这是可以说得通的。也可以理解是i个不同元素节点组成的二叉搜索树的个数为dp[i]dp[i]:1到i为节点组成的二叉搜索树的个数为dp[i]有2个元素的搜索树数量就是dp[2]。有1个元素的搜索树数量就是dp[1]。有0个元素的搜索树数量就是dp[0]。
2025-01-02 20:58:09
327
原创 动态规划解决整数拆分问题
注意这里在确定dp[i]时从1到i遍历j时更新dp[i]需要比较三个内容,分别是原始的dp[i],j*(i-j)以及j*dp[i-j],取这三个数的最大值更新dp[i],从dp[i]的定义来说,拆分数字2,得到的最大乘积是1,这个没有任何异议。j的结束条件是 j < i - 1 ,其实 j < i 也是可以的。遍历i一定是从前向后遍历,先有dp[i - j]再有dp[i]dp[i]:分拆数字i,可以得到的最大乘积为dp[i]其实可以从1遍历j,然后有两种渠道得到dp[i].严格从dp[i]的定义来说,
2025-01-02 20:36:51
536
原创 动态规划解决步骤
5.返回最终结果,如果中途出现错误可以将dp数组打印出来。1.确定dp数组的含义,以及确定dp数组的大小和维度。4.确定遍历顺序,遍历dp数组并进行赋值。2.确定问题中的递推公式。
2025-01-01 15:05:30
389
原创 多线程相关面试题
程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存。进程就是用来加载指令、管理内存、管理 IO的。当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给CPU执行。不同的进程使用不同的内存空间,在当前进程下的所有线程可以共享内存空间。进程是正在运行的程序实例,进程中包含了线程,每个线程执行不同的任务。线程更轻量,线程上下文切换成本一般比进程上下文切换低。一个进程可以分为一到多个线程。
2024-12-31 14:01:42
298
原创 贪心算法解决单调递增数字问题
从后遍历数字中的每一位,如果遍历到第i位数字时它的前一位数字比它大(严格大于),令它前一位数字减1,同时令flag=i。遍历结束后,令该数字的第flag位及其之后的全部数字都变成9。定义一个变量flag,表示需要将之后的数字全部变成9的位置。最后返回最终的数字即可。
2024-12-27 15:39:54
678
原创 贪心算法解决监控二叉树问题
如果该节点不为空,依次获取该节点的左子结点的状态和右子节点的状态。如果左子结点和右子节点有一个节点的状态为无覆盖(0),那么令count++,同时在该节点处安装一个摄像头,返回1;为了让摄像头数量最少,我们要尽量让叶子节点的父节点安装摄像头,这样才能摄像头的数量最少。那么空节点不能是无覆盖的状态,这样叶子节点就要放摄像头了,空节点也不能是有摄像头的状态,这样叶子节点的父节点就没有必要放摄像头了,而是可以把摄像头放在叶子节点的爷爷节点上。所以把摄像头放在叶子节点的父节点位置,才能充分利用摄像头的覆盖面积。
2024-12-27 15:35:46
412
原创 划分字母区间
设置一个left变量和right变量,分别表示区间的左端点和右端点。从头遍历一遍字符串,并更新右端点,right = max(right,a[s.charAt(i)-'a'])为字符的最远出现下标,如果找到字符最远出现位置下标和当前下标相等,则找到了分割点。此时结果数组增加(right-left+1),同时更新left = right。遍历一遍字符串,统计每一个字符最后出现的位置。可以预先设置一个大小为26的数组,其中每个位置的元素代表该位置的小写字母最后出现的位置。
2024-12-25 14:42:46
240
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人