- 1.虚拟内存的实现原理
- 2.项目用到的redis cache?作用是什么?
- 3.redis cache会有什么问题?
- 4.保证Redis与MySQL的一致性
- 5.进程线程的区别
- 6.算法:题目:给定一个字符串s,一个Set< Character>,然后说在s中找到最短的substring,包含所有Set< Character>里面的字符:滑动窗口
1.虚拟内存的实现原理
- 虚拟内存的实现原理涉及到操作系统的内存管理和硬件的支持。它是一种在内存管理中的抽象技术,将物理内存分为多个独立的区域,并为每个区域分配一个唯一的虚拟地址。
- 具体来说,虚拟内存将进程使用的内存分为多个页面(通常为4KB或8KB),每个页面都有一个唯一的虚拟地址。当进程需要访问某个页面时,操作系统会检查该页面是否已经在物理内存中,如果已经在内存中,则直接访问该页面;如果不在内存中,则操作系统会将该页面从磁盘上的虚拟内存中读取到内存中,并将其映射到进程的虚拟地址空间中。
- 虚拟内存不仅仅简单地存放进程的一部分并且与内存可以互相交换。它还涉及到许多复杂的机制和算法,例如页面置换算法、页面预读技术、页面共享技术等,以提高系统的性能和效率。
- 同时,虚拟内存也是操作系统中非常重要的一部分,它为多任务操作系统的正常运行提供了必要的支持。
2.项目用到的redis cache?作用是什么?
- 提高性能:Redis Cache位于内存中,因此访问速度比磁盘存储更快。当应用程序需要读取或写入大量数据时,使用Redis可以提高性能。
- 缓存热点数据:如果应用程序有大量数据,但不是所有的数据都被频繁访问,那么Redis可以用来缓存这些热点数据。当数据被访问时,它可以从Redis中快速获取,而不是从磁盘中读取。
- 实现分布式缓存:Redis是跨平台的,可以在多个服务器之间进行复制。因此,它可以用作分布式缓存,提供数据的一致性。
- 持久化存储:虽然Redis主要作为内存数据结构存储,但它也支持将数据持久化到磁盘。这可以防止在系统崩溃时丢失数据。
- 支持丰富的数据结构和操作:Redis支持多种数据结构,并提供了丰富的操作来处理这些数据结构。这使得Redis不仅仅是一个简单的缓存解决方案,还可以用作数据库和消息代理。
3.redis cache会有什么问题?
在使用Redis Cache时,需要注意以下几点:
- 内存限制:由于Redis数据存储在内存中,因此需要注意内存限制。如果数据量太大,可能会导致内存溢出。
- 数据一致性:在多个服务器之间复制数据时,需要考虑数据的一致性问题。
- 过期策略:需要设定合理的过期策略,以避免数据长期占用内存。
- 连接管理:需要管理好与Redis服务器的连接,避免频繁创建和关闭连接。
4.保证Redis与MySQL的一致性
- 数据库事务处理:使用数据库事务可以确保在执行过程中发生错误时,操作可以回滚并保持数据的一致性。在MySQL中,可以使用BEGIN,COMMIT和ROLLBACK语句来处理事务。
- 使用乐观锁:对于并发操作,使用乐观锁可以确保在多个线程或进程同时访问和修改数据时,数据的一致性得到保证。在更新数据时,先检查数据的版本号,如果版本号与预期不符,则说明数据已经被其他线程或进程修改,此时可以回滚或重新尝试操作。
- 使用分布式锁:如果涉及到多个Redis实例或多个数据库,可以使用分布式锁来确保数据的一致性。分布式锁可以使用Redis的SETNX命令或第三方分布式锁实现来实现。
- 数据校验:定期对Redis和MySQL中的数据进行校验和比较,以确保数据的一致性。可以使用脚本或监控工具来定期执行数据校验操作。
5.进程线程的区别
- 资源拥有:
- 进程是操作系统资源分配的基本单元,它拥有独立的地址空间、文件描述符等资源。每个进程都有自己的代码和数据空间,程序之间的切换会有较大的开销。
- 线程是处理器任务调度和执行的基本单位,它是进程的一部分,共享进程的地址空间和资源,因此线程之间的切换开销相对较小。
- 开销:创建和销毁一个进程需要保存寄存器、栈信息以及进行资源分配和回收等操作,开销较大。而线程的创建和销毁只需保存寄存器和栈信息,开销较小。
- 通信和切换:进程间通信(IPC)需要通过操作系统进行,切换开销相对较大。线程间可以直接共享进程的地址空间和资源,切换开销相对较小。同一进程下的线程共享全局变量、静态变量等数据,这使得线程之间的通信更方便,但如何处理好同步与互斥是编写多线程程序的难点。
- 并发性:进程是独立的执行单元,具有自己的调度算法,在并发条件下更加稳定可靠。而线程共享进程的资源,线程之间的调度和同步比较复杂,对并发条件的处理需要更多的注意。多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
6.算法:题目:给定一个字符串s,一个Set< Character>,然后说在s中找到最短的substring,包含所有Set< Character>里面的字符:滑动窗口
“滑动窗口算法通常用于解决数组或字符串中的连续子数组或子字符串问题,它可以通过维护一个窗口来减少不必要的计算。
思路:
使用两个指针来定义一个窗口,一个指针指向窗口的左边界,另一个指针指向窗口的右边界。我们还需要一个哈希表来记录窗口中每个字符出现的次数。
实现步骤:
- 初始化一个哈希表,将Set< Character>中的所有字符作为键,将它们的出现次数初始化为0。
- 初始化两个指针left和right,都指向字符串s的开头。
- 初始化一个变量minLen,表示最短子串的长度,初始值为正无穷大。
- 进入循环,移动右指针right,直到窗口中包含Set< Character>中的所有字符:
- 在每次移动右指针时,将s[right]加入窗口中,并更新哈希表中s[right]的出现次数。
- 如果窗口中包含了Set< Character>中的所有字符,进入下一步;否则,继续移动右指针。
- 进入循环,移动左指针left,直到窗口中不再包含Set< Character>中的所有字符:
- 在每次移动左指针时,更新minLen为当前窗口长度和minLen的较小值。
- 从窗口中删除s[left],并更新哈希表中s[left]的出现次数。
- 如果窗口中仍然包含Set< Character>中的所有字符,继续移动左指针;否则,退出循环。
- 返回minLen,即为最短子串的长度。
代码实现:
代码语言:javascript复制public int shortestSubstring(String s, Set<Character> chars) {
// 将Set<Character>转换为字符数组
char[] charArray = new char[chars.size()];
int i = 0;
for (char c : chars) {
charArray[i ] = c;
}
// 初始化哈希表
Map<Character, Integer> charCount = new HashMap<>();
for (char c : charArray) {
charCount.put(c, 0);
}
// 初始化指针和变量
int left = 0, right = 0;
int minLen = Integer.MAX_VALUE;
int missingCount = charCount.size(); // 记录窗口中缺少的字符数量
// 移动右指针,直到窗口中包含所有字符
while (right < s.length()) {
char c = s.charAt(right);
if (charCount.containsKey(c)) {
charCount.put(c, charCount.get(c) 1);
if (charCount.get(c) == 1) {
missingCount--;
}
}
right ;
// 移动左指针,直到窗口中不再包含所有字符
while (missingCount == 0) {
minLen = Math.min(minLen, right - left);
c = s.charAt(left);
if (charCount.containsKey(c)) {
charCount.put(c, charCount.get(c) - 1);
if (charCount.get(c) == 0) {
missingCount ;
}
}
left ;
}
}
return minLen;
}
- 原文链接:https://github.com/warthecatalyst/What-to-in-Graduate-School/blob/main/秋招的面经/华科计科第二人的秋招报告.md