代码随想录算法训练营第六天| 242.有效的字母异位词 、 349. 两个数组的交集 、202. 快乐数 、 1. 两数之和

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;  // 返回空指针
}

总结:

若遇到查表格的问题可以直接想到哈希算法,若是循环类的问题可以使用快慢指针。

  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值