集合、八股文面试、MySQL、学成在线

本文分享了一套力扣刷题的策略和技巧,涵盖了从简单到难题目的复习方法,详细解析了多种经典算法题,如链表、字符串操作、二叉树遍历等,并提供了代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、集合

P499 集合介绍

数组不足之处:1.数组长度必须指定,一旦指定,不能修改。2.数组内的元素必须是同一类型。3.使用数组增加/删除元素的示意代码,比较麻烦。

集合的优点:1.可以动态保存任意多个对象,使用比较方便。2.提供了一系列方便的操作对象的方法:add、remove、set、get等。3.使用集合添加、删除新元素的示意代码。

P500 集合体系图

集合主要分为2组:

1.单列集合(在集合里放单个元素)

Collection里面有2个重要的子接口list和set。

2.双列集合(在集合里放键值对元素)

P501 Collection方法

public interface Collection<E> extends iterable<E>

1.collection实现子类可以存放多个元素,每个元素可以是Object

2.有些Collection的实现类,可以存放重复元素。

3.List是有序的,Set是无序的。

4.Collection接口没有直接实现类,是通过子接口Set和List来实现的。

P502 迭代器遍历

1.Iterator对象成为迭代器,用于遍历Collection集合中的元素。

2.所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即返回一个迭代器。

3.Iterator用于遍历集合

iterator.hasNext()可以判断是否有下一个元素,iterator.next()可以获取下一个元素。

public class Main {
    public static void main(String[] args) {
        Collection col = new ArrayList();
        col.add(new Book("三国演义","罗贯中",10.1));
        col.add(new Book("小李飞刀","古龙",5.1));
        col.add(new Book("红楼梦","曹雪芹",34.6));
        Iterator iterator = col.iterator();
        while(iterator.hasNext()){//判断迭代器是否为空
            Object obj = iterator.next();
            System.out.println(obj);
        }
        iterator = col.iterator(); //重置迭代器
        while(iterator.hasNext()){
            Object obj = iterator.next();
            System.out.println(obj);
        }
    }
}

class Book{
    private String name;
    private String author;
    private double price;
    public Book(String name, String author, double price) {
        this.name = name;
        this.author = author;
        this.price = price;
    }
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public String getAuthor() {return author;}
    public void setAuthor(String author) {this.author = author;}
    public double getPrice() {return price;}
    public void setPrice(double price) {this.price = price;}
    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                '}';
    }
}

P503 集合增强for

语法如下:

for(元素类型 元素名:集合名或数组名){
      访问元素
}

 增强for的底层仍然是迭代器,能够遍历集合和数组。

P505 List接口方法

List接口基本介绍:

1.往list集合中添加的元素是有序的,可以理解为队列,先进先出。

2.list集合里面的元素可以重复。

方法:

list.indexOf(对象名称)   可以返回该对象所在位置

list.add(下标,对象名称)   可以在下标的位置插入对象,原本的对象后移

list.set(下标,对象名称)  可以将下标位置的元素改为新的对象

list.subList(开始位置下标,结束位置下标)   可以返回开始到结束的对象,前闭后开,取不到结束位置

P508 List排序练习

public class Main {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(new Books("红楼梦","曹雪芹",100));
        list.add(new Books("西游记","吴承恩",10));
        list.add(new Books("水浒传","施耐庵",9));
        list.add(new Books("三国演义","罗贯中",80));
        sort(list);
        for (Object o :list) {
            System.out.println(o);
        }
    }
    public static void sort(List list){
        for(int i=0;i<list.size()-1;i++)
            for(int j=0;j<list.size()-1-i;j++){
                //取出对象Book
                Books books1 = (Books) list.get(j);
                Books books2 = (Books) list.get(j + 1);
                if(books1.getPrice()> books2.getPrice()){
                    list.set(j,books2);
                    list.set(j+1,books1);
                }
            }
    }
}

