哈希法
组成:包括数组、Set集合、Map
选择:我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
但是哈希法也是牺牲了空间换取了时间
一、字母异位分组
1. 就是比较某个字母出现的次数一不一致,但是因为英文字母并不能直接当数组的索引,利用char和英文字母相邻的性质,转换成索引。
2. 统计次数时,并没有传统的比较两个字母出现的次数一不一致,而是直接通过在同一个数组相加减的方式,进行标识,从而减少了新建数组的麻烦。
class Solution {
public boolean isAnagram(String s, String t) {
// 用来记录26个字母的次数
int [] record = new int[26];
for(int i =0 ; i<s.length();i++){
// todo 这段代码是关键
record[s.charAt(i) - 'a']++; // 利用char类型和英文小写字母的特点,巧妙的用数组存储了
}
for(int j = 0;j<t.length();j++){
record[t.charAt(j) - 'a']--;
}
for(int i : record){
if(i != 0){
return false;
}
}
return true;
}
}
二、两个数组的交集
这道题和上道题很像,也要找相同的数,但是这道题需要求相同的数,因此需要转换列表用来存储数据,再转换成数组
public class Intersection {
public int[] intersection(int[] nums1, int[] nums2) {
int [] hash1 = new int [1001];
int [] hash2 = new int [1001];
for(int i = 0; i< nums1.length;i++){
hash1[nums1[i]] = 1;
}
int count = 0;
for(int i = 0;i<nums2.length;i++){
hash2[nums2[i]] = 1;
}
// 用列表的原因在于,不知道到底有多少个元素
List<Integer> list = new ArrayList<>();
for(int i = 0;i<1001;i++){
if(hash1[i] >0 && hash2[i] > 0){
list.add(i);
}
}
// 列表转换成数组
int[] arr = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
arr[i] = list.get(i);
}
return arr;
}
}
三、快乐数
关键点:标准n为1,只要一出现以前的数,则排除掉
public class HappyData {
public boolean isHappy(int n) {
Set<Integer> set = new HashSet<>(); // 去重,防止出现无限循环
while(n!=1 && !set.contains(n)){
set.add(n);
n = sumOfSquares(n);
}
return n == 1;
}
// 计算一个数的每个数字的平方和
public static int sumOfSquares(int num) {
int sum = 0;
while (num != 0) {
int digit = num % 10;
sum += digit * digit;
num /= 10;
}
return sum;
}
}
四、两数之和
这里选择用Map,因为需要数据和返回索引
public class TwoSum {
public int[] twoSum(int[] nums, int target) {
int[] res = new int[2];
if(nums == null || nums.length == 0){
return res;
}
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < nums.length; i++){
int temp = target - nums[i]; // 遍历当前元素,并在map中寻找是否有匹配的key
if(map.containsKey(temp)){
res[1] = i;
res[0] = map.get(temp);
break;
}
map.put(nums[i], i); // 如果没找到匹配对,就把访问过的元素和下标加入到map中
}
return res;
}