Map、Set和哈希表的应用练习(数据结构系列15)

news2025/1/12 0:58:40

目录

前言:

练习题:

结束语:


前言:

在上一节博客中小编给大家介绍了Map、Set和哈希表的一些简单的知识点,同时也给大家简单的演示了一下如何使用他们里面的一些基础方法,那么接下来让小编带着你们一起来将这些知识点运用起来吧!

练习题:

1.有10个数据,并且数据有重复的,要求我们对里面的数据进行去重操作。

思路分析:

我们要想达到去重的效果的话,那么我们先来回忆一下小编上节中给大家所讲的Map和Set两种,哪一种更适合去重呢?答案是Set,在Set中我们就只存储key值,且在Set中是不可以重复存储key值的,所以使用Set就可以很好的达到我们想要的效果。接下来我们就使用代码来实现一下吧。


代码展示:

package Map_Set和Hash练习题;
//有10个数据,并且数据有重复的,要求我们对里面的数据进行去重操作
import java.util.HashSet;
import java.util.Set;

public class Test1 {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();
        //对下面的一组数据进行去重
        int[] array = {1,1,2,3,2,4,5,5,6,6};
        for (int i = 0; i < array.length; i++) {
            set.add(array[i]);
        }
        System.out.println(set);
    }
}


结果展示:


2.有10个数据,并且数据有重复的,找到第一个重复的数据。

思路分析:

与上述的情况差不多,只不过需要我们在放入set中的时候进行判断一下这个元素是不是在set里面已经存在了,如果存在那么就直接输出,结束循环,如果不存在那么就将其放入到set中。你可以将set想象成一个麻袋,你要往麻袋里面存放这些数据,当你在放的时候要查看一下麻袋中是不是存在这个值,如果存在的话就不放了,如果不存在的话就放入其中。


代码展示:

package Map_Set和Hash练习题;

import java.util.HashSet;
import java.util.Set;

//有10个数据,并且数据有重复的,找到第一个重复的数据
public class Test2 {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();
        int[] array = {1,2,2,3,4,5,6,8,4};
        for (int x: array) {
            if (!set.contains(x)) {
                set.add(x);
            }else {
                System.out.println(x);
                break;
            }
        }
    }
}


结果展示:


3.统计10W个数据当中重复出现数据[val >= 2]出现的次数。

思路分析:

对于上述情况我们既要存储数据,又要统计数据出现的次数,此时就是一个k-v模型,我使用Map就可以达到我们想要的效果了,我先将数据都存储到map中去,然后再对map里面的键值对进行遍历,如果发现有val>=2的就将其输出并记录次数即可。


代码展示:

package Map_Set和Hash练习题;

import java.util.HashMap;
import java.util.Map;

//统计10W个数据当中重复出现数据[val >= 2]出现的次数
public class Test3 {
    public static void main(String[] args) {
        Map<Integer, Integer> map = new HashMap<>();
        //这里我们就先用十个数据进行模拟一下10W个数据
        int[] array = {1,2,2,3,4,5,6,7,8,4};
        //先将数据都放入到map中
        for (int x : array) {
            if (map.get(x) == null) {
                map.put(x,1);
            }else {
                map.put(x, map.get(x) + 1);
            }
        }
        //在进行遍历里面的键值对,查看里面的value值>=2的,统计并输出
        int count = 0;
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            if (entry.getValue() >= 2) {
                count++;
                System.out.println("key: " + entry.getKey() + " val: " + entry.getValue());
            }
        }
        System.out.println("val >= 2的有:" + count + "个");
    }
}


结果展示:


4.只出现一次的数字

题目描述如下所示:

给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

思路分析:

这里我们使用Set来进行做题,同样将set想象成一个麻袋,如果里面没有相同的则放入,如果存在的话就将里面的那个取出来,最后剩下的就是我们要找的数字。
代码展示:

package Map_Set和Hash练习题;

import java.util.HashSet;
import java.util.Set;

//只出现一次的数字
public class Test4 {
    public static int singleNumber(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for (int x : nums) {
            if (!set.contains(x)) {
                set.add(x);
            }else {
                set.remove(x);
            }
        }
        for (int x : nums) {
            if (set.contains(x)) {
                return x;
            }
        }
        return 0;
    }
    public static void main(String[] args) {
        int[] array = {1,1,2,2,3,5,5,6,6,8,8};
        int ret = singleNumber(array);
        System.out.println("其中" + ret + "只出现了一次!");
    }
}


结果展示:


 5.复制随机带指针的链表值

题目描述如下所示:

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。
你的代码 只 接受原链表的头节点 head 作为传入参数。

思路分析:


代码展示:

package Map_Set和Hash练习题;

import java.util.HashMap;
import java.util.Map;
//定义一个结点
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}

