HashMap和HashSet相关oj题

OJ题地址:
136. 只出现一次的数字
138. 复制带随机指针的链表
771. 宝石与石头
牛客:旧键盘打字
692. 前K个高频单词

目录

只出现一次的数字

复制带随机指针的链表

宝石与石头

旧键盘打字

前k个高频单词


只出现一次的数字

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

思路:
1.利用HashSet,遍历数组,如果HashSet中未包含该元素则进行添加,若包含该元素就进行移除
2.利用异或运算(^),相同为0,不同为1,这样就找出只出现一次的元素

思路2的实现:

//思路2:利用异或^,时间复杂度O(N),空间复杂度O(1)
class Solution {
    public int singleNumber(int[] nums) {
        int temp = 0;
        for(int num : nums){
            temp ^= num;
        }
        return temp;
    }
}

思路1的实现:

//思路1:相同add,不同remove,迭代器输出
class Solution {
    public int singleNumber(int[] nums) {
        HashSet<Integer> set = new HashSet<>();
        for(int num : nums){
            if(!set.contains(num)){
                set.add(num);
            }
            else
            {
                set.remove(num);
            }
        }
        Iterator it = set.iterator();
        return (int)it.next();
    }
}

复制带随机指针的链表

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

思路:利用HashMap<已有节点的地址,新生成节点的地址>,接着利用已有节点的指向来操作新节点。

class Solution {
    public Node copyRandomList(Node head) {
        //利用HashMap<已有节点的地址,生成的新节点的地址>
        HashMap<Node,Node> hashMap = new HashMap<>();
        Node cur = head;
        //设置每个已有节点和新节点之间key-value关系
        while(cur != null){
            Node temp = new Node(cur.val);//val域
            hashMap.put(cur,temp);//设置key-value
            cur = cur.next; //cur继续向后走
        }
        cur = head;//指向首节点
        while(cur != null){
            //进行连接
            hashMap.get(cur).next = hashMap.get(cur.next);
            hashMap.get(cur).random = hashMap.get(cur.random);
            cur = cur.next;
        }
        //返回新链表的首位置
        return hashMap.get(head);
    }
}

宝石与石头

题意:给你一个字符串 jewels 代表石头中宝石的类型,另有一个字符串 stones 代表你拥有的石头。 stones 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。字母区分大小写,因此 "a" 和 "A" 是不同类型的石头。
简单来说:就是在一堆石头里面找宝石的个数....

思路:利用HashSet存储宝石的种类,遍历每一个石头去寻找宝石,如果找到宝石,那宝石的个数加1

class Solution {
    public int numJewelsInStones(String jewels, String stones) {
        Set<Character> set = new HashSet<>();
        //存储宝石
        for(char ch : jewels.toCharArray()){
            set.add(ch);
        }
        int count = 0;
        //在石头中找宝石
        for(char ch : stones.toCharArray()){
            if(set.contains(ch)){
                count++;
            }
        }
        return count;
    }
}

旧键盘打字

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

思路:利用HashSet存储真实(real)文字的每一个字符,接着去遍历应该(ideal)输入的文字,如果Set中不包含该字符,则进行输出(但是该字符可能会有多个,会重复输出,因此需要去判断

import java.util.*;
public class Main{
    public static void func(String ideal , String real){
        //set1存储真实的文字字符
        Set<Character> set1 = new HashSet<>();
        for(char ch : real.toUpperCase().toCharArray()){
            set1.add(ch);
        }
        
        //set2存储坏了的键盘字符
        Set<Character> set2 = new HashSet<>();        
        for(char ch : ideal.toUpperCase().toCharArray()){
            //ideal中可能会有重复的,重复输出
            if(!set1.contains(ch)&&!set2.contains(ch)){
                System.out.print(ch);
                set2.add(ch);
            }
            //为啥不直接拿set2去接收去重?
            //是因为全部接收输出顺序就会发生改变
        }
    }
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        //应该输入的文字(ideal)
        String ideal = scanner.nextLine();
        //现实输入的文字
        String real = scanner.nextLine();
        func(ideal,real);
    }
}

前k个高频单词

题意:给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。
返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。

思路:首先利用HashMap<String,Integer>记录每个字符串出现的次数,接着再利用优先队列建立k小堆,最终逆序输出结果。

class Solution {
       public List<String> topKFrequent(String[] words, int k) {

        //1.利用HashMap去统计
        HashMap<String,Integer> hashMap = new HashMap<>();
        for(String str : words){
            if(!hashMap.containsKey(str)){
                hashMap.put(str,1);
            }
            else{
                hashMap.put(str,hashMap.get(str)+1);
            }
        }

        //2.利用优先队列进行排序       
        //出现问题了:此时优先队列无法比较(这是个Entry类),利用匿名类实现compre()
        PriorityQueue<Map.Entry<String,Integer>> priorityQueue =
                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() - o2.getValue() == 0){
                            return o2.getKey().compareTo(o1.getKey());
                        }
                        //==的情况需要判断字典序
                        return o1.getValue() - o2.getValue();
                    }
                });

        //hashMap.entrySet()的返回类型是Set<Map.Entry<K, V>>
        for(Map.Entry<String,Integer> entry : hashMap.entrySet()){
            //建立小堆
            if(priorityQueue.size() < k){
                priorityQueue.offer(entry);
            }
            else{
                //num存放的是堆顶
                Map.Entry<String,Integer>  num = priorityQueue.peek();
                //比较元素大小
                if(num.getValue() < entry.getValue()){
                    priorityQueue.poll();
                    priorityQueue.offer(entry);
                }//比较字典序
                else if(num.getValue() == entry.getValue()){
                    if(num.getKey().compareTo(entry.getKey()) > 0){
                        priorityQueue.poll();
                        priorityQueue.offer(entry);
                    }
                }
            }
        }
        // 3.放入ArrayList里面,然后逆序就结束了
        ArrayList<String> arrayList = new ArrayList<>();
        while(priorityQueue.size() != 0){
            Map.Entry<String,Integer> entry = priorityQueue.poll();
            arrayList.add(entry.getKey());//从小到大排序了
        }
        //arrayList里面没有逆序方法,需要用Collections(工具类)类中的reverse()方法
        Collections.reverse(arrayList);
        return arrayList;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值