目录
- Map接口实现类的特点
- Map接口的常见方法
- Map六大遍历方式
- Map练习1
- code
- 编程练习2
- code
- 编程练习3
- 思路
- code
Map接口实现类的特点
- Map与Collection并列存在,是Map集合体系的顶级接口
- Map的有些子实现存储数据是有序的(LinkedHashMap),有些子实现存储数据是无序的(HashMap)
- 用于保存具有映射关系的数据:Key-Value。key和value之间存在单向一对一关系,即通过指定的key总能找到对应的value
- Map中的key和value可以是任何引用类型的数据
- Map中的key不允许重复,原因和HashSet一样
- Map中的value可以重复
- Map的有些子实现允许存储null作为key(比如HashMap),有些子实现不允许存储null作为key(比如TreeMap)
- Map的key可以为null,value也可以为null,但是key为null只能有一个,value 为null可以多个
- 常用String类作为Map的key
package cs.kaoyan.javase.com.map;
import java.util.HashMap;
import java.util.Map;
public class Test1 {
public static void main(String[] args) {
Map map = new HashMap();
map.put("no1","zhang san");
map.put("no2","li si");
map.put("no1","wang wu");//可以加入,会替换no1的zhang san
map.put("no3","wang wu");//no.不同,可以加入
//{no2=li si, no1=wang wu, no3=wang wu}
System.out.println(map);
map.put(null,null);
//null作为key唯一,所以会替换上面作为value的null
map.put(null,"abc");
//null作为value可以有多个
map.put("no4",null);
map.put("no5",null);
//{no2=li si, null=abc, no1=wang wu, no4=null, no3=wang wu, no5=null}
System.out.println(map);
//get方法,传入key,会返回对应的value
//li si
System.out.println(map.get("no2"));
//wang wu
System.out.println(map.get("no3"));
}
}
Map接口的常见方法
package cs.kaoyan.javase.com.map;
import java.util.HashMap;
import java.util.Map;
public class Test3 {
public static void main(String[] args) {
Map map = new HashMap();
map.put("zhang san",18);
map.put("li si",19);
map.put("wang wu",20);
map.put("zhao liu",21);
map.put("xiao qi",22);
map.put("chang feng",23);
map.put("tian ming",24);
// 7
System.out.println(map.size());
//remove:根据键删除映射关系
map.remove("li si");
//get: 根据键获取值
//22
System.out.println(map.get("xiao qi"));
// 6
System.out.println(map.size());
//False
System.out.println(map.isEmpty());
//True
System.out.println(map.containsKey("tian ming"));
//清空
map.clear();
// 0
System.out.println(map.size());
}
}
Map六大遍历方式
Map不是Iterable的子接口,也就意味着Map没有Iterator方法,所以Map没有办法法"直接"调用foreach循环
- containsKey:查找键是否存在
- containsValue:查找值是否存在
- keySet:获取所有的键(获得map中key的集合视图)
- values:获取所有的值(获得map中value的集合视图)
- entrySet:获取所有关系(获得键值对集合)
- get: 根据键获取值
Map练习1
假设Map中存储了一批<String,User>类型的key-value用户信息,删除User的age是18岁的同学
code
package cs.kaoyan.javase.com.map;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/***
* 假设Map中存储了一批<String,User>类型的key-value用户信息
* 删除User的age是18岁的同学
*/
public class Test5 {
public static void main(String[] args) {
Map<String, User> map = new HashMap<>();
map.put("zs", new User("zs", 18));
map.put("ls", new User("ls", 19));
map.put("wu", new User("wu", 20));
map.put("zl", new User("zl", 21));
map.put("aa", new User("aa", 18));
//删除User的age是18岁的同学
//不可以一边遍历,一边删除,不然会出现并发修改异常ConcurrentModificationException
//先获得key,再通过key获得value
ArrayList list = new ArrayList();
Set<String> allKey = map.keySet();
for (String key : allKey) {
//通过key会返回一个user对象
User user = map.get(key);
if (user.age == 18){
//将所有年龄为18的对象的key存入list之中
list.add(key);
}
}
//遍历list,删除key
for (Object o : list) {
map.remove(o);
}
//{zl=User{"zl",21}, ls=User{"ls",19}, wu=User{"wu",20}}
System.out.println(map);
}
}
编程练习2
给定一个整数数组和一个目标值,找出数组中和为目标值的两个数, 返回它们的索引。
你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。
比如:nums = [2, 7, 11, 15], target = 9.
因为 nums[0] + nums[1] = 2 + 7 = 9. 所以返回 [0, 1].
code
package cs.kaoyan.javase.com.map;
import java.util.Arrays;
public class Test6 {
public static void main(String[] args) {
int[] ints = {2,7,11,15};
//answer数组用来存储答案
int[] answer = {0,0};
int target = 9;
//方法一:暴力算法,时间复杂度O(n*n)
/*for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (ints[i] + ints[j] == target){
answer[0] = i;
answer[1] = j;
}
}
}
System.out.println(answer[0] + " " + answer[1]);*/
//方法二:二分算法,时间复杂度O(nlogn)
//二分需要保证数组有序(数组本身已经有序,可以不写)
Arrays.sort(ints);
int size = ints.length;
for (int i = 0; i < size; i++) {
//在长度为size的数组ints中,找到元素target - ints[i]所在的下标
int index2 = binarySearch(ints, size, target - ints[i]);
if (index2 != -1){
//存在两数之和等于target
answer[0] = i;
answer[1] = index2;
//假设只有一组答案,满足即可结束循环
break;
}
}
System.out.println(answer[0] + " " + answer[1]);
}
/**
* 查找元素x在数组a的下标
* @param a:表示数组
* @param n:表示数组的长度
* @param x:表示要查找的目标元素
* @return:x在数组a的下标
*/
public static int binarySearch(int a[],int n,int x) {
int L = 0;
int R = n - 1;
//ans用来记录查找要查找元素的下标(一般设置为负数)
int ans = -1;
//二分查找条件:L <= R
while (L <= R) {
int Mid = (L + R) >> 1;
if (a[Mid] == x) {
//查找到目标元素
ans = Mid;
break;
}
if (a[Mid] < x) {
L = Mid + 1;
} else {
R = Mid - 1;
}
}
//如果返回-1说明未找到要查找的目标元素x
return ans;
}
}
编程练习3
给你一份『词汇表』(字符串数组)words和一张『字母表』(字符串)chars。
假如你可以用chars中的『字母』(字符)拼写出words中的某个『单词』(字符串),那么我们就认为你掌握了这个单词。注意:每次拼写时,chars中的每个字母都只能用一次。返回词汇表words中你掌握的所有单词的长度之和。
示例 1:
输入:words = [“cat”,“bt”,“hat”,“tree”], chars = “atach”
输出:6
解释:可以形成字符串 “cat” 和 “hat”,所以答案是 3 + 3 = 6。
示例 2:
输入:words = [“hello”,“world”,“leetcode”], chars = “welldonehoneyr”
输出:10
解释:可以形成字符串 “hello” 和 “world”,所以答案是 5 + 5 = 10。
思路
参考博客
遇到字符串仅包含小写(或者大写)英文字母的题,都可以试着考虑构造长度为26的数组。这样数组每个位置分别代表一个字母,统计出字母出现的次数。本题中,既要统计字母表中字母出现的次数,也要统计单词中字母出现的次数。如果字母表中字母出现的次数大于等于单词中每种字母出现的次数,那么这个单词就可以由字母表拼写出来。以字母表 "atach"和 词汇"cat"为例,过程图示如下:
code
package cs.kaoyan.javase.com.map;
public class Test7 {
public static void main(String[] args) {
String[] words = {"hello","world","leetcode"};
String chars = "welldonehoneyr";
int sum1 = countAllWordsLength(words, chars);
System.out.println(sum1);//10
String[] words2 = {"cat","bt","hat","tree"};
String chars2 = "atach";
int sum2 = countAllWordsLength(words2, chars2);
System.out.println(sum2);//6
}
public static int countAllWordsLength (String[] words,String chars){
int result = 0;
int[] charsCount = count(chars);
//遍历字符串数组
for (int i = 0; i < words.length; i++) {
int[] wordsCount = count(words[i]);
//挨个判断字符串数组中的每一个字符串是否可以由给定的字符组成
if (contains(wordsCount,charsCount)){
//累计可以被组成的字符串的长度
result += words[i].length();
}
}
return result;
}
/**
* 判断给定的字符是否可以组成字符串
* @param stringCount:一个数组,存储待判断字符串的字母个数
* @param charCount:一个数组,存储给定字符串的字母个数
* @return:可以组成返回true,否则返回false
*/
public static boolean contains(int[] stringCount,int[] charCount){
for (int i = 0; i < 26; i++) {
//如果待判断的字符串中某个单词出现的次数大于
//给定字符串中某个字母出现的次数,表明不能组成这个字符串
if (stringCount[i] > charCount[i]){
return false;
}
}
return true;
}
/**
* 计算一个单词中26个字母出现的次数
* @param s:传入一个单词
* @return:一个整型数组
*/
public static int[] count(String s){
//新建一个整型数组,用来存放每个英文字母出现的次数
int[] charCountArray = new int[26];
//遍历字符串
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
charCountArray[(int)c - 'a'] += 1;
}
return charCountArray;
}
}