Java集合与数据结构——Map & Set 习题练习

一、map & set 基础练习


1.有十万个数据,找到第一个重复的数据

在这里插入图片描述

就是说我们 在这个题上用了 set 的有关性质 , 我们有十万个数据,要查找到第一个重复的数据,我们可以这样: 我们将 list 中的数据一个一个放入 set中,如果 set没有这个数据,那么就 放入set中,如果 set中包含了这个数据,那么打印这个数据,同时 break;


2. 有十万个数据,去除掉所有重复的数据

在这里插入图片描述

直接遍历这个数组,将数组所有数据全部放进 set中,重复的数据自然会 插入失败,所以最后 set 中的元素全都是 不重复的数据.


3.有十万个数据,统计每个数据出现了多少次

使用map 和 set 来解题

在这里插入图片描述

这道题非常经典,所以我们 一定要理解深刻

我们将 数组中的 各个数据,及数据出现的次数 作为一个键值对 放入Map 中

put之前先判断 map 中之前是否有 key ,如果没有的话,map.getKey() == null ,我们就直接 map.put( key,1 ).

如果没有的话,先 int count = map.getKey(), 得到这个key之前出现的次数,然后 map.put(key,count+1)

最后遍历 map,将map的所有键值对 全部打印出来.


二、 刷题练习


1. 只出现一次的数字

在这里插入图片描述

题解代码1:
在这里插入图片描述

写这个代码的思路: 我们有一个 Set 的集合,先遍历数组,如果Set 里不包含 nums[i],那么就把 nums[i] 放入 set 中,但是如果 Set 中包含 nums[i] ,那么就把 set中的 nums[i] 删除.

到最后 set中剩下的就是只出现一次 的数字

题解代码2:

在这里插入图片描述

写这个思路的代码: 这个是用Map 记录了nums 数组中每一个数据出现的次数,最后遍历 map.entrySet(),当 entry.getVaue()==1 时,这个数据就出现了一次,返回 entry.getKey().

如果在这组数据中没有单独出现的数字,那么返回-1(不要那么严谨,只是了解逻辑即可,不需要联系业务逻辑.)


2. 复制随机指针

在这里插入图片描述

比如说我们有这样一个链表,我们要做到的就是 复制这样一组相同结构的 链表

这里有一个注意点,同样也是难点:就是引用的复制

我们在复制节点的时候,不能够全部一块复制,否则就会出现这样的情况

在这里插入图片描述

我们发现复制节点的全部信息的话,新节点指向的next 、random 指向的还是原节点的位置

所以 next、random 我们要重新赋值,新节点新链表的结构要像原链表一样…

在这里插入图片描述

我们如何解决呢?

我们在 遍历原链表的时候,每走一个节点 cur ,就 new 一个新的节点 node ,原节点和新节点是一一对应的关系,map.put(cur,node ).

我们可以通过这样,来使新的节点组成 原链表的关系

map.get(cur).next = map.get(cur.next)
map.get(random).next = map.get(cur.random);

题解代码:

在这里插入图片描述


3.宝石与石头

在这里插入图片描述

(1)暴力破解法


暴力法的思路很直观,遍历字符串 stones,对于 stones 中的每个字符,遍历一次字符串 jewels,如果其和 jewels 中的某一个字符相同,则是宝石。


(2) Hash集合法


方法一中,对于字符串stones 中的每个字符,都需要遍历一次字符串 jewels,导致时间复杂度较高O(m*n)。如果使用哈希集合存储字符串 jewels 中的宝石,则可以降低判断的时间复杂度。

遍历字符串 jewels,使用哈希集合存储其中的字符,然后遍历字符串 stones,对于其中的每个字符,如果其在哈希集合中,则是宝石。时间复杂度 O(m+n)

题解代码:
在这里插入图片描述

4. 坏键盘打字

在这里插入图片描述

题解代码:

在这里插入图片描述

题解思路:

这个题非常注意 输出的格式. 输出的时候找出的键盘全都是 大写的字母数字

  1. str 1 ---- 期望输出的字符串
  2. str 2 — 实际输出的字符串

设置 一个 setAutal 将实际输出的键的大写字符放入到 setAutal 中

先将 str2 的字符转换成为 大写 ,然后 str2 转换成数组 ,foreach 遍历.

将大写的 str2 字符放入到 setAutal 集合中.

设置一个 setBroken 将坏的键 放入到 这个集合中

怎么判断这是一个坏的键呢?

