Map和Set(常见的使用方法 及 习题)

目标: 用Map和Set实现类:HashMap / TreeMap / HashSet / TreeSet;
学会TreeMap / TreeSet 背后的数据结构搜索树的原理和简单实现;
学会HashMap / HashSet 背后的数据结构哈希表的原理和简单实现。
应用: 检索。在大量的数据元素中找到某个特定的元素而进行的工作。
模型: 一般把搜索的数据称为关键字(key),和关键字对应的称为值(value),所以模型会有两种:(1)纯key模型 ,即Set要解决的事情,只需判断关键字是否在集合中(不能有重复),没有关联的value;(2)key-value模型 ,即Map要解决的事情,需要根据指定key找到关联的value

1、Map的简单使用

在这里插入图片描述
遍历Map的4种方式!

Map的常用方法:
在这里插入图片描述

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

public class MapSet {
    public static void main(String[] args) {
        Map<String,String> map=new HashMap<>();//HashMap是Map其中的一个类
        //HashMap<Integer,String> map1=new HashMap<>();//这是一个具体的类,哈希表可以看成是一个表格
        map.put("孟德","曹操");
        map.put("小张","张飞");
        map.put("小关","关羽");
        map.put("小刘","刘备");
        System.out.println(map);
        System.out.println(map.get("小张"));

        for(Map.Entry<String,String> entry : map.entrySet()){
            System.out.println(entry.getKey()+":"+ entry.getValue());
        }
    }
}

在这里插入图片描述

2、Set的简单使用

set里的key不能重复,若出现重复,只会存储其中一个。
TreeSet底层是二叉搜索树(红黑树),会按照key的大小关系来排序,默认大小为11,2n+1扩充。
set的常用方法:
在这里插入图片描述

import java.util.*;
public class MapSet {
	public static void main(String[] args) {
        Set<Integer> set=new TreeSet<>();
        set.add(1);
        set.add(21);
        set.add(6);
        set.add(19);
        System.out.println(set);

        Iterator<Integer> it=set.iterator();//迭代器,遍历集合中的对象
        while(it.hasNext()){
            System.out.println(it.next());//打印的时候判断是否有下一个,若有下一个就打印它,it继续往下走判断是否有下一个
        }
    }
}

在这里插入图片描述

练习题:

1、找出10万个数据当中,第一个重复的元素

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Random;
public class MapSet {
    public static void main(String[] args) {
        Random random=new Random();
        ArrayList<Integer> list=new ArrayList<>();
        for(int i=0;i<10_0000;i++){//生成10万个数据,每个数据都是在0到6000,必然有重复的
            list.add(random.nextInt(6000));
        }
        HashSet<Integer> set=new HashSet<>();
        for(Integer val:list){//拿到一个数据后,遍历list,看list里是否存在这个数据,如果存在就说明它重复了,如果不存在就把这个数据添加进去
            if(set.contains(val)){
                System.out.println("找到了第一个重复的元素:"+val);
                return;
            }else{
                set.add(val);
            }
        }
    }
}

在这里插入图片描述
2、去除10万个数据中重复的数据

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Random;
public class MapSet {
    public static void main(String[] args) {
        Random random=new Random();
        ArrayList<Integer> list=new ArrayList<>();
        for(int i=0;i<10_0000;i++){//生成10万个数据,每个数据都是在0到6000
            list.add(random.nextInt(6000));
        }
        HashSet<Integer> set=new HashSet();
        //set.addAll(list);
        for(Integer val:list){
            set.add(val);//set中的这个方法就是不能将已经添加过的数据再添加一次,所以用该方法去重再合适不过了
        }
        System.out.println(set);
    }
}

在这里插入图片描述中间还有好多数据就不一一截取了~~~

在这里插入图片描述
3、统计出10万个数据里,重复的数据出现了几次,这些重复的数据是哪些

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class MapSet{
    public static void main(String[] args) {
        Random random=new Random();
        ArrayList<Integer> list=new ArrayList<>();
        for(int i=0;i<10_0000;i++){//生成10万个数据,每个数据都是在0到6000
            list.add(random.nextInt(6000));
        }
        HashMap<Integer,Integer> map=new HashMap();
        //key—>重复出现的数据
        //value—>重复的数据出现了几次
        for(Integer key:list){//从list中获取数据放到map里
            if(map.get(key)==null){//返回key对应的value,若为空说明这个数是第一次出现
                map.put(key,1);//把value添加进去,
            }else{//如果返回的value值不为空就说明,这个value对应的key已经出现过
                Integer val= map.get(key);//获取当前key所对应的value值(即key之前已经出现过的次数)
                map.put(key,val+1);//再在其基础上加1,就可以统计出它出现的次数
            }
        }
        for(Map.Entry<Integer,Integer> entry : map.entrySet()){//打印map
            System.out.println(entry.getKey()+"这个数字重复出现了"+entry.getValue()+"次!");
        }
    }
}

在这里插入图片描述
中间还有好多数据就不一一截取了~~~

在这里插入图片描述
4、给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。题目地址