//复制随机带指针的链表值
public class Test5 {
    public Node copyRandomList(Node head) {
        Map<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);
    }
    public static void main(String[] args) {
        //由于小编这里只是简单的实现了一下函数,对链表没有具体的实现,大家可以自己实现一下,进行测试
    }
}

6.宝石与石头

题目描述如下所示:

给你一个字符串 jewels 代表石头中宝石的类型,另有一个字符串 stones 代表你拥有的石头。 stones 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。

字母区分大小写,因此 "a" 和 "A" 是不同类型的石头。

思路分析:

首先我们先将宝石中的字母存放到set中去,然后我们在对石头进行遍历,如果发现在set中存在就将计数器加加一下,最终我们就可以统计出石头中宝石的个数了。
代码展示:

package Map_Set和Hash练习题;

import java.util.HashSet;
import java.util.Set;

//宝石与石头
public class Test6 {
    public static int numJewelsInStones(String jewels, String stones) {
        Set<Character> set = new HashSet<>();
        //计数器
        int count = 0;
        //1.遍历宝石将宝石的字母都放入到set中
        for (int i = 0; i < jewels.length(); i++) {
            char ch = jewels.charAt(i);
            set.add(ch);
        }
        //2.遍历石头看set中是否存在
        for (int i = 0; i < stones.length(); i++) {
            char ch = stones.charAt(i);
            if (set.contains(ch)) {
                count++;
            }
        }
        return count;
    }
    public static void main(String[] args) {
        String jewels = "aA";
        String stones = "aAAbbbb";
        int ret = numJewelsInStones(jewels, stones);
        System.out.println("在石头中有" + ret + "个宝石!");
    }
}


结果展示:


 7.坏键盘打字

题目描述如下所示:

旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现。现在给出应该输入的一段文字、以及实际被输入的文字,请你列出肯定坏掉的那些键。

思路分析:

我们先将输入的字符串都以大写的方式放入到set中去,然后在将输出的字符串以大写的方式放入的新建的setBroken中去,然后在看两个中是否都包含了输入的字符,如果没有则输出。
代码展示:

package Map_Set和Hash练习题;

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

//坏键盘打字
public class Test7 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            String str1 = scanner.nextLine();
            String str2 = scanner.nextLine();
            error_BordKey(str1, str2);
        }
    }

    private static void error_BordKey(String str1, String str2) {
        Set<Character> set = new HashSet<>();
        //将输入的都放入到set中
        for (char ch : str2.toUpperCase().toCharArray()) {
            set.add(ch);
        }
        //将输出的在存放到另一个set中,然后判断两个中是否都包含ch如果都不包含那就说明是坏键。
        Set<Character> setBroken = new HashSet<>();
        for (char ch : str1.toUpperCase().toCharArray()) {
            if (!set.contains(ch) && !setBroken.contains(ch)) {
                setBroken.add(ch);
                System.out.print(ch);
            }
        }
    }
}


结果展示:


8.前K个高频单词

题目描述:

给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。

返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。

思路分析:

既然这里涉及到了统计单词的频率,那么我们就使用Map来将其统计出来和我们上面用到的方法一样,第二步我们在创建出一个小根堆,第三步我们将Map中的数据依次存放到小根堆中,注意当小于K的时候我们就直接存放进去即可,当大于K的时候我们就要与堆顶元素进行比较了,首先我们先来比较频率,如果频率不同则将大频率的放入小根堆中即可,但是如果频率相同则我们就需要进行比较单词首字母了,这里我们是按照字典序进行排序的,操作完成之后,此时小根堆里存放的就是我们需要的数据了,但是按照题目的要求是要按单词出现频率由高到低排序,所以我们要将数据先存放到一个线性表中,然后再进行反转输出即可。
代码展示:

package Map_Set和Hash练习题;

import java.util.*;

//前K个高频单词
public class Test8 {
    public static List<String> topKFrequent(String[] words, int k) {
        //1.遍历数组 统计每个单词出现的频率
        Map<String, Integer> hashMap = new HashMap<>();
        for (String str: words) {
            if (hashMap.get(str) == null) {
                hashMap.put(str, 1);
            }else {
                hashMap.put(str, hashMap.get(str) + 1);
            }
        }

        //2.建立小根堆
        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) {
                if (o1.getValue().compareTo(o2.getValue()) == 0) {
                    return o2.getKey().compareTo(o1.getKey());
                }
                return o1.getValue().compareTo(o2.getValue());
            }
        }
        );

        //3.遍历hashMap把里面的数据放到小根堆里面
        for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
            if (minHeap.size() < k) {
                minHeap.offer(entry);
            }else {
                //小根堆放满了k个,下一个entry和堆顶元素比较
                Map.Entry<String, Integer> top = minHeap.peek();
                //堆顶的频率小于当前entry的频率就出队,然后入队entry
                if (top.getValue().compareTo(entry.getValue()) < 0) {
                    minHeap.poll();
                    minHeap.add(entry);
                }else {
                    //频率相同的情况
                    if (top.getValue().compareTo(entry.getValue()) == 0) {
                        if (top.getKey().compareTo(entry.getKey()) > 0) {
                            minHeap.poll();
                            minHeap.add(entry);
                        }
                    }
                }
            }
        }
        //4.此时小根堆当中已经有了结果
        List<String> ret = new ArrayList<>();
        for (int i = 0; i < k; i++) {
            String key = minHeap.poll().getKey();
            ret.add(key);
        }
        Collections.reverse(ret);
        return ret;
    }
    public static void main(String[] args) {
        String[] words = {"i", "love", "leetcode", "i", "love", "coding"};
        int k = 2;
        System.out.println(topKFrequent(words, k));
    }
}