class Books{
    private  String name;
    private String author;
    private double price;
    public Books(String name, String author, double price) {
        this.name = name;
        this.author = author;
        this.price = price;
    }

    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public String getAuthor() {return author;}
    public void setAuthor(String author) {this.author = author;}
    public double getPrice() {return price;}
    public void setPrice(double price) {this.price = price;}
    @Override
    public String toString() {return "名称:"+name+"\t\t价格:"+price +"\t\t作者:"+author;}
}

P509 ArrayList注意事项

ArrayList里面可以放入空值。

ArrayList是线程不安全的,因为没有synchronized关键字修饰。

在多线程下可以使用vector。

P510 ArrayList扩容机制

1. ArrayList中维护了一个Object类型的数组elementData。transient Object[] elementData。

transient表示瞬间、短暂的,表示该属性不会被序列化。

2. 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加,则扩容elementData为10,如果要再次扩容,则扩容elementData为1.5倍。(比如从0到10到15到22到33...)

3.如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。(比如从8到12到18到27)

P511 ArrayList底层源码1

分析使用无参构造器,创建和使用ArrayList的源码:

1.调用无参构造方法,创建了一个空的elementData数组。

2.执行add方法。先确定是否要扩容。确定数组大小可容纳之后再进行赋值。

3.该方法确定minCapacity。第1次扩容为10。

4.modCount是记录当前集合被修改的次数(防止多个线程同时修改)。minCapacity-elementData.length>0的意思是如果最小容量大于当前数组实际大小,数组长度不够,调用grow进行扩容。

5.oldCapacity+oldCapacity>>1相当于是oldCapacity的1.5倍。

第1次oldCapacity和newCapacity为0,会进入第1个if语句,所以minCapacity=10的值会被赋给newCapacity。

第2次及以后就是按照1.5倍进行扩容。

扩容使用的是Arrays.copyof(),因为要把原数组的数据拷贝到新数组。

注意:IDEA在默认情况下,Debug显示的数据是简化后的,如果希望看到完整的数据,需要设置。

P512 ArrayList底层源码2

下图是调用有参构造器,对数组初始化,进行扩容的情况:实则是创建了一个指定大小的elementData数组。

如果是有参数的构造器,扩容机制:

1.第一次扩容就按照elementData的1.5倍扩容。

2.整个执行的流程还是和前面一样。

P513 Vector注意事项

Vector带有synchronized是线程安全的。

单线程操作的情况用ArrayList,多线程操作的情况用Vector。

P514 Vector源码解读

Vector无参时大小默认为10,扩容是按2倍进行扩容。

首先进行装箱:

‘’

下面这个方法添加数据到集合:

确定是否需要扩容,elementData.length为当前数组大小,minCapacity为当前存入元素的个数。

如果需要的数组大小不够用就扩容。第1次扩容时capacityIncrement为0,因此走的是oldCapacity这条,而oldCapacity一开始为10,因此newCapacity为20。

P515 双向链表模拟

特点:

1.LinkedList底层实现了双向链表和双端队列的特点。

2.可以添加任意元素(元素可以重复),包括null。

3.线程不安全,没有实现同步。

LinkedList的底层结构:

1.LinkedList底层维护了一个双向链表。

2.LinkedList中维护了两个属性first和last分别指向首节点和尾节点。

3.每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表。

4.所以LinkedList元素的添加和删除,不是通过数组完成的,相对来说效率较高。

P516 LinKedList源码图解

装箱操作如下:

一开始last为null,l也等于null。new Node<>(l,e,null)表示prev指向null,next也指向null。

对于新节点:newNode和last和first都指向newNode。最初新节点的示意图如下:

对于第2个新节点,new Node<>(l,e,null)其中l代表新节点的前屈节点,指向的是前面一个节点,然后last会指向newNode,最后旧节点l的后继节点会指向新节点,很妙,如下图:

linkedList.remove()方法用于删除节点,没传参数默认删除第1个节点。

将f指向的双向链表的第一个节点拿掉

