242.有效的字母异位词
题目链接/文章讲解/视频讲解: 代码随想录
给定两个字符串
s
和t
,编写一个函数来判断t
是否是s
的字母异位词。注意:若
s
和t
中每个字符出现的次数都相同,则称s
和t
互为字母异位词。
分析及思路
判断是否相等,首先要进行一个数组的存储,直到它出现的次数,在与第二个字符串进行判断。我们用一个数组存储所有的字母,即26个英文字母,a对应hash[0],b对应hash[1]一次存储26个英文字母。把第一个字符串存进去,出现一个字母对应的数组就增加1,到另一个数组就执行减法。最后再从头开始判断数组所有值是否全为0,有一个不为零则就代表不是字母异位词。
代码及注释
int hash[26];
bool isAnagram(char* s, char* t) {
// 定义一个整型变量i并初始化为0
int i = 0;
// 获取字符串s和t的长度
int S_length = strlen(s);
int T_length = strlen(t);
// 使用memset函数将hash数组中的所有元素初始化为0
memset(hash, 0, sizeof(hash));
// 遍历字符串s,将每个字符出现的次数存入hash数组中对应的位置
for(i=0;i<S_length;i++)
{
hash[s[i]-'a']++;
}
// 遍历字符串t,将每个字符出现的次数从hash数组中对应的位置减去
for(i=0;i<T_length;i++)
{
hash[t[i]-'a']--;
}
// 再次遍历hash数组,如果有任何元素不为0,则返回false,表示不是anagram
for(i=0;i<26;i++)
{
if(hash[i]!=0)
return false;
}
// 如果遍历完hash数组所有元素都为0,则返回true,表示是anagram
return true;
}
349. 两个数组的交集
题目链接/文章讲解/视频讲解:代码随想录
给定两个数组
nums1
和nums2
,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
分析及思路
和上面的题目一样,我们存储第一个数组的数值到哈希表中,在用第二个表进行查询。
代码及注释
int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize) {
// 创建一个大小为1001的哈希表数组,并初始化为0
int Hash[1001] = {0};
// 计算两个数组的较小长度
int lessSize = nums1Size < nums2Size ? nums1Size : nums2Size;
// 创建一个动态分配内存的整型数组,用于存储交集元素
int * result = (int *) calloc(lessSize, sizeof(int));
// 交集元素的计数器
int count = 0;
// 遍历第一个数组,将数组元素作为哈希表的索引,并将对应位置的值设为1
for(int i=0;i<nums1Size;i++)
{
Hash[nums1[i]] = 1;
}
// 遍历第二个数组,如果哈希表对应位置的值大于0,则将该元素加入交集数组,并将哈希表对应位置的值设为0
for(int i=0;i<nums2Size;i++)
{
if(Hash[nums2[i]]>0)
{
result[count++] = nums2[i];
Hash[nums2[i]] = 0;
}
}
// 将交集元素的数量赋值给returnSize指针所指向的变量
*returnSize = count;
// 返回交集数组的指针
return result;
}
202. 快乐数
题目链接/文章讲解:代码随想录
编写一个算法来判断一个数
n
是不是快乐数。「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果
n
是 快乐数 就返回true
;不是,则返回false
。
方法1:哈希表法用数组
分析及思路
首先要分析,这个数怎么样才能不是快乐数,也就是无限循环,循环的意思就是有重复值,又返回到了查表格是否有该值的操作,我们就可以想到用哈希标解决。 我们把每次的求和值存下来,直到重复是返回false,否则到1返回true。
代码及解释
// 定义一个函数,计算一个数的各个位数的平方和
int get_sum(int n) {
int sum = 0;
int number;
while(n)
{
number = n%10; // 取出个位数
sum = sum + number*number; // 计算平方和
n = n/10; // 去掉个位数
}
return sum; // 返回平方和
}
// 定义一个函数,判断一个数是否是快乐数
bool isHappy(int n) {
int hash[163] = {0}; // 定义一个数组用于记录平方和出现的次数
int sum_next = get_sum(get_sum(n)); // 计算初始数的平方和
while(sum_next!=1) // 当平方和不为1时循环
{
hash[sum_next]++; // 记录平方和出现的次数
if(hash[sum_next]>=2) // 如果平方和出现次数大于等于2,返回false
return false;
sum_next = get_sum(sum_next); // 计算下一个平方和
}
return true; // 当平方和为1时,返回true
}
卡哥的求和代码
int get_sum(int n) { // 定义一个函数,参数为整数n,返回值为整数
int sum = 0; // 初始化一个变量sum,用于存储和
div_t n_div = { .quot = n }; // 定义一个div_t类型的结构体变量n_div,初始化其quot成员为n
while (n_div.quot != 0) { // 当n_div的quot成员不为0时,执行循环
n_div = div(n_div.quot, 10); // 将n_div的quot成员除以10,更新n_div的值
sum += n_div.rem * n_div.rem; // 将n_div的rem成员的平方加到sum上
}
return sum; // 返回sum
}
方法2:双指针法
分析及思路
类似于142.环形链表II,它们在同一个表格中循环,并且它们的速度差为1,快指针总会追到慢指针,也就是他们相等时跳出循环,若没有循环则它们一定会因为都等于1退出循环,若有循环则一定会以非1退出循环,则我们在最后判断fast是否等于1即可判断它是不是快乐数。
代码及注释
// 定义一个函数,计算一个数的各个位数的平方和
int get_sum(int n) {
int sum = 0;
int number;
while(n)
{
number = n%10; // 取出个位数
sum = sum + number*number; // 计算平方和
n = n/10; // 去掉个位数
}
return sum; // 返回平方和
}
// 定义一个函数,判断一个数是否是快乐数
bool isHappy(int n) {
int fast = get_sum(n); // 使用快慢指针法,快指针每次计算两次平方和
int slow = n; // 慢指针每次计算一次平方和
while(fast!=slow) // 当快慢指针不相等时循环
{
slow = get_sum(slow); // 慢指针计算下一个平方和
fast = get_sum(get_sum(fast)); // 快指针计算下一个平方和
}
return fast==1; // 当快指针的平方和为1时,返回true
}
1. 两数之和
题目链接/文章讲解/视频讲解:代码随想录
给定一个整数数组
nums
和一个整数目标值target
,请你在该数组中找出 和为目标值target
的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
分析及思路
目标数是由两个数组成的,当我们拿到一个数时实际上时在查找另一个数,此时我们又可以转换为哈希表查值。我们在使用到一个值时在表中查找它的另一半,若没有则记录该值的下标及值,若有直接返回两个下标。
代码及注释
typedef struct { // 定义一个结构体
int key; // 键
int value; // 值
UT_hash_handle hh; // 使这个结构体可哈希化
} map; // 结构体类型为map
map* hashMap = NULL; // 定义一个hashMap指针,初始值为空
void hashMapAdd(int key, int value){ // 定义一个函数,向哈希表中添加键值对
map* s; // 定义一个map类型的指针s
// key already in the hash?
HASH_FIND_INT(hashMap, &key, s); // 在哈希表中查找是否已经存在这个键
if(s == NULL){ // 如果没有找到
s = (map*)malloc(sizeof(map)); // 分配内存给s
s -> key = key; // 给s的key赋值
HASH_ADD_INT(hashMap, key, s); // 将s添加到哈希表中
}
s -> value = value; // 给s的value赋值
}
map* hashMapFind(int key){ // 定义一个函数,根据键查找值
map* s; // 定义一个map类型的指针s
// *s: output pointer
HASH_FIND_INT(hashMap, &key, s); // 在哈希表中查找键对应的值
return s; // 返回值
}
void hashMapCleanup(){ // 定义一个函数,清理哈希表
map* cur, *tmp; // 定义两个map类型的指针cur和tmp
HASH_ITER(hh, hashMap, cur, tmp){ // 遍历哈希表
HASH_DEL(hashMap, cur); // 从哈希表中删除cur
free(cur); // 释放cur的内存
}
}
void hashPrint(){ // 定义一个函数,打印哈希表
map* s; // 定义一个map类型的指针s
for(s = hashMap; s != NULL; s=(map*)(s -> hh.next)){ // 遍历哈希表
printf("key %d, value %d\n", s -> key, s -> value); // 打印键和值
}
}
int* twoSum(int* nums, int numsSize, int target, int* returnSize){ // 定义一个函数,找到数组中两个数的和等于目标值的下标
int i, *ans; // 定义整型变量i和指针ans
// hash find result
map* hashMapRes; // 定义一个map类型的指针hashMapRes
hashMap = NULL; // 初始化哈希表为空
ans = malloc(sizeof(int) * 2); // 分配内存给ans
for(i=0;i<numsSize;i++){ // 遍历数组
hashMapRes = hashMapFind(target - nums[i]); // 在哈希表中查找目标值与当前值的差值
if(hashMapRes){ // 如果找到
ans[0] = i; // 第一个下标为i
ans[1] = hashMapRes -> value ; // 第二个下标为hashMapRes的value
*returnSize = 2; // 返回的大小为2
return ans; // 返回结果
}
hashMapAdd(nums[i],i); // 将当前值和下标添加到哈希表中
}
hashMapCleanup(); // 清理哈希表
return NULL; // 返回空
}
卡哥代码
typedef struct {
int key; // 键
int value; // 值
UT_hash_handle hh; // 使该结构体可哈希化
} map; // 定义map结构体类型
map* hashMap = NULL; // 哈希表指针初始化为空
void hashMapAdd(int key, int value){ // 添加键值对到哈希表
map* s; // 定义map指针s
// 键是否已经存在于哈希表中?
HASH_FIND_INT(hashMap, &key, s); // 在哈希表中查找键为key的元素
if(s == NULL){ // 如果键不存在
s = (map*)malloc(sizeof(map)); // 分配内存空间
s -> key = key; // 设置键
HASH_ADD_INT(hashMap, key, s); // 将元素添加到哈希表中
}
s -> value = value; // 设置值
}
map* hashMapFind(int key){ // 在哈希表中查找键对应的值
map* s; // 定义map指针s
// *s: 输出指针
HASH_FIND_INT(hashMap, &key, s); // 在哈希表中查找键为key的元素
return s; // 返回查找结果
}
void hashMapCleanup(){ // 清理哈希表
map* cur, *tmp; // 定义map指针cur和tmp
HASH_ITER(hh, hashMap, cur, tmp){ // 遍历哈希表
HASH_DEL(hashMap, cur); // 从哈希表中删除当前元素
free(cur); // 释放内存空间
}
}
void hashPrint(){ // 打印哈希表内容
map* s; // 定义map指针s
for(s = hashMap; s != NULL; s=(map*)(s -> hh.next)){ // 遍历哈希表
printf("key %d, value %d\n", s -> key, s -> value); // 打印键值对
}
}
int* twoSum(int* nums, int numsSize, int target, int* returnSize){ // 寻找两数之和
int i, *ans; // 定义整型变量i和整型指针ans
// 哈希表查找结果
map* hashMapRes; // 定义map指针hashMapRes
hashMap = NULL; // 初始化哈希表为空
ans = malloc(sizeof(int) * 2); // 分配内存空间
for(i = 0; i < numsSize; i++){ // 遍历数组
// 键代表 nums[i] 的值,值代表所在 index;
hashMapAdd(nums[i], i); // 将nums[i]和其下标添加到哈希表中
}
hashPrint(); // 打印哈希表内容
for(i = 0; i < numsSize; i++){ // 再次遍历数组
hashMapRes = hashMapFind(target - nums[i]); // 在哈希表中查找target - nums[i]对应的值
if(hashMapRes && hashMapRes -> value != i){ // 如果找到且不是同一个元素
ans[0] = i; // 设置结果数组的第一个值
ans[1] = hashMapRes -> value ; // 设置结果数组的第二个值
*returnSize = 2; // 设置返回数组的大小为2
return ans; // 返回结果数组
}
}
hashMapCleanup(); // 清理哈希表
return NULL; // 返回空指针
}
总结:
若遇到查表格的问题可以直接想到哈希算法,若是循环类的问题可以使用快慢指针。