Java-数据结构-Map和Set(三)-习题 o(´^`)o

目录

❄️一、习题一(只出现一次的数字):

❄️二、习题二(随机链表的复制):

❄️三、习题三(宝石与石头):

❄️四、习题四(旧键盘):

❄️五、习题五(前k个高频单词):

❄️总结:


❄️一、习题一(只出现一次的数字):

☑ 题的传送门:

只出现一次的数字


这道题呢,有两种快速的解法,其一就是用 ^ 运算,其二就是使用 HashSet 来计算,我们一一来看,这些的解法:

其一:(^解法)

**我们呢在****相同的数字 ^**的时候呢就会为 0 ,所以我们的数字在 ^ 的时候呢,最后的出的数字就是我们的出现一次的数字,比如 1^1^2 = 2

代码:

java 复制代码
class Solution {
    public int singleNumber(int[] nums) {
        int ret = nums[0];
        for(int i = 1;i < nums.length; i++) {
            ret = ret ^ nums[i];
        }
        return ret;
    }
}

其一:(HashSet的解法)

我们每次检查 HashSet 中呢是否有 nums[i] 这个数值,如果有呢就把这个数值从 HashSet中删除,如果没有这个数值,就把其入 HashSet 中,最后在 HashSet 中的数值就是我们要找的值

代码:

java 复制代码
class Solution {
    public int singleNumber(int[] nums) {
        HashSet<Integer> set = new HashSet<>();
        for(int s : nums) {
            if(set.contains(s)) {
                set.remove(s);
            }else {
                set.add(s);
            }
        }
        for(int i = 0; i < nums.length;i++) {
            if(set.contains(nums[i])) {
                return nums[i];
            }
        }
        return -1;
    }
}

❄️二、习题二(随机链表的复制):

☑ 题的传送门:

随机链表的复制


这道题呢不是简单得直接把 链表复制下来就结束的。这道题呢还是比较麻烦的,这个需要深拷贝的,这里呢,我们使用 HashMap 来做。

因为呢 我们这道题的 random 可能指向的是自己也可能是空,也可能是 跳跃的指向。而且我们拷贝之后呢,我们新的节点是一个 新的地址 ,这样呢我们直接拷贝的话,我们的 next 和 random 这个就不是指向我们下一个节点了。

步骤:

1、我们先把链表的节点的值拷贝到 HashMap 中

2、我们的 HashMap 里面存放的是 <Node,Node>

3、根据我们 HashMap 中拷贝的节点值,再把对应的 next 和 random 拷贝进去。

OK,理解这个步骤之后呢,我们来看看代码如何编写的:

java 复制代码
class Solution {
    public Node copyRandomList(Node head) {
       HashMap<Node,Node> map  = new HashMap<>();
       Node cur = head;

       while (cur != null) {
        Node node = new Node(cur.val);
        map.put(cur,node);
        cur = cur.next;
       }

       cur = head;

       while(cur !=null) {
        map.get(cur).next = map.get(cur.next);
        map.get(cur).random = map.get(cur.random);
        cur = cur.next;
       }

       return  map.get(head);
    }
}

❄️三、习题三(宝石与石头):

☑ 题的传送门:

宝石与石头


这个题呢还是比较简单的,我们直接使用 HashSet 就可以快速解决。

步骤:

1、我们先把 "宝石" 中的每一个字符放到 HashSet 中

2、遍历 "石头" 这个字符串,之后查看 HashSet 中是否存在 这个字符,如果存在 count++

是不是非常简单,所以呢我们来看看代码:

java 复制代码
class Solution {
    public int numJewelsInStones(String jewels, String stones) {
        HashSet<Character> set = new HashSet<>();
        for(int i = 0;i < jewels.length();i++) {
            //先把宝石类型的字符串都放到HashSet中
            char ch = jewels.charAt(i);
            set.add(ch);
        }
        int count = 0;
        for(int j = 0;j < stones.length();j++) {
            //根据HashSet中的值和石头的字符一一比较,相同的count++
            char ch = stones.charAt(j);
            if(set.contains(ch)) {
                count++;
            }
        }
        return count;
    }
}

OK,这个题就是这个样子的非常的简单的,我们来看看下一道题。


❄️四、习题四(旧键盘):

☑ 题的传送门:

旧键盘


这个题呢和我们上面的题呢是差不多的思路。

步骤:

1、先把 两个字符串 都转换成大写的

2、之后把 键盘坏的打的字符串 都放到 HashSet 中

3、我们再创建一个 HashSet ,遍历 好的键盘的打出来的字符

4、如果开始的那个 HashSet 中没有 好的字符 并且 后创建的那个 HashSet 中没有这个字符的话,就将其打印出来,并且放到后面的 HashSet 中。

这个题呢,还是比较好理解的,所以呢我们直接来看代码如何编写的:

java 复制代码
import java.util.Scanner;
import java.util.HashSet;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            String str1 = in.nextLine();
            String str2 = in.nextLine();
            func(str1,str2);
        }
    }

    public static void func(String str1,String str2) {
        //转成大写
        str1 = str1.toUpperCase();
        str2 = str2.toUpperCase();

        //把坏的键盘的字符串放到 HashSet 中
        HashSet<Character> set1 = new HashSet<>();
        for(int i = 0; i < str2.length();i++) {
            char ch = str2.charAt(i);
            set1.add(ch);
        }

        HashSet<Character> set2 = new HashSet<>();        
        //遍历str1 看看set1 和 set2 中是否 存在
        //如果不存在就放到 set2 中 并且 打印
        for(int i = 0; i < str1.length();i++) {
            char ch = str1.charAt(i);
            if (!set1.contains(ch) && !set2.contains(ch)) {
                set2.add(ch);
                System.out.print(ch);
            }
        }
    }
}

OK,这个就是这个题的代码,上面的那个题麻烦一些。


❄️五、习题五(前k个高频单词):

☑ 题的传送门:

前k个高频单词


这道题呢就比较难了,看到这个 "前k个" 是不是想起了我们以前介绍过的 Top-k 问题,我们的这道题呢就是存在 Top-k 问题的 并且和 HashMap 联合一起做这道题,才可以,我们来看看如何做到的。

步骤:

1、先定义一个 HashMap 里面的 key-value 是 String-Integer ,我们的 Integer 用来记录对应的String出现了几次。

2、建立 小根堆 这里不是简单的存储 Integer 而是存储 HashMap 的底层的 Map.Entry<String,Integer>,根据这里的Integer 来进行比较的,但是这里呢要注意的是,当不同的单词出现的次数相同的时候呢,我们根据 字典的顺序进行存储,所以这里的 创建小根堆 是要传一个新的比较器的

3、每次去 map 的数据,先把 堆的长度 和 k进行比较:

如果:堆的长度 < k 的话,就直接入堆

如果:堆的长度 >= k 的话,我们还需要判断:

如果:堆顶数据的value值 < map的 value 值的话,说明map对应的 key 出现的次数多, 就把 堆顶的数据进行出堆,并且把 map的这个数据 入堆。

如果: 堆顶数据的value值 == map的 value 值的话。我们就要判断对应的 key 的大小了

如果:堆顶数据的key 值 > map的 key 值的话,我们就把堆顶数据 出堆,并且把 map 的数据进行 入堆。

4、我们创建一个 ArrayList 的集合,把 堆中的 k 个 String 都放到 ArrayList 中,这个时候还是存在问题的,这时 ArrayList 中存放的是从小到大的排序,我们要把其 翻转过来。

5、对其 ArrayList 进行翻转。

这个呢就是这道题的大体思路了,我们来看看如何进行编写的代码:

java 复制代码
class Solution {
   public List<String> topKFrequent(String[] words, int k) {
        HashMap<String,Integer> map = new HashMap<>();
        //1. 统计每个单词出现的次数
        for(String word : words) {
            if(map.get(word) == null) {
                map.put(word,1);
            }else {
                int val = map.get(word);
                map.put(word,val+1);
            }
        }

        //2. 建立小根堆
        PriorityQueue<Map.Entry<String,Integer>> minHeap = new PriorityQueue<>(new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                if(o1.getValue().compareTo(o2.getValue()) == 0) {
                    return o2.getKey().compareTo(o1.getKey());
                }
                return o1.getValue().compareTo(o2.getValue());
            }
        });
        //3.遍历map
        for(Map.Entry<String,Integer> entry : map.entrySet()) {
            if(minHeap.size() < k) {
                minHeap.offer(entry);
            }else {
                Map.Entry<String,Integer> top = minHeap.peek();
                if(top.getValue().compareTo(entry.getValue()) < 0) {
                    minHeap.poll();
                    minHeap.offer(entry);
                }else if(top.getValue().compareTo(entry.getValue()) == 0) {
                    if(top.getKey().compareTo(entry.getKey()) > 0) {
                        minHeap.poll();
                        minHeap.offer(entry);
                    }
                }
            }
        }
        ArrayList<String> list = new ArrayList<>();

        for (int i = 0; i < k; i++) {
            Map.Entry<String,Integer> tmp = minHeap.poll();
            list.add(tmp.getKey());
        }
        //e-2 b-5 c-6
        Collections.reverse(list);
        return list;
    }
}

❄️总结:

OK,这次关于我们的 哈希表 相关的练习题呢,到这里就结束了,让我们下次再见,下次呢我们就要进入新的知识章节了,让我们尽情期待吧!!!拜拜~~~

相关推荐
全栈Blue6 分钟前
详解代理模式-【静态代理与JDK动态代理】(非常的斯国一)
java·代理模式
易辰君20 分钟前
python爬虫 - 初识爬虫
开发语言·爬虫·python
长天一色28 分钟前
【C语言系统编程】【第三部分:网络编程】3.2 数据传输和协议
c语言·开发语言·网络
customer0832 分钟前
【开源免费】基于SpringBoot+Vue.JS美容院管理系统(JAVA毕业设计)
android·java·vue.js·spring boot·spring cloud·开源
结衣结衣.35 分钟前
Python基础语法1
开发语言·笔记·python·学习·编程·编程语法
风雨「83」39 分钟前
centos已安装python3.7环境,还行单独安装python3.10环境,如何安装,具体步骤
linux·开发语言·python
太自由1 小时前
SpringBoot之Profile的两种使用方式
java·spring boot·后端·profile·springboot多环境配置·profile注解
tiantian17)1 小时前
深入学习并发编程中的 synchronized
java·学习
碳苯1 小时前
【rCore OS 开源操作系统】Rust HashMap应用 知识点及练习题
开发语言·rust·操作系统
hakesashou1 小时前
php与python建站的区别有哪些
开发语言·php