调用linkedList.set(索引下标,新值) 把对象为索引下标中的值改为新值。

调用linkedLide.get(下标) 可以得到下标中的对象。

二、八股文面试

1.1 导学课程 P1

面试题的背后逻辑->拆解问题讲解->回答方式及参考回答。

举例:在MySQL中,如何定位慢查询?——聚合查询,多表查询,表数据量大的查询,深度分页查询。

1.2 企业简历筛选规则 P2

HR(不懂得技术)获取到简历,会对简历进行初步筛选(学历、院校、经验、年龄、跳槽频率)。

然后HR会把简历交给部门负责人继续筛选(是否符合当前项目的技术栈,是否符合业务条件,有高可用高并发经验优先、熟悉基于公有云的开发经验、有团队管理经验),通过后会让HR通知面试。

1.3 简历注意事项 P3

一份完整的简历包含如下几个部分:

在保障真实的前提下,可以适当美化:1.基本信息 2.教育背景 3.求职意向 4.工作经历

5.职业技能

要放到简历的黄金位置(HR刷简历的重要参考,放在中间或中下位置)

基本准则:写在简历上的必须能聊,不然就别写。

参考公式:职业技能=必要技术+其他技术(选择性体现)

针对性地引导面试官(让他问一些你想让他问的)

6.项目经历

项目个数以自己的工作经历为准,时间比较久的可以只写标题或不写。

项目要体现业务深度或技术深度。

有没有主导设计过xx模块开发。

尽可能展示指标数据(达到了多少QPS、达到了多少的数据量)

不要过于夸张,关键在于突出难点和亮点(有的话可以写,没有的话可以不写,属于锦上添花):7.个人优势 8.个人荣誉。

1.4 应届生找练手项目 P4

一般是在开源网站GitHub或者Gitee上找。找星星多的。

然后在本地想尽一切办法把项目运行起来,然后debug跟踪代码的逻辑,梳理完业务之后,看自己是否能独立完成。

找到项目中1~2个业务点深入挖掘,然后多方位参考(参考多种实现方式,可以在Gitee或GitHub上找其它项目,或者b站课程,或者博客文章)。

1.功能实现

业务功能实现:用户名、密码登录,二维码登录,手机短信登录,用户、角色、权限管理和分配。

技术方案支撑:RBAC模型、Spring Security或Apache Shiro

2.常见问题

token刷新问题、加密、解密、XSS防跨站攻击

3.权限系统设计

可扩展性、高可用性、通用性(能够把模块抽象出来,给其它的项目使用)。

1.5 面试过程 P5

面试的形式:

单轮面试:只有技术面试(中小企业,创业型公司,外包公司)

两轮面试:第一、二轮技术面(大部分公司)

三轮面试:第一、二轮技术面,第三轮HR终面(上市公司、大厂)

面试官角色:

资深开发人员(技术经理):技术最好,多数参与首轮面试。

业务部门经理:技术一般,多数参与终面,可以决定你的薪资(思考能力和抗压能力)。

HR:辅助业务部门考察候选人(性格、沟通能力、合作能力、学习能力)

面试过程:

一定要用总分结构表述。

自我介绍(比如我叫什么,我的工作经历,主要是哪几个阶段)

所有的都要提前准备。

常看招聘要求(比如想找20k的工作就看25k的工作要求,凡事都要要求更高一级)。

1.6 redis开篇 P6

注意与实际业务进行关联:大致有2大类问题。

使用场景:

缓存:穿透、击穿、雪崩、双写一致、持久化、数据过期策略、淘汰策略。

分布式锁:setnx,redisson,

计数器,保存token,消息队列,延迟队列。

其他面试题:

集群:主从、哨兵、集群

事物、Redis为什么快

1.7 缓存穿透 P7

问题:我看你做的项目中都用到了redis,你在最近的项目中哪些场景用到了redis呢?

提问目的:一是验证你项目场景的真实性,二是作为深入发问的切入点。

