查漏补缺第十六期(华为二面)
前言
目前正在出一个查漏补缺专题
系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~
本专题主要以Java
语言为主, 好了, 废话不多说直接开整吧~
算法题: 奇偶链表 (力扣328题)
给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。
第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。
请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。
输入: head = [1,2,3,4,5]
输出: [1,3,5,2,4]
输入: head = [2,1,3,5,6,4,7]
输出: [2,3,6,7,1,5,4]
public class Q328 {
public static class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
this.next = null;
}
}
public static ListNode oddEvenList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode oddHead = head;
ListNode evenHead = head.next;
ListNode oddTail = oddHead;
ListNode evenTail = evenHead;
while (evenTail != null && evenTail.next != null) {
oddTail.next = evenTail.next;
oddTail = oddTail.next;
evenTail.next = oddTail.next;
evenTail = evenTail.next;
}
oddTail.next = evenHead;
return oddHead;
}
public static void main(String[] args) {
// Test Case 1: [1,2,3,4,5]
ListNode head1 = new ListNode(1);
head1.next = new ListNode(2);
head1.next.next = new ListNode(3);
head1.next.next.next = new ListNode(4);
head1.next.next.next.next = new ListNode(5);
ListNode result1 = oddEvenList(head1);
printList(result1); // Expected: [1,3,5,2,4]
// Test Case 2: [2,1,3,5,6,4,7]
ListNode head2 = new ListNode(2);
head2.next = new ListNode(1);
head2.next.next = new ListNode(3);
head2.next.next.next = new ListNode(5);
head2.next.next.next.next = new ListNode(6);
head2.next.next.next.next.next = new ListNode(4);
head2.next.next.next.next.next.next = new ListNode(7);
ListNode result2 = oddEvenList(head2);
printList(result2); // Expected: [2,3,6,7,1,5,4]
}
private static void printList(ListNode head) {
while (head != null) {
System.out.print(head.val + " ");
head = head.next;
}
System.out.println();
}
}
上述代码中,我们使用两个指针oddHead
和evenHead
来分别表示奇数节点链表的头和偶数节点链表的头。然后,我们使用oddTail
和evenTail
来分别表示奇数节点链表的尾部和偶数节点链表的尾部。
在遍历原始链表时,我们将奇数位置的节点连接到oddTail
后面,并将偶数位置的节点连接到evenTail
后面。最后,我们将奇数节点链表的尾部连接到偶数节点链表的头部,从而完成重新排序。
时间复杂度为O(n),其中n是链表的节点数 空间复杂度O(1)
Mysql常用的数据类型
MySQL中常用的数据类型包括以下几种:
-
整数类型(Integer Types):用于存储整数值,常见的整数类型有:
TINYINT
:占用1字节,范围为-128到127(有符号)或0到255(无符号)。SMALLINT
:占用2字节,范围为-32768到32767(有符号)或0到65535(无符号)。MEDIUMINT
:占用3字节,范围为-8388608到8388607(有符号)或0到16777215(无符号)。INT
:占用4字节,范围为-2147483648到2147483647(有符号)或0到4294967295(无符号)。BIGINT
:占用8字节,范围为-9223372036854775808到9223372036854775807(有符号)或0到18446744073709551615(无符号)。
-
浮点数类型(Floating-Point Types):用于存储浮点数值,常见的浮点数类型有:
FLOAT
:占用4字节,单精度浮点数,范围约为-3.402823466E+38到-1.175494351E-38、0和1.175494351E-38到3.402823466E+38。DOUBLE
:占用8字节,双精度浮点数,范围约为-1.7976931348623157E+308到-2.2250738585072014E-308、0和2.2250738585072014E-308到1.7976931348623157E+308。
-
定点数类型(Decimal Types):用于存储精确的小数值,常见的定点数类型有:
DECIMAL(M, D)
:占用可变长度,用于存储固定精度的小数,M表示总位数,D表示小数位数。
-
字符串类型(String Types):用于存储文本数据,常见的字符串类型有:
CHAR(N)
:固定长度的字符串,最多存储N个字符。VARCHAR(N)
:可变长度的字符串,最多存储N个字符。TEXT
:可变长度的文本字符串,最多存储65535个字符。
-
日期和时间类型(Date and Time Types):用于存储日期和时间数据,常见的日期和时间类型有:
DATE
:存储日期,格式为'YYYY-MM-DD'。TIME
:存储时间,格式为'HH:MM:SS'。DATETIME
:存储日期和时间,格式为'YYYY-MM-DD HH:MM:SS'。TIMESTAMP
:存储日期和时间,范围为'1970-01-01 00:00:01'到'2038-01-19 03:14:07'。
-
布尔类型(Boolean Type):用于存储布尔值,常见的布尔类型有:
BOOL
:存储布尔值,取值为TRUE或FALSE。BOOLEAN
:存储布尔值,取值为TRUE或FALSE。
-
枚举类型(Enumeration Type):用于存储枚举值,枚举类型定义了一个可选值的列表,常见的枚举类型有:
ENUM('value1', 'value2', ...)
:存储从列表中选择的一个值。
-
集合类型(Set Type):用于存储集合值,集合类型定义了一个可选值的列表,常见的集合类型有:
SET('value1', 'value2', ...)
:存储从列表中选择的一个或多个值。
除了上述常见的数据类型外,MySQL还支持其他一些特殊的数据类型,如二进制类型(Binary Types)、JSON类型
等,用于存储特定类型的数据。
Java集合框架的主类是什么,HashSet有没有继承Collection
Java集合框架的主类是java.util.Collection
。
HashSet
是Collection
接口的实现类,它实现了Set
接口,因此它同时继承了Collection
接口和Set
接口。Set
接口是Collection
接口的子接口,用于表示不允许重复元素的集合。HashSet
通过哈希表实现,它不保证元素的顺序,且允许使用null
元素。
在继承关系中,HashSet
的继承关系如下:
HashSet -> AbstractSet -> AbstractCollection -> Object
可以看到,HashSet
直接继承了AbstractSet
类,而AbstractSet
类又是通过继承AbstractCollection
类实现的,最终都继承自Object
类。所以,HashSet
间接继承了Collection
接口。
有了解过哪些排序算法,说说原理
以下是一些经典的排序算法:
-
冒泡排序(Bubble Sort):比较相邻元素的大小,并根据需要交换它们的位置,重复这个过程直到整个序列排序完成。
-
选择排序(Selection Sort):每次从未排序的部分选择最小(或最大)的元素,并将其放置在已排序部分的末尾,重复这个过程直到整个序列排序完成。
-
插入排序(Insertion Sort):将未排序部分的元素逐个插入到已排序部分的合适位置,重复这个过程直到整个序列排序完成。
-
快速排序(Quick Sort):选择一个基准元素,将序列分割为两部分,小于基准元素的放在左边,大于基准元素的放在右边,然后对左右两部分递归地进行快速排序。
-
归并排序(Merge Sort):将序列分割为较小的子序列,然后递归地排序子序列,最后将排序好的子序列合并成一个有序序列。
-
堆排序(Heap Sort):构建一个最大(或最小)堆,然后将堆顶元素与最后一个元素交换,然后重新调整堆使其满足堆的性质,重复这个过程直到整个序列排序完成。
-
计数排序(Counting Sort):根据序列中每个元素的计数,统计小于或等于该元素的元素个数,然后根据统计结果将元素放置到正确的位置。
-
桶排序(Bucket Sort):将元素分配到不同的桶中,对每个桶中的元素进行排序,最后按照桶的顺序将所有元素合并成一个有序序列。
-
基数排序(Radix Sort):根据元素的位数将序列排序,从最低位到最高位依次进行排序,最终得到有序序列。
String能否被继承
在Java中,String
类是被final
修饰的,因此不能被继承。当一个类被声明为final
时,意味着它不能被其他类所继承。
这是因为String
类在Java中被设计为不可变(immutable
)的,即一旦创建了一个String
对象,就不能修改其内容。这种设计有助于字符串的安全性和线程安全性。如果String
类可以被继承,那么子类可能会重写String
类中的方法,从而可能破坏字符串的不可变性。
因此,为了保持字符串的特性和安全性,Java语言设计者将String
类声明为final
,禁止其他类继承它。如果需要在String
类的基础上进行扩展或自定义,可以通过创建新的类并包含String
对象作为成员变量来实现。
Java内存泄露了该如何排查
Java内存泄漏是指在程序中存在不再使用的对象,但由于某些原因(例如对象的引用未被正确释放),导致这些对象无法被垃圾回收器回收,最终导致内存占用过高或内存不足的问题。
以下是一些用于排查Java内存泄漏问题的常用方法:
-
使用内存分析工具:使用专业的内存分析工具(如Eclipse Memory Analyzer、VisualVM、MAT等)来检测和分析内存泄漏问题。这些工具可以提供详细的内存使用情况、对象引用关系等信息,帮助定位内存泄漏的源头。
-
检查代码:仔细审查代码,查找潜在的内存泄漏点。特别关注以下情况:
- 长期持有对象的引用,导致无法被垃圾回收。
- 静态集合或缓存中的对象未被正确移除。
- 未关闭的IO流或数据库连接。
- 监听器或回调未正确注销。
- 大对象或大集合未及时释放。
-
内存监控和日志:使用Java的内存监控工具(如JVM自带的
jstat
命令)监视内存使用情况,并通过日志记录关键的内存分配、回收和对象生命周期等信息。这有助于发现内存占用异常或内存泄漏的迹象。 -
Heap Dump分析:当发现内存泄漏问题时,生成Heap Dump文件,然后使用内存分析工具来分析该文件。Heap Dump提供了当前Java堆内存的快照,可以查看对象实例、引用关系和内存占用等信息,帮助定位内存泄漏的原因。
-
性能测试和压力测试:在进行性能测试和压力测试时,监测系统的内存使用情况。如果发现内存持续增长或内存占用过高,可能存在内存泄漏的问题。
-
代码审查和重构:请同事或其他开发者对代码进行审查,从不同的角度来寻找潜在的内存泄漏问题。有时候可能需要对代码进行重构,以避免潜在的内存泄漏风险。
静态代理和动态代理
在Java中,静态代理和动态代理都是实现代理模式的方式,用于实现对对象的间接访问控制。代理模式可以通过代理对象来控制目标对象的访问,并可以在目标对象的方法执行前后执行额外的操作。
静态代理(Static Proxy): 静态代理是在编译期间就已经确定代理类和被代理类的关系,需要手动编写代理类。代理类和被代理类都实现相同的接口,代理类持有被代理类的实例,并在代理类的方法中调用被代理类的方法。静态代理的关键是在代理类中显式地创建被代理类的对象,并在方法调用前后添加额外的逻辑。
静态代理的优点是简单、易于理解和实现,缺点是当被代理类的方法增加或修改时,代理类也需要相应地进行修改。
// 接口:定义被代理对象和代理对象共同的行为
interface Subject {
void doSomething();
}
// 被代理类
class RealSubject implements Subject {
public void doSomething() {
System.out.println("RealSubject is doing something.");
}
}
// 代理类
class ProxySubject implements Subject {
private RealSubject realSubject;
public ProxySubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
public void doSomething() {
System.out.println("ProxySubject is doing something before RealSubject.");
realSubject.doSomething();
System.out.println("ProxySubject is doing something after RealSubject.");
}
}
// 使用静态代理
public class StaticProxyExample {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
ProxySubject proxySubject = new ProxySubject(realSubject);
proxySubject.doSomething();
}
}
动态代理(Dynamic Proxy): 动态代理是在运行时动态生成代理类的方式,不需要手动编写代理类。Java中的动态代理机制是通过反射来实现的。代理类在运行时根据指定的接口或类动态生成,代理类的方法会被重定向到调用处理器(InvocationHandler)中的invoke方法。在invoke方法中可以执行额外的逻辑,如在方法调用前后进行一些操作。
Java中提供了java.lang.reflect
包来支持动态代理。常用的动态代理类有Proxy
和InvocationHandler
。Proxy
类用于创建代理类的实例,InvocationHandler
接口定义了代理类的调用处理器。
动态代理的优点是可以在运行时动态地生成代理类,无需手动编写代理类,适用于代理多个类或接口的情况。缺点是相对于静态代理,动态代理的实现较为复杂。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 接口:定义被代理对象和代理对象共同的行为
interface Subject {
void doSomething();
}
// 被代理类
class RealSubject implements Subject {
public void doSomething() {
System.out.println("RealSubject is doing something.");
}
}
// 实现 InvocationHandler 接口的调用处理器类
class ProxyHandler implements InvocationHandler {
private Object target;
public ProxyHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Proxy is doing something before RealSubject.");
Object result = method.invoke(target, args);
System.out.println("Proxy is doing something after RealSubject.");
return result;
}
}
// 使用动态代理
public class DynamicProxyExample {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
InvocationHandler handler = new ProxyHandler(realSubject);
// 创建动态代理类的实例
Subject proxySubject = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
handler
);
proxySubject.doSomething();
}
}
总结:
静态代理
和动态代理
都是实现代理模式的方式,用于实现对对象的间接访问控制。静态代理
需要手动编写代理类,而动态代理
是在运行时动态生成代理类。静态代理在编译期间确定代理类和被代理类的关系,动态代理在运行时根据接口或类动态生成代理类。动态代理使用反射机制来实现,在调用处理器中可以添加额外的逻辑。
结束语
大家可以针对自己薄弱的地方进行复习, 然后多总结,形成自己的理解,不要去背~
本着把自己知道的都告诉大家,如果本文对您有所帮助,点赞+关注
鼓励一下呗~
相关文章
- 查漏补缺第一期(Redis相关)
- 查漏补缺第二期(synchronized & 锁升级)
- 查漏补缺第三期(分布式事务相关)
- 查漏补缺第四期(Mysql相关)
- 查漏补缺第五期(HashMap & ConcurrentHashMap)
- 查漏补缺第六期(京东一面)
- 查漏补缺第七期(美团到店一面)
- 查漏补缺第八期(阿里一面)
- 查漏补缺第九期(阿里二面)
- 查漏补缺第十期(网易实习一面)
- 查漏补缺第十一期(网易实习二面)
- 查漏补缺第十二期(网易实习三面)
- 查漏补缺第十三期(滴滴实习一面)
- 查漏补缺第十四期(滴滴实习二面)
- 查漏补缺第十五期(华为一面)
项目源码(源码已更新 欢迎star⭐️)
往期设计模式相关文章
- 一起来学设计模式之认识设计模式
- 一起来学设计模式之单例模式
- 一起来学设计模式之工厂模式
- 一起来学设计模式之建造者模式
- 一起来学设计模式之原型模式
- 一起来学设计模式之适配器模式
- 一起来学设计模式之桥接模式
- 一起来学设计模式之组合模式
- 一起来学设计模式之装饰器模式
- 一起来学设计模式之外观模式
- 一起来学设计模式之享元模式
- 一起来学设计模式之代理模式
- 一起来学设计模式之责任链模式
- 一起来学设计模式之命令模式
- 一起来学设计模式之解释器模式
- 一起来学设计模式之迭代器模式
- 一起来学设计模式之中介者模式
- 一起来学设计模式之备忘录模式
- 一起来学设计模式之观察者模式
- 一起来学设计模式之状态模式
- 一起来学设计模式之策略模式
- 一起来学设计模式之模板方法模式
- 一起来学设计模式之访问者模式
- 一起来学设计模式之依赖注入模式
设计模式项目源码(源码已更新 欢迎star⭐️)
Kafka 专题学习
- 一起来学kafka之Kafka集群搭建
- 一起来学kafka之整合SpringBoot基本使用
- 一起来学kafka之整合SpringBoot深入使用(一)
- 一起来学kafka之整合SpringBoot深入使用(二)
- 一起来学kafka之整合SpringBoot深入使用(三)
项目源码(源码已更新 欢迎star⭐️)
ElasticSearch 专题学习
项目源码(源码已更新 欢迎star⭐️)
往期并发编程内容推荐
- Java多线程专题之线程与进程概述
- Java多线程专题之线程类和接口入门
- Java多线程专题之进阶学习Thread(含源码分析)
- Java多线程专题之Callable、Future与FutureTask(含源码分析)
- 面试官: 有了解过线程组和线程优先级吗
- 面试官: 说一下线程的生命周期过程
- 面试官: 说一下线程间的通信
- 面试官: 说一下Java的共享内存模型
- 面试官: 有了解过指令重排吗,什么是happens-before
- 面试官: 有了解过volatile关键字吗 说说看
- 面试官: 有了解过Synchronized吗 说说看
- Java多线程专题之Lock锁的使用
- 面试官: 有了解过ReentrantLock的底层实现吗?说说看
- 面试官: 有了解过CAS和原子操作吗?说说看
- Java多线程专题之线程池的基本使用
- 面试官: 有了解过线程池的工作原理吗?说说看
- 面试官: 线程池是如何做到线程复用的?有了解过吗,说说看
- 面试官: 阻塞队列有了解过吗?说说看
- 面试官: 阻塞队列的底层实现有了解过吗? 说说看
- 面试官: 同步容器和并发容器有用过吗? 说说看
- 面试官: CopyOnWrite容器有了解过吗? 说说看
- 面试官: Semaphore在项目中有使用过吗?说说看(源码剖析)
- 面试官: Exchanger在项目中有使用过吗?说说看(源码剖析)
- 面试官: CountDownLatch有了解过吗?说说看(源码剖析)
- 面试官: CyclicBarrier有了解过吗?说说看(源码剖析)
- 面试官: Phaser有了解过吗?说说看
- 面试官: Fork/Join 有了解过吗?说说看(含源码分析)
- 面试官: Stream并行流有了解过吗?说说看
推荐 SpringBoot & SpringCloud (源码已更新 欢迎star⭐️)
博客(阅读体验较佳)
转载自:https://juejin.cn/post/7249381456049012795