Map && Set,带你进入Java最常用到的两个接口 - 细节狂魔

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
img

正文

实践 - 后面两个不演示,用的少


boolean add(E e) 添加元素 - 但重复元素不会被添加成功

在这里插入图片描述


void clear() - 清空集合

在这里插入图片描述


boolean contains(Object o) - 判断 o 是否在集合中

在这里插入图片描述


Iterator iterator() - 返回迭代器

可参考 List 接口相关知识 - ArrayList数据结构

在这里插入图片描述


此时,我们再来迭代器是如何打印 Set 中的元素。

在这里插入图片描述


boolean remove(Object o) - 删除集合中的 o

在这里插入图片描述


int size() - 返回set中元素的个数

在这里插入图片描述


boolean isEmpty() - 检测set是否为空,空返回true,否则返回false

在这里插入图片描述


Object[] toArray() - 将set中的元素转换为数组返回

在这里插入图片描述


注意事项:


1、Set 是继承自 Collection 的 接口类

2、Set 中 值存储了 Key,并且要求 Key 一定要唯一

3、Set 的底层是 使用 Map 来实现,其使用 Key 与 Object 的 一个默认对象作为 “键值对” 插入到Map中的

4、Set 最大的功能就是集合中的元素进行去重

5、 实现 Set 接口的常用类 有 TreeSet 和 HashSet,还有一个linkedHashSet,LinkedHashSet 是在 HashSet 的基础上 维护了一个双向链表来记录元素的插入次序。

在这里插入图片描述

6、Set 中 Key 不能修改,如果要修改,先将原来的删除掉,然后再重新插入。

7、Set 中不能插入 null 的 key

8、TreeSet 和 HashSet 的区别

| Set底层结构 | TreeSet | HashSet |

| — | — | — |

| 底层结构 | 红黑树 | 哈希桶 |

| 插入/删除/查找时间 | O(log2 N) | O(1) |

| 是否有序 | 关于Key有序 | 不一定有序 |

| 线程安全 | 不安全 | 不安全 |

| 插入/删除/查找区别 | 按照红黑树的特性来进行插入和删除 | 1. 先计算key哈希地址 2. 然后进行插入和删除 |

| 比较与覆写 | key必须能够比较,否则会抛出ClassCastException异常 | 自定义类型需要覆写equals和hashCode方法 |

| 应用场景 | 需要Key有序场景下 | Key是否有序不关心,需要更高的时间性能 |


面试题练习

====================================================================

LeetCode - 136. 只出现一次的数字


在这里插入图片描述


解题思维一:HashSet - 这个思维不适合这题,主要锻炼对 HashSet的掌握。

将所有数据存储 HashSet 中,根据 Set 的 特性,我们明白 Set 具有去重的功能。

所以,我们不能一股脑全部将数据存入,需要作出判断。

思路:在存入数据的时候,去判断存入的数据,在Set 中 是否存在,如果存在,则将该数据删除。

不存在就存入。

【注意题干!最多就两个相同数据】

取出的时候,只需要遍历数组,通过 contains 方法,判断是否包含元素 Key。找到了就返回 Key。

如果没有找到那个只出现一次的 Key,就返回 -1。


代码如下

class Solution {

public int singleNumber(int[] nums) {

Set set = new HashSet<>();

for(int i : nums){

if(set.contains(i)){

set.remove(i);

}else{

set.add(i);

}

}

int result = 0;

for(int i : nums){

if( set.contains(i)){

result = i;

}

}

return result;

}

}

在这里插入图片描述


解题思维二:HashMap - 【key 为 元素, Value 为 出现次数】

将数据全部存入 HashMap 中,并在存入的过程中判断该元素 在HashMap 中是否存在。

如果存在,说明它已经有一个了【value = 1】,即我们需要在此基础上加上1。反之,如果 HashMap中不存在该元素,返回的Value 为 null,此时就是第一次存入,将 对应 Key - Value 存入。

取出的时候,只需要遍历数组,通过 get 方法,返回其 Value 值,如果等于1,就返回 对应 Key。

如果没有找到那个只出现一次的 Key,就返回 -1。


代码如下

class Solution {

public int singleNumber(int[] nums) {

Map<Integer,Integer> map = new HashMap<>();

for(int i : nums){

Integer count = map.get(i);

count = count == null ? 1 : ++count;

map.put(i, count);

}

for(int i : nums){

Integer count = map.get(i);

if(count == 1){

return i;

}

}

return -1;

}

}

在这里插入图片描述


解题思维二: 异或

利用异或的特性: 相同为零,相异为1。

而题目说: 数组中只有一个出现一次的元素,其它都是两次。也就是说 一旦进行异或,这些出现2次的元素最终异或的结果为 零,而 只出现一次的元素 与 零进行异或,其结果还是 只出现一次的元素。

