目录
一.只出现一次的数字
二.宝石与石头
三.旧键盘
四.给定一个数组,统计每个元素出现的次数
五.前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 处理多个 caseString 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设置1map.put(x,1);}else{//如果3出现了1次之后,我们要先获取3对应的个数,然后+1int 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>>() {@Overridepublic 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>>() {@Overridepublic 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->2if(top.getValue().compareTo(entry.getValue())==0){//频率相同,按字母顺序if(top.getKey().compareTo(entry.getKey())>0){//getKey()得到key值minHeap.poll();minHeap.offer(entry);}}}}}//2 3 4List<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;}
}
好好的生活,来又去,去又来。