Collection与Map

集合框架概述

数组的特点与弊端

特点

  • 数组一旦初始化,长度就已经确定了
  • 数组中的多个元素是依次紧密排列的,有序的,可重复
  • 数组一旦初始化完成,其元素的类型就是确定的,不是此类型的元素,就不能添加到数组中
  • 元素的类型既可以是基本数据类型,也可以是引用数据类型

弊端

  • 数组一旦初始化,长度就已经不可变了
  • 数组中存储数据特点的单一性,对于无序的,不可重复的场景的多个数据就不行了
  • 数组中可用的方法,属性都极少
  • 针对于数组中元素的删除,插入操作,性能较差(尾部添加性能并不差)

Java集合框架体系

java.util.Collection:存储一个一个数据

  • List
    • 存储有序的,可重复的数据
    • ArrayList
    • LinkedList
    • Vector
  • Set(底层其实就是Map,只使用了Map的键,来保证唯一,不可重复)
    • 存储无序的,不可重复的数据
    • HashSet
    • LinkedHashSet
    • TreeSet

java.util.Map:存储一对一对数据

  • HashMap
  • LinkedHashMap
  • TreeMap
  • Hashtable
  • Properties

Collection接口

  • add(Object obj)/addAll(Collection coll)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    /**
    * add()
    * addAll()
    */
    @Test
    public void test1() {
    Collection collection = new ArrayList();
    collection.add("aa");
    collection.add("bb");
    collection.add(123);
    collection.add(new Object());
    collection.add(new Person("tom", 12));
    System.out.println(collection);

    Collection collection1 = new ArrayList();
    collection1.add("cc");
    System.out.println(collection1.size());
    collection1.addAll(collection);
    System.out.println(collection1.size());
    System.out.println(collection1);
    }
  • size(),isEmpty(),contains(Object obj),containsAll(Collection coll),equals()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    /**
    * int size()
    * isEmpty()
    * contains(Object obj)
    * containsAll(Collection coll)
    * equals(Object obj)
    */
    @Test
    public void test2() {
    Collection collection = new ArrayList();
    collection.add("aa");
    collection.add("bb");
    collection.add(128);
    collection.add(new Person("111", 123));
    System.out.println(collection.isEmpty());
    // contains比的是值(equals),而不是地址
    System.out.println(collection.contains(128));
    // 只有Person重写了equals,下面才会相等,因为不重写equals的话,就是使用的Object的equals,也就是`==`,同样是判断地址
    System.out.println(collection.contains(new Person("111", 123)));

    Collection coll1 = new ArrayList();
    coll1.add("aa");
    coll1.add("cc");
    System.out.println(collection.containsAll(coll1));
    }
  • clear(),remove(),removeAll(),retainAll()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    @Test
    public void test3() {
    Collection coll1 = new ArrayList();
    coll1.add("AA");
    System.out.println(coll1);
    coll1.clear();
    System.out.println(coll1);

    coll1.add(new Person("tom", 11));
    coll1.add(new Person("tom", 11));
    // remove方法会调用contains方法,意思就是,如果没有重写equals,那么就不能通过这样的形式删除
    coll1.remove(new Person("tom", 11));
    System.out.println(coll1);

    // removeAll()
    coll1.add("AA");
    coll1.add(111);

    Collection coll2 = new ArrayList();
    coll2.add("AA");
    coll2.add("BB");
    coll2.add("CC");
    // 删除coll1中和coll2相交的部分
    // coll1.removeAll(coll2);
    // System.out.println(coll1);

    // 从coll1中删除两个集合不同的元素,只留下交集
    coll1.retainAll(coll2);
    System.out.println(coll1);

    }
  • Object[] toArray():返回包含当前集合中所有元素的数组
  • hashCode():获取集合对象的哈希值
  • iterator():返回迭代器对象,用于集合遍历(后面讲)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Test
    public void test4() {
    Collection collection = new ArrayList();
    collection.add("aa");
    collection.add("bb");
    collection.add(128);
    Object[] array = collection.toArray();

    int i = collection.hashCode();
    System.out.println(i);
    }

ArrayList集合和数组之间的转换
集合转换为数组,那么这个新的数组跟原集合就没有关系了,改变集合的值,不会影响到数组的值
但是如果是对数组使用Arrays.asList(Object[] obj)方法,来让一个数组转化为一个集合,此时的集合是只读(可以使用set,但是不能使用add和remove)的,且数组改变,会影响到集合的值