遍历 str1 期望输出的字符串(记得直接大写遍历),如果 setAutal 不包含 str1 中的键,把那个键 存入到 setBroken.


打印的时候 有几点注意: 他打印的规则 ,一定是遍历期望打印的数组,一个一个字符遍历,只要 期望打印的字符 在 setAutal 中没有的话,那么先放进 setBroken ,然后 打印 这个字符 ch,我们为什么要放进 setBroken 呢? 因为打印之前还有一个条件,就是 setBroken 中已经有的就不打印了.否则就会出现 这个坏的键 重复打印.


5.前 k 个高频单词


题目描述:

在这里插入图片描述

题解代码:

在这里插入图片描述


这道题可以说的上是 以前做leetcode 以来代码量最多的一道题了,我先说一句没那么简单,但也是有 基本的 topK问题变形而来的.

我先说写这个题的逐步思路吧…


1.首先这个是一个 topK 问题,要求我们把 出现次数最多的 k 个数据 输出,,我们已经学过了 map,将他给我们提供的 字符串数组进行遍历,得到每个数据 与其对应的 出现的次数

在这里插入图片描述

2.接下来是topK 的思路,找到 次数最多的k个数据,那我们就要建立一个 大小为k 的小堆

在这里插入图片描述


3.往堆中 放入 map 中的数据

在这里插入图片描述

当 大于 k 时,往堆中放数据 ,要注意: 当遍历元素 出现次数 与 堆顶元素出现次数 相同时 ,比较字符串,字符串小的优先入队.


4.因为返回的是 List ,所以用一个 list 来接收堆中的数据

在这里插入图片描述


5.我们来看一下 测试通过的情况.

在这里插入图片描述

我们发现 解答错误,具体来看一下,发现有一个问题没有解决, 我们只在 当 k+1 遍历元素的时候提供了 当出现次数相等时比较字符串大小的思路, 但是我们在 当 minheap.siez()<k ,没有提供 这个,所以在我们建小堆的时候 应该处理一下这种情况


6.处理 当 size<k 时建堆的情况

在这里插入图片描述

7.我们再来看一下 ,测试的情况

在这里插入图片描述

又出现了解答错误,我们发现他想要我们输出的是从大到小的 出现次数的结果,但是我们建立的小堆,每次弹出最小的放入 list 中,这是从小到大的结果,为了解决这个输入问题,我们呢可以逆置顺序表.


8.逆置顺序

在这里插入图片描述


9.再来测试我们的结果

在这里插入图片描述

发现又是解答错误,这是为什么呢?

之前在没有逆置之前,我们已经解决了 这个 k < minHeap.size() 的问题,现在逆置了一下,又把我们正确的结果给颠倒了,所以现在 我们将之前 建堆时 出现次数相等

return o1.getKey().compareTo(o2.getKey());

改为----

return o2.getKey().compareTo(o1.getKey())

这样就恢复到正确的顺序了.


10.最后完整版测试情况.

在这里插入图片描述

最后成功通过…


6.下厨房

题目描述:

在这里插入图片描述

我们先 理清一下这道题目 想要表达什么意思,这道题就是牛牛 输入的每一行是他想要 做的一道菜所需要的 材料,注意: 菜 与 菜 之间的材料 很可能会重复 ,现在要 求一共有多少种材料

思路:

1.首先肯定要用 set 集合遍历每一种 材料,来存储 这些不同的材料,相当于 去重了.

在这里插入图片描述

2.这是多行输入

在这里插入图片描述

3.我们要把他输入的每一行的 字符串 以空格为 分隔符 ,把每一个材料 专门 放在 一个数组中. 要用到 字符串的分割函数 split

在这里插入图片描述

7.斐波那契数列

1.题目描述:

在这里插入图片描述

2.思路:

(1) 构建斐波那契数列,同时输入一个 n

在这里插入图片描述

(2)写一个循环 ,目的是找到 n 的左右两边 的斐波那契数 , 循环的条件就是 f2<n

当循环跳出来时 ,f2 >= n , f1 必定 小于 n ,所以
在这里插入图片描述

(3) 此时 f2 >= n , f1 必定 小于 n ,我们要计算 n 到斐波那契数需要最少的步数

比较 f1-n 和 f2-n 的绝对值,可以得到 n 距离 f1、f2 哪一个最近

谁比较小,就打印谁的绝对值

在这里插入图片描述

代码展示:

在这里插入图片描述



今天的分享到这里就结束了,感谢大家的欣赏!!



  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RAIN 7

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值