赞
踩
主要的数据结构:
二分搜索树:在Java标准库中对应TreeMap(基于红黑树-二分平衡搜索树RBTree的实现)/TreeSet
哈希表:在Java标准库中对应HashMap(基于哈希表的实现)/HashSet
set:其实就是披着Set外衣的Map,也是Collection接口的子接口,一次保存一个元素,和List集合最大的区别在于:
Set集合保存的元素不能重复,List可以重复,Collection接口一次只能保存一个元素
经常使用Set集合来进行去重处理
这个两个结合一般是用来进行查找操作
Map接口和Collection没有任何关系
Map接口就是最顶层的父接口,表示保存的是一对键值对对象
接口示意图
Set集合常用方法
方法 | 含义 |
---|---|
boolean add(E e) | 添加一个元素,若要元素不存在则添加成功,返回True;若添加失败,返回False |
boolean contains(Object o) | 判断一个元素o是否在当前set存在 |
boolean remove(Object o) | 在Set集合中删除指定元素,若该元素不存在,删除失败返回false;否则删除该元素,返回True |
在Set集合中没有提供修改的方法,若需要修改元素,只能先把要修改的元素删除,在添加新元素
遍历Set集合:使用for-each循环
public class SetTest { public static void main(String[] args) { Set<Integer> set = new HashSet<>(); System.out.println(set.add(1)); System.out.println(set.add(1)); System.out.println(set.add(2)); System.out.println(set.add(3)); System.out.println(set.contains(3)); System.out.println(set.contains(4)); System.out.println(set.remove(2)); for (int i : set) { System.out.print(i + " "); } } } 输出: true false true true true false true 1 3
Map接口的常用方法:保存的是一对键值对元素 <key,value>
方法 | 含义 |
---|---|
V put(K key, V value) | 添加一对键值对 |
boolean containsKey(Object key) | 判断元素在当前Map的key中是否存在 |
boolean containsValue(Object value) | 判断元素在当前Map的value中是否存在 |
Set<Map.Entry<K, V>> entrySet(); | 返回Map中所有的键值对对象Map.Entry[]对象 |
Set keySet(); | 返回当前Map接口中所有的key值集合,因为是不重复的,所以使用了Set集合 |
Collection values(); | 返回当前Map接口中所有的value值集合,因为是可以重复的,所以使用collection接口接收 |
V get(Object key); | 根据相应的key值取得相应的value值,若Key不存在,返回null |
default V getOrDefault(Object key, V defaultValue) | 根据相应的key值取得相应的value值,若key不存在,返回默认值defaultVal |
V remove(Object key); | 删除指定k值的一对键值对,返回value值 |
Map中键值对的类型是: Map.Entry ,它是一个对象,其中包含两个方法:
entry.getKey(): 获取当前键值对的Key
entry.getValue(): 获取当前键值对的value
Map集合的遍历
public static void main(String[] args) {
// key不重复,value可以重复
Map<Integer,Integer> map = new HashMap<>();
// 1 = 10
map.put(1,10);
map.put(2,20);
// value可以重复,用一个key会得到一个value
map.put(3,10);
System.out.println(map.containsKey(3));
System.out.println(map.containsValue(40));
// Map.Entry[],遍历
for (Map.Entry<Integer,Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
}
Map的put()方法说明
即是新增又是修改
添加一个新的键值对:
若key不存在,就新增一个Map.Entry对象,保存到Map中。若Key已存在,修改原来的value为新的value,返回修改前的value值
Map接口中,元素添加的顺序和保存的顺序没有必然联系
public static void main(String[] args) { Map<String,Integer > map = new HashMap<>(); map.put("王五",10); map.put("李四",12); map.put("孙武",13); map.put("张三",14); System.out.println(map.put("王五",22)); //取出所有的key Set<String> keys = map.keySet(); System.out.println("当前所有的key为"); for (String str : keys){ System.out.print(str + " "); } System.out.println(); //取出所有的value Collection<Integer> values = map.values(); for (Integer age : values){ System.out.print(age + " "); } } 输出: 10 当前所有的key为 李四 张三 孙武 王五 12 14 13 22 //乱序
- Map接口中元素的添加顺序和元素的保存顺序没有必然的联系
- HashMap中保存的元素顺序由hash函数来决定
- TreeMap中保存的元素顺序由TreeMap中的comparTo方法决定
- 要使用TreeMap保存元素,该类要么实现Comparable接口要么传入一个比较器
public static void main(String[] args) {
Map<String,Integer > map = new HashMap<>();
map.put("王五",10);
map.put("李四",12);
map.put("孙武",13);
map.put("张三",14);
System.out.println(map.toString());
}
输出:
{李四=12, 张三=14, 孙武=13, 王五=10} //乱序
TreeMap不覆写ComparTo方法的结果 ----报错
HashMap不会报错-----这两个用的是不同的底层结构
public class MapTest {
public static void main(String[] args) {
Map<ZhangSan,String> map = new TreeMap<>();
map.put(new ZhangSan(),"test");
}
}
class ZhangSan {}
报错:
jcl.ZhangSan cannot be cast to java.lang.Comparable
HashMap是可以保存Null值的,HashMap的key和value都能为null,但是key为null的时候,有且只有一个
TreeMap中key不能为空,value可以为空
HashMap
public static void main(String[] args) {
Map<String ,String > map = new HashMap<>();
map.put(null,null);
map.put(null,"test");
System.out.println(map.toString());
}
输出:
{null=test}
看一个代码
public static void main(String[] args) {
Map<String,String> map = new TreeMap<>();
try {
map.put(null,null);
}catch (NullPointerException e) {
System.out.println("key为空");
}
map.put("张三",null);
System.out.println(map);
}
输出:
key为空
{张三=null}
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
输入: [2,2,1]
输出: 1
思路:利用Map集合保存每个元素和出现的频次,然后遍历map,道道频次为一的那个元素。
public int singleNumber(int[] nums) {
// 1.先扫描原数组,将每个元素以及出现的频次保存到Map中
Map<Integer,Integer> map = new HashMap<>();
for (int i : nums) {
map.put(i,map.getOrDefault(i,0) + 1);
}
// 2.遍历这个map,找到频次为1的那个元素
int ret = 0;
for (Map.Entry<Integer,Integer> entry : map.entrySet()) {
if (entry.getValue().equals(1)) {
ret = entry.getKey();
}
}
return ret;
}
给你一个整数数组
nums
,除某个元素仅出现 一次 外,其余每个元素都恰出现 **三次 。**请你找出并返回那个只出现了一次的元素。输入:nums = [2,2,3,2]
输出:3
这道题和上面的题目一样,代码都不用换,只要找到频次为1的元素就可以了
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n 个全新节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对e应的两个节点 x 和 y ,同样有 x.random --> y 。
返回复制链表的头节点。
思路:利用Map集合-它保存的是key和value的映射关系
- 遍历原链表构造新链表,在Map集合中维护原链表和新链表的映射关系
- 再次遍历原链表,通过映射关系维护新链表的next和random
class Node { int val; Node next; Node random; public Node(int val) { this.val = val; this.next = null; this.random = null; } } class Solution { public Node copyRandomList(Node head) { //1.遍历原链表,构造Map集合维护原链表结点和新链表结点的映射关系 //原1 = 新1 Map<Node,Node> map = new HashMap<>(); for (Node x = head; x != null;x = x.next){ Node node = new Node(x.val); map.put(x,node); } //2.再次遍历原链表,通过映射关系维护新链表的next和random for (Node x = head; x != null;x = x.next ){ //新的结点的next = 原结点的next map.get(x).next = map.get(x.next); //新节点的random = 原节点的random map.get(x).random = map.get(x.random); } //原链表的头结点对应新链表的头结点 return map.get(head); } }
给定一种规律 pattern 和一个字符串 s ,判断 s 是否遵循相同的规律。
这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 str 中的每个非空单词之间存在着双向连接的对应规律。
输入: pattern = “abba”, str = “dog cat cat dog”
输出: true输入: pattern = “aaaa”, str = “dog cat cat dog”
输出: false
思路:这种题目是模式匹配问题,都可以采用Map映射结构解决
图下图所示,将其翻译成数字保存到Map集合中。
public boolean wordPattern(String pattern, String s) { //按照空格分隔 String[] str = s.split(" "); //两个字符长度不一样,肯定不是匹配的 if (str.length != pattern.length()) { // pattern = "abba" str = "dog cat cat" return false; } // 建立pattern和str关于数字的映射关系 int count = 1; Map<String,Integer> map1 = new HashMap<>(); StringBuilder sb1 = new StringBuilder(); for (String temp : str) { if (map1.containsKey(temp)) { sb1.append(map1.get(temp)); }else { map1.put(temp,count); sb1.append(count ++); } } count = 1; Map<Character,Integer> map2 = new HashMap<>(); StringBuilder sb2 = new StringBuilder(); // pattern = "abba" for (int i = 0; i < pattern.length(); i++) { char c = pattern.charAt(i); if (map2.containsKey(c)) { sb2.append(map2.get(c)); }else { map2.put(c,count); sb2.append(count ++); } } // 1221 1221 return sb1.toString().equals(sb2.toString()); }
给你一个字符串 jewels 代表石头中宝石的类型,另有一个字符串 stones 代表你拥有的石头。 stones 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。
字母区分大小写,因此 “a” 和 “A” 是不同类型的石头。
输入:jewels = “aA”, stones = “aAAbbbb”
输出:3
思路:使用Set集合保存jewels中的字符
扫描stones字符串,判断出现的每个字符是否在set中已经存在,若存在就说明是个宝石
public int numJewelsInStones(String jewels, String stones) { // 使用Set集合保存jewels中的字符 Set<Character> set = new HashSet<>(); for (int i = 0; i < jewels.length(); i++) { set.add(jewels.charAt(i)); } // 扫描stones字符串,判断出现的每个字符是否在set中已经存在,若存在就说明是个宝石 int ret = 0; for (int i = 0; i < stones.length(); i++) { if (set.contains(stones.charAt(i))) { // 是个宝石 ret ++; } } return ret; }
旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现。现在给出应该输入的一段文字、以及实际被输入的文字,请你列出肯定坏掉的那些键。
输入描述:
输入在2行中分别给出应该输入的文字、以及实际被输入的文字。每段文字是不超过80个字符的串,由字母A-Z(包括大、小写)、数字0-9、
以及下划线“_”(代表空格)组成。题目保证2个字符串均非空。
输出描述:
按照发现顺序,在一行中输出坏掉的键。其中英文字母只输出大写,每个坏键只输出一次。题目保证至少有1个坏键。
思路:因为Set和Map保存元素的顺序和添加顺序无关,所以实际的字符串去扫描期望的字符串,才能保证按照发现顺序输出
public class BadKey { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String expectedStr = null; String actualStr = null; while (scanner.hasNextLine()) { expectedStr = scanner.nextLine(); actualStr = scanner.nextLine(); } // 输出的字母需要大写,都转为大写处理 expectedStr = expectedStr.toUpperCase(); actualStr = actualStr.toUpperCase(); // 遍历实际输入的字符串,存入到Set中 Set<Character> set = new HashSet<>(); for (int i = 0; i < actualStr.length(); i++) { set.add(actualStr.charAt(i)); } // 拿着实际输入的set去遍历期望输入的字符串 // 所谓的坏键就是期望中有,而实际中不存在的字符 // 因为期望中存在而实际不存在的字符有可能有多个,因此输出时需要过滤重复元素 Set<Character> single = new HashSet<>(); for (int i = 0; i < expectedStr.length(); i++) { char c = expectedStr.charAt(i); // 坏键就是期望中存在,但是实际不存在 if (!set.contains(c)) { if (single.add(c)) { System.out.print(c); } } } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。