哈希
哈希
哈希表(Hash Table)是一种常见的数据结构,提供高效的查找、插入和删除操作。
(一)HashMap
HashMap 是 Java 中基于哈希表实现的 Map 接口的一个具体实现
1. put(key, value) : 插入元素
-
作用:将指定的键值对插入到哈希表中。如果键已存在,则更新其对应的值。
-
时间复杂度:平均 O(1)
Map<String, Integer> map = new HashMap<>();
map.put("apple", 3); // 键 "apple" 对应的值为 3
map.put("banana", 5); // 键 "banana" 对应的值为 5
map.put("apple", 4); // 键 "apple" 已存在,更新值为 4
2. get(key) : 查找元素
- 作用:根据给定的键返回对应的值。如果键不存在,返回
null。 - 时间复杂度:平均 O(1),最坏情况 O(n)(当发生大量哈希冲突时)。
Integer value = map.get("apple"); // 返回 4
Integer value2 = map.get("orange"); // 返回 null
3. containsKey(key) : 检查是否包含某个键
- 作用:检查哈希表中是否包含指定的键。
- 时间复杂度:O(1)
boolean contains = map.containsKey("apple"); // 返回 true
boolean contains2 = map.containsKey("orange"); // 返回 false
4. containsValue(value) : 检查是否包含某个值
-
作用:检查哈希表中是否包含指定的值。
-
时间复杂度:O(n)(需要遍历所有值)。
boolean containsValue = map.containsValue(4); // 返回 true
5. remove(key) : 删除指定键的元素
- 作用:从哈希表中删除指定键值对。
- 时间复杂度:平均 O(1),最坏情况下 O(n)。
map.remove("apple"); // 删除键 "apple" 及其对应的值
6. size() : 获取哈希表大小
-
作用:返回哈希表中键值对的数量。
-
时间复杂度:O(1)
int size = map.size(); // 返回哈希表中键值对的数量
7. isEmpty() : 检查哈希表是否为空
-
作用:检查哈希表是否为空。如果没有元素,返回
true。 -
时间复杂度:O(1)
boolean isEmpty = map.isEmpty(); // 返回 true 如果哈希表为空
8. clear() : 清空哈希表
-
作用:删除哈希表中的所有元素。
-
时间复杂度:O(n),需要删除所有元素。
map.clear(); // 清空哈希表中的所有键值对
9. keySet() : 获取所有键的集合
-
作用:返回哈希表中所有键的集合。
-
时间复杂度:O(n)
Set<String> keys = map.keySet(); // 返回所有键的集合
10. values() : 获取所有值的集合
-
作用:返回哈希表中所有值的集合。
-
时间复杂度:O(n)
Collection<Integer> values = map.values(); // 返回所有值的集合
11.getOrDefault(key, defaultValue) : 获取键的值或默认值
-
作用:根据给定的键返回值。如果键不存在,返回指定的默认值。
-
时间复杂度:O(1)
Integer value = map.getOrDefault("apple", 0); // 返回 4
Integer value2 = map.getOrDefault("orange", 0); // 返回 0 (默认值)
12.putIfAbsent(key, value) : 如果键不存在,则插入键值对
-
作用:只有当指定的键不存在时,才插入新的键值对。若键已存在,则不会修改值。
-
时间复杂度:O(1)
map.putIfAbsent("apple", 3); // 如果 "apple" 不存在,则插入,否则不做任何操作
13.replace(key, oldValue, newValue) : 替换键对应的值(只有值匹配时替换)
-
作用:只有当指定的键对应的值为
oldValue时,才会用newValue替换原值。 -
时间复杂度:O(1)
map.replace("apple", 4, 10); // 如果 "apple" 的值是 4,则将其替换为 10
(二)HashSet
HashSet 是 Java 中基于哈希表实现的 Set 接口的一个具体实现类。HashSet 用于存储不重复的元素,且不保证元素的顺序。
1. add(E e) : 添加元素
- 作用:将指定的元素添加到
HashSet中。如果元素已存在,则不添加。 - 返回值:如果元素成功添加,返回
true;如果元素已存在,则返回false。 - 时间复杂度:平均 O(1),最坏情况下 O(n)(当发生大量冲突时)。
HashSet<String> set = new HashSet<>();
set.add("apple"); // 返回 true
set.add("banana"); // 返回 true
set.add("apple"); // 返回 false,因为 "apple" 已经存在
2. remove(Object o) : 删除元素
-
作用:从
HashSet中删除指定的元素。如果元素存在,则删除并返回true,否则返回false。 -
返回值:
true表示元素成功删除,false表示元素不存在。 -
时间复杂度:平均 O(1),最坏情况下 O(n)(当发生大量冲突时)。
set.remove("banana"); // 返回 true
set.remove("orange"); // 返回 false,因为 "orange" 不存在
3.contains(Object o) : 判断是否包含元素
-
作用:检查
HashSet中是否包含指定的元素。 -
返回值:如果集合中包含指定的元素,返回
true;否则返回false。 -
时间复杂度:平均 O(1),最坏情况下 O(n)(当发生大量冲突时)。
boolean hasApple = set.contains("apple"); // 返回 true
boolean hasOrange = set.contains("orange"); // 返回 false
4. size() : 获取集合大小
- 作用:返回
HashSet中元素的数量。 - 时间复杂度:O(1)
int size = set.size(); // 返回集合中元素的个数
5. isEmpty() - 判断集合是否为空
- 作用:检查
HashSet是否为空。 - 返回值:如果集合为空,返回
true;否则返回false。 - 时间复杂度:O(1)
boolean isEmpty = set.isEmpty(); // 返回 true 如果集合为空
6. clear() - 清空集合
- 作用:删除
HashSet中的所有元素。 - 时间复杂度:O(n),需要删除所有元素。
set.clear(); // 清空集合中的所有元素
Leetcode相关题目总结
1. 两数之和
import java.util.ArrayList;
class Solution {
public int[] twoSum(int[] nums, int target) {
//1.创建一个哈希表,用来存储已遍历的元素及其索引(key:元素的值-----value:元素的索引)
Map <Integer,Integer> hastable=new HashMap <Integer,Integer>();
//2.遍历数组中的每个元素
for(int i=0;i<nums.length;i++){
//计算当前元素需要的配对值
int aim=target-nums[i];
//判断该配对值是否已经在哈希表中出现过
if(hastable.containsKey(aim)){ // 如果存在,说明找到了两个数,它们的和为target
//返回配对值的下标和当前元素的下标
return new int[]{i,hastable.get(aim)};
}
//如果没有找到,记录当前元素的值及其索引
hastable.put(nums[i],i);
}
//3.如果遍历完数组没有找到符合条件的两个数,返回空数组
return new int[0];
}
}
49. 字母异位词分组
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
Map <String,List<String>> map =new HashMap <String,List<String>>();
for(String str:strs){
//1.将String类型的字符串转换成字符数组
char[] array=str.toCharArray();
//2.调用Arrays类提供的sort()方法,对字符型数组进行排序
Arrays.sort(array);
//3.将排序后的字符数组转换回String类型
String key=new String(array);
//4.声明一个list,用于存放map中与key对应的value(即所有字母异位词)
//根据给定的key查找对应的value。如果key存在,则返回与该key关联的value;如果key不存在,则返回默认值,即new ArrayList<String>()(一个新的空字符串列表)
List<String> list = map.getOrDefault(key,new ArrayList<String>());
//5.将当前处理的字符串也加入list
list.add(str);
//6.向list插入一个新的键值对(如果key已经存在,则更新其对应的value)
map.put(key,list);
}
//将 map 中的所有值(即 List<String> 类型的集合)转换为一个 ArrayList 并返回
return new ArrayList <List<String>>(map.values());
}
}
128.最长连续序列
class Solution {
public int longestConsecutive(int[] nums) {
// Step 1: 将数组中的元素添加到一个 HashSet 中,去重。
Set<Integer> num_set=new HashSet<Integer>();
for(int num:nums){
num_set.add(num);
}
// Step 2: 初始化最大连续序列长度。
int longestStreak=0;
// Step 3: 遍历 HashSet 中的每个元素。
for(int num:num_set){
//判断当前数字是否**可能**是一个最长连续序列的起点
//(如果 num-1 不在集合中,说明 num 是一个新序列的起点)
if(!num_set.contains(num-1)){
int currentNum=num;
int currentStreak=1;
//向右扩展序列,直到没有连续数字
while(num_set.contains(currentNum+1)){
currentNum+=1;
currentStreak+=1;
}
//更新最大连续序列长度
longestStreak = Math.max(longestStreak, currentStreak);
}
}
// Step 4: 返回最长连续序列的长度
return longestStreak;
}
}
-
时间复杂度是 O(n)
-
为何使用 HashSet?:
- 频繁查找:最核心的操作是判断某个元素是否存在于集合中。使用 HashSet的 常数时间复杂度 O(1) 查找非常适合此类问题。每次判断是否存在
num-1和num+1时,查找操作非常频繁,选择 HashSet能够保证效率。 - 去重:由于题目要求元素唯一,HashSet自带去重功能,这使得我们不需要手动判断是否插入重复元素。
- 频繁查找:最核心的操作是判断某个元素是否存在于集合中。使用 HashSet的 常数时间复杂度 O(1) 查找非常适合此类问题。每次判断是否存在
浙公网安备 33010602011771号