所以,我们要做的就是将数组的所有元素进行异或,其结果就是 只出现一次的元素。


代码如下

class Solution {

public int singleNumber(int[] nums) {

int result = nums[0];

for(int i = 1;i < nums.length;i++){

result ^= nums[i];

}

return result;

}

}

在这里插入图片描述


LeetCode - 138. 复制带随机指针的链表


在这里插入图片描述


思维一 : 叠代实现

你们可以直接看我这篇博客复制带随机指针的链表 - Java - 迭代实现


思维二 : HashMap

在这里插入图片描述


代码如下

class Solution {

public Node copyRandomList(Node head) {

Map<Node,Node> map = new HashMap<>();

Node tmp = head;

while(tmp != null){

Node node = new Node(tmp.val);

map.put(tmp,node);

tmp = tmp.next;

}

tmp = head;

while(tmp != null){

map.get(tmp).next = map.get(tmp.next);

map.get(tmp).random = map.get(tmp.random);

tmp = tmp.next;

}

return map.get(head);

}

}

在这里插入图片描述


LeetCode - 771. 宝石与石头


在这里插入图片描述


解题思维一 :HashSet

利用HashSet的去重机制,去记录 jewels 字符串中的 “宝石类型”/ 字符。

至于为什么用HashSet:是因为我们不需要去记录每个类型宝石的对应的个数。

只需要去统计宝石的总个数。

后面,创建一个整形变量result去记录宝石的个数,只需要去 遍历stones字符串,利用 HashSet 的 contains 方法去判断 stones 字符串里的 字符 是在存在HashSet 中,如果存在就加一。最终返回累加结果。


代码如下

// 时间复杂度:O(m+n),其中m是字符串jewels 的长度,n 是字符串stones 的长度。

// 空间复杂度:O(m),其中 m 是字符串jewels 的长度。使用哈希集合存储字符串jewels 中的字符个数。

class Solution {

public int numJewelsInStones(String jewels, String stones) {

Set set = new HashSet<>();

for(int i = 0;i < jewels.length();i++){

set.add(jewels.charAt(i));

}

int result = 0;

for(int i = 0;i < stones.length();i++){

if(set.contains(stones.charAt(i))){

result++;

}

}

return result;

}

}

在这里插入图片描述


解题思维二 :暴力

双重循环:外层 遍历 jewels,内层遍历 stones。

思路:先定义一个整形变量 result ,每拿到一个 jewels的字符,就到 stones 去里看看有没有“符合条件的宝石”。

有 : result++。

最后返回累加的结果。


代码如下

//时间复杂度:O(mn),其中 m 是字符串 jewels 的长度,n 是字符串stones 的长度。

// 空间复杂度:O(1)。只需要维护常量的额外空间

class Solution {

public int numJewelsInStones(String jewels, String stones) {

int result = 0;

for(int i = 0;i < jewels.length();i++){

char ch = jewels.charAt(i);

for(int j = 0;j < stones.length();j++){

if(stones.charAt(j) == ch){

result++;

}

}

}

return result;

}

}

在这里插入图片描述


牛客网 - 旧键盘 (20)


在这里插入图片描述


解题思维 : HashSet

为了方便大家理解,我将输入的数据整理一下。

在这里插入图片描述

我们的思路:还是利用HashSet 去做。

在这里插入图片描述


代码如下

import java.util.*;// 导包

public class Main{

public static void function(String strExpect,String strActtal){

Set setA = new HashSet<>();

// strActtal 先转大写,再转为数组

for(char ch : strActtal.toUpperCase().toCharArray()){

setA.add(ch);

}

Set setP = new HashSet<>();

// strExpect 先转大写,再转为数组

for(char ch : strExpect.toUpperCase().toCharArray()){

if(!setA.contains(ch) && !setP.contains(ch)){

System.out.print(ch);

setP.add(ch);

}

}

}

public static void main(String[] args){

// 循环输入

Scanner sc = new Scanner(System.in);

while(sc.hasNextLine()){

String strExpect = sc.nextLine();

String strActtal = sc.nextLine();

function(strExpect,strActtal);

}

sc.close();// 资源回收

}

}

在这里插入图片描述


LeetCode - 692. 前K个高频单词


在这里插入图片描述


题目分析

在这里插入图片描述

看到上面框选的文字,我们脑中的第一个想法:这涉及到 TopK - 问题

在这里插入图片描述

既然是TopK 问题,再加上题目要求返回的是 前k个出现次数最多额单词。

那么,我们就需要建立一个 小根堆。

但这不是难点,难点下面图所框选的。

在这里插入图片描述

下面我们就分析一下这两个条件。

在这里插入图片描述