一个注意点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void test6() {
// 这里其实就是自动装箱后,数组的每一项变成集合的每一项
Integer[] arr = new Integer[]{1, 2, 3};
List<Integer> list = Arrays.asList(arr);
System.out.println(list); // 打印的是集合中的元素
System.out.println(list.size());

// 但是这里,是将int[] 这个数组对象,看成一个对象,装入了集合,集合中只有一个数组对象
int[] arr1 = new int[]{1, 2, 3};
List list1 = Arrays.asList(arr1);
System.out.println(list1); // 打印的是地址值
System.out.println(list1.size());
}

小总结:向Collection中添加的元素,一般要求元素所属的类一定要重写equals,因为Collection中的相关方法(contains,remove)要调用equals()


iterator迭代器
用来遍历集合元素的

两个重要的方法

  • hashNext()
  • next():指针下移,将下移以后集合位置上的元素返回

搭配使用,可以用来遍历集合

1
2
3
4
5
6
7
8
9
10
11
@Test
public void test1() {
Collection coll1 = new ArrayList();
coll1.add("AAA");
coll1.add("BBB");
coll1.add("CCC");
Iterator iterator = coll1.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}

增强for循环的原理就是使用的迭代器,实际上是语法糖,来简化迭代器的使用

List

List,用于存储有序的,可以重复的数据

List中的常用方法除了Collection中的方法外,还有一些其他的

因为List是有序的,进而就有索引,就会有一些针对索引的操作方法

  • remove(int index)删除指定索引的元素
  • set(int index,Object obj)给指定索引设置值
  • get(int index)获取指定索引的元素
  • add(int index,Object obj)指定位置插入
  • addAll(int index,Collection eles)插入多个
  • indexOf(Object obj)返回obj在集合中首次出现的位置
  • lastIndexOf(Object obj)返回obj在当前集合中末次出现的位置
  • subList(int fromIndex,int toIndex)返回从fromIndex到toIndex-1位置的子集合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void test1() {
List list = new ArrayList();
list.add("111");
list.add("222");
list.add(new Person("BB", 1));
list.forEach(System.out::println);

System.out.println("===");

list.add(1, "testInsert");
list.forEach(System.out::println);

}

三个List实现类

  • ArrayList:最常用的List实现类
  • LinkedList:基于双向链表的结构
  • Vector:List的一个古老的实现类

Set

Set:存储无序的,不可重复的数据

开发中,相较于List和Map,Set使用比较少

Set中的实现类

  • HashSet:底层使用的是HashMap
  • LinkedHashSet(继承的HashSet,在现有的结构上,又添加了一组双向链表,用于记录添加元素的先后顺序,即:我们可以按照添加元素的顺序实现遍历,便于频繁的查询操作)
  • TreeSet:底层使用红黑树存储,可以按照添加的元素的指定的属性进行遍历

HashSet

  • 无序性 != 随机性
    这里的无序性,是指添加元素的位置是无序的,不像ArrayList一样是依次排列紧密的
  • 不可重复性
    添加到Set中的元素是不能相同的,比较的标准:需要判断hashCode得到哈希值与equals得到的结果,哈希值相同且equals返回true才是相同

如果Person没有重写hashCode方法,那么最下面的语句就会输出false,如果没有重写,调用的就是Object中的hashCode,Object 类的默认 hashCode 实现是为每个不同的对象实例返回不同的哈希码,即使这些对象在逻辑上是“相等的”(即它们的 equals 方法可能返回 true)。,这也就解释了为什么不重写hashCode,下面语句就返回false了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Test
public void test1() {
Set set = new HashSet();

set.add("AA");
set.add(123);
set.add("BB");
set.add("CC");
set.add("DD");
set.add(new Person("tom", 11));
for (Object o : set) {
System.out.println(o);
}

System.out.println(set.contains(new Person("tom", 11)));
}

小总结:添加到HashSet/LinkedHashSet中的元素的要求:要求元素所在的类要重写equals和hashCode方法

TreeSet

TreeSet的底层是红黑树,添加数据后,可以按照添加的元素的指定的大小顺序进行遍历

要求添加到TreeSet中的元素必须是同一个类型的对象,否则会报类型转换异常,因为TreeSet中会将其元素相互比较

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void test1() {
TreeSet set = new TreeSet();
set.add("AA");
set.add("BB");
set.add("CC");
set.add("DD");
set.add(123);
for (Object o : set) {
System.out.println(o);
}
}

TreeSet添加自定义的类,那自定义类要实现Comparable接口,或者TreeSet中传入一个Comparator对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 按照年龄从小到达排序,年龄相同则按照姓名从小到大
@Override
public int compareTo(Object o) {
if (o == this) {
return 0;
}
if (o instanceof User) {
User u = (User) o;
int result1 = Integer.compare(this.age, u.age);
if (result1 != 0) {
// 不相同,则直接返回
return result1;
}
return this.name.compareTo(u.name);
}
throw new RuntimeException("类型错误");
}

