Map 和S et 是 一种专门 用来进行搜索的 数据结构。 适合动态查找 。
一、Map(存储key-value)
1、map.put(K的类型 key, V的类型 value) 往里放元素
Map
map=new HashMap<>(); map.put("abc",3);//put是往里放元素 map.put("bit",2); map.put("hello",4); System.out.println(map);//会自动调用toString方法 注意:hashmap存储元素的时候,不是按照存储的顺序进行打印的。
存储的时候,是根据哈希函数来进行存储的。
Map
map = 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为3
3、V的类型 =map.getOrDefault(key,没有key所对值时要返回的值)
map.getOrDefault("bit2",98);//找不到bit2,也就找不到对应的value,此时就返回设定的value值98
4、V的类型 =map.remove(key) 删除
Integer ret2=map.remove("bit");//删除值为bit的 System.out.println(ret2);//2
5、Set
set=map. keySet() 返回所有 key 的不重复集合因为Set这个集合当中存储的元素都是不重复的
Map
map = 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
=map. values() 返回所有 value 的可重复集合7、Set> =map. entrySet() 返回所有的 key-value 映射关系Map
map = 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
注意:
二、Set(存储key)会自动去重
常见方法:
1、set.add(E e) 添加元素,但重复元素不会被添加成功
Set
set=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() 返回迭代器Set
set=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,否则返回false8、Object[] =set.toArray() 将set中的元素转换为数组返回9、boolean =set.containsAll(Collection> c) 集合c中的元素是否在set中全部存在,是返回true,否则返回 false10、boolean =ret.addAll(Collection extends E> c) 将集合c中的元素添加到set中,可以达到去重的效果
练习题:
1、给定1W个数据,统计每个数据出现的次数(思路:用Map)
思路:将每个值都放在map里,每次放的时候检查一下,如果有这个值,则在原来值所对的value值+1,如果没这个值,则把这个值放在map里,value值为1
public static Map
func1(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 Set
func2(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){ HashSet
set=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) { HashSet
set=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) { Map
map=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) { HashSet
set=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){ HashSet
set=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 List
topKFrequent(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; }