缓存:缓存三兄弟(穿透、击穿、雪崩)、双写一致、持久化、数据过期策略、数据淘汰策略。

分布式锁:setnx,redisson。

消息队列、延迟队列:数据类型的选择。

答题技巧:结合项目的业务进行回答。

如果发生了缓存穿透、击穿、雪崩,该如何解决?

什么是缓存穿透?

场景:根据文章的id,查询文章的详情:api/news/getById/1

流程:根据id查询文章,首先会去查redis,如果命中就返回结果,如果查不到,就去查DB,把数据存储到redis,返回结果。

缓存穿透:查询一个不存在的数据,mysql查询不到数据也不会直接写入缓存,就会导致每次请求都查找数据库。

出现场景:有人恶意攻击系统,参数放在路径上,制造假的id请求。

解决方案1:缓存空数据,查询返回的数据为空,就把空结果进行缓存。

优点:简单。

缺点:消耗内存,可能发生不一致的问题(一开始确实没有数据,缓存了null,后面添加了数据,缓存的数据未过期,仍旧查找缓存,结果和数据库不一致)。

解决方案2:布隆过滤器,拦截不存在的数据

思路:根据id查询文章首先会查询布隆过滤器,如果布隆过滤器中不存在,则直接返回;如果布隆过滤器中存在,在查redis。要求缓存预热时,要预热布隆过滤器。

1.8 缓存击穿 P8

1.9 缓存雪崩 P9

1.10 双写一致性

1.11 持久化

1.12 数据过期策略

1.13 数据淘汰策略

1.14 分布式锁使用场景

1.15 分布式锁实现原理

1.16 主从复制、主从同步流程

1.17 哨兵模式、集群脑裂

1.18 分片集群、数据读写规则

1.19 redis是单线程的为什么快

三、MySQL

 P58 课程介绍

存储引擎、索引、SQL优化、视图/存储过程/触发器、锁、InnoDB引擎、MySQL管理。

P59 存储引擎 MySQL体系结构

连接层:校验用户名和密码以及客户端权限。

服务层:绝大部分核心功能是在服务层实现。

引擎层:数据存储和提取方式,如InnoDB、MyISAM等。索引是在存储引擎层实现的,不同存储引擎有不同索引结构。

存储层:存入磁盘中。

P60 存储引擎 简介

引擎是一个机器的核心部分。在合适的场景选用合适的引擎。

存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式。

查看数据库的存储引擎:show engines

查看建表的存储引擎:show create table 表

P61 存储引擎 InnoDB介绍

兼顾高可靠性和高性能的通用存储引擎。MySQL5.5之后成为默认存储引擎。

特点:

1.DML操作(数据增删改)遵循ACID模型,支持事务

2.行级锁,提高并发访问性能。

3.支持外键FOREIGN KEY约束,保证数据的完整性和正确性。

P62 存储引擎 MyISAM和Memory

P63 存储引擎 选择

P64 存储引擎 小结

P65 MySQL安装

P66 索引 概述

索引是帮助MySQL高效获取数据的数据结构(有序)。数据库需要维护索引的数据结构,数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构是索引。

无索引:全表扫描(逐条逐行往下查找,查找到1条数据后还要接着查找)。

劣势:降低增删改的效率。

P67 索引 结构介绍

索引是在存储引擎层实现,不同引擎有不同结构:

默认指定的是B+树索引:

P68 索引 结构Btree

中间元素向上分裂。

P69 索引 结构B+tree

假如一颗B树有n个阶,会有n-1个key。

B+Tree的特点是:所有的元素都会出现在叶子节点。非叶子节点只起到索引的作用。叶子节点形成的是单向链表。

P70 索引 结构 hash

先计算hash值,将键值换成新的hash值,映射到对应的槽位上,存储到hash表中。

Hash索引只能用于等值查询,不支持范围查询,无法完成排序操作,查询效率高,通常只需要一次检索,效率更高。

