写在前面:
哈希表理论知识:代码随想录 (programmercarl.com)
根据一个散列函数能够直接对应读取元素的方法。
更官方一点:哈希表是根据关键码的值而直接进行访问的数据结构。
举个例子,数组其实就是一个哈希表,比如array[0]就代表数组array中的第0号元素,可以根据键值直接定位到元素位置。
当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法
一、242. 有效的字母异同
学习(视频)文章链接:' 代码随想录 (programmercarl.com)'
力扣链接:Loading Question... - 力扣(LeetCode)
题目内容:
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
示例:
输入: s = "anagram", t = "nagaram" 输出: true输入: s = "rat", t = "car" 输出: false
1.第一想法:
初看的时候,名字有点唬人,但其实仔细想想就是统计待比较单词中各字母的频数,然后判断是否符合定义,用两个数组即可完成,每个数组大小为26,下标可以由ASCII码的差值来计算即可!
2.随想录后的思考与收获:
思路有点类似,但减少了空间,可以使用同一个,扫描第一个单词时正向统计,扫描第二个单词时负向减少,可以做到减少空间的情况下并不降低效率。数组如果有的元素不为零0,说明字符串s和t一定是谁多了字符或者谁少了字符,return false。
3.自己实现过程中的困难:
这个还好,比较常规
4.代码:
直接模拟就OK
bool isAnagram(char * s, char * t){
int res[26] = {0};
int len1 = strlen(s);
int len2 = strlen(t);
for(int i = 0; i < len1; i++)
{
res[s[i] - 'a']++;
}
for(int j = 0; j < len2; j++)
{
res[t[j] - 'a']--;
}
for(int k = 0; k < 26; k++)
{
if(res[k] != 0)
return false;
}
return true;
}
5.结果:
6.反思:
看看别人的:
Python耍无赖调用库
二、349. 两个数组的交集
学习链接:代码随想录 (programmercarl.com)
力扣链接:349. 两个数组的交集 - 力扣(LeetCode)
题目内容:
给定两个数组 nums1
和 nums2
,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
示例:
1.第一想法:
直接想到的就是先排序,然后依次用两个指针,指向内容相同者复制进新数组,否则直接返回新数组。(但这样做与哈希表主题不符合)
2.录后:
两种情况:
2.1不限制元素大小范围的情况下 :使用set数据结构;
2.2限制元素大小范围的情况下,可以使用上一道题目中的思路,用数组做哈希映射。
3.代码:
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) {//循环变量i,整数,无比较对象,把自己全部加进去,使用add()方法
set1.add(i);
}
//遍历数组2的过程中判断哈希表中是否存在该元素
for (int i : nums2) {
if (set1.contains(i)) {
resSet.add(i);
}
}
return resSet.stream().mapToInt(x -> x).toArray();//这句没看懂
}
4.思考:
C++和Java到底使用哪个来写,是自己没确定的,但是思路一定还是要多练习,说实话,这个C++的代码没看懂,我这篇都没看懂呀!!!
三、202. 快乐数
学习链接:代码随想录 (programmercarl.com)
题目内容:
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
示例:
输入:19
输出:true
解释:
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1
1.第一思路:
乍一看,觉得它是模拟题,首先外围要写一个分割数字各个数位的函数,主逻辑为一个循环,每次首先判断该数字是否出现过,仅当未出现过,进入循环;设置临时变量用于存放每一个数位数字的平方和,单次循环的最后判断是否为1,若是,则直接返回True。
其中的数字是否出现过,需要哈希函数来解决,比如建一个数组用于记录数字是否出现过;或者使用哈希序列,python中可以直接使用in基本算法来判断,已经计算过的和可以在循环开始时存放在集合中。
最后直接return False
2.录后:
思路类似,着重点出难点和重点,如何分离各个数位,在哪里选择哈希法。
3.代码:
void select(int argc,int &file){//file代表当前和的各个数位上的数字
int temp=argc %10;
while(temp!=0){
file[i++]=temp;
temp=temp/10;
}
}
bool Judge(int a){//s代表曾经出现过的和值
for(int i=0;i<s.length();i++)
{
if(a==s[i])return true;
}
return false;
}
bool main(int num){
int file[MAXINT];
int s[MAXINT];
int addin=num,x=0;
while(!Judge(addin)){
s[x++]=addin;
select(addin,file);//计算各数位的数字
for(int i=0;i<s.length();i++)
{
addin+=file[i]*file[i];
}
if(addin==0)
return true;
}
return false;
}
4.思考:
没运行,但思路是这样,码的有点慢,还是不够熟练。看看别人的:
Java版:
class Solution {
public boolean isHappy(int n) {
Set<Integer> record = new HashSet<>();
while (n != 1 && !record.contains(n)) {
record.add(n);
n = getNextNumber(n);
}
return n == 1;
}
private int getNextNumber(int n) {
int res = 0;
while (n > 0) {
int temp = n % 10;
res += temp * temp;
n = n / 10;
}
return res;
}
}
四、两数之和
学习链接:代码随想录 (programmercarl.com)
题目:
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
1.第一思路
二重循环,大循环用于遍历数组,小循环用于寻找后续序列中是否含有target-nums[i]的元素存在,且不允许和nums[i]相同,随时记录两个下标
2.录后
判断序列中是否含有某元素,就是要想到哈希法。
使用map数据结构,map中的存储结构为 {key:数据元素,value:数组元素对应的下标}。
在遍历数组的时候,只需要向map去查询是否有和目前遍历元素匹配的数值,如果有,就找到的匹配对,如果没有,就把目前遍历的元素放进map中,因为map存放的就是我们访问过的元素。
3.代码
C++版本:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
std::unordered_map <int,int> map;
for(int i = 0; i < nums.size(); i++) {
// 遍历当前元素,并在map中寻找是否有匹配的key
auto iter = map.find(target - nums[i]);
if(iter != map.end()) {
return {iter->second, i};
}
// 如果没找到匹配对,就把访问过的元素和下标加入到map中
map.insert(pair<int, int>(nums[i], i));
}
return {};
}
};
Java版:
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;
}
写在最后:最近事情很乱,自己也很颓,导致断更数日,罪过罪过,以后要加油呀!!要由紧迫感,把每一次学习的时候都带入即将失业的情景,焉能学不好?有点势力了,但现实如此,加油,乐超!!