如果这个compareTo方法中只比较了一个属性,那么在插入对象时,这个属性相同,就会判断为相同的属性,根本不会调用equals和hashCode方法,也就是说,在TreeSet中,判断相同的标准就是使用排序的方法了

下面是使用定制排序的方式,也就是不需要自定义类实现Comparable接口,而是给TreeMap传入一个Comparator接口的实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Test
public void test3() {
Comparator comparator = (o1, o2) -> {
// 姓名从大到小,年龄从小到大
if (o1 instanceof User && o2 instanceof User) {
User u1 = (User) o1;
User u2 = (User) o2;
int result = u1.getName().compareTo(u2.getName());
if (result != 0) {
return -result;
}
return Integer.compare(u1.getAge(), u2.getAge());
}
throw new RuntimeException("类型错误");
};
// 传入comparator
TreeSet set = new TreeSet(comparator);
set.add(new User("tom", 11));
set.add(new User("aom", 13));
set.add(new User("bom", 13));
set.add(new User("tom", 14));

set.forEach(System.out::println);
}

Set案例
定义方法如下:public static List duplicateList(List list)

  • 参数List只存在Integer的对象
  • 在List内去除重复数字值,尽量简单
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public class TestDup {
    public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(2);
    list.add(3);
    List result = duplicateList(list);
    list.forEach(System.out::println);
    System.out.println("===");
    result.forEach(System.out::println);
    }

    /**
    * - 参数List只存在Integer的对象
    * - 在List内去除重复数字值,尽量简单
    *
    * 可以遍历然后add,但是也可以用构造方法直接将list转换为set,还可以将set直接转换为list
    *
    * @param list
    * @return
    */
    public static List duplicateList(List<Integer> list) {
    HashSet<Integer> hashSet = new HashSet<>(list);
    List resultList = new ArrayList(hashSet);
    return resultList;
    }

Set案例二
编写一个程序,获取10个1-20的随机数,要求随机数不能重复,并把最终的随机数输出到控制台

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TestRandom {
public static void main(String[] args) {
HashSet<Integer> set = new HashSet();
List<Integer> list = new ArrayList();
while (set.size() < 20) {
int a = (int) (Math.random() * 20) + 1;
list.add(a);
set.add(a);
}
set.forEach(System.out::println);
System.out.println("+++");
System.out.println(list.size());
}
}

还有一个案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class HashSetDemo {
public static void main(String[] args) {
Set<Person> set = new HashSet();
Person p1 = new Person(1001, "AA");
Person p2 = new Person(1002, "BB");
set.add(p1);
set.add(p2);
System.out.println(set);

p1.setName("CC");
// 由于插入p1时,是按照1001和AA进行的hash运算,而这里将AA改为CC,那么remove时,会根据1001和CC进行哈希运算来找到具体的存储位置,就可能找不到,所以就不会删除
set.remove(p1);
System.out.println(set);

// 添加一个1001 CC 也是可以添加进去的
set.add(new Person(1001, "CC"));
// 虽然对象的属性是一样的,但是hash值是不同的,老的那个1001 CC的哈希值依然是根据之前的1001 AA计算得来的
System.out.println(set);

// 再添加一个1001 AA
set.add(new Person(1001, "AA"));
// 虽然这个1001 AA 和之前的1001 AA的哈希值相同,但是equals是不同的,所以并不会重复
System.out.println(set);
}
}

20231118104715

Map接口

java.util.Map:存储一对一对数据

  • HashMap,Map主要实现类,线程不安全的,可以添加null的key和value值
    • LinkedHashMap,是HashMap的子类,在HashMap使用的数据结构的基础上,增加了双向链表,用于记录添加元素的先后顺序,可以按照添加的元素的指定的大小顺序进行遍历,对于频繁遍历的数据,可以优先考虑此结构
  • TreeMap,底层使用红黑树存储,可以按照添加的key-value中的key元素的指定属性的大小顺序进行遍历
  • Hashtable,Map的古老实现类,线程安全的,不可以添加null的key和value值
    • Properties,其key和value都是String类型,常用来处理属性文件

HashMap

HashMap中的key用Set来存放,不允许重复,即同一个HashMap对象所对应的类,须重写hashCode()和equals方法(不重写,也能存,不过可能会有问题,参考Set)

HashMap中的一个key-value就构成了一个Entry,所以的entry彼此之间是不可重复的,无序的,所有的entry就构成了一个Set集合


