Map 和S et 是 一种专门 用来进行搜索的 数据结构。 适合动态查找 。
一、Map(存储key-value)
Map 是一个接口类,该类没有继承自 Collection ,该类中存储的是1、map.put(K的类型 key, V的类型 value) 往里放元素
Mapmap=new HashMap<>(); map.put("abc",3);//put是往里放元素 map.put("bit",2); map.put("hello",4); System.out.println(map);//会自动调用toString方法
注意:hashmap存储元素的时候,不是按照存储的顺序进行打印的。
存储的时候,是根据哈希函数来进行存储的。
Mapmap = new HashMap<>(); map.put("abc", 3); map.put("bit", 2); map.put("bit", 4); System.out.println(map); 注意: 存储元素时,如果key相同,value值会被覆盖
2、V的类型 =map.get(key) 通过key值获取value值
int ret=map.get("abc");//ret为33、V的类型 =map.getOrDefault(key,没有key所对值时要返回的值)
map.getOrDefault("bit2",98);//找不到bit2,也就找不到对应的value,此时就返回设定的value值984、V的类型 =map.remove(key) 删除
Integer ret2=map.remove("bit");//删除值为bit的 System.out.println(ret2);//25、Set
set=map.keySet() 返回所有 key 的不重复集合 因为Set这个集合当中存储的元素都是不重复的
Mapmap = new HashMap<>(); map.put("abc", 3);//put是往里放元素4 map.put("bit", 2); map.put("hello", 4); Set set=map.keySet();//此时就把所有key=放在了set里 System.out.println(set);//abc bit hello 6、Collection
7、Set=map. values() 返回所有 value 的可重复集合 > =map.entrySet() 返回所有的 key-value 映射关系 Mapmap = new HashMap<>(); map.put("abc", 3); map.put("bit", 2); map.put("bit", 4); map.put(null,null);//用HashMap可以放null,但是用TreeMap不可以放null System.out.println(map); Set > entrySet=map.entrySet();//也就是在Set里,每个元素的类型是Map.Entry for (Map.Entry entry:entrySet) {//遍历Set System.out.println(entry.getKey()+"->"+entry.getValue()); } 8、boolean =map.containsKey(Object key) 判断是否包含 key
9、boolean =map.containsValue(Object value) 判断是否包含value
注意:
1. Map是一个接口,不能直接实例化对象,如果要实例化对象只能实例化其实现类TreeMap或者HashMap 2. Map中存放键值对的Key是唯一的,value是可以重复的 3.对于HashMap来说,在Map中插入键值对时,key可以为空 对于TreeMap来说,在Map中插入键值对时,key不能为空,否则就会抛NullPointerException异常,但是value可以为空 4. Map中的Key可以全部分离出来(keySet方法),存储到Set中来进行访问(因为Key不能重复)。 5. Map中的value可以全部分离出来(values方法),存储在Collection的任何一个子集合中(value可能有重复)。 6. Map中键值对的Key不能直接修改,value可以修改,如果要修改key,只能先将该key删除掉,然后再来进行 重新插入。 7. TreeMap和HashMap的区别
二、Set(存储key)会自动去重
常见方法:
注意: 1. Set是继承自Collection的一个接口类 2. Set中只存储了key,并且要求key一定要唯一 3.实现Set接口的常用类有TreeSet和HashSet,还有一个linkedHashSet 4.Set中的Key不能修改,如果要修改,先将原来的删除掉,然后再重新插入 5. Set中不能插入null的key 6. Set最大的功能就是对集合中的元素进行去重 7.TreeSet和HashSet的区别1、set.add(E e) 添加元素,但重复元素不会被添加成功
Setset=new HashSet<>(); set.add(1);//往set里添加元素 set.add(2); set.add(1); System.out.println(set); 2、set.clear() 清空集合
3、boolean =set.contains(Object o) 判断 o 是否在集合中 4、Iterator=set.iterator() 返回迭代器 Setset=new HashSet<>(); set.add(1);//往set里添加元素 set.add(2); set.add(3); Iterator iterator=set.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } 5、boolean =set.remove(Object o) 删除集合中的 o
6、int =set.size() 返回set中元素的个数
7、boolean =set.isEmpty() 检测set是否为空,空返回true,否则返回false 8、Object[] =set.toArray() 将set中的元素转换为数组返回 9、boolean =set.containsAll(Collection> c) 集合c中的元素是否在set中全部存在,是返回true,否则返回 false 10、boolean =ret.addAll(Collection extends E> c) 将集合c中的元素添加到set中,可以达到去重的效果
练习题:
1、给定1W个数据,统计每个数据出现的次数(思路:用Map)
思路:将每个值都放在map里,每次放的时候检查一下,如果有这个值,则在原来值所对的value值+1,如果没这个值,则把这个值放在map里,value值为1
public static Mapfunc1(int[]array){//key是关键字 value是出现的次数 Map map=new HashMap<>(); //判断array中的元素是否在map中,如果不在就是1,在就是在原来的基础上+1 for (int x:array) {//取出数组里的每个元素x if(map.get(x)==null){//看x在不在map里 map.put(x,1); }else{ int val=map.get(x);//如果在看看已经出现几次了 map.put(x,val+1);//再在原来的基础上+1 } return map; } } public static void main(String[] args) { int[]array=new int[1_0000]; Random random=new Random(); for (int i = 0; i < array.length; i++) { array[i]=random.nextInt(1000);//随机生成1000个数据,保证了10000个数据里有重复的 } Map map=func1(array); System.out.println(map); } 2、将1W个数据中的数据去重(涉及到去重,用Set )
public static Setfunc2(int[]array){ HashSet set=new HashSet<>(); for (int x:array) {//将数组里的每个元素放入Set,就可以达到去重的效果 set.add(x); } return set; } 3、从1W个数据中,找出第一个重复的数据
思路:每次把元素放到Set里,放之前都检查一下set中是不是已经有了
public static int func3(int[]array){ HashSetset=new HashSet<>(); for (int x:array) { if(set.contains(x)){//如果set里面包含x则证明x是第一个重复的 return x; } set.add(x); } return -1; }
4、题目:只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
public int singleNumber(int[] nums) { HashSetset=new HashSet<>(); for (int x:nums) { if(set.contains(x)){//如果在set里就移出去,最后剩下的就是只出现一次的 set.remove(x); }else{ set.add(x); } } //此时返回set里只存在的那个值,就是所求 for (int i = 0; i < nums.length; i++) { if(set.contains(nums[i])){ return nums[i]; } } return -1; }
5、 复制带随机指针的链表
题意:
思路:用cur遍历链表,链表不为空就创建一个新的节点,然后利用map存一下老节点和新节点的映射关系,直到cur遍历结束,然后再重新遍历cur,根据cur节点从map中找到与cur相对应的值,这样就可以复制链表的next指向和random指向了
public Node copyRandomList(Node head) { Mapmap=new HashMap<>(); Node cur=head; while(cur!=null){//第一次遍历 Node node=new Node(cur.val); map.put(cur,node);//在map里存好映射关系 cur=cur.next; } cur=head; while(cur!=null){ map.get(cur).next=map.get(cur.next); map.get(cur).random=map.get(cur.random); cur=cur.next; } return map.get(head);//返回复制后链表的头节点 }
6、 宝石与石头
给你一个字符串 jewels 代表石头中宝石的类型,另有一个字符串 stones 代表你拥有的石头。 stones 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。
字母区分大小写,因此 "a" 和 "A" 是不同类型的石头。
思路:把宝石放到Set里,再遍历石头,若有和Set里元素重复的,计数器++
public int numJewelsInStones(String jewels, String stones) { HashSetset=new HashSet<>(); for(Character c:jewels.toCharArray()){//将宝石里的元素都放到Set里 set.add(c); } int count=0; for(Character c:stones.toCharArray()){//遍历石头里的元素 if(set.contains(c)){//如果set里有和石头元素相同的,就证明这个石头元素是宝石计数器++ count++; } } return count; }
7、旧键盘 (20)__牛客网
题目:旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现。现在给出应该输入的一段文字、以及实际被输入的文字,请你列出肯定坏掉的那些键
思路:把实际输出的放到Set里,然后用i遍历预期输出的,如果i的值不在set里,则证明是坏键,但是这时的坏键可能重复输出了,所以还需要把这些坏键再次放入另一个Set里,如果重复则不放,不重复则放入并打印(如果都放入Set,之后再拿出Set里的值会出现顺序的问题)
import java.util.*; public class Main{ //strExce:7_This_is_a_test strActual:_hs_s_a_es public static void func(String strExce,String strActual){ HashSetset=new HashSet<>(); for (char ch:strActual.toUpperCase().toCharArray()) {//将strActual转换成大写再将里面的值放入set set.add(ch); } HashSet broken=new HashSet<>();//用来去除坏键中的重复键 for (char ch:strExce.toUpperCase().toCharArray()) {//遍历预期输出的值 //if(!set.contains(ch)){//如果Set里不包含该值证明该值为坏键(但是此时这些坏键可能有重复的) if(!set.contains(ch)&&!broken.contains((ch))){ System.out.print(ch);//如果坏键的broken里面也没有该值说明是坏键,并且此时也保证了坏键能不重复的输出 broken.add(ch); } } } public static void main(String[]args){ Scanner in=new Scanner(System.in); while(in.hasNextLine()){ String strExce=in.nextLine(); String strActual=in.nextLine(); func(strExce,strActual); } } }
8、前K个高频单词
给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。
返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。
意思是:
思路:因为返回前 k 个出现次数最多的单词,需要建一个小堆
因为最后是由高到低排序,所以将堆顶弹出后还需逆置
public ListtopKFrequent(String[] words,int k){ HashMap map=new HashMap<>(); //1、统计每个单词出现的次数 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 > minHeap=new PriorityQueue<>(k, new Comparator >() { @Override public int compare(Map.Entry o1, Map.Entry o2) { if(o1.getValue().compareTo(o2.getValue())==0){//因为在入堆的时候要调用compare,这个情况是在值相等的情况下,单词建大堆到时候逆置就正好由字典顺序输出了 return o2.getKey().compareTo(o1.getKey()); } return o1.getValue()-o2.getValue();//小根堆o1-o2 } }); //3、遍历Map for (Map.Entry entry:map.entrySet()) { if(minHeap.size() 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 ret=new ArrayList<>(); for (int i = 0; i < k; i++) { Map.Entry top=minHeap.poll(); ret.add(top.getKey());//最后只留下key值 } Collections.reverse(ret);//最后逆置 return ret; }



