文章放置于:https://github.com/zgkaii/CS-Notes-Kz,欢迎批评指正!
哈希表使用 O(N) 空间复杂度存储数据,并且以 O(1) 时间复杂度求解问题。
- Java 中的 HashSet 用于存储一个集合,可以查找元素是否在集合中。如果元素有穷,并且范围不大,那么可以用一个布尔数组来存储一个元素是否存在。例如对于只有小写字符的元素,就可以用一个长度为 26 的布尔数组来存储一个字符集合,使得空间复杂度降低为 O(1)。
- Java 中的 HashMap 主要用于映射关系,从而把两个元素联系起来。HashMap 也可以用来对元素进行计数统计,此时键为元素,值为计数。和 HashSet 类似,如果元素有穷并且范围不大,可以用整型数组来进行统计。在对一个内容进行压缩或者其它转换时,利用 HashMap 可以把原始内容和转换后的内容联系起来。
1. 数组中两个数的和为给定值
1. Two Sum (Easy)
可以先对数组进行排序,然后使用双指针方法或者二分查找方法。这样做的时间复杂度为 O(NlogN),空间复杂度为 O(1)。
用 HashMap 存储数组元素和索引的映射,在访问到 nums[i] 时,判断 HashMap 中是否存在 target - nums[i],如果存在说明 target - nums[i] 所在的索引和 i 就是要找的两个数。该方法的时间复杂度为 O(N),空间复杂度为 O(N),使用空间来换取时间。
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (map.containsKey(target - nums[i])) return new int[]{map.get(target - nums[i]), i};
else map.put(nums[i], i);
}
return null;
}
2. 判断数组是否含有重复元素
217. Contains Duplicate (Easy)
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
}
return set.size() < nums.length;
}
3. 最长和谐序列
594. Longest Harmonious Subsequence (Easy)
Input: [1,3,2,2,5,2,3,7]
Output: 5
Explanation: The longest harmonious subsequence is [3,2,2,2,3].
和谐序列中最大数和最小数之差正好为 1,应该注意的是序列的元素不一定是数组的连续元素。
public int findLHS(int[] nums) {
HashMap<Integer, Integer> map = new HashMap<>();
int res = 0;
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
for (int key : map.keySet()) {
if (map.containsKey(key + 1)) res = Math.max(res, map.get(key) + map.get(key + 1));
}
return res;
}
4. 最长连续序列
128. Longest Consecutive Sequence (Hard)
Given [100, 4, 200, 1, 3, 2],
The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4.
要求以 O(N) 的时间复杂度求解。
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int num : nums) set.add(num);
int max = 0;
for (int num : set) {
if (!set.contains(num - 1)) {
int currentNum = num;
int currentStreak = 1;
while (set.contains(currentNum + 1)) {
currentNum += 1;
currentStreak += 1;
}
max = Math.max(max, currentStreak);
}
}
return max;
}
5. TinyURL 的加密与解密
535. Encode and Decode TinyURL(Medium)
当你输入一个URL https://leetcode.com/problems/design-tinyurl 时,它将返回一个简化的URL http://tinyurl.com/4e9iAk.
利用 HashMap 就可以存储精简后的 url 到原始 url 的映射,使得不仅可以显示简化的 url,也可以根据简化的 url 得到原始 url 从而定位到正确的资源)。
Map<Integer, String> map = new HashMap();
String host = "http://tinyurl.com/";
public String encode(String longUrl) {
int key = longUrl.hashCode();
map.put(key, longUrl);
return host+key;
}
public String decode(String shortUrl) {
int key = Integer.parseInt(shortUrl.replace(host,""));
return map.get(key);
}
6. 有效的字母异位词
242. Valid Anagram(Easy)
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。如果输入字符串包含 unicode 字符怎么办?
public boolean isAnagram(String s, String t) {
if (s.length() != t.length()) {
return false;
}
Map<Character, Integer> table = new HashMap<Character, Integer>();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
table.put(ch, table.getOrDefault(ch, 0) + 1);
}
for (int i = 0; i < t.length(); i++) {
char ch = t.charAt(i);
table.put(ch, table.getOrDefault(ch, 0) - 1);
if (table.get(ch) < 0) {
return false;
}
}
return true;
}
7. 字母异位词分组
49. Group Anagrams(Medium)
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
public List<List<String>> groupAnagrams(String[] strs) {
if (strs == null || strs.length == 0) return new ArrayList<>();
Map<String, List<String>> map = new HashMap<>();
for (String s : strs) {
char[] ca = new char[26];
// 统计字符串中每个字符出现的次数,作为哈希表的键。
for (char c : s.toCharArray()) ca[c - 'a']++;
String key = String.valueOf(ca);
if (!map.containsKey(key))
map.put(key, new ArrayList<>());
map.get(key).add(s);
}
return new ArrayList<>(map.values());
}