常用方法

  • 添加/修改
    • Object put(key,value)将指定的key-value添加到(或修改)当前map对象中
    • void putAll(Map m)将m中所有的key-value对存放到当前map中
  • 删除操作
    • Object remove(key):移除指定key的key-value对,并返回value
    • void clear(),清空当面map中的所有数据
  • 元素查询操作
    • Object get(Object key),获取指定key对应的value
    • containsKey(key)是否包含指定的key
    • containsValue(Object value),是否包含指定的value
    • int size()返回map中key-value对的个数
    • isEmpty(),判断当前map是否为空
    • equals(Object obj):判断当前map和参数对象obj是否相等
  • 元视图操作的方法
    • Set keySet():返回所有key构成的set集合
    • Collection values()返回所有value构成的Collection集合
    • Set entrySet(),返回所有key-value对构成的Set集合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@Test
public void test3() {
Map<String, String> map = new LinkedHashMap<>();
map.put("11", "22");
map.put("110", "220");
map.put("12", "00");
map.put("00", "11");
Set<String> strings = map.keySet();
System.out.println(strings);
Collection<String> values = map.values();
System.out.println(values);
Set<Map.Entry<String, String>> entries = map.entrySet();
System.out.println(entries);
System.out.println("--");
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println("key=" + key + " value=" + value);
}
}

@Test
public void test4() {
// 遍历map
Map<String, String> map = new LinkedHashMap<>();
map.put("11", "22");
map.put("110", "220");
map.put("12", "00");
map.put("00", "11");

for (String s : map.keySet()) {
String values = map.get(s);
System.out.println(values);
}

System.out.println("===");

String value = map.remove("00");
System.out.println(value);

System.out.println("===");

for (String s : map.keySet()) {
String values = map.get(s);
System.out.println(values);
}

System.out.println("---");
map.put("11", "testUpdate");
System.out.println(map);
}

TreeMap

可以按照添加的key-value中的key元素的指定属性的大小顺序进行遍历

需要考虑使用自然排序或定制排序,且TreeMap中添加的key必须是同一个类型的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Test
public void test2() {
Map<User, String> map = new TreeMap<>();
map.put(new User("tom", 11), "11");
map.put(new User("aom", 13), "22");
map.put(new User("tom", 13), "33");
map.put(new User("tom", 14), "44");
Set<Map.Entry<User, String>> entries = map.entrySet();
for (Map.Entry<User, String> entry : entries) {
System.out.println(entry);
}
}

// 定制排序
@Test
public void test3() {
Comparator comparator = (o1, o2) -> {
if (o1 instanceof User && o2 instanceof User) {
User u1 = (User) o1;
User u2 = (User) o2;
// 先根据姓名从小到达排
int result1 = u1.getName().compareTo(u2.getName());
if (result1 != 0) {
return result1;
}
// 姓名相同,根据年龄从小到大排
return u1.getAge() - u2.getAge();
}
throw new RuntimeException("类型错误");
};
Map<User, String> map = new TreeMap<>(comparator);
map.put(new User("tom", 11), "11");
map.put(new User("aom", 13), "22");
map.put(new User("tom", 13), "33");
map.put(new User("tom", 14), "44");
Set<Map.Entry<User, String>> entries = map.entrySet();
for (Map.Entry<User, String> entry : entries) {
System.out.println(entry);
}
}

还有关于Properties的使用

1
2
3
4
5
6
7
8
9
10
@Test
public void test1() throws IOException {
File file = new File("test.properties");
System.out.println(file.getAbsolutePath());
FileInputStream fis = new FileInputStream(file);
Properties properties = new Properties();
properties.load(fis);
System.out.println(properties.getProperty("name"));
System.out.println(properties.getProperty("password"));
}

Collections工具类

Collections是一个操作Set,List和Map等集合的工具类

Collection和Collections的区别
Collection是集合框架中的用于存储一个一个元素的接口,又分为List和Set等子接口,而Collections是用于操作集合框架的工具类


常用api

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
@Test
public void test1() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);

// 打乱顺序-随机排序
Collections.shuffle(list);
System.out.println(list);

// 从小到大排序
Collections.sort(list);
System.out.println(list);

// 定制排序-逆序
Collections.sort(list, (o1, o2) -> -o1 - o2);
System.out.println(list);

// 将指定list集合中的i处元素和j处元素进行交换
Collections.swap(list, 0, 4);
System.out.println(list);
}