支持hash索引的存储引擎是Memory引擎。

P71 索引 结构 思考题

为什么InnoDB存储引擎选择使用B+tree索引结构?

因为相对于二叉树,层级更少,搜索效率更高。

B树的叶子节点和非叶子节点都会存放数据,会导致一个节点占用一个磁盘块(页,大小固定为16K),存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低。

P72 索引 分类

主键索引:针对表中主键创建的索引。默认自动创建,只能有一个。PRIMARY。

唯一索引:避免同一张表中某数据列中的值重复。可以有多个。UNIQUE。

常规索引:快速定位特定数据。可以有多个。

聚集索引(Clustered Index):将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据。(默认主键索引是聚集索引。如果不存在主键,使用第一个唯一索引作为聚集索引。如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引。)

聚集索引下面挂的是这一行的行数据。

二级索引(Secondary Index):将数据与索引分开存储,索引结构的叶子结点关联的是对应的主键。

如果没有指定索引,数据也存入了。

这里涉及到回表查询,先走二级索引查询,先查询到主键值,然后再到聚集索引中进行查询,拿到某一行的行数据。

P141 MVCC基本概念

当前读:读到的是记录的最新版本,要保证其他并发事务不能修改当前的记录,会对读取的记录进行加载。

快照读:简单的select不加锁就是快照读,读的是记录的可见版本,有可能是历史数据,不加锁是非阻塞读。

MVCC:Multi-Version Concurrency Control多版本并发控制,维护一个数据的多个版本,使得读写操作没有冲突,快照读为MYSQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现需要依赖数据库记录中的三个隐式字段:undo log日志、readView。

P142 MVCC隐藏字段

DB_TRX_ID:最近修改事务ID,记录插入这条记录或最后一次修改该记录的事物ID。

DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本,用于配合undo log指向上一个版本。

DB_ROW_ID:隐藏主键,如果表结构没有指定主键,将会生成隐藏字段。

P143 MVCC undolog版本链

undo log:回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志。

当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除。

而update、delete的时候,产生的undo log日志不仅在回滚。

不同事务或者相同事务对同一条记录进行修改,会导致该记录的undolog生成一条记录版本链表,链表头部是最新的旧数据,链表的尾部是最早的旧记录。

P144 MVCC readview介绍

P145 MVCC原理分析(RC级别)

P146 MVCC原理分析(RR级别)

四、学成在线

5.13 微信扫码认证 接口调研 P120

5.14 微信扫码认证 接口定义 P121

5.15 微信扫码认证 接入逻辑 P122

5.16 微信扫码认证 测试与总结 P123

5.17 授权什么是RBAC P124

5.18 授权 数据模型 P125

5.19 授权 微服务授权方法 P126

5.19 授权 从数据库查询权限 P127

5.20 授权 细粒度授权 P128

六、选课

6.1 P129

6.2 P130

6.3 P131

6.4 P132

6.5 P133

6.6 P134

七、支付

7.1 P135

7.2 P136

7.3 P137

7.4 P138

7.5 P139

7.6 P140

7.7 P141

7.8 P142

7.9 P143

7.10 P144

7.11 P145

7.12 P146

7.13 P147

7.14 P148

7.15 P149

7.16 P150

7.17 P151

7.18 P152

7.19 P153

7.20 P154

7.21 P155

7.22 P156

7.23 P157

八、在线学习

8.1 P158

8.2 P159

8.3 P160

8.4 P161

8.5 P162

8.6 P163

8.7 P164

8.8 P165

8.9 P166

九、项目部署

9.1 P167

9.2 P168

9.3 P169

9.4 P170

9.5 P171

9.6 P172

十、项目优化总结

10.1 P173

10.2 P174

10.3 P175

10.4 P176

10.5 P177

10.6 P178

10.7 P179

10.8 P180

10.9 P181

10.10 P182

10.11 P183

10.12 P184

10.13 P185

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值