Java中哈希

哈希的本质是用空间换时间,把查找从 O(n) 降到 O(1) 平均。

HashSet

存不存在 / 去重,用于判断某元素是否出现过、数组去重、集合交集

Set<Integer> set = new HashSet<>();

set.add(3); // 添加元素

set.add(3); // 重复元素不会加入

set.contains(3); // 判断是否存在

set.remove(3); // 删除元素

典型题:两数之和、数组去重、判断重复元素、两数组交集

HashMap

计数 / 映射,用于字符统计、频率统计、值到索引映射

Map<Integer, Integer> map = new HashMap<>();

for (int n : nums) {

// 如果 n 不存在,默认返回 0,然后 +1

map.put(n, map.getOrDefault(n, 0) + 1);

}

两个Integer代表泛型,指key 和 value 都是整数,map.put(n, map.getOrDefault(n, 0) + 1);这行代码是哈希计数的经典写法,意思是给n做出现次数统计。map.getOrDefault(n, 0)去map里取n的值,如果n不存在,就返回默认值0map是指数组)。因为我们要统计出现次数,每遇到一次就加1。map.put(n, ...)代表把更新后的次数放回map里,如果n原来不存在,会自动创建。

典型题:字母异位词、出现次数最多的元素、前缀和 + 哈希、两数之和

TreeMap / TreeSet

有序哈希,用于需要自动排序、范围查询

Set<Integer> set = new TreeSet<>();

Map<Integer, Integer> map = new TreeMap<>();

基本用法:

TreeSet<Integer> set = new TreeSet<>();

set.add(5);

set.add(3);

set.add(8);

set.add(3); // 重复元素不会加入

System.out.println(set); // 3, 5, 8 自动升序
TreeMap<Integer, String> map = new TreeMap<>();

map.put(3, "C");

map.put(1, "A");

map.put(2, "B");

map.put(2, "BB"); // key=2 更新 value

System.out.println(map); // {1=A, 2=BB, 3=C} 自动按 key 排序

LinkedHashMap / LinkedHashSet

保序哈希,用于保持插入顺序 + 哈希效率

Map<Integer, Integer> map = new LinkedHashMap<>();

Set<Integer> set = new LinkedHashSet<>();

基本用法:

Set<Integer> set = new LinkedHashSet<>();

set.add(3);

set.add(1);

set.add(5);

set.add(1); // 重复元素不会加入

System.out.println(set); // 3, 1, 5 插入顺序保持
Map<Integer, String> map = new LinkedHashMap<>();

map.put(3, "C");

map.put(1, "A");

map.put(2, "B");

map.put(2, "BB"); // key=2 更新 value

System.out.println(map); // {3=C, 1=A, 2=BB} 插入顺序保持

哈希在算法中的 10 大经典用法

判断元素是否存在

复制代码
Set<Integer> set = new HashSet<>();
if (set.contains(x)) {}

去重

复制代码
Set<Integer> set = new HashSet<>();

for (int n : nums) {
    set.add(n);    // HashSet 自动去重
}

统计频率

复制代码
Map<Integer, Integer> map = new HashMap<>();
for (int n : nums)
    map.put(n, map.getOrDefault(n, 0) + 1);

字符串计数(异位词)

复制代码
int[] cnt = new int[26];
for (char c : s.toCharArray()) cnt[c - 'a']++;

两数之和(值 → 下标)

复制代码
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
    int need = target - nums[i];
    if (map.containsKey(need)) return new int[]{map.get(need), i};
    map.put(nums[i], i);
}

前缀和 + 哈希(子数组和为 k)

复制代码
Map<Integer, Integer> map = new HashMap<>();
map.put(0, 1);
int sum = 0, res = 0;
for (int n : nums) {
    sum += n;
    res += map.getOrDefault(sum - k, 0);
    map.put(sum, map.getOrDefault(sum, 0) + 1);
}

两数组交集

复制代码
Set<Integer> set = new HashSet<>();
for (int n : nums1) set.add(n);
Set<Integer> res = new HashSet<>();
for (int n : nums2) if (set.contains(n)) res.add(n);

判断重复元素

复制代码
Set<Integer> set = new HashSet<>();
for (int n : nums)
    if (!set.add(n)) 
        return true;

分组(分类)

复制代码
Map<String, List<String>> map = new HashMap<>();
for (String s : strs) {
    String key = sort(s);
    map.computeIfAbsent(key, k -> new ArrayList<>()).add(s);
}

最近最少使用缓存(LRU)

复制代码
class LRUCache extends LinkedHashMap<Integer, Integer> {
    protected boolean removeEldestEntry(Map.Entry eldest) {
        return size() > capacity;
    }
}

数组哈希 vs Map 哈希

当 key 范围固定小(如 a-z):

int\[\] hash = new int26;

hashc - 'a'++;

当 key 范围大或不连续:

Map<Integer, Integer> map = new HashMap<>();

相关推荐
左左右右左右摇晃9 分钟前
手写Tomcat原理整理
java·开发语言·笔记·tomcat
孫治AllenSun12 分钟前
【JVM】四大引用类型分析
java·开发语言·jvm
于慨14 分钟前
安装java
java
夕除15 分钟前
sign 是什么
java·前端
Penina101840 分钟前
代码如何导入idea
java·intellij idea
.Hypocritical.1 小时前
Maven笔记——2
java·笔记·maven
huohuopro1 小时前
手写 Tomcat 步骤教程
java·网络
snow@li1 小时前
Java:Lombok 完整讲解
java
Shadow(⊙o⊙)1 小时前
高并发内存池:Part-1——定长内存池
java·前端·javascript
国服第二切图仔1 小时前
17-config命令 - 配置管理系统
java·前端·javascript