leetcode3 哈希
有限空间映射无限空间
有序化快速查询 解决映射查询
核心应用: 提速 空间和时间
001 两数之和
哈希代替遍历
一般来说处理Java数据量需要和10^9进行比较
提示:
2 <= nums.length <= 10^4
-10^9 <= nums[i] <= 10^9
-10^9 <= target <= 10^9
java整型占用四个字节 范围为: -2^31-2^31
class Solution {// public int[] twoSum(int[] nums, int target) {// Map<Integer, Integer> map = new HashMap<>();// for (int i = 0; i < nums.length; i++){// if(map.containsKey(target - nums[i])){// return new int[]{i,map.get(target - nums[i])};// }// map.put(nums[i],i);// }// return new int[]{};// }public int[] twoSum(int[] nums, int target) {HashMap<Integer, Integer> map = new HashMap<>();for (int i = 0; i < nums.length; i++) {int choose = nums[i];int diff = target - choose;if(map.containsKey(diff)){return new int[]{map.get(diff),i};}else{map.put(choose,i);}}return null;}
}
049 字母异位词
借助对数据重新标准化来定制哈希从而聚合数据
第一种方法:把它们都排序,发现“身份证”一样。
核心思想:找到一个“身份证”
如果把两个词的字母按字母表顺序重新排列,得到的结果是相同的,那么它们就是字母异位词。
- "eat" -> 排序后 -> "aet"
- "tea" -> 排序后 -> "aet"
- "ate" -> 排序后 -> "aet"
看,它们排序后的结果都是 "aet"。所以,我们可以把这个排序后的字符串 "aet" 当作这组词共同的“身份证”或“标签”。
算法的思路就是:
- 遍历输入的每一个单词。
- 为每个单词生成一个“身份证”(即排序后的字符串)。
- 把拥有相同“身份证”的单词都放到同一个组里。
public List<List<String>> groupAnagrams(String[] strs) {HashMap<String, List<String>> map = new HashMap<>();for (String key : strs) {final char[] chars = key.toCharArray();Arrays.sort(chars);String sortKey = new String(chars);if(map.containsKey(sortKey)){map.get(sortKey).add(key);}else {List<String> s = new ArrayList<>();s.add(key);map.put(sortKey,s);}}return new ArrayList<>(map.values());}
第二种方法:不排序,而是数一数每个单词里 a-z 字母的个数。
通过分解目标结构的规则来实现分步查找
新的核心思想:用字母计数当“身份证”
1. Word
类:制作和比较“身份证”
这个类是这段代码的精髓。它把一个普通的 String
包装成了一个带有“字母计数身份证”的对象。
2. Solution
类:主分组逻辑
这部分和上一个版本的代码结构几乎一模一样,只是把用作“身份证”的 String
换成了我们自己定义的 Word
对象。
插入一个注意:equals() 和 hashCode() 要一起重写:hashCode()
负责快速缩小范围(定位书架),equals()
负责在小范围内精确查找(逐本核对)。两者必须协同工作,标准必须统一,否则整个系统就会崩溃。
equals() 方法:告诉 Java 如何判断两个 Word 对象是否“相等”
我们认为,只要它们的“身份证”(counts 数组)完全一样,它们就相等
hashCode() 方法:为 Word 对象生成一个“哈希码”(一个整数)
Java 的 HashMap 用这个哈希码来快速定位对象。
规则:如果两个对象 equals() 为 true,那么它们的 hashCode() 必须相同。
我们直接用“身份证”(counts 数组)来生成哈希码,完美符合规则。
public List<List<String>> groupAnagrams(String[] strs) {HashMap<Word, List<String>> map = new HashMap<>();for (String key : strs) {Word word = new Word(key);if(map.containsKey(word)){map.get(word).add(key);}else {List<String> s = new ArrayList<>();s.add(key);map.put(word,s);}}return new ArrayList<>(map.values());}//“身份证”本体:一个长度为26的整数数组,记录了字符串中每个字母出现的次数class Word {int[] counts;Word(String s) {final char[] chars = s.toCharArray();counts = new int[26];for (char c : chars) {int index = c-'a';counts[index]++;}}// --- 以下两个方法是让 Word 对象能作为 HashMap 的 Key 的关键 ---public boolean equals(Object o) {return Arrays.equals(counts, ((Word) o).counts);}public int hashCode() {return Arrays.hashCode(counts);}}
128.最长连续序列
public int longestConsecutive(int[] nums) {HashSet<Integer> set = new HashSet<>();for (int num : nums) {set.add(num);}int res = 0;int count = 0;for (int n : set) {if (!set.contains(n - 1)) {count = 1;int current = n;while (set.contains(current + 1)) {current++;count++;}res = Math.max(res, count);}}return res;}
哈希核心目的
空间换时间为代码提速
要观察数据规模的提示