● 数组就是一张哈希表,通过下标可以直接访问数组中的元素
● 哈希表用来判断一个元素是否出现在集合里
● 学生名字是否在学校里,索引直接查询,O(1)
● 本质上是牺牲空间换取时间
● 把学生姓名转化为数值,可能大于哈希表大小,再进行取模运算,保证学生姓名落在哈希表上
● 但学生数量可能大于哈希表大小,产生哈希碰撞
● 多个元素映射到了同一个位置
● 发生冲突的元素存储在链表中
● 要选择适当的哈希表大小,数组空值太多浪费内存,链表太长查找浪费时间
● 保证哈希表大小大于元素数量,依靠哈希表中的空位解决问题
● 下一个位置存放多余元素的信息
● 数组
● set
● map
● 力扣题目链接
● 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
● 使用哈希表,时间复杂度O(n) 空间复杂度O(1)
class Solution {
public boolean isAnagram(String s, String t) {
int[] hash = new int[26]; // 使用数组即可,长度不超过26
for (char c : s.toCharArray()) {
hash[c - 'a']++; // 遍历s,把对应位置元素++
}
for (char c : t.toCharArray()) {
hash[c - 'a']--; // 遍历t,把对应位置元素--
if (hash[c - 'a'] < 0) return false; // t比s多了某个字母,返回false
}
for (int num : hash) {
if (num != 0) return false; // 结束再遍历一遍,如果s比t多了某个字母,返回false
}
return true;
}
}
// 使用hashMap也可以,但慢一些
class Solution {
public boolean isAnagram(String s, String t) {
Map<Integer, Integer> hash = new HashMap();
for (char c : s.toCharArray()) {
hash.put(c - 'a', hash.getOrDefault(c - 'a', 0) + 1); // 把k对应的v + 1
}
for (char c : t.toCharArray()) {
if (!hash.containsKey(c - 'a')) return false; // 如果没有对应的k,返回false
hash.put(c - 'a', hash.get(c - 'a') - 1); // 把k对应的v - 1
if (hash.get(c - 'a') == 0) hash.remove(c - 'a'); // 如果v减为0,删掉k
}
return hash.isEmpty(); // 如果map为空,说明符合要求
}
}
● 力扣题目链接
● 题意:给定两个数组,编写一个函数来计算它们的交集。
● 使用set接收一个集合并去重,然后遍历另外的集合,求交集
● 最好stram流处理
● 注:set中,如果已经有元素1,再add元素1,会返回false,对集合没有影响,也不会报错
● 时间复杂度O(m + n) 空间复杂度O(n)
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> hash = new HashSet();
Set<Integer> res = new HashSet();
for (int num : nums1) { // 遍历nums1并去重
hash.add(num);
}
for (int num : nums2) { // 遍历nums2,如果元素是交集中的,加入res
if (hash.contains(num)) res.add(num);
}
return res.stream().mapToInt(x -> x).toArray(); // 转为数组
}
}
// 使用数组也可以
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
int[] hash = new int[1005];
Set<Integer> res = new HashSet();
for (int num : nums1) {
hash[num] = 1;
}
for (int num : nums2) {
if (hash[num] == 1) res.add(num);
}
return res.stream().mapToInt(x -> x).toArray();
}
}
● 力扣题目链接
● 编写一个算法来判断一个数 n 是不是快乐数。
● 「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
● 如果 n 是快乐数就返回 True ;不是,则返回 False 。
● 不断循环,拿到下一个数字,看是否之前出现过(在set中),出现过返回false,如果发现结果为1,结束循环,返回true
● 时间复杂度O(logn) 空间复杂度O(logn)
class Solution {
public boolean isHappy(int n) {
Set<Integer> hash = new HashSet();
while (n != 1) {
if (hash.contains(n)) return false; // 一旦发现出现过n,不是快乐数
hash.add(n); // 添加元素
n = getNextNum(n); // 拿到下一个数字
}
return true; // n = 1,退出循环,是快乐数
}
private int getNextNum(int n) { // 返回n各位数字平方和
int res = 0;
while (n != 0) { // 注意这里的循环考虑
int temp = n % 10;
res += temp * temp;
n = n / 10;
}
return res;
}
}
● 力扣题目链接
● 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
● 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
● 使用HashMap即可,k是数组中的元素,v是元素位置
● 遍历数组,如果map中有tar - nums[i] 这个k,找到了,返回新数组即可
● 如果没有,别忘了put进去
● 时间复杂度O(n) 空间复杂度O(n)
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> hash = new HashMap();
for (int i = 0; i < nums.length; i++) {
if (hash.containsKey(target - nums[i])) {
return new int[]{hash.get(target - nums[i]), i};
}
hash.put(nums[i], i);
}
return null;
}
}