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<>();

相关推荐
论文复现现场19 分钟前
WRF、FEA 能用 L40S 加速吗?求解器检查、断点恢复与长期运行
java·数据库·算法·wrf·有限元分析·gpu计算·断点续算
ZhengEnCi21 分钟前
用 AI 写代码为什么拼到最后还是拼人:算力瓶颈与领域专家提示词的本质差异
算法·架构
啃瓜子的松鼠37 分钟前
泛微OAe9-后端二开异步调用
java
秋天的怀念_David1 小时前
第二十一夜 · 数字黑洞与西西弗斯的惩罚
java·程序人生·算法
外收内放2 小时前
Python基础语法练习题(73)
java·前端·python
Wang's Blog2 小时前
Java 项目实战: 交友项目 - 环信后台发送消息测试
java·交友
用户3721574261352 小时前
Java 操作 Word 脚注和尾注:添加、读取与删除
java
碧海银沙音频科技研究院2 小时前
在PC电脑上用Whisper→Marian算法实现离线语音翻译功能
算法·whisper
小嘉丶学长2 小时前
Day14 · 字典与集合
java·开发语言·网络·python·学习·1024程序员节
字节探索2 小时前
Spring Boot 接口幂等性设计:从唯一索引到 Redis+Lua 的工程实践
java·spring boot