遇到需要判断一个元素是否出现过的场景也应该第一时间想到哈希法!
242.有效的字母异位词
题目链接:242. 有效的字母异位词 - 力扣(LeetCode)
文章/视频链接:代码随想录 (programmercarl.com)
看完代码随想录的想法
定义长度为26的数组,将a-z映射到下标为0-25的位置,扫面字符串s时,相应字母+1,扫描字符串时相应字母-1,最后再遍历该数组,若不全为0,则返回false,否则返回true。
用哈希法时一般选择这三种数据结构:数组,Set,Map
class Solution {
public boolean isAnagram(String s, String t) {
int[] words = new int[26];
for(int i = 0;i<s.length();i++){
words[s.charAt(i)-'a']++;//a-z映射下标为0-25,如果存在相应字母+1
}
for(int i = 0;i<t.length();i++){
words[t.charAt(i)-'a']--;
}
for (int i = 0; i < 26; i++) {
if(words[i]!=0)
return false; //一旦有某个字母数量不为0,则说明不是异位词
}
return true;
}
}
349.两个数组的交集
题目链接:. - 力扣(LeetCode)
文章/视频链接:代码随想录 (programmercarl.com)
第一想法
首先就是输出唯一,所以先将两个数组去重,装入set容器中。接着设置长度为1001的数组,因为案例中可能会包含1000这个元素。接着仿照第1题,键是元素,值是在两个set中出现的次数之和。映射完后遍历数组,值是0,1,2,其中值为2的为公共元素,1为只出现其中一个,0表示都没有出现。将值为2的元素添加到arrayList之中,但由于泛型是包装类,最后还得将integer[]转换为int[]返回。
由于代码过于丑陋,就暂时不放上来了。
最后形式转换代码如下:
ArrayList<Integer> arrayList = new ArrayList<Integer>();
for (int i = 0; i < 1000; i++) {
if (result[i] == 2)
arrayList.add(i);
}
Integer[] returnResult = new Integer[arrayList.size()];//arrayList和array同样大小
arrayList.toArray(returnResult); //先将<Integer>arrayList转换为Integer[] array数组
return Arrays.stream(returnResult).mapToInt(Integer::intValue).toArray();//再将Integer[] array转换为 int[] array;
【Java】int[] 数组 和 Integer数组的转换 - SHINJI_KUN - 博客园 (cnblogs.com)
看完代码随想录想法
但是要注意,使用数组来做哈希的题目,是因为题目都限制了数值的大小。
而这道题目没有限制数值的大小,就无法使用数组来做哈希表了。
而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费
代码
class Solution1 {
public int[] intersection(int[] nums1, int[] nums2) {
HashSet<Integer> set = new HashSet<Integer>();
for (int i = 0; i < nums1.length; i++) {
set.add(nums1[i]);
}
HashSet<Integer> resultSet = new HashSet<Integer>();
for (int i = 0; i < nums2.length; i++) {
if (set.contains(nums2[i])) {//如果2也有此元素,那么就添加到最终结果集中
resultSet.add(nums2[i]);
}
}
return resultSet.stream().mapToInt(Integer::intValue).toArray();
}
}
202.快乐数
文章/视频链接:代码随想录 (programmercarl.com)
第一想法:
难点在于对于每个数位上取值操作要熟悉吧。不知道循环的终止条件
看完随想录想法:
题目的无限循环等价位sum会重复出现。那么快速判断一个元素是否出现在集合里时,就可以考虑哈希法,并且数字没有限制且较为稀疏,选择数据结构set
class Solution {
public boolean isHappy(int n) {
HashSet set = new HashSet();
while (n!=1&&!set.contains(n)){//继续循环的条件:数字n不为1,或者以前没有出想过。一旦为1,意味着正常结束,一旦出想过,则会出现死循环。
set.add(n);//未出现过则先加入set集合中
n = getSum(n);
}
return n==1;//n为1则正常结束,为快乐数;n不为1,则说明是将要进入死循环而导致的循环结束,不是快乐数
}
public int getSum(int n){
int result = 0;
while (n > 0) { //最后个位数/10,一定结果为0,循环结束条件。
int temp = n % 10; //先取末位数
result += temp*temp; //取数后平方相加
n = n / 10; //更新
}
return result;
}
}
1.两数之和
文章/视频链接:代码随想录 (programmercarl.com)
第一想法
第一想法就是这个题我做过,印象里还记得评论。
有人相爱,有人夜里开车看海,有人leetcode第一题都做不出来。
用Map解决的话,键为每个元素,值为目标值-此元素。判断值存不存在此数,接着返回下标即可。没做出来。
看完代码随想录想法
本题需要一个集合存放我们遍历过的元素,然后再遍历数组的时候询问这个元素,某元素是否出现在这个集合中。所以考虑哈希法。
本题不仅要考虑到元素有没有遍历过,还要知道所对应的下标。用map正合适,key存放元素,value存放下标。数组结构也是下标和元素的映射关系,但是我们是通过元素找下标,选用map,若从下标找元素,则用数组。
在遍历数组的时候,只需要向map查询是否有何目前遍历元素匹配的数值,如果有,就找到的匹配对,若没有,则将遍历元素放入map中,map就是我们访问的元素。
代码
class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> map = new HashMap<>();//map是用来存放已访问的元素信息
int[] result = new int[2];
for (int i = 0; i < nums.length; i++) {
if(map.containsKey(target-nums[i])){//若有匹配的键值对
result[0] = i;
result[1] = map.get(target-nums[i]);
return result;
}else{
//若没有匹配,则放入map集合中
map.put(nums[i],i);
}
}
return null;
}
}