Map和Set的五道相关题目

题目一:只出现一次的数字

在这里插入图片描述
思路一:
采用HashSet来完成,但是这种方法效率比较低。
前提:Set具有去重的特点

因此,我们先将所有的数据存储在HashSet中,然后进行判断,如果已经存在,则删除;如果还没有的话,则存入。

然后,再通过遍历数组,判断里面的元素是什么,取出来。

在这里插入图片描述

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

在这里插入图片描述
思路二:HashMap方式
将数据存入 HashMap 中,此时key 为 元素, Value 为 出现次数。

在存入的过程中判断该元素在HashMap 中是否存在。如果存在,value=1,并且在此基础上加上1。

否则,返回的Value 为 null,没有这个元素,此时就是第一次存入,将对应 Key - Value 存入。

取出的时候,遍历数组,通过 getValue方法,返回其 Value 值,如果等于1,就返回 对应 Key。如果没有找到那个只出现一次的 Key,就返回 -1。

class Solution {
    public static int singleNumber(int[] nums) {
        Map<Integer,Integer> map = new HashMap<>();
        for (int i:nums){
            if(map.containsKey(i)){
                map.put(i,map.get(i)+1);
            }else{
                map.put(i,1);
            }
            
        }
        for (Map.Entry<Integer,Integer>entry : map.entrySet()){
            if (entry.getValue()==1) return entry.getKey();
        }
        return 0;
    }
}

思路三:异或
在这里插入图片描述异或运算满足交换律和结合律:

  • a^b ^c ^ b ^ c =a ^ (b ^ b) ^ (c ^c) = a ^0 ^0 =a
public static int singleNumber(int[] nums) {
       int num = 0;
       for(int a :nums){
           num ^=a;
       }
       return num;
    }

题目二:复制带随机指针的链表

题目:
在这里插入图片描述分析:
题目要求我们复制一个长度为 n 的链表,该链表除了每个节点有一个指针指向下一个节点外,还有一个额外的指针指向链表中的任意节点或者 null,如下图所示:
在这里插入图片描述通过画的图可以看到,就是将原来的链表的内容还有指针的指向复制到另外一个地址上面。

思路一:哈希表方式解决

  1. 创建一个HashMap,分别存储新旧结点的地址
    <key,value>对应<旧结点地址,新节点地址>

  2. 再次遍历链表的时候把对应的值设置上

  3. 原节点和新节点是一一对应的关系“

    • map.get(原节点),得到的就是对应的新节点
    • map.get(原节点.next),得到的就是对应的新节点.next
    • map.get(原节点.random),得到的就是对应的新节点.random

上节课讲过Map的常用方法:
链接:
在这里插入图片描述了解完这些,代码就很简单了

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);
        }
        return map.get(head);
    }

思路二:直接复制,然后分割链表

  1. 据遍历到的原节点创建对应的新节点,每个新创建的节点是在原节点后面
  2. 设置新链表的随机指针
  3. 将两个链表分离开,再返回新链表就可以了

在这里插入图片描述

public Node copyRandomList(Node head) {
        if(head==null) {
            return null;
        }
        Node p = head;
        //1.在每个原节点后面创建一个新节点
        while(p!=null) {
            Node newNode = new Node(p.val);
            newNode.next = p.next;
            p.next = newNode;
            p = newNode.next;
        }
        p = head;
        //2.设置新节点的随机结点
        while(p!=null) {
            if(p.random!=null) {
                p.next.random = p.random.next;
            }
            p = p.next.next;
        }
        Node dummy = new Node(-1);
        p = head;
        Node cur = dummy;
        //3.分割链表
        while(p!=null) {
            cur.next = p.next;
            cur = cur.next;
            p.next = cur.next;
            p = p.next;
        }
        return dummy.next;
    }

题目三:宝石与石头

题目:
在这里插入图片描述分析:
题意很简单,就是给你第一个关于宝石的字符串,然后看看石头字符串里面是否有,如果有,则返回有多少个;没有就返回0.