结果展示:


结束语:

好啦这节博客的内容小编就分享到这里啦!这节中小编主要是针对上一节博客的知识点和大家一起来练习了几道习题与大家一起实战演习一下,希望这节中大家能对上一节小编所讲的Map、Set和哈希表有更深刻的了解,大家继续跟紧小编的步伐,一起往前冲!!!想要学习的同学记得关注小编和小编一起学习吧!如果文章中有任何错误也欢迎各位大佬及时为小编指点迷津(在此小编先谢过各位大佬啦!)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/602079.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

当心!经济学家分析:未来三年内做好随时失业的准备

AI人工智能又来抢饭碗了&#xff0c;这次竟然通过了公认难考的会计行业考试&#xff01; 近期&#xff0c;OpenAI的大语言模型最新版GPT-4已经完成美国注册会计师&#xff08;简称CPA&#xff09;考试&#xff0c;四大主要会计考试所有科目的平均得分为85.1。 而在CPA考试中&…

落地页设计的营销心理学(三)

本文是「落地页设计的营销心理学」这个主题系列文章的收官篇&#xff0c;要给大家分享关于用户行动号召、提高用户参与度和整个营销落地页结构的设计。 回顾系列文章&#xff1a; 《落地页设计的营销心理学&#xff08;一&#xff09;》 《落地页设计的营销心理学&#xff08…

C++进阶 —— 线程库(C++11新特性)

十&#xff0c;线程库 thread类的简单介绍 在C11之前涉及多线程问题&#xff0c;都是和平台相关的&#xff0c;如windows和Linux下各有自己的接口&#xff0c;这使代码的可移植性较差&#xff1b;C11中最重要的特性就是对线程进行支持&#xff0c;使得C在并行编程时不需要依赖…

【社区图书馆】《写作脑科学》

文章目录 前言语言和思维写作技巧创造性思维总结 前言 杨滢著的《写作脑科学》是一本关于写作的科学读物&#xff0c;它深入探讨了人类大脑是如何进行创造性思维和表达的。这本书让我对写作有了全新的认识&#xff0c;也为我提供了一些实用的技巧和策略来提高自己的写作能力。…

整理 钢琴教材 约翰·汤普森现代钢琴教程(大汤)

邮箱不能及时回复,现放到网盘里了,文末按需自取 约翰-汤普森钢琴教程1 文件名:(大汤1)约翰汤普森现代钢琴教程 1 超清PDF 文件大小:9.9 MB 下载地址:https://download.csdn.net/download/qq_36040764/85051148 约翰-汤普森钢琴教程2 文件名:(大汤2)约翰汤普森现…

Python3中goto的用法

Python3代码指定跳转可以使用goto这个库&#xff1a; 安装&#xff1a; pip install goto-statement 一般安装的版本是1.2 需要做以下修改才能正常使用&#xff1a; python 使用goto&#xff0c;遇到的问题解决_奶嘴偷走初吻的博客-CSDN博客python goto 出现报错:Attribut…

Python difflib的使用