@Test
public void test2() {
List<String> list = Arrays.asList("AA", "BB", "CC", "DD");
// 根据元素的自然排序,返回给定集合的最大元素
String max = Collections.max(list);
System.out.println(max);

// 让max有min的效果
String max1 = Collections.max(list, (o1, o2) -> -o1.compareTo(o2));
System.out.println(max1);

String min = Collections.min(list);
System.out.println(min);

// 让min有max的效果
String min1 = Collections.min(list, (o1, o2) -> -o1.compareTo(o2));
System.out.println(min1);

// 查找(要保证有序才可以用)
int i = Collections.binarySearch(list, "AA");
System.out.println(i);

int time = Collections.frequency(list, "AA");
System.out.println(time);
}

@Test
public void test3() {
List<String> src = Arrays.asList("AA", "BB", "CC", "DD");
List<Object> dest = Arrays.asList(new Object[src.size()]);
// 这里又涉及到 "只读"list的赋值了,其实这里dest创建时,里面是一个一个null的数据,而下面copy时,是给null的数据进行set赋值,并非add
Collections.copy(dest, src);
System.out.println(dest);
}

@Test
public void test4() {
// 提供了多个unmodifiableXxx()方法,该方法返回指定Xxx的不可修改的视图
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);

// 设置为只读
List<Integer> unmodifiableList = Collections.unmodifiableList(list);
unmodifiableList.set(0, 1);
System.out.println(unmodifiableList);
}

@Test
public void test5() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);

// 返沪一个线程安全的list
List<Integer> list1 = Collections.synchronizedList(list);
System.out.println(list1);

Map<String, String> map = new HashMap<>();
map.put("11", "22");
Map<String, String> map1 = Collections.synchronizedMap(map);
System.out.println(map1);
}

一个发牌案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Test
public void test6() {
String[] num = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};
String[] color = {"方片", "梅花", "红桃", "黑桃"};

ArrayList<String> poker = new ArrayList<>();
for (int i = 0; i < num.length; i++) {
for (int i1 = 0; i1 < color.length; i1++) {
poker.add(num[i] + color[i1]);
}
}

poker.add("大王");
poker.add("小王");

// 洗牌
Collections.shuffle(poker);

System.out.println(poker.size());

List<String> one = new ArrayList<>();
List<String> two = new ArrayList<>();
List<String> three = new ArrayList<>();
List<String> last = new ArrayList<>();

for (int i = 0; i < poker.size(); i++) {
// i等于51时,表示已经分到最后三张牌了
if (i >= poker.size() - 3) {
last.add(poker.get(i));
}
if (i % 3 == 0) {
one.add(poker.get(i));
} else if (i % 3 == 1) {
two.add(poker.get(i));
} else if (i % 3 == 2) {
three.add(poker.get(i));
}
}

System.out.println(one);
System.out.println(two);
System.out.println(three);
System.out.println(last);

}

Map练习题

其实是两道面试题,都是使用到了HashMap

查找排名最接近荣誉的排名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class ClosestRankFinder {
public static int findClosestRank(Map<Integer, Integer> user) {
// 要找到的 那个最接近荣誉的排名
int closestRank = -1;
// 存储当前最小差异值
int minDifference = Integer.MAX_VALUE;

// 遍历user
for (Map.Entry<Integer, Integer> entry : user.entrySet()) {
int currentRank = entry.getKey();
int currentHonor = entry.getValue();
// 排名和荣誉值的差值
int difference = Math.abs(currentRank - currentHonor);

if (difference <= minDifference) {
minDifference = difference;
closestRank = currentRank;
}
}

return closestRank;
}

public static void main(String[] args) {
Map<Integer, Integer> user = new HashMap<>();
user.put(1, 93);
user.put(10, 55);
user.put(15, 30);
user.put(20, 19);
user.put(23, 11);
user.put(30, 2);
int closestRank = findClosestRank(user);
System.out.println("排名最接近荣誉值的是:" + closestRank);
}
}

判断str1字符串重排后是否能组成str2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Test
public void test3() {
// 解决str1是steak,而str2是steakk,那么str1是无法重排后得到str2的,但是使用set集合的话,结果仍然会输出true
String str1 = "kstedak";
String str2 = "steakk";

Map<Character, Integer> map = new HashMap<>();
char[] charArray = str1.toCharArray();
for (char c : charArray) {
// 插入这个字符,如果数量为0,那就是没有这个字符,此时给这个字符数量加1
map.put(c, map.getOrDefault(c, 0) + 1);
}

for (char c : str2.toCharArray()) {
if (!map.containsKey(c) || map.get(c) == 0) {
// 不包含key或者key不够
System.out.println(false);
return;
}
map.put(c, map.get(c) - 1);
}
System.out.println(true);

}