思路一:利用哈希集合

  1. 先把jewels字符串的字母存到哈希集合当中
  2. 遍历stones字符串,看看里面是否包含jewels的字母,如果包含,则利用计数器++。
public int numJewelsInStones(String jewels, String stones) {
        HashSet<Character> set = new HashSet<>();
        for(Character ch:jewels.toCharArray()){
            set.add(ch);
        }
        int count = 0;
        for(Character ch: stones.toCharArray()){
            if(set.contains(ch)){
                count++;
            }
        }
        return count;
    }

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

ublic int numJewelsInStones(String jewels, String stones) {
        int count = 0;
        for (int i = 0; i < stones.length(); i++) {
            char stone = stones.charAt(i);
            for (int j = 0; j < jewels.length(); j++) {
                char jewel = jewels.charAt(j);
                if (stone == jewel) {
                    count++;
                    break;
                }
            }
        }
        return count;
    }

题目四:旧键盘

题目:
在这里插入图片描述思路:采用HashSet方式

  1. 先创建一个HashSet,把键盘的实际输出存到里面
  2. 然后创建另外一个HashSet,坏的摁键值存到里面,方式是通过遍历预期输出的值,与我们第一个HashSet里面存放的值做比较。如果没有的话,则说明这个摁键是坏的
import java.util.*;

public class Main{
    public static void func(String strExce,String strAactual){
        HashSet<Character> set = new HashSet<>();
        //两次转换,先转为大写,再转为数组
        for(char ch:strAactual.toUpperCase().toCharArray()){
            set.add(ch);
        }
        
        HashSet<Character> broken = new HashSet<>();
        for(char ch: strExce.toUpperCase().toCharArray()){
            if(!set.contains(ch) && !broken.contains(ch)){
                System.out.print(ch);
                broken.add(ch);
            }
        }
    }
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        while(scanner.hasNextLine()){
            String str1 = scanner.nextLine();
            String str2 = scanner.nextLine();
            func(str1,str2);
        }
    }
}

题目五:前K个高频单词

题目:
在这里插入图片描述
思路:
利用哈希表 & 优先队列(堆)

  1. 用map统计每个单词出现的次数

  2. 建立一个大小为K的小根堆

  3. 遍历Map
    (1)判断堆是否满,如果不满直接入堆。
    (2)判断词频是否相同,如果相同,则比较单词的大小,单词小的入堆

  4. 输出堆内元素,并翻转

public static List<String> topKFrequent(String[] words, int k) {
        HashMap<String,Integer> map = new HashMap<>();
        //1、统计每个单词出现的次数 map
        for (String s : words) {
            if(map.get(s) == null) {
                map.put(s,1);
            }else {
                int val = map.get(s);
                map.put(s,val+1);
            }
        }
        //2、建立一个大小为K的小根堆
        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()-o2.getValue();
            }
        });
        //3、遍历Map
        for (Map.Entry<String,Integer> entry : map.entrySet()) {
            if(minHeap.size() < k) {
                minHeap.offer(entry);
            }else {
                //说明堆中 已经放满了K个元素,需要看堆顶元素的数据 和当前的数据的大小关系
                Map.Entry<String,Integer> top = minHeap.peek();
                //判断频率是否相同,如果相同,比较单词的大小,单词小 的入堆
                if(top.getValue().compareTo(entry.getValue()) == 0) {
                    if(top.getKey().compareTo(entry.getKey()) > 0) {
                        minHeap.poll();
                        minHeap.offer(entry);
                    }
                }else {
                    if(top.getValue().compareTo(entry.getValue()) < 0) {
                        minHeap.poll();
                        minHeap.offer(entry);
                    }
                }
            }
        }
        List<String> ret = new ArrayList<>();
        for (int i = 0;i < k;i++) {
            Map.Entry<String,Integer> top = minHeap.poll();
            ret.add(top.getKey());
        }
        Collections.reverse(ret);
        return ret;
    }

总结:以上就是五道Map和Set的相关题目。

  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

十叶知秋

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

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

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

打赏作者

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

抵扣说明:

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

余额充值