不行了,今天玩了一天没学习,到了晚上才开始刷题。。看我今晚上能不能把它刷出来!
哈希表理论基础
首先切记!什么时候想到用哈希法,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
遇到哈希问题首先要想到的三种数据结构:数组、set、map。关于哈希表基础可以b站上看一下青大王卓老师的视频(查找模块),当时我的数据结构就是在她那里入门的哈哈哈。
哈希表就类似于数组,下标也是从0开始,可以通过哈希函数将某个数存放在表中的某个空间里。
开始做题!
注:每道题前面的题号都对应力扣上的题
242.有效的字母异位词(简单)
给定两个字符串 s
和 t
,编写一个函数来判断 t
是否是 s
的字母异位词。
注意:若 s
和 t
中每个字符出现的次数都相同,则称 s
和 t
互为字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram" 输出: true
思考:第一次做哈希题,先看了一下卡哥思路,我们用哈希表来存放字符串s中字母的出现频率,之后减去字符串t中字母的出现频率,若最后表中存放的为0,则互为字母异位词。
代码实现:
class Solution {
public boolean isAnagram(String s, String t) {
int []haxi=new int[26];
for (char i:s.toCharArray()) {
haxi[i-'a']++;
}
for (char i:t.toCharArray()){
haxi[i-'a']--;
}
for (int i = 0; i < haxi.length; i++) {
if(haxi[i]!=0)
return false;
}
return true;
}
}
总结:如果用哈希表做法的话,这道题其实也挺简单的。注意遍历字符串中某单个元素的方法。
349.两个数组的交集(简单)
给定两个数组 nums1
和 nums2
,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2] 输出:[2]
思考:这个题借用上题的方法,用哈希问题中的数组法很快就能做出来。当然用set方法比用数组更好,HashSet可以处理哈希法中出现数据量极大的情况,而数组法比较浪费内存,可以参考数组与List的比较。但我之前没接触过set,所以用数组法写了一遍。这里用的是卡尔的代码。
set分类:set、multi-set(这两类的底层实现为红黑树)、unordered-set(底层实现为哈希值)。
unordered-set做映射和取值操作的效率是最高的,所以本题可以用unordered-set来解答。
代码实现:
Hash数组法
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
int[] hash1 = new int[1002];
int[] hash2 = new int[1002];
for(int i : nums1)
hash1[i]++;
for(int i : nums2)
hash2[i]++;
List<Integer> resList = new ArrayList<>();
for(int i = 0; i < 1002; i++)
if(hash1[i] > 0 && hash2[i] > 0)
resList.add(i);
int index = 0;
int res[] = new int[resList.size()];
for(int i : resList)
res[index++] = i;
return res;
}
}
HashSet法
import java.util.HashSet;
import java.util.Set;
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) {
return new int[0];
}
Set<Integer> set1 = new HashSet<>();
Set<Integer> resSet = new HashSet<>();
//遍历数组1
for (int i : nums1) {
set1.add(i);
}
//遍历数组2的过程中判断哈希表中是否存在该元素
for (int i : nums2) {
if (set1.contains(i)) {
resSet.add(i);
}
}
//方法1:将结果集合转为数组
return resSet.stream().mapToInt(x -> x).toArray();
//方法2:另外申请一个数组存放setRes中的元素,最后返回数组
int[] arr = new int[resSet.size()];
int j = 0;
for(int i : resSet){
arr[j++] = i;
}
return arr;
}
}
总结:学会如何将Array和Set集合中存放的数据转化为数组。
202.快乐数(简单)
编写一个算法来判断一个数 n
是不是快乐数。
「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n
是 快乐数 就返回 true
;不是,则返回 false
。
示例 1:
输入:n = 19 输出:true
思考:
这个题直接看示例就能理解了。因为不确定n未来会变成多少数,为了减少内存,首先先考虑Set方法,将求得的数字放进Set中。
那么如何进行查找呢?查找的条件是如果Set中出现了1,那么n就是快乐数。
如果一直没有出现n,那Set中的数字岂不是要一直加下去?当然不是,如果Set中出现了重复的数字,那么n就一定不是快乐数。
接下来照着这个思路写代码吧!
代码实现:
class Solution {
public int Nextnum(int n){
int getnext=0;
while(n!=0){
int x=(n%10)*(n%10);
getnext+=x;
n/=10;
}
return getnext;
}
public boolean isHappy(int n) {
Set set=new HashSet<>();
while (n!=1){
if(set.contains(n))
return false;
set.add(n); //把下一个数存储到set中
n=Nextnum(n);
}
return true;
}
}
总结:其实这道题我刚开始做的时候是把思路想错了,我想的竟然是把每一位数存在Set里。。。总之,还是得学会思维发散啊。熟练掌握哈希法中数组法与set的灵活运用。
1.两数之和
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9 输出:[0,1] 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
思考:其实这道题吧,首先我想到的是用暴力法解决,但我们要学会优化,所以这道题最好还是用哈希法来解答。我是第一次接触map,所以直接去看的卡尔视频讲解,放个链接在这。梦开始的地方,Leetcode:1.两数之和,学透哈希表,map使用有技巧!_哔哩哔哩_bilibili
代码实现:
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;
总结:好好看视频,可以知道map中每次存放的是key和value。当然我们要分配好什么是key,什么是value。例如本题中打破了以往的惯性思维,将数组元素存放到key,而将下标值存放到value里。如果set解决的是找出数组元素,那么map解决的就是不仅要找出数组元素,还要找出对应的元素下标值。这里的代码也需要着重理解。