今天做了一个从list的内容取出一个与指定内容尽可能相似的内容,做完之后抽个几分钟记录下 difflib的作用 比对2个文件的差异. 使用的时候直接 import difflib 即可 get_close_matches 作用 匹配最大相似的内容返回结果 list1 ["abc", "acd", "…

NIO编程

目录 1、什么是NIO编程&#xff1f; 为什么说Java NIO是非阻塞的&#xff1f; 2、Java NIO 通道(Channel)详解 如何获取Channel对象&#xff1f; 3、Java NIO 缓冲区(Buffer)详解 &#xff08;1&#xff09;获取缓冲区对象 &#xff08;2&#xff09;将数据写入Buffer以…

没学过编程,本科学历,Java学到什么程度才能找工作?

好程序员之前写过多篇Java找工作方面的文章&#xff0c;今天说说零Java基础找工作的事情。首先请大家明确如下的要点。 1、在没有真实Java工作项目经验的前提下&#xff0c;靠自学&#xff0c;哪怕到培训班学&#xff0c;一定是无法真正掌握到能干Java项目的地步&#xff0c;原…

SpringData 基础篇

Spring Data 故事背景一&#xff1a;基础概念1.1 什么是SpringData1.2 为什么要用SpringData 二&#xff1a;JPA与Hibernate、MyBatis关系2.1 JPA与JDBC2.1.1 特点2.1.2 JPA规范提供2.1.3 JDBC的不足 2.2 Hibernate与JPA2.2.1 关系 2.3 mybatis 和Hibernate 三&#xff1a;Hibe…

裁剪与复原

目录 模型假设 模型建立 模型求解 通过建立匹配模型实现对破碎文件的拼接复原。 模型假设 模型建立 首先对每个图片按像素值进行二值化量化&#xff0c;可以得到19个1980*72的矩阵&#xff0c;再提取每个举证最左和最右的像素值采用绝对距离法建立像素匹配模型。 二值化是图…

大数据时代——生活、工作与思维的重大变革

最近读了维克托迈尔 – 舍恩伯格的《大数据时代》&#xff0c;觉得有不少收获&#xff0c;让我这个大数据的小白第一次理解了大数据。 作者是大数据的元老级先驱。 放一张帅照&#xff0c;膜拜下。 不过这本书我本人不推荐从头读一遍&#xff0c;因为书中的核心理念并不是特…

Django实现接口自动化平台(二)认证授权登录【持续更新中】

上一章&#xff1a; Django实现接口自动化平台&#xff08;一&#xff09;日志功能【持续更新中】_做测试的喵酱的博客-CSDN博客 下一章&#xff1a; Django实现接口自动化平台&#xff08;三&#xff09;实现注册功能【持续更新中】_做测试的喵酱的博客-CSDN博客 一、认证与…

FineBI6.0基础学习第二课 集团毛利率下滑的原因

【案例背景】 在本期分析案例中,您将扮演一个大型商品零售集团的数据分析师,应对经理交给你的任务——发现集团毛利率下滑的原因,并给出建议; 随着您一步一步的探索分析,您将通过对商品和订单的相关历史数据的分析,逐步找出影响毛利率的关键要素,并给出相应的分析结论,…

静态误差分析

分类 随机误差、系统误差、粗大误差。 随机误差&#xff1a; 大部分随机误差满足正态分布&#xff0c;具有对称性、单峰性、有界性、抵偿性。 对称性&#xff1a;绝对值相等的正负误差出现的次数相等。 单峰性&#xff1a;绝对值越小的误差出现次数越多。 有界性&#xff1…

GIS在地质灾害危险性评估与灾后重建中的实践

第一章 基本概念与平台介绍 1、基本概念 地质灾害类型 地质灾害发育特征与分布规律 地质灾害危害特征 地质灾害孕灾地质条件分析 地质灾害诱发因素与形成机理 ​ 2、GIS原理与ArcGIS平台介绍 GIS简介 ArcGIS基础 空间数据采集与组织 空间参考 空间数据的转换与处理 …

ReID专栏(三) 注意力的应用

前言 本文中提出了一种用于行人重识别的注意感知特征学习方法。该方法由一个部分注意分支&#xff08;PAB&#xff09;和一个整体注意分支&#xff08;HAB&#xff09;组成&#xff0c;并与基础再识别特征提取器进行了联合优化。由于这两个分支建立在主干网络上&#xff0c;因此…

NumPy 数值计算基础

NumPy 数值计算基础 Numpy简介Numpy创建数组对象第一种:利用array函数创建ndarray数组第二种:利用arange函数:创建等差一维数组第三种:利用linspace函数:创建等差一维数组&#xff0c;接收元素数量作为参数。第三种:利用linspace函数:创建等差━维数组&#xff0c;接收元素数量…

剑指 Offer 18. 删除链表的节点解题思路

文章目录 题目解题思路 题目 给定单向链表的头指针和一个要删除的节点的值&#xff0c;定义一个函数删除该节点。 返回删除后的链表的头节点。 注意&#xff1a;此题对比原题有改动 示例 1: 输入: head [4,5,1,9], val 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二…

Windows程序设计 学习笔记 第九章 子窗口控件

目录&#xff1a; 文章目录 一&#xff0c;按钮类1.创建子窗口拓展1——获取对话框字符尺寸的方法拓展2——获取实例句柄的方法2.子窗口传递消息给父窗口3.父窗口传递信息给子窗口拓展3 窗口句柄与ID 的相互获取① 已知窗口句柄 获取 ID②已知子窗口ID 获取 子窗口句柄 4. 按钮…