下面,我们一个个来解决问题。 先来解决第一个问题:返回的答案应该按单词出现频率由高到低排序

import java.util.*;

public class Manuscript{

public static List topKFrequent(String[] words, int k) {

// 1、 统计 每个单词的出现的次数 》》 map

HashMap<String,Integer> map = new HashMap<>();

for(String s : words){

if(map.get(s) == null){

map.put(s,1);

}else{

int val = map.get(s);

map.put(s,val+1);

}

}

// 第二步 建立一个 大小为 K 的小根堆。【Key - word,Value - 出现次数】

// 利用 entrySet 方法,将 Key - Value 结合。看作一个整体

PriorityQueue<Map.Entry<String,Integer>> minHeap = new PriorityQueue<>(k, new Comparator<Map.Entry<String, Integer>>() {

@Override

public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {

return o1.getValue() - o2.getValue();

// 以 出现次数 大小 为比较规则。

}

});

// 遍历map,建堆。

for (Map.Entry<String,Integer> entry:map.entrySet()) {

// 先放入 K 个 元素。

if(minHeap.size() < k){

minHeap.offer(entry);

}else {

// 说明堆中 已经放满了 K 个元素,接下里需要看堆顶元素的数据 和 当前的数据的大小关系

Map.Entry<String,Integer> top = minHeap.peek();

//判断频率是否相同,如果相同,比较单词的大小,单词ASCII小 的 入队。

// 因为题目要求:如果不同的单词有相同出现频率, 按字典顺序 排序

// a ~ z ASCII码:97 ~ 122

if(entry.getValue().compareTo(top.getValue()) == 0 ){

if(top.getKey().compareTo(entry.getKey()) > 0){

minHeap.poll();

minHeap.offer(entry);

}

}else{

// 出现频率高:入堆。

if(entry.getValue().compareTo(top.getValue()) > 0){

minHeap.poll();

minHeap.offer(entry);

}

}

}

}

System.out.println(minHeap);

// 返回值类型 创建

List ret = new ArrayList<>();

for(int i = 0;i < k;i++){

Map.Entry<String,Integer> top = minHeap.poll();

ret.add(top.getKey());

}

// 反转/ 逆置

Collections.reverse(ret);

return ret;

}

public static void main(String[] args) {

String[] worlds = {“the”, “day”, “is”, “sunny”, “the”, “the”, “the”, “sunny”, “is”, “is”};

List list = topKFrequent(worlds,4);

System.out.println(list);

}

}

在这里插入图片描述

但是,还没完。还有一个点没有解决 : 就是在前 K个出现次数最多的单词里,存在两个出现次数一样的不同单词。需要按照字母表顺序排序排列。

就比如,我们代入示例1的结果。

在这里插入图片描述

这个问题出在哪里呢?就在下图的代码位置

在这里插入图片描述


代码如下

public class Manuscript{

public List topKFrequent(String[] words, int k) {

// 1、 统计 每个单词的出现的次数 》》 map

HashMap<String,Integer> map = new HashMap<>();

for(String s : words){

if(map.get(s) == null){

map.put(s,1);

}else{

int val = map.get(s);

map.put(s,val+1);

}

最后

面试题文档来啦,内容很多,485页!

由于笔记的内容太多,没办法全部展示出来,下面只截取部分内容展示。

1111道Java工程师必问面试题

MyBatis 27题 + ZooKeeper 25题 + Dubbo 30题:

Elasticsearch 24 题 +Memcached + Redis 40题:

Spring 26 题+ 微服务 27题+ Linux 45题:

Java面试题合集:

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

public class Manuscript{

public List topKFrequent(String[] words, int k) {

// 1、 统计 每个单词的出现的次数 》》 map

HashMap<String,Integer> map = new HashMap<>();

for(String s : words){

if(map.get(s) == null){

map.put(s,1);

}else{

int val = map.get(s);

map.put(s,val+1);

}

最后

面试题文档来啦,内容很多,485页!

由于笔记的内容太多,没办法全部展示出来,下面只截取部分内容展示。

1111道Java工程师必问面试题

[外链图片转存中…(img-LyryQ6GG-1713638813389)]

MyBatis 27题 + ZooKeeper 25题 + Dubbo 30题:

[外链图片转存中…(img-0gdPpmlN-1713638813390)]

Elasticsearch 24 题 +Memcached + Redis 40题:

[外链图片转存中…(img-H1MhVaeH-1713638813391)]

Spring 26 题+ 微服务 27题+ Linux 45题:

[外链图片转存中…(img-AUvKxJuo-1713638813391)]

Java面试题合集:

[外链图片转存中…(img-NTOxiBur-1713638813392)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-pJnJmNPq-1713638813392)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 24
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值