思路:数组所有元素进行异或,因为相同的数字异或结果是0,0异或任何数字都是任何数字。
交换律:a ^ b ^ c <=> a ^ c ^ b;
任何数于0异或为任何数 0 ^ n => n;
相同的数异或为0: n ^ n => 0;
var a = [2,3,2,4,4];
2 ^ 3 ^ 2 ^ 4 ^ 4等价于 2 ^ 2 ^ 4 ^ 4 ^ 3 => 0 ^ 0 ^3 => 3

class Solution {
    public int singleNumber(int[] nums) {
        int ret=0;
        for(int i=0;i<nums.length;i++){
            ret^=nums[i];
        }
        return ret;
    }
}
class Solution {
    public int singleNumber(int[] nums) {
        HashSet<Integer> hashSet=new HashSet<>();
        //遍历数组,将数组中的数据往 hashSet里放,如果里面已经有和即将要放进去的数据
        // 相等那就移除hashSet里的数据,如果没有就可以添加进去,是否移除需进行两次判断
        for (int i = 0; i < nums.length ; i++) {
            if(hashSet.contains(nums[i])){
                hashSet.remove(nums[i]);
            }else{
                hashSet.add(nums[i]);
            }
        }
        //System.out.println(hashSet);
        Iterator<Integer> it=hashSet.iterator();//构造迭代器,遍历集合中的对象,使返回的数据是整型
        return it.next();
    }
}

5、复制带随机指针的链表。题目地址

思路:
在这里插入图片描述

class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
class Solution {
    public Node copyRandomList(Node head) {
        if(head==null){return head;}
        Node cur=head;

        Map<Node,Node> map=new HashMap<>();
        //这一步是将新旧节点的值放进map,然后根据key和value找它们之间对应的关系
        while(cur!=null){
            Node node=new Node(cur.val);//不为空,new一个新节点,获取节点的val
            //然后将原来的节点和new的节点存到map中
            map.put(cur,node);
            cur=cur.next;
        }
        //新旧节点的映射关系已全部处理完成
        cur=head;//回来继续处理next和random
        while(cur!=null){//下面两句仔细看,“.next”在括号外和括号内的区别
            map.get(cur).next=map.get(cur.next);
            map.get(cur).random=map.get(cur.random);
            cur=cur.next;
        }
        return map.get(head);
    }
}

6、宝石和石头。给定字符串J 代表石头中宝石的类型,和字符串 S代表你拥有的石头。 S 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。题目地址

class Solution {
    public int numJewelsInStones(String J, String S) {
        Set<Character> set=new HashSet<>();
        //将用字符串表示的宝石转化为字符数组存进map
		for(char j:J.toCharArray()){
			set.add(j);
		}
		int count=0;
		//接着遍历石头
		for(char s:S.toCharArray()){
            //看map中是否存在相同的字符,若存在那就数量加1,若不存在就继续往后遍历 
			if(set.contains(s)){
				count++;
			}
		}
		return count;
	}
}

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

输入输出描述示例:
期望显示的英文:7_This_is_a_test
实际显示的英文: _hs_s_a_es
求哪些键盘坏了:7TI
按照发现顺序,在一行中输出坏掉的键。其中英文字母只输出大写,每个坏键只输出一次。题目保证至少有1个坏键。

import java.util.HashSet;
import java.util.Scanner;
public class MapSet{
    public static void main(String[] args){
        Scanner scanner=new Scanner(System.in);
        String espected=scanner.nextLine();//7_This_is_a_test
        String actual=scanner.nextLine();//_hs_s_a_es

        //把实际的字符转换为大写存放到集合中
        HashSet<Character> setActual=new HashSet<>();
        for(char s : actual.toUpperCase().toCharArray()){  //先转换为大写再转换为字符,存到s里
            setActual.add(s);
        }
        HashSet<Character> setBroken=new HashSet<>();
        for(char ex:espected.toUpperCase().toCharArray()){  //先转换为大写再转换为字符,存到ex里
            //当setActual(存的是actual)不包含ex(存放的是espected),要打印那个字符,但后续会有重复,
            //所以加一条判断重复过的就不用再打印,就是把不包含的那个键先打印再放入setBroken,
            //当后续出现的字符与setBroken里有重复的时,就跳过这个条件不打印也不再放入setBroken
            if(!setActual.contains(ex) && !setBroken.contains(ex)){
                System.out.print(ex);
                setBroken.add(ex);
            }
        }
    }
}

在这里插入图片描述
8、给一非空的单词列表,返回前 k 个出现次数最多的单词。返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率,按字母顺序排序。题目地址

// 力扣上的官方答案,先摆在这里,回头写注释!
class Solution {
    public List<String> topKFrequent(String[] words, int k) {
        Map<String, Integer> count = new HashMap();
        for (String word: words) {
            count.put(word, count.getOrDefault(word, 0) + 1);
        }
        PriorityQueue<String> heap = new PriorityQueue<String>(
                (w1, w2) -> count.get(w1).equals(count.get(w2)) ?
                w2.compareTo(w1) : count.get(w1) - count.get(w2) );

        for (String word: count.keySet()) {
            heap.offer(word);
            if (heap.size() > k) heap.poll();
        }

        List<String> ans = new ArrayList();
        while (!heap.isEmpty()) ans.add(heap.poll());
        Collections.reverse(ans);
        return ans;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值