数据结构-Map&Set【基础】

Map接口

Map是一个接口类,没有继承自Collection,该类中存储的是<K,V>键值对,并且K是不重复的,而V可以重复。
在这里插入图片描述

常用方法

在这里插入图片描述

添加元素

添加一对元素到Map接口中,使用put方法,其中key不能重复。如果当前key存在,会更新对应的value值。

在这里插入图片描述
若要保证Map接口元素元素的添加顺序和保存顺序相同,使用LinkedHashMap
在这里插入图片描述

注意, put方法身兼两职:添加 + 更新
若Key不存在,将新的键值对插入Map集合中;若K存在,更新对应的value,返回更新前的value值。

在这里插入图片描述

查询元素

Map接口中的查询,调用get方法,根据Key值查询value值,若不存在返回null。
在这里插入图片描述
还有一个常用方法getOrDefault,根据key值查询value值,若value不存在,返回默认值。
在这里插入图片描述

Map接口的遍历

在Java中,继承了Iterable接口的子类可以直接使用for-each循环来遍历。而Map没有继承这个接口,所以当需要遍历Map接口时,我们要将Map转为Set(Set继承了Iterable接口)。Map保存的是一对元素,在内部保存的是一个个不重复的Entry对象,通过entrySet()这个方法将一对元素转为Entry对象,转完之后Set就保存了一个个不重复的Entry对象。此时通过entry.getKey()entry.getValue()方法取得entry对象的Key和Value值。
在这里插入图片描述

注意:实现Map接口的常用类有TreeMapHashMap,在TreeMap中插入键值对时,key不能为空,否则就会抛NullPointerException异常,value可以为空。但是HashMap的key和value都可以为空。
在这里插入图片描述

常用Map子类的关系

TreeMapHashMap
内部数据结构红黑树哈希表
key和value是否允许为nullkey不能为null,value可以为null,key必须具备可比较的性质或传入比较器对象key和value都可以为null
是否有序对于key有序,这个大小关系由Comparable或者比较器对象来决定无序
是否线程安全不安全不安全

Set接口

在这里插入图片描述
Set接口是Collection的子接口,保存了单个不重复的元素其实Set接口的本质就是Map,Set是将元素保存在了Map的Key上,因此Set是不重复元素的集合。
在这里插入图片描述

常用方法

在这里插入图片描述

添加元素

Set中使用add方法添加元素,当添加的元素不同时,返回true,相同时,返回false。
在这里插入图片描述

查询是否包含

contains()方法。
在这里插入图片描述

注意,实现Set接口的常用类有TreeSetHashSet,还有一个LinkedHashSet,LinkedHashSet是在HashSet的基础上维护了一个双向链表来记录元素的插入次序。 TreeSet中不能插入null的key,HashSet可以。 Set最大的功能就是对集合中的元素进行去重
在这里插入图片描述

Map和Set的OJ练习

宝石与石头

1、描述:
给你一个字符串 jewels 代表石头中宝石的类型,另有一个字符串 stones 代表你拥有的石头。 stones 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。字母区分大小写,因此 “a” 和 “A” 是不同类型的石头。
在这里插入图片描述
2、思路:
先把jewels中的每个字符串保存在Set中,拿着这个集合去扫描Stones,如果jewels中的字符在Stones中,则是宝石,否则就是石头。

3、代码实现

public class Num771_NumJewelsInStones {
    public int numJewelsInStones(String jewels, String stones) {
        //使用set保存每个宝石的类型
        Set<Character> set = new HashSet<>();
        for (int i = 0; i < jewels.length(); i++) {
            set.add(jewels.charAt(i));
        }
        //扫描石头字符,所谓的宝石其实就是石头字符中出现的宝石字符
        int nums = 0;
        for (int i = 0; i < stones.length(); i++) {
            char c = stones.charAt(i);
            if(set.contains(c)){
                nums ++;
            }
        }
        return nums;
    }
}

坏键盘打字

1、描述: 旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现。现在给出应该输入的一段文字、以及实际被输入的文字,请你列出肯定坏掉的那些键。
在这里插入图片描述
2、代码实现

public class NewCode_BadKeys {
// 注意类名必须为 Main, 不要有任何 package xxx 信息
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            String expected = in.nextLine().toUpperCase();
            String actual = in.nextLine().toUpperCase();
            //使用set集合存储实际的字符
            Set<Character> set = new HashSet<>();
            for(int i = 0;i<actual.length();i++){
                set.add(actual.charAt(i));
            }
            //2、拿着实际存在的字符扫描期望的字符串找到坏键
            //所谓的坏键就是期望中存在但set中不存在的字符
            Set<Character> badkey= new LinkedHashSet<>();
            for(int i = 0;i<expected.length();i++){
                char c = expected.charAt(i);
                if(!set.contains(c)){
                    badkey.add(c);
                }
            }
            //最终将badkey中字符输出
            for(char c : badkey){
                System.out.print(c);
            }

            //换行进行下一次输入
            System.out.println();
        }
    }
}

复制带随机指针的链表

1、描述: 给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。返回复制链表的头节点。
在这里插入图片描述
2、思路: 这个题非常有意思,如果只是单纯的复制一个链表,只需要定义一个虚拟头节点然后尾插元素即可,但这个链表带有了随机的指针,也就是说当前节点不仅会指向下一个节点,还会随机指向其他任意位置的节点。如何才能深拷贝这个带有随机指针的链表呢?做法也很巧妙,使用Map集合。找到新旧链表之间节点的映射关系以及随机指针的映射关系。
在这里插入图片描述
3、代码实现

public Node copyRandomList(Node head) {
    Map<Node,Node> nodesMap = new HashMap<>();
    //遍历原链表,构建新链表,保存在map接口中,将新旧链表的相同节点作为一对映射关系
    Node tmp = head;
    while(tmp != null){
        Node node = new Node(tmp.val);
        nodesMap.put(tmp,node);
        tmp = tmp.next;
    }
    //再遍历每个节点,通过原链表构建新链表的next和random引用
    tmp = head;
    while(tmp != null){
        //构建新链表的next
        nodesMap.get(tmp).next = nodesMap.get(tmp.next);
        //构建random
        nodesMap.get(tmp).random = nodesMap.get(tmp.random);
        tmp = tmp.next;
    }
    //最终通过原链表的头找到一一映射关系来得到新链表的头
    return nodesMap.get(head);
}

继续加油努力!!!
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值