【Java数据结构】——五道算法题让你灵活运用Map和Set

目录

一.只出现一次的数字

二.宝石与石头

三.旧键盘

四.给定一个数组,统计每个元素出现的次数

五.前K个高频单词


一.只出现一次的数字

136. 只出现一次的数字 - 力扣(LeetCode)

算法原理:我们将nums中每个元素都存入到set中去,但是存入是有条件的,如果不存在就加进去,如果已经存在了那么我们就就将那个值移除。然后循环结束后我们看到只剩下一个元素,然后我们再次遍历这个数组,因为set中就包含了一个元素,那么如果遍历后那个数存在在set中,那么就返回那个值,否则返回-1;

class Solution {
    public int singleNumber(int[] nums) {
        HashSet<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;
            }//然后遍历,如果包含就返回x
        }
        return -1;

    //     TreeSet<Integer> set=new TreeSet<>();
    //     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 -1;
    // }
}

二.宝石与石头

771. 宝石与石头 - 力扣(LeetCode)

算法原理:我们设定一个HashSet,然后先将宝石中的字符串各个字符都存入到set中去,然后继续遍历石头字符串,如果石头中的字符串在set中,那么就计数++

class Solution {
    public int numJewelsInStones(String jewels, String stones) {
        HashSet<Character>set=new HashSet<>();
        //先让宝石里面的各个字符都放进hashset中
        for(char x:jewels.toCharArray()){
            set.add(x);
        }//ToCharArray( )的用法,将字符串对象中的字符转换为一个字符数组。
        int sum=0;
        //然后遍历石头里的各个字符,判断是否包含在set里面,如果包含就sum++
        for(char ch:stones.toCharArray()){
            if(set.contains(ch)){
                sum++;
            }
        }
        return sum;
    }
}

toCharArray是将字符串转为字符数组。


三.旧键盘

旧键盘 (20)__牛客网 (nowcoder.com)

题目解析:

  • 我们输入第一行 (键盘没坏) ——7_This_is_a_test
  • 输入第二行   (键盘坏了)—— _hs_s_a_es

我们看到坏掉的字符有  7T i i t t 但是我们本题说明了,只输出大写,所以在第一行输入的时候,t和T都是一样的。而且题目也限制了,每个坏键只输出一次。

俩个条件:1.每个坏键只输出一次   2.只输出大写(说明在输入第一行中,t和T都是一样的)

算法原理:

我们用str1记录第一行,用str2记录第二行。我们先将str2遍历一遍,将str2中每个元素都存入到set中,然后遍历str2字符串,如果遇到不包含的元素,我们就输出,但是如果后面遇到同样 比如 上面的字符串7_This_is_a_test,中i出现了俩次,题目规定坏键只能输出一次。所以这时候我们就再定义一个set2,俩个条件,那个元素既不包含str1,也不包含在str2中,我们才输出,并且让那个值加到set2中。

所以我们 看到俩个条件,每个坏键只能输出一次,所以当前面已经出现的字符,我们就不能在输出了,此时就需要在创建一个set2,还有一个条件就是 不区分大小写,T和t都是同一个字母,所以哪个已经输出了,那么t就不能输出了,所以我们直接将俩个字符串的每个字符都弄成大写。

import java.util.*;
 
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            String str1 = in.nextLine();
            String str2 = in.nextLine();
            func(str1,str2);
        }
    }
 
    private static void func(String str1,String str2){
        HashSet<Character> set1=new HashSet<>();
        for(char ch: str2.toUpperCase().toCharArray()){
            set1.add(ch);
        }//先将字符串2放入set中
        //然后再遍历字符串1,如果字符串1中有元素不包含再字符串1和字符串2中,那么就输出,并且将该字符加进set2中
        HashSet<Character> set2=new HashSet<>();
        //先转大写,然后转字符数组
        for(char ch:str1.toUpperCase().toCharArray()){
            if(!set1.contains(ch) && !set2.contains(ch)){
                System.out.print(ch);
                set2.add(ch);
            }
        }
    }
}

我们需要先将字符串的每个元素转成大写,然后转成字符数组。


四.给定一个数组,统计每个元素出现的次数

解题思路:

map中有个方法是get(),获取key得到value,我们依次遍历array数组,如果我们获取到key,如果返回的value值是空,我们就put假如到map中,并计入key和value=1,如果value值不等于空,那么我们就先获取当前key的value值,然后让value值加1.

//给定一个数组,然后输出每个元素出现的个数
        int[] array={1,2,3,3,1,4};
        HashMap<Integer,Integer>map=new HashMap<>();
        for(Integer x:array){
            if(map.get(x)==null){
                //如果x出现个数是null,那么我们就将value设置1
                map.put(x,1);
            }else{
                //如果3出现了1次之后,我们要先获取3对应的个数,然后+1
                int value=map.get(x);
                map.put(x,value+1);
            }
        }
        for (Map.Entry<Integer,Integer>entry: map.entrySet()){
            System.out.println("key: "+entry.getKey()+"  value: "+entry.getValue());
        }

 然后Map中有个Entry<K,V>,调用entrySet()就能得到所有的key-value映射关系。


