目录
Day5的算法学习到哈希表相关,现在先简单复习哈希表的相关内容:
1.可以将哈希表理解为一个数组,存放的是一些由hashCode转化成索引存放在哈希表中的内容。
(1)哈希函数:要将例如要查找某学校一个学生姓名是否在内,那么只需要将全校学生姓名映射在此哈希表中,然后进行查找;那么首先是如何映射?通过hashCode将各名字转化为相应索引,hashCode能将任何类型进行这样转化,要注意转化后的索引还需要进行一个取余操作避免超出哈希表长,转化成索引后再放入到哈希表中;
(2)哈希碰撞:是指两个元素被hashCode转化后的索引是一样的,也就会在同一个位置。
(3)哈希表分类:数组、set集合、map
-如何选择使用?
-一般情况下,如果数值较少,特别散的、跨度大的使用数组就会很浪费所以考虑其他;若数据量较小且跨度不大的,可选择使用数组。
2.注意:要判断一个元素是否在集合里或者是否存在,首先都应该考虑到使用哈希表。
242.有效的字母异位
题目链接:https://leetcode.cn/problems/valid-anagram/
首先了解异位字母的定义:两个单词长度相同,包含的字母全都相同,只是字母位置不同,构成不同的词。
代码随想录学习后:题目说明这两个词的构成字母都是小写;字母总共就26个,所以就是在两个单词中涉及到的字母与出现次数是否相同进行判断;
首先设置一个长度位26的int数组,这里说明一下:数组从0开始的索引,'a'对应的是0位置,'z'对应是索引为25位置;然后遍历第一个词,利用charAt将字母转化减去‘a’,获得在数组的对应位置并且++,++是对这个字母出现的频率进行统计,那么数组对应字母的位置就是它出现的频率数;接着遍历第二个词,按照以上的方法找到在数组对应位置,但是在统计频数这里变成--,若对应位置字母每出现一次就减1;
以上统计出现频率若同一字母在两个词中出现次数一样那么字母对应位置的值会进行加减运算最后为0;所以最后遍历数组,若全为1说明是满足的;当出现一个不为0那表示两个词出现不一样的字母或者同一字母出现的次数不同,所以不为异位词。
*用来统计小写字母出现的频率可以考虑使用以上方法。
class Solution {
public boolean isAnagram(String s, String t) {
int [] result=new int[26];
for(int i=0;i<s.length();i++){
result[s.charAt(i)-'a']++;
}
for(int j=0;j<t.length();j++){
result[t.charAt(j)-'a']--;
}
for(int i=0;i<result.length;i++){
if(result[i]!=0){
return false;
}
}
return true;
}
}
349.两个数组的交集
题目链接:https://leetcode.cn/problems/intersection-of-two-arrays/submissions/
代码随想录学习后:
此题是二刷,之前第一次也是直接按照题解思路来理解的。
要求两个数组的交集,此题的题目里面说明:最后输出的交集里面的数都是唯一且无序的;关键词:不重复(唯一)、无序,是set集合的特征;所以设计两个set集合,一个集合对应一个数组,首先遍历第一个数组将得到数据加入set集合中;接着遍历第二个数组,在里面需要判断遍历到的第二个数组内的数,在第一个集合里是否包含;若包含,就将此值加入第二个set集合中;最后将得到的第二个set集合可直接转化为数组返回;或者遍历第二个集合将值放入另创的数组中再返回。
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> set1=new HashSet<Integer>();
Set<Integer> set2=new HashSet<Integer>();
int n=0;
for(int i=0;i<nums1.length;i++){
set1.add(nums1[i]);
}
for(int j=0;j<nums2.length;j++){
if(set1.contains(nums2[j])){
set2.add(nums2[j]);
}
}
int [] result=new int [set2.size()];
for(int j:set2){
result[n++]=j;
}
return result;
}
}
202.快乐数
题目链接:https://leetcode.cn/problems/happy-number/
快乐数 定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。
第一想法:看到题目,理解是:给出数n,对这个数的个位和十位甚至百位上的数平方后相加,然后将得到的值也继续进行此操作,若最后得到的和为1时,也就是快乐数;我关于如何去执行这个过程是完全没有思路,但是我知道的是需要获取到n的个位十位数这些的。
代码随想录加题解学习后:首先看定义中所说可能出现的情况:(1)最后和为1即为快乐数;(2)可能出现无限循环情况;那么我们就要注意从第二点入手进行判断;以下两张图是从LeetCode题解里面截出来的,看图进行对这两种情况的理解:
当n为116时,按照快乐数的规律进行计算,最后会出现值重复的过程也就是出现无限循环,当出现这种情况那次数不为快乐数,返回false;
当n为7这种情况时计算到最后为1,那么说明这个数为快乐数;
接着就是整个的思路:
(一).首先先进行对于快乐数定义的规律进行计算,对n进行判断,若大于0时,对n取余首先获得个位数平方,然后对n/10判断n是否大于0,再进行取余获得十位数,最后获取到和,以此类推。
(二).根据(一)获得每个数结果平方和后,就要对这个“和”进行判断,如果这个和为1那么就直接返回true;如果和不为1时,要判断所求的和中是否出现一样的数,那么这个就要用到set集合,若这个和,set里面不包含,那么就将这个和加入set集合中,之后继续调用(一)中的方法继续求下一个和;如果是set里面已经包含了这个和,那说明接下来再继续算会进入循环了,即是说明不符合快乐数的定义,返回false。
这道题很重要的是对上图出现情况的理解,这样才能理解set集合出现的作用。
class Solution {
private int judgeSum(int n){
int sum=0;
int temp=0;
while(n>0){
temp=n%10;
sum+=temp*temp;
n=n/10;
}
return sum;
}
public boolean isHappy(int n) {
Set<Integer> set=new HashSet<Integer>();
while(n!=1&&!set.contains(n)){
set.add(n);
n=judgeSum(n);
}
if(n==1){
return true;
}
return false;
}
}
1.两数之和
题目链接:https://leetcode.cn/problems/two-sum/submissions/
第一想法:利用暴力解法,设置两个for循环,然后一个一个值相加进行尝试,但是这样的效率低。
代码随想录学习后:主要思路是:首先设置Map集合,这个集合的key是数组里的数值,而value是对应索引值;再设置一个for循环遍历数组,然后用目标值减去遍历到索引对应的值,之后对此值进行判断看是否包含在Map集合内;若包含就获取到Map中这个值(key)对应索引(value)还有循环中遍历的索引放入新建数组中;若不包含,就将此值和此值的索引加入Map集合中。
注意:对于此题我开始是使用“双指针法”的,但是在这题使用是错误的;因为使用双指针法的前提条件是数组已经排好序;那么这题返回的结果是值对应的索引,那如果对这个数组进行排序就会改变索引值导致不符合要求。
问题:那这题需要如何改变要求才能使用“双指针法”?
回答:若此题要求返回的结果是数组里面满足要求的数值,那么可以使用“双指针法”。
暴力解法:
class Solution {
public int[] twoSum(int[] nums, int target) {
//暴力解法,for循环嵌套for循环得出数相加
int sum=0;
int [] result=new int [2];
for(int i=0;i<nums.length;i++){
for(int j=i+1;j<nums.length;j++){
sum=nums[i]+nums[j];
if(sum==target){
result[0]=i;
result[1]=j;
}
}
}
return result;
}
}
哈希表解法:
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> map=new HashMap<Integer,Integer>();
int []result=new int[2];
int temp;
for(int i=0;i<nums.length;i++){
temp=target-nums[i];
if(map.containsKey(temp)){
result[0]=i;
result[1]=map.get(temp);
return result;
}
map.put(nums[i],i);
}
return new int[0];
}
}
总结:
今天发现最大的问题是:对于条件判断中if和while的使用情况不够清晰,或者说针对不一样的条件无法完全用准,导致不能全部通过测试,后续需要再对这两个条件判断加深理解还有实际运用。