-
- 搜索
-
模型
-
Map 的使用
-
- 常用方法
-
Set 的使用
-
- 常见方法:
-
题目练习
-
- 只出现 1 次的数字
-
复制带随机指针的链表
-
宝石和石头
-
旧键盘打字
-
前 K 个高频单词
Map 和 Set是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关
一般把搜索的数据称为关键字(Key),和关键字对应的称为值(Value),将其称之为 Key-value 的键值对,所以模型会有两种
-
纯 key 模型 :即,我们 Set 要解决的事情,只需要判断关键字在不在集合中即可,没有关联的 Value —— 例:有一个英文词典,快速查找一个单词是否在词典中
-
Key-Value 模型 :即,我们 Map 要解决的事情,需要根据指定 Key 找到关联的 Value
例:梁山好汉的江湖绰号:每个好汉都有自己的江湖绰号
Map 中存储的就是 Key - Value 的键值对,Set 中只存储了 Key
Map.Entry<K, V>
Map.Entry<K, V> 是 Map 内部实现的用来存放 <key, value> 键值对映射关系的内部类,该内部类中主要提供了<key, value>的获取,value的设置以及Key的比较方式
| 方法 | 说明 |
| — | — |
| K getKey( ) | 返回 Entry 中的 key |
| V getValue( ) | 返回 Entry 中的 value |
| V setValue(V value) | 将键值对中的 value 替换为指定 value |
常用方法
| 方法 | 说明 |
| — | — |
| V get (Object key) | 返回 key 对应的 value |
| V getOrDefault (Object key,V defaultValue) | 返回 key 对应的 value,key 不存在,返回默认值 |
| V put (K key,V value) | 设置 key 对应的 value |
| V remove (Object key) | 删除 key 对应的映射关系 |
| Set keySet ( ) | 返回所有 key 的不重复集合 |
| Collection values ( ) | 返回所有 value 的可重复集合 |
| Set<Map.Entry <K, V> > entrySet( ) | 返回所有的 key-value 映射关系 |
| boolean containsKey (Object key) (高效) | 判断是否包含 key |
| boolean containsValue (Object value) (低效) | 判断是否包含 value |
HashMap 使用示例:
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
// put(key, value):插入key-value的键值对
map.put(1,“hello~”);
// key value 重复
map.put(1,“hello”);
map.put(6,“Java”);
map.put(3,“Cpp”);
// put(key,value): key 为null
map.put(null,“Python”);
// put(key,value): value 为null
map.put(2,null);
System.out.println(map.get(null));
System.out.println(map);
// 返回 key 对应的 value
System.out.println(map.get(6));
// 找不到 返回会null
System.out.println(map.get(10));
// 打印所有的 key
for (Integer key : map.keySet()) {
System.out.print(key + " ");
}
System.out.println();
// 打印所有的 value
for (String value : map.values()) {
System.out.print(value + " ");
}
System.out.println();
// 按照映射关系打印
for (Map.Entry<Integer,String> entry : map.entrySet()) {
System.out.println(entry);
}
// 是否包含 key
System.out.println(map.containsKey(6));
//是否包含 value
System.out.println(map.containsValue(“Java”));
}
输出结果:
TreeMap 使用示例:
1.插入键值对
public static void main(String[] args) {
Map<String,String> map = new TreeMap<>();
//插入键值对
map.put(“西游记”,“吴承恩”);
map.put(“红楼梦”,“曹雪芹”);
map.put(“狂人日记”,“鲁迅”);
// value 重复
map.put(“阿Q正传”,“鲁迅”);
// key 重复
map.put(“阿Q正传”,“key不能重复”);
System.out.println(map.get(“阿Q正传”));
}
输出结果:
如果key存在,会使用 value 替换原来 key 所对应的 value,返回旧 value
key 不能为null
key 为null,会抛出 NullPointerException 异常
public static void main(String[] args) {
Map<String,String> map = new TreeMap<>();
// key 不能为 null,否则抛出异常
map.put(null,“异常~”);
}
输出结果:
value 可以为null
public static void main(String[] args) {
Map<String,String> map = new TreeMap<>();
// value 可以为null
map.put(“value为null”,null);
System.out.println(map.get(“value为null”));
}
输出结果:
注意事项:
-
Map 是一个接口,不能直接实例化对象,如果要实例化对象只能实例化其实现类 TreeMap 或者HashMap
-
TreeMap 中存放键值对的 key 是唯一的,value 是可以重复的
-
在 TreeMap 中插入键值对时,key 不能为空,否则就会抛 NullPointerException 异常,但是 value 可以为空
-
Map 中的 key 可以全部分离出来,存储到 Set 中来进行访问 (因为 key 不能重复)
-
Map 中的 value 可以全部分离出来,存储在 Collection 的任何一个子集合中 (value可能有重复)
-
Map 中键值对的 key 不能直接修改,value 可以修改,如果要修改 key,只能先将该 key 删除掉,然后再进行重新插入
-
HashMap 和 TreeMap 的区别
| Map底层结构 | TreeMap | HashMap |
| — | — | — |
| 底层结构 | 红黑树 | 哈希桶 |
| 插入 / 删除 / 查找时间复杂度 | O(logN) | O(1) |
| 是否有序 | 关于 key 有序 | 无序 |
| 线程是否安全 | 不安全 | 不安全 |
| 插入 / 删除 / 查找区别 | 需要进行元素比较 | 通过哈希函数计算哈希地址 |
| 比较与重写 | key 必须能够比较,否则会抛出 ClassCastException 异常 | 自定义类型需要重写 equals 和 hashCode 方法 |
| 应用场景 | 需要 key 有序场景下 | key 是否有序不关心,需要更高的时间性能 |
Set与Map主要的不同:
-
Set 是继承自 Collection 的接口类
-
Set 中只存储了 key
常见方法:
| 方法 | 说明 |
| — | — |
| boolean add(E e) | 添加元素,但重复元素不会被添加成功 |
| void clear( ) | 清空集合 |
| boolean contains(Object o) | 判断 o 是否在集合中 |
| Iterator iterator( ) | 返回迭代器 |
| boolean remove(Object o) | 删除集合中的 o |
| int size( ) | 返回set中元素的个数 |
| boolean isEmpty( ) | 检测 set 是否为空,空返回 true,否则返回 false |
| Object[] toArray( ) | 将 set 中的元素转换为数组返回 |
| boolean containsAll(Collection<?> c) | 集合 c 中的元素是否在 set 中全部存在,是返回 true,否则返回 false |
| boolean addAll(Collection<? extends E> c) | 将集合 c 中的元素添加到 set 中,可以达到去重的效果 |
HashSet 代码示例:
public static void main(String[] args) {
//1.实例化 Set
Set set = new HashSet<>();
//2.插入元素 : add
set.add(“hello”);
set.add(“Java”);
set.add(“Cpp”);
// 插入null
set.add(null);
//3.判断某个值是否存在
System.out.println("Java: " + set.contains(“Java”));
System.out.println("Python: " + set.contains(“Python”));
System.out.println("Cpp: " + set.contains(“Cpp”));
System.out.println("null: " + set.contains(“null”));
//4.删除某个值
System.out.println(“删除Cpp…”);
set.remove(“Cpp”);
System.out.println("Cpp: " + set.contains(“Cpp”));
//删除null
System.out.println(“删除null…”);
System.out.println("null: " + set.contains(null));
//5.打印Set
// a) 直接打印
System.out.println(set);
// b) 循环遍历,使用迭代器
// 迭代器的泛型参数 要和 集合类中保存的元素参数类型一致
// 集合类内部自己实现自己版本的迭代器,不同的集合类 内部的迭代器类型不同,迭代方式也不同
System.out.print(“使用迭代器打印:”);
Iterator iterator = set.iterator();
while (iterator.hasNext()){
String next = iterator.next();
System.out.print(next + " ");
}
}
输出结果:
TreeSet 代码示例:
public static void main(String[] args) {
//1.实例化 Set
Set set = new TreeSet<>();
//2.插入元素
set.add(“Hello”);
set.add(“Java”);
set.add(“Cpp”);
// 不能插入null,会抛出 空指针异常
// set.add(null);
//3.判断某个值是否存在
System.out.println("Java: " + set.contains(“Java”));
System.out.println("Python: " + set.contains(“Python”));
System.out.println("Cpp: " + set.contains(“Cpp”));
// contains(key): key为null,抛出空指针异常
// System.out.println("null: " + set.contains(null));
//4.删除某个值
System.out.println(“删除Cpp…”);
set.remove(“Cpp”);
System.out.println("Cpp: " + set.contains(“Cpp”));
//删除null
System.out.println(“删除null…”);
// remove(key): key为null,抛出空指针异常
// set.remove(null);
// System.out.println("null: " + set.contains(null));
//5.打印 set
// a) 直接打印
System.out.println(set);
// b) 迭代器打印
System.out.print(“使用迭代器打印:”);
Iterator iterator = set.iterator();
while (iterator.hasNext()){
String next = iterator.next();
System.out.print(next + " ");
}
}
输出结果:
注意事项:
-
Set 是继承自 Collection 的一个接口类
-
Set 中只存储了 key,key 是唯一的,不能重复
-
Set 最大的功能就是对集合中的元素进行去重
-
Set 中的 Key 不能修改,如果要修改,先将原来的删除掉,然后再重新插入
-
TreeSet 和 HashSet 的区别
| Set | TreeSet | HashSet |
| — | — | — |
| 底层结构 | 红黑树 | 哈希桶 |
| 插入 / 删除 / 查找时间复杂度 | O(logN) | O(1) |
| 是否有序 | 关于 key 有序 | 不一定有序 |
| 线程是否安全 | 不安全 | 不安全 |
| 插入 / 删除 / 查找区别 | 按照红黑树的特性来进行插入和删除 | 1. 先计算 key 哈希地址;2. 然后进行插入和删除 |
| 比较与重写 | key 必须能够比较,否则会抛出 ClassCastException 异常 | 自定义类型需要重写 equals 和 hashCode 方法 |
| 应用场景 | 需要 key 有序场景下 | key是否有序不关心,需要更高的时间性能 |
只出现 1 次的数字
题目: 在线OJ
思考:
方法一: 通过 Map 统计每个数字出现的次数,再遍历 Map 找到那个只出现一次的数字
-
创建 Map<Integer,Integer>,key:当前出现的数字;value:该数字出现次数
-
遍历统计次数即可~
方法二: 按位异或 A ^ B ^ A = B;A ^ 0 = A,异或规则,相同为0,相异为1
代码实现:
- 方法1
public int singleNumber(int[] nums) {
// key : 当前数字
// value : 数字出现次数
Map<Integer,Integer> map = new HashMap<>();
for (int x : nums) {
Integer value = map.get(x);
// 当前数字在 map 中不存在,新增一个键值对
if(value == null){
map.put(x,1);
}
//这个数字已经存在了
else{
map.put(x,value + 1);
}
}
// 遍历 map ,找到出现次数为1的数
for (Map.Entry<Integer,Integer> entry : map.entrySet()) {
// getValue 得到的是一个 Integer 包装类
// 使用 equals,相当于对 1 自动装箱
// 使用 == ,相当于对 Integer 自动拆箱
if(entry.getValue().equals(1)){
return entry.getKey();
}
}
//没找到
return 0;
}
- 方法2
public int singleNumber(int[] nums) {
int result = 0;
for (int x : nums) {
result ^= x;
}
return result;
}
复制带随机指针的链表
题目: 在线OJ
思考:
-
创建一个 Map <Node,Node>,key:旧链表的节点;value:新链表的节点(旧链表对应节点的拷贝)
-
Map 结构创建好了之后,遍历旧链表,取出节点在 Map 中找到对应的 value
例:新node1.next = map.get (旧node1.next);
新node1.random = map.get (旧node1.random);
代码实现:
public Node copyRandomList(Node head) {
//1.创建 map
Map<Node,Node> map = new HashMap<>();
//2.遍历旧链表,把旧链表的每个节点 依次插入到map中
// key: 旧链表节点
// value: 新链表节点
for (Node cur = head;cur != null;cur = cur.next){
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
小编在这里分享些我自己平时的学习资料,由于篇幅限制,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!
程序员代码面试指南 IT名企算法与数据结构题目最优解
这是” 本程序员面试宝典!书中对IT名企代码面试各类题目的最优解进行了总结,并提供了相关代码实现。针对当前程序员面试缺乏权威题目汇总这一-痛点, 本书选取将近200道真实出现过的经典代码面试题,帮助广“大程序员的面试准备做到万无一失。 “刷”完本书后,你就是“题王”!
《TCP-IP协议组(第4版)》
本书是介绍TCP/IP协议族的经典图书的最新版本。本书自第1版出版以来,就广受读者欢迎。
本书最新版进行」护元,以体境计算机网络技不的最新发展,全书古有七大部分共30草和7个附录:第一部分介绍一些基本概念和基础底层技术:第二部分介绍网络层协议:第三部分介绍运输层协议;第四部分介绍应用层协议:第五部分介绍下一代协议,即IPv6协议:第六部分介绍网络安全问题:第七部分给出了7个附录。
Java开发手册(嵩山版)
这个不用多说了,阿里的开发手册,每次更新我都会看,这是8月初最新更新的**(嵩山版)**
MySQL 8从入门到精通
本书主要内容包括MySQL的安装与配置、数据库的创建、数据表的创建、数据类型和运算符、MySQL 函数、查询数据、数据表的操作(插入、更新与删除数据)、索引、存储过程和函数、视图、触发器、用户管理、数据备份与还原、MySQL 日志、性能优化、MySQL Repl ication、MySQL Workbench、 MySQL Utilities、 MySQL Proxy、PHP操作MySQL数据库和PDO数据库抽象类库等。最后通过3个综合案例的数据库设计,进步讲述 MySQL在实际工作中的应用。
Spring5高级编程(第5版)
本书涵盖Spring 5的所有内容,如果想要充分利用这一领先的企业级 Java应用程序开发框架的强大功能,本书是最全面的Spring参考和实用指南。
本书第5版涵盖核心的Spring及其与其他领先的Java技术(比如Hibemate JPA 2.Tls、Thymeleaf和WebSocket)的集成。本书的重点是介绍如何使用Java配置类、lambda 表达式、Spring Boot以及反应式编程。同时,将与企业级应用程序开发人员分享一些见解和实际经验,包括远程处理、事务、Web 和表示层,等等。
JAVA核心知识点+1000道 互联网Java工程师面试题
企业IT架构转型之道 阿里巴巴中台战略思想与架构实战
本书讲述了阿里巴巴的技术发展史,同时也是-部互联网技 术架构的实践与发展史。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
发器、用户管理、数据备份与还原、MySQL 日志、性能优化、MySQL Repl ication、MySQL Workbench、 MySQL Utilities、 MySQL Proxy、PHP操作MySQL数据库和PDO数据库抽象类库等。最后通过3个综合案例的数据库设计,进步讲述 MySQL在实际工作中的应用。
[外链图片转存中…(img-7R29QMcx-1713472448777)]
Spring5高级编程(第5版)
本书涵盖Spring 5的所有内容,如果想要充分利用这一领先的企业级 Java应用程序开发框架的强大功能,本书是最全面的Spring参考和实用指南。
本书第5版涵盖核心的Spring及其与其他领先的Java技术(比如Hibemate JPA 2.Tls、Thymeleaf和WebSocket)的集成。本书的重点是介绍如何使用Java配置类、lambda 表达式、Spring Boot以及反应式编程。同时,将与企业级应用程序开发人员分享一些见解和实际经验,包括远程处理、事务、Web 和表示层,等等。
[外链图片转存中…(img-AvUYGdRl-1713472448778)]
JAVA核心知识点+1000道 互联网Java工程师面试题
[外链图片转存中…(img-hMvoIwDi-1713472448779)]
[外链图片转存中…(img-gPZms78y-1713472448780)]
企业IT架构转型之道 阿里巴巴中台战略思想与架构实战
本书讲述了阿里巴巴的技术发展史,同时也是-部互联网技 术架构的实践与发展史。
[外链图片转存中…(img-wF6P4cPp-1713472448781)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!