五.前K个高频单词

692. 前K个高频单词 - 力扣(LeetCode)

算法原理:

1.首先我们要记录每个字符串出现的次数(请看第4题)

2.遍历好统计的Map,把每组数据存储到小根堆中

如果频率相同,按字母比较(从小到大)——大根堆,频率不同,按频率高到低(从大到小)——小根堆。

//遍历好统计的Map,把每组数据存储到小根堆中
        PriorityQueue<Map.Entry<String,Integer>>minHeap =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().compareTo(o2.getValue()) == 0) {
                    return o2.getKey().compareTo(o1.getKey());
                }
        //放元素的时候 如果频率不同 我们转变为小根堆-》按照频率大小排序
                return o1.getValue().compareTo(o2.getValue());
            }
        });
        //小根堆 o1在前o2在后  大根堆o1在后o2在前

因为我们要分情况 建大堆 还是建小堆。


然后遍历Map,利用Map的entrySet(),找前k个出现单词数最多的,你要找频率最大单词,如果堆的元素小于k,那么我们就直接将Map的键值对都offer进去,如果大于k,我们就要先获取堆顶元素,然后判断堆顶元素的value值是不是小于当前的entry的value,如果小于,那么就将堆顶删除,然后让offer当前的元素,如果大于,就继续循环,如果堆顶的value等于entry的value(说明出现的频率是相等的)那么,我们就要比较当前堆顶的key值和entry的key值是大于还是小于,如果大于,那么就要将当前的删除,然后offer当前entry值。


class Solution {
     public List<String> topKFrequent(String[] words, int k) {
        //先统计每个单词出现个数
        Map<String,Integer>map=new HashMap<>();
        for (String word:words) {
            if(map.get(word)==null){
                map.put(word,1);
            }else{
                int val=map.get(word);
                map.put(word,val+1);
            }
        }
        //遍历好统计的Map,把每组数据存储到小根堆中
        PriorityQueue<Map.Entry<String,Integer>>minHeap =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().compareTo(o2.getValue()) == 0) {
                    return o2.getKey().compareTo(o1.getKey());//大根堆
               }
                return o1.getValue().compareTo(o2.getValue());//小根堆
            }//小根堆 o1在前o2在后  大根堆o1在后o2在前
        });
        for (Map.Entry<String,Integer> entry:map.entrySet()) {
            if(minHeap.size()<k){//map里面的元素小于k,那么直接进堆就行了
                minHeap.offer(entry);
            }else {
                //你要找最大的频率的单词
                Map.Entry<String,Integer>top=minHeap.peek();
                //如果栈顶的元素个数小于现在的元素,那么就让栈顶删除,将他放入栈中
                //小根堆堆顶元素是最小的,如果比堆顶元素还小,那么就放入
                if(top.getValue().compareTo(entry.getValue())<0){
                    minHeap.poll();
                    minHeap.offer(entry);
                }else{
                    //def->2  abc->2
                    if(top.getValue().compareTo(entry.getValue())==0){
                        //频率相同,按字母顺序
                        if(top.getKey().compareTo(entry.getKey())>0){
                            //getKey()得到key值
                            minHeap.poll();
                            minHeap.offer(entry);
                        }
                    }
                }
            }
        }
        //2 3 4
        List<String>ret=new ArrayList<>();
        for (int i = 0; i <k ; i++) {
            Map.Entry<String,Integer>top=minHeap.poll();
            ret.add(top.getKey());
        }
        //拿到的是 2 3 4,然后需要逆置
        Collections.reverse(ret);//Collections是逆置
        return ret;
    }
}

好好的生活,来又去,去又来。

  • 17
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
java笔试算法 目录 :envelope: 说明 项目介绍 该文档主要是笔主在学习 Java 的过程中的一些学习笔记,但是为了能够涉及到大部分后端学习所需的技术知识点我也会偶尔引用一些别人的优秀文章的链接。文档大部分内容都是笔者参考书籍以及自己的原创。少部分面试回答参考了其他人已有答案,上面都已注明。 该文档涉及的主要内容包括: Java数据结构算法、计算机网络与数据通信、 操作系统、主流框架、数据存储、架构、面试必备知识点等等。相信不论你是前端还是后端都能在这份文档中收获到东西。 关于转载 如果需要引用到本仓库的一些东西,必须注明转载地址!!!毕竟大多都是手敲的,或者引用的是我的原创文章,希望大家尊重一下作者的劳动:grinning_face_with_big_eyes::grinning_face_with_big_eyes::grinning_face_with_big_eyes:! 如何对该开源文档进行贡献 笔记内容大多是手敲,所以难免会有笔误,你可以帮我找错别字。 很多知识点我可能没有涉及到,所以你可以对其他知识点进行补充。 现有的知识点难免存在不完善或者错误,所以你可以对已有知识点的修改/补充。 为什么要做这个开源文档? 在我们学习Java的时候,很多人会面临我不知道继续学什么或者面试会问什么的尴尬情况(我本人之前就很迷茫:grinning_face_with_smiling_eyes:)。所以,我决定通

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值