Leetcode 242. 有效的字母异位词
思路
暴力解法很容易想到,用两层for循环,同时记录重复出现的字母,时间复杂度为(n^2)。当要快速判断一个元素是否出现集合里的时候,可以考虑哈希法。
由于本题出现的所有元素都只是小写字母a~z,它们在ASCII码表上的值是连续的。由此可以定义一个数组hash[26],数组其实就是一个简单哈希表,来存储字符串中每个字母出现的次数。
当遍历字符串s时,只需要将哈希表中 s[i] - ‘a’ 所在的元素+1 操作,并不需要记住每个字母都ASCII值,只要求出一个相对于’a’的数值就可以了。例如当s[i]='a’时,此时hash[0]++;当s[i]='c’时,此时hash[2]++。
当遍历字符串t时,由于题目只需要判断两字符中各字母出现的次数是否相等,可以将字符串t中的各个字母映射哈希表索引上的数值-1。
如果两者为有效的字母异位词,则哈希数组中每个元素为0;否则,就不是有效的字母异位词。
代码(Java)
写法1:哈希法
时间复杂度: O(n)
空间复杂度: O(1)
class Solution {
public boolean isAnagram(String s, String t) {
int hash[]=new int[26];//0~25分别存放26个字母出现的顺序
char[] s_arr=s.toCharArray();
char[] t_arr=t.toCharArray();
for (int i=0;i<s_arr.length;i++){
hash[s_arr[i]-'a']++;//根据ASCII码,遍历s的每个字母存入hash数组中
}
for (int i=0;i<t_arr.length;i++){
hash[t_arr[i]-'a']--;//根据根据ASCII码,当t中的字母出现与s中相同字母时,数组中代表该字母的元素减1
}
for (int i=0;i<hash.length;i++){
if (hash[i]!=0){//若符合字母异位词,则hash数组中的每个元素为0
return false;
}
}
return true;
}
}
代码随想录链接
下面是代码随想录的文章链接与视频链接,帮助大家更好地理解这道题。
文章
视频
Leetcode 349. 两个数组的交集
思路
这道题又是判断数据结构中某个元素是否出现,很容易用哈希表来解决。由于题目中强调输出结果中的每个元素一定是唯一的,也就是说输出的结果是去重的, 同时可以不考虑输出结果的顺序。
因为题目限制了元素的大小,所以使用数组来做这道题。如果没有限制元素的大小,就无法使用数组来做哈希表了,则用另一种结构体HashSet。另外,如果元素个数比较少,但分散、跨度非常大,使用数组就造成空间的极大浪费。
然而,HashSet是一个不允许有重复元素的集合,但由于HashSet 基于 HashMap 来实现的,所以HashSet把数值映射到Key上都要做hash计算的,所以速度比数组慢。
代码(Java)
写法1:Hash数组
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
int hash[]=new int[1003];
Set<Integer> result=new HashSet<>();//存放结果,用set去重
for (int i=0;i<nums1.length;i++){
hash[nums1[i]]=1;//
}
for (int i=0;i<nums2.length;i++){
if (hash[nums2[i]]==1){
result.add(nums2[i]);
}
}
return result.stream().mapToInt(x->x).toArray();
}
}
写法2:HashSet
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
if(nums1.length==0||nums2.length==0||nums1==null||nums2==null){
return new int[0];
}
Set<Integer> set1=new HashSet<>();
Set<Integer> result=new HashSet<>();
//将nums1的元素存入set1
for (int i = 0; i < nums1.length; i++) {
set1.add(nums1[i]);
}
//筛选nums2中与nums1相同的元素,存入result
for (int i = 0; i < nums2.length; i++) {
if (set1.contains(nums2[i]))
result.add(nums2[i]);
}
//将set转化为数组
return result.stream().mapToInt(x->x).toArray();
}
}
代码随想录链接
下面是代码随想录的文章链接与视频链接,帮助大家更好地理解这道题。
文章
视频
Leetcode 202. 快乐数
思路
前面我们提到,当需要快速判断一个元素是否出现集合里时,要考虑哈希法。而这道题目使用哈希法,因为在对n每个位置的数字求平方和sum的过程中,sum会重复出现,则需要哈希表来判断sum是否重复出现,如果重复了就return false,否则一直找到平方和为1。判断sum是否重复出现就可以使用HashSet。
难点
- 如何获取n每个位置的数字?
这里可以拿具体的数字来模拟。假设有n=321,拿到末尾数1很容易,直接对n%10;接着要拿到数字2时,我们可以先让1消失,则n/=10此时n=32,再进行取模操作。
代码(Java)
class Solution {
public boolean isHappy(int n) {
Set<Integer> appearedNum = new HashSet<>();
while(n!=1 && !appearedNum.contains(n)){
appearedNum.add(n);
n=getSum(n);
}
return n==1?true:false;
}
private int getSum(int n){//拿到每个位置的数字的平方和
int sum=0;
while (n>0){
int temp = n%10;
sum+=temp*temp;
n/=10;
}
return sum;
}
}
代码随想录链接
下面是代码随想录的文章链接,帮助大家更好地理解这道题。
文章
Leetcode 1. 两数之和
思路
这道题的暴力解法很容易想到,也是Leetcode刷题“梦开始的地方”,两层for循环嵌套,此时的时间复杂度为O(n^2)。
前面我们提到,当需要快速判断一个元素是否出现集合里时,要考虑哈希法。本题,我们需要一个集合来存放遍历过的元素,当遍历数组的元素时,还需要访问该集合。例如我们遍历到了一个数x,此时需要访问遍历过的元素集合,找到是否存在数值为(target-x)的元素。
不仅要知道元素有没有遍历过,还需要知道该元素对应的下标,所以这里需要使用 <key,value>结构 来存放,key存放元素,value存放下标,所以使用 HashMap。
难点
- 为什么用key存放元素,value存放下标?
因为要判断的是某元素是否出现过,而HashMap就是能快速查找key是否在该map中出现过,所以key存放元素,同时题目还需要返回元素下标,所以value存放下标。
代码(Java)
写法1:暴力解法
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] res = new int[2];
for(int i=0;i<nums.length;i++){
for(int j=i+1;j<nums.length;j++){
if(nums[i]+nums[j]==target){
res[0]=i;
res[1]=j;
break;
}
}
}
return res;
}
}
写法2:HashMap
class Solution {
public int[] twoSum(int[] nums, int target) {
if (nums.length==0 || nums==null){
return new int[0];
}
Map<Integer,Integer> map=new HashMap<>();//存放已遍历过的元素
int[] ret=new int[2];//结果数组
for (int i=0;i<nums.length;i++){
int temp = target-nums[i];//需要访问Map中是否有该元素
if (map.containsKey(temp)){//在Map找到了该元素
ret[0]=map.get(temp);//拿到Map中元素的下标存入结果数组
ret[1]=i;
break;
}
map.put(nums[i],i);//没找到,则把访问到的元素和下标加入到Map中
}
return ret;
}
}
代码随想录链接
下面是代码随想录的文章链接与视频链接,帮助大家更好地理解这道题。
文章
视频
总结
今天学习了哈希表,当需要快速判断一个元素是否出现集合里时,要考虑哈希法。而哈希结构有三种,分别是数组、set、map。
在上面的题目中,可以感受到三者的应用场景有所不同。采用哪一种还需